CONCEPT · 55 minutes
Learn to wire real tools into the support-request agent using the Anthropic SDK tool-use API, and understand why shared tool context beats isolated parallel calls.
When I first wired a knowledge-base search into the support-request agent I was building, I made a mistake that took a full day to diagnose. The tool call worked — the KB search returned results — but the agent's final response was worse than before I added the tool.
The issue wasn't the tool itself. It was context contamination. I was feeding raw KB results directly into the next prompt without controlling how the model would interpret them. The agent started treating KB articles as authoritative instructions rather than reference material, and its responses drifted sideways. I had added a capability without understanding what would land in the shared conversation context as a result.
That failure taught me the real lesson behind tool orchestration: it is not about how many tools you wire up, or how cleverly you route between them. It is about what lands in the shared context after each tool call, and whether the model can reason clearly from that accumulated picture.
This is the anti-multi-agent thesis at the tool level. Parallel tool calls that write to isolated contexts fail for the same reason parallel agents fail — each call makes assumptions the others cannot see. A sequential tool-use pattern where each result is appended to the shared conversation history is almost always more reliable, even when it is slower.
Think of tools like power outlets in a workshop. The outlet does not care what you plug in, but what you plug in determines everything about the work. One well-placed outlet powering the right tool beats six outlets wired to the wrong things.
Key insight: The tool-use API does not just add capabilities — it controls what information lands in the conversation context. How you structure tool results shapes everything the model knows next.
Before wiring tools into the support agent, I want to show you the actual API shape, because the mental model matters as much as the code. The Anthropic SDK tool-use flow has three steps.
Each step is a separate API call, and each call extends the shared messages list. The model never calls your function directly — it issues a structured request for you to call it, and you feed the result back as a message. This design is deliberate: the model's only contact with the outside world is through the messages it sends and receives. Everything it knows about what the tool returned is in that list.
First, you send a message with tool definitions attached. Second, the model replies with a tool_use block that names the tool and provides its inputs. Third, you call the real function, then send the result back as a tool_result block. The model finishes with a plain text response on the next call.
The critical thing to internalize is step three: you are always the one running the function. The model never has direct access to your code or your infrastructure. It produces a structured request; you execute it; you return the output. That boundary is what makes tool-augmented agents inspectable — every tool call and its result is a visible message in the conversation history.
Here is the minimal baseline — a regular call without tools, to anchor the shape before we add complexity. Every more complex pattern you will see in this module is an extension of this same call:
The response object carries stop_reason, usage, and a content list. For a plain text reply, content[0] is a TextBlock and stop_reason is "end_turn". Those two values anchor everything that follows: stop_reason tells you what the model wants to do next, and content tells you what it produced this turn.
At this baseline stage the model has no external data. It reasons from its training and the messages list alone. Adding tools changes what information reaches the model, but the fundamental structure — a messages list, a stop_reason, and a content list — stays exactly the same throughout the more complex patterns ahead.
Now add a tool definition. The Anthropic SDK uses input_schema — not parameters — to describe the tool's expected inputs. This is the correct shape:
The description fields are not decorative metadata. The model reads the tool description and every property description when deciding whether to call the tool and what value to pass. A vague description produces inconsistent inputs; "Search query derived from the ticket content" anchors the model to the ticket text rather than letting it invent a free-form query.
The required array enforces intent at the API level. Marking "query" as required means the model cannot issue the call with a missing field — it will seek clarification from the user instead. That is a lightweight guardrail that lives in the tool definition, not in separate validation code downstream.
Common mistake: Using "parameters" instead of "input_schema" in tool definitions. The Anthropic SDK requires input_schema. Using parameters silently produces an unexpected-key error when the tool fires.
To send a message with the tool available, pass tools=[...] to client.messages.create. The model decides whether to call the tool based on the message content. You do not tell the model to use the tool; you tell it the tool is available and let it decide. This is what distinguishes a tool-augmented LLM from a rule-based dispatcher: the model reasons about whether a tool is relevant rather than always routing through it.
When the model does call the tool, stop_reason is "tool_use" rather than "end_turn":
When you inspect that output, you will see stop_reason tool_use and a content list containing a ToolUseBlock with a name and input. The model has decided which tool to call and what to pass to it, but it has not yet seen any result — it is waiting for you to execute the function and return the output.
The response.content list can contain more than one block. Always iterate rather than indexing at position zero; the model sometimes prepends a reasoning trace before the ToolUseBlock. Indexing directly when that preamble is present causes you to silently skip the actual tool call.
The support agent needs two tools: KB search to find relevant articles, and ticket history to see what has happened with this customer before. Having both lets the model triangulate — a known-good answer from the KB combined with whether this exact issue has surfaced before.
Notice the difference from the context-contamination failure in the introduction. There, raw KB results landed in the context without the model knowing what to make of them. Here, each tool returns a structured, labeled result appended to messages in turn order. The model sees "I searched the KB and found X; I fetched ticket history and found Y" — not a blob of undifferentiated text.
Here is the second tool definition, following the same input_schema shape:
Having both tools registered in the same call does not mean the model calls both on every turn. It calls whichever tools it judges necessary given the ticket. For a routine export error it might call KB search only; for a repeat customer with a billing dispute it will reach for ticket history first. The model self-directs from the descriptions alone — you do not route between tools explicitly.
This self-direction is why descriptions must be specific. Two broadly named tools with vague descriptions produce unpredictable selection. Two concretely described tools with distinct scopes produce deterministic selection that matches your intent without additional orchestration code.
When stop_reason == "tool_use", the model has named a tool and provided its inputs. You extract that block, call your function, then append both the model's tool_use block and your tool_result to the messages list before the next call:
The append order matters. The assistant message carrying response.content goes first, then the user message carrying the tool_result. This preserves the alternating role structure the API requires: user, assistant, user, assistant. Breaking that order — or sending the tool_result as an assistant message — produces a role-alternation error on the next call.
The tool_use_id in the tool_result block is how the model matches each result to the call that produced it. When a response contains multiple tool calls, each tool_result must carry the correct id. Supplying the wrong id or omitting it causes the model to misread which result corresponds to which call on the following turn.
Putting it together: the agent loop calls tools as needed, appending each result to shared context, until the model produces a final "end_turn" response. This is the complete pattern — no framework, no abstraction layer, just the Anthropic SDK and a messages list:
The while True loop handles the case where the model makes sequential tool calls before writing its final answer. In practice the support agent rarely needs more than two calls — one for KB search, one for ticket history — but the loop accommodates any sequence the model produces without you specifying it in advance.
The else: break catches any stop reason the code does not explicitly handle. The API currently returns "end_turn", "tool_use", "max_tokens", or "stop_sequence". The break prevents an infinite loop if an unexpected value arrives, at the cost of returning the fallback message instead of a live response.
What is working here: Each tool result is appended to messages before the next call. The model always sees the full history — what was looked up, what was found, in sequence. That is shared context, not isolated results.
Compare this to the context-contamination failure from the introduction. The original mistake was feeding raw KB results without labeling them — the model had no way to distinguish article content from conversation content. The tool_result message type makes that distinction explicit. The model knows exactly where each piece of information came from and which tool call produced it.
Pause and predict: if the KB search returns three articles and the ticket history shows the customer opened the same issue twice last month, what does the model know going into its final response?
It knows both. That is the point. The messages list accumulates everything — the original ticket, which tools were called, what they returned — and the model reasons from the complete picture. No tool's output is hidden from the reasoning that follows.
This is the tool-level expression of the path's spine. If you called both tools in parallel and merged their results before sending them, you would lose something subtle — the model cannot see which tool was called first, or why, or what question each tool was answering. Those implicit decisions get stripped out of context, and the model has to guess.
Sequential tool calls with shared context is not a performance limitation to work around. It is the architecture that works.
The latency cost of sequential calls is real but bounded — for a support ticket response, waiting an extra 500ms for a more reliable answer is the right trade. For the cases where parallel execution matters, the pattern still applies: merge results into a single context-aware message before the next model call, rather than routing separate contexts to separate model instances.
Reflective prompt: When would you limit the number of tools available? A model with ten tools must choose among ten before doing anything useful. A model with two tools focused on the problem almost always makes better, more confident tool selections — and spends fewer tokens on the decision itself.
The support agent I built settled on exactly two tools — KB search and ticket history — because adding more tools increased tool-selection uncertainty without improving response quality. The model was spending tokens deciding which of eight tools to call instead of calling the two it needed.
Two focused tools with clear descriptions and formatted results. That was the working pattern.
Context contamination: If your tool returns raw data — JSON blobs, database rows, unformatted API responses — the context fills with noise the model has to parse before it can reason. Format tool results as readable summaries. The tool's job is not just to fetch data; it is to contribute clean signal to the shared context.
Tool count matters more than most practitioners expect. The support agent I eventually settled on uses exactly two tools. Early versions used five — KB search, ticket history, customer profile, product catalog, and an escalation checker. The model spent a meaningful portion of its token budget deciding which tools to call before calling any of them. Trimming to two focused tools with clear, non-overlapping descriptions cut that overhead and produced more reliable responses.
The pattern holds across agents: start with the minimum tools the task actually requires, not the full set of tools that might conceivably help. You can always add tools later when you have evidence a specific capability is missing. Removing a tool from an already-deployed agent is much harder.
Measure token usage before and after adding a tool. If the model spends more tokens on tool-selection reasoning than it spends on the final response, that is a sign the tool set is too large or too broadly described.
The next module adds a human reviewer to this same agent: when the model's confidence is low after consulting the tools, a person steps in before the response goes out. That escalation pattern builds directly on the tool-use loop you have here — the shared context that accumulates across tool calls is exactly what the human reviewer will read.
Application-level questions on tool-use API shape, shared context, and common failure modes.
1. What value does `response.stop_reason` hold when the model wants to call a tool?
Correct Answer: B
The Anthropic SDK uses `"tool_use"` as the stop_reason when the model wants to invoke a tool. `"end_turn"` means the model produced a final text response. The other strings are not valid Anthropic stop reasons.
2. A developer writes a tool definition using `"parameters"` instead of `"input_schema"`. What is the most likely outcome?
Correct Answer: D
The Anthropic SDK requires `input_schema`. Using `parameters` is silently accepted by the API but produces an unexpected-key error when the model actually tries to fire the tool. Always use `input_schema`.
3. After calling a tool and receiving a result, what `role` should the tool_result message use?
Correct Answer: D
Tool results are sent with `role: "user"` and `content` containing a list with one object of `type: "tool_result"`. The assistant's `tool_use` block must be appended first (as `role: "assistant"`), then the tool result as `role: "user"`.
4. Why must you append the assistant's `tool_use` block to `messages` before appending the `tool_result`?
Correct Answer: B
The Anthropic API requires a `tool_use` block from the assistant to precede a matching `tool_result`. Without it, the conversation is malformed and the API rejects the request. Including both keeps the shared context coherent — the model sees what it asked for and what came back.
5. If you called KB search and ticket history in parallel and merged their results into a single message, what context would the model lose?
Correct Answer: B
When tool results are merged before sending, the model receives facts but loses the conversational thread — which question each tool was answering, what the model was thinking when it chose each tool, and the ordering of decisions. Sequential tool calls with shared context preserve this implicit reasoning trace.
6. The model returns `stop_reason == "end_turn"` on the very first call, before any tool has been invoked. What does this mean?
Correct Answer: B
A model with tools available will use them only when it judges they are needed. `end_turn` on the first response means the model produced a text answer directly. This is correct behavior — tool use is optional, not mandatory.
7. What is 'context contamination' in tool orchestration?
Correct Answer: C
Context contamination happens when tool results land in the conversation as JSON blobs, database rows, or raw API responses the model must interpret before it can use them. Formatting tool results as readable summaries reduces noise and lets the model reason more accurately from the accumulated context.
8. When should you actively limit the number of tools available to the model?
Correct Answer: C
A model choosing among ten tools spends tokens on tool-selection reasoning before doing any useful work. Two focused tools with clear descriptions almost always outperform ten loosely defined tools. The goal is to focus the model on the problem, not to maximize available capabilities.