Developer Foundations β The Basics the Architect Exam Assumes
The Architect exam never asks you to define a token or a system prompt, but nearly every structured-output, tool and reliability question assumes you know them cold. This page is that layer, drawn from the Developer (CCDV-F) guide's LLM fundamentals, Claude API mechanics, prompt engineering, output handling and tool implementation topics. Each section is short and ends with links into the deeper pages.
π¬ is agentic implementation always has loop or even without loop is considered agentic? For example the user uploads an invoice and it get populated into db with just a single tool_use and llm call and multi turn like refund which happens in a loop
Answer
The short answer is that a loop is necessary but not sufficient. What makes a system agentic is who decides the next step. If the model chooses which tool to call next and when to stop, it is agentic. If your code fixes the path in advance, it is a workflow, even if a tool call is involved.
Beyond the focus section. Section 1 covers how a single call produces tokens. It doesn't define "agentic." The answer below uses general knowledge and Anthropic's published workflow-vs-agent distinction. It links back to Section 1 where it can.
The mental model
Section 1 says the model writes its answer "one token at a time" and that "the API is stateless: send the history every time." Put those together:
One call = the model reads the context window and emits tokens. A tool_use block is also just emitted tokens. It is a request, and your code performs the action.
The agentic loop = your code runs the requested tool and appends the tool_result to the messages array. It then calls the model again, and repeats while stop_reason is "tool_use". It stops when the model returns stop_reason: "end_turn".
The loop is the mechanism. Agency is the model controlling the loop: how many turns it takes, which tool it calls, in what order, and when it is done.
Your two examples
Invoice β DB
Refund
Shape
One call, often with tool_choice: {"type":"tool","name":"record_invoice"}
Repeated calls until end_turn
Who picks the path?
Your code. The tool is used as a schema for structured output.
The model: look up the order β check the policy β issue the refund or escalate
Number of steps
Fixed (1)
Unknown in advance, decided at runtime
Classification
Workflow (structured-output extraction)
Agent
Main risk
Content errors: a schema-valid invoice with a made-up vendor
Wrong actions or wrong ordering, so you need hooks and escalation rules
So the invoice pipeline is not agentic. It is a single LLM call with a forced tool acting as a JSON schema, and your code does the DB write. Section 1's recall question applies directly here: if the document has no vendor, the model will still produce a plausible one. That is why this design needs validation, not a loop.
The traps the exam sets
"Multi-turn = agentic." No. A chatbot that goes back and forth with a user over many turns but has no tools is not agentic. The agentic loop is several model calls within one user request, driven by stop_reason.
"Uses a tool = agentic." No. Forced tool_choice for extraction is structured output. The model has no choice to make.
"More autonomy is better." For a fixed, predictable task like invoice ingestion, the correct answer is the simplest design that works, which is a workflow. Choosing an agent there is over-engineering, and the exam treats it as a distractor.
Ending the loop. Exit on stop_reason: "end_turn". Don't exit by parsing the text for "done." Also cap iterations as a safety net.
A gray area: if the invoice call offers optional tools with tool_choice: auto and the model decides whether to call one, that is a single loop iteration where the model had a choice. That leans agentic, but it is a weak case. The exam cares about the clear endpoints.
Memory hook
Code picks the path β workflow. Model picks the path β agent. The loop is just how the model gets to keep picking.
The same messages array mechanics from Section 1 (stateless, resend everything) are why each loop iteration costs more input tokens than the one before. That cost is a real reason to prefer a workflow when the path is known.
The two designs fail in different ways. A workflow fails on content: a fluent answer that is wrong, caught by validation. An agent fails on actions: the wrong step or the wrong order, caught by hooks and escalation. Getting the pattern right tells you which safeguards you need.
βββββββββββββββββββββββββββββββββββββββββββββββββ
2 Β· Where every instruction lives in one request
The single most useful picture for structured-output questions: each kind of instruction has exactly one home, and each home has a different strength.
A. With a tool (the argument shape is enforced):
JSON
{
"model": "claude-β¦",
"max_tokens": 1024,
"system": "You extract invoice fields. If a field is not stated in the document, return null.",
"messages": [
{ "role": "user", "content": "<document>β¦invoice textβ¦</document> Extract the fields." }
],
"tools": [
{
"name": "record_invoice",
"description": "Record the extracted invoice. Use once per document.",
"input_schema": {
"type": "object",
"properties": {
"vendor": { "type": ["string", "null"] },
"total_cents": { "type": "integer" }
},
"required": ["vendor", "total_cents"],
"additionalProperties": false
},
"strict": true
}
],
"tool_choice": { "type": "tool", "name": "record_invoice" }
}
Not supplied in this example β defaults and disabled features
This fragment or unpacked request variable does not prove a field is omitted. Inspect the complete enclosing request; do not infer defaults from missing lines.
Switch either block to Tree to open one level at a time. Each numbered home below is one top-level key.
Home
What it does
Strength
β system
Standing rules: role, extraction rules, when to use null, few-shot examples
Guidance (probabilistic)
β‘ messages
This turn's task and data; for multi-turn, the whole history
The input
β’ tools[].input_schema + strict
The shape of a tool call's arguments
Enforced shape, not truth
β£ tool_choice
Whether a tool call happens at all: auto, any, or one forced tool
Enforced call
β€ output_config.format
The shape of the final text answer when you don't need a tool
Enforced shape, not truth
β₯ Your code, after the response
Business rules: totals sum, fields consistent; retry with the error
Checked truth
Where does "return null when the vendor isn't stated" go, and why isn't that enough on its own?
The instruction goes in system, and the schema must allow null (β’ or β€). Instruction without a nullable field leaves nowhere legal to put "missing"; a nullable field without the instruction leaves the model unsure when to use it.
π¬ tool_choice has type:'tool' what other options the type has? it is a tool_choice obviously it is a tool, so why type?
Answer
tool_choice is not a tool. It's the policy for whether Claude calls a tool (home β£ in the table: "Whether a tool call happens at all"). type names which policy you picked. Read "type": "tool" as "the mode is: force one specific tool."
The mental model: type picks the mode
tool_choice is a tagged union: one object that can take several shapes. type is the tag that says which shape you sent. Only one mode needs extra fields, and that's why a tag is required.
type
Meaning
Extra fields
Where it comes from
"auto"
Claude decides whether to call a tool or answer in text
none
Focus section
"any"
Claude must call a tool, but it chooses which one
none
Focus section
"tool"
Claude must call this tool
name (required)
Focus section
"none"
Claude must not call any tool, even though tools are defined
none
Beyond the section (general API knowledge)
This is why a plain string wouldn't work. "tool" alone doesn't say which tool. The object form lets it carry name:
Beyond the section (general API knowledge): the same object can also carry "disable_parallel_tool_use": true. It can't be a bare string because it holds more than one setting.
The traps the exam sets
any vs tool. Both force a call. any means "some tool, you pick." tool + name means "exactly this one." For single-schema extraction like the invoice example, the answer is { "type": "tool", "name": "record_invoice" }. Using any with several tools defined leaves Claude free to pick the wrong schema.
Forcing a call is not the same as forcing correct content. β£ guarantees a call happens. β’ (input_schema + strict) guarantees its shape. Neither guarantees truth. Only β₯, your code after the response, checks that. If a question offers "force tool_choice" as the fix for wrong totals, it's a distractor.
β£ vs β€. If you want structured JSON and don't need a tool, use output_config.format. Don't build a fake tool and force it with tool_choice. Both are valid, but the section's framing (option B, "Without a tool") marks β€ as the direct home for the final answer's shape.
Beyond the section: extended thinking. With extended thinking on, only auto and none are supported. Forcing with any or tool errors. This is a classic "why did my request fail" item.
A tagged union makes invalid combinations easy to reject. name is only legal when type is "tool", so the API can validate the object's shape before the model sees anything.
The name of the field (tool_choice) says what topic the object is about. type says which option you chose within it. Keep those separate and every type in the API reads the same way.
βββββββββββββββββββββββββββββββββββββββββββββββββ
Memory hook:tool_choice is the policy, type is the mode: auto = may, any = must (any tool), tool = must (this one, add name), none = mustn't.
π¬ In the tool input schema each property does it also have a description, and if it does then does the description help model to behave in certain way, like providing addition instruction about the property?
Answer
Yes. Every property in input_schema can have its own "description", and Claude reads it. It guides the model but is not enforced. The focus section's example leaves property descriptions out. It only has a tool-level "description": "Record the extracted invoice. Use once per document." So most of what follows comes from general knowledge of the API and is labeled that way.
The mental model
Split the schema into two layers:
Part of the schema
Example
Strength
Structural keywords: type, required, enum, additionalProperties, with "strict": true
"type": ["string", "null"]
Enforced shape. The section's β’ calls this "Enforced shape, not truth".
description text (tool-level or per-property)
"description": "Grand total in integer cents, e.g. $12.50 β 1250. Tax included."
Guidance (probabilistic). It has the same strength as β system, even though it sits inside β’.
(Beyond the section:) Here is a property with a description:
JSON
"total_cents": {
"type": "integer",
"description": "Invoice grand total in cents, including tax. Convert $12.50 to 1250. Never include currency symbols."
},
"vendor": {
"type": ["string", "null"],
"description": "Legal name of the seller as printed. null if no seller is named. Do not guess from the email domain."
}
The model uses that text to decide what value goes in the field: units, format, how to tell apart look-alike fields, and when to use null. Anthropic's tool-use guidance treats detailed descriptions (for the tool and its parameters) as the biggest lever on how well tools get called.
The trap the exam sets
"The description says cents, so the value is guaranteed to be in cents." Wrong. strict guarantees that total_centsis an integer. It does not guarantee the integer is correct. A value in dollars, like 12, is still a valid integer. Checking the truth belongs to β₯: "Your code, after the responseβ¦ Checked truth."
"Putting the rule in a description makes it enforced." Wrong. An instruction doesn't become enforced just because it sits inside the schema. Only the structural keywords are enforced.
The recall-check pairing still applies. The section says the null rule needs both an instruction and a nullable type. (Beyond the section:) A property description is a valid second place for the "when to use null" instruction, and it sits right next to the field. The type still has to allow null (["string", "null"]), or there's no legal way to express "missing".
(Beyond the section, worth knowing:) Structured outputs don't support every JSON Schema constraint. Examples include numeric bounds and string-length limits. Anthropic's SDK helpers handle this by removing the unsupported keywords and moving them into the description. That downgrades them from enforced to guidance. It's the same pattern again: you still need to validate them in your own code.
Contrast the exam may force
Tool description tells the model whether and when to call the tool. With tool_choice: auto or any, it drives which tool gets picked. With a forced tool, as in the section's example, the choice has already been made.
Property description tells the model what to put in each argument.
system holds rules that apply to the whole task (role, extraction policy, few-shot examples).
The same logic applies to β€ output_config.format.schema. Descriptions there also guide what fills each field of the final answer.
Memory hook:Keywords are the fence, descriptions are the signpost, and your code is the inspector.
The section says each instruction has "exactly one home." description is the one place where that gets blurry. It sits in the enforced part of the request (β’) but only guides, like β . Sorting a request by strength (guides, enforces, or checks), not by location, answers most structured-output questions on the exam.
A strong distractor is "add a clearer description" when the actual failure is a wrong type or a missing null option. Those are fixed with schema keywords. The reverse is also true: a wrong-but-valid value (dollars instead of cents) is fixed with a description, few-shot examples, and validation in β₯ followed by a retry.
βββββββββββββββββββββββββββββββββββββββββββββββββ
2b Β· system and content: string or array?
Same rule for both: a string is shorthand for one text block. Use the array of blocks form only when you need something the shorthand cannot express. The model reads both forms the same way; choosing the array does not make instructions stronger.
1 Β· system as a string (the default):
JSON
{
"system": "You extract invoice fields. If a field is not stated in the document, return null."
}
2 Β· system as an array of text blocks: the same instructions split so the long, stable part can be cached while a short per-request part varies:
{
"messages": [
{ "role": "user", "content": "Extract the fields from the invoice below." },
{
"role": "user",
"content": [
{ "type": "document", "source": { "type": "base64", "media_type": "application/pdf", "data": "β¦" } },
{ "type": "text", "text": "Extract the fields from this invoice." }
]
}
]
}
The first message is a string (one text block). The second needs an array because it carries a document block next to the text. Tool turns always use arrays: the assistant's tool_use blocks and your tool_result blocks cannot be written as a string.
You needβ¦
system
messages[].content
Plain text, one part
string
string
Cache only the stable part
array of text blocks + cache_control
array + cache_control on a block
An image or PDF
not allowed in system
array: image / document block + text
Send a tool result
β
array: tool_result block(s)
Replay the model's tool request
β
the assistant's array, unchanged, including tool_use
Is an instruction in a system array block "stronger" than the same text as a string?
No. Both forms become the same text for the model. The array exists for structure: several parts, a per-part setting such as cache_control, or (in content) non-text blocks. Pick the string unless you need one of those.
Few-shot vs prefill: few-shot shows finished examples. Prefill starts the answer for the model (for example, a trailing {). Prefill only nudges; it can't be combined with extended thinking and isn't supported on the newest models. For guaranteed JSON, use β’ or β€.