A\
Lessons/Domain 2
2.312 min

Distribute tools appropriately across agents and configure tool choice

How you spread tools across agents and how you constrain the model's tool decision are two of the highest-leverage reliability knobs in an agentic system. Give a single agent too many tools, or tools outside its job, and selection quality collapses. Scope each agent to a tight set that matches its role, add only the narrow cross-role tools it needs for high-frequency cases, and use tool_choice to guarantee the model calls a tool (or a specific tool) when the workflow demands it.

Scoped tool distribution across subagentsCoordinator (holds Task tool)Web Search agenttools:web_searchload_documentload_document validates the URLDocument Analysis agenttools:read_documentextract_data4-5 tools, role-scopedSynthesis agenttools:write_reportverify_fact (scoped cross-role)handles the simple 85% inlinecomplex 15% -> back through coordinatorAnti-patternGiving every agent all ~18 tools degrades selection and invites cross-specialization misuse(e.g., the synthesis agent running open-ended web searches instead of synthesizing).tool_choice (per Messages API request):auto = may return text | any = must call some tool | {type:tool,name} = must call that toolForced choice governs only the first call; enforce a sequence with follow-up turns.
Scoped tool distribution in a multi-agent research system: each subagent gets only its role's tools, the synthesis agent gets one narrow cross-role verify_fact tool, and complex cases route back through the coordinator.

More tools means worse selection

Every tool you expose to an agent is another branch the model must weigh on each turn. Selection reliability degrades as the option count grows: an agent handed roughly 18 tools makes noticeably worse choices than one scoped to the 4-5 it actually needs. The decision space widens, similar-sounding tools compete, and the model misroutes.

The fix is not a smarter router bolted on top of the model. It is reducing the number of options the model has to reason about in the first place. Treat 4-5 relevant tools per agent as a working guideline, and be suspicious of any single agent that accumulates a large, general-purpose tool registry 'for flexibility.'

This is why multi-agent designs partition tools: each subagent sees only its slice. The coordinator, not any individual worker, holds the overall picture and decides who to invoke.

Scope tools to the agent's role

Agents given tools outside their specialization tend to misuse them. A synthesis agent whose job is to combine findings, if handed a full web-search toolset, will start running searches instead of synthesizing, blurring the separation of concerns the architecture depends on. The tool being available is itself the temptation.

Restrict each subagent's tool set to what its role requires. A web-search agent gets search and document-loading tools; a document-analysis agent gets extraction and reading tools; a synthesis agent gets report-writing tools. In the Claude Agent SDK you express this per subagent through its AgentDefinition, whose tools field lists exactly the tools that agent may call. Claude Code exposes the same idea through allowedTools / disallowedTools.

Scoping is a correctness mechanism, not just tidiness: it makes cross-specialization misuse structurally impossible rather than merely discouraged by the prompt.

Scoped cross-role tools for high-frequency needs

Strict scoping can create latency if an agent constantly needs one small capability owned by another agent. In a research system, a synthesis agent frequently needs to verify a date, name, or statistic while combining findings. Routing every check back through the coordinator to the web-search agent adds round trips and can inflate latency substantially.

The right answer is a narrow, purpose-built cross-role tool, not full access to the other agent's toolbox. Give the synthesis agent a scoped verify_fact tool that handles the common simple case (the 85% of checks that are quick lookups), while genuinely complex investigations still delegate back through the coordinator to the search specialist.

This is the principle of least privilege applied to agents: grant the minimum extra capability that removes the bottleneck, and keep the escalation path for the hard cases. Handing the synthesis agent the entire web-search toolset to 'save round trips' over-provisions it and reintroduces the misuse problem you scoped away.

Prefer constrained tools over generic ones

A generic tool invites generic (and unsafe) use. A fetch_url tool that will retrieve any URL lets an agent wander onto arbitrary pages; the model has no built-in sense of what a valid target is. Replacing it with a constrained load_document tool that validates the URL is a document source narrows both the surface area and the failure modes.

Constraining the tool is often better than adding a prompt instruction telling the agent not to misuse the generic tool, because the constraint is enforced in code rather than probabilistically obeyed. The tool's contract does the work.

This pairs with tool-description quality (task 2.1): a tightly scoped tool with a precise description is far easier for the model to select correctly than a broad tool whose description has to enumerate everything it might do.

tool_choice: auto, any, and forced

tool_choice is a Messages API request parameter that controls whether and which tool the model must use on that request. There are three behaviors to know cold:

  • {"type": "auto"} (the default when tools are provided): the model decides whether to call a tool or reply with plain text. It may return conversational text and skip tools entirely.
  • {"type": "any"}: the model must call one of the provided tools, but chooses which. It cannot return a text-only answer. Use this when you need to guarantee a tool call, for example to force structured output instead of prose.
  • {"type": "tool", "name": "extract_metadata"}: forced selection. The model must call that specific named tool.
{
  "model": "claude-sonnet-4-5",
  "tools": [ ... ],
  "tool_choice": {"type": "tool", "name": "extract_metadata"}
}

A useful related flag is disable_parallel_tool_use: true, which restricts the model to a single tool call. Note that forcing a tool (any or a specific tool) is not compatible with extended thinking.

Two distinct levers, and forcing a sequence needs turns

Keep two mechanisms separate in your head. Tool distribution decides which tools an agent has (set once via AgentDefinition.tools or allowedTools). tool_choice decides what the model must do with the tools it has on a single request. They solve different problems: distribution prevents misuse and improves selection; tool_choice guarantees behavior on a given call.

Forced selection only governs the first tool call. You cannot express 'call extract_metadata, then call enrich, then finish' in one tool_choice. To enforce an order, force the first tool on the first request, take its result, and then make a follow-up request (often with tool_choice: auto) for the subsequent steps. Trying to encode a multi-step pipeline into a single forced tool_choice is a category error.

So the pattern for 'run extract_metadata before any enrichment tool' is: request 1 forces extract_metadata; you execute it and return the result; request 2 lets the model proceed with enrichment.

Anti-patterns to avoid

avoid
Giving every agent access to the full tool registry 'for flexibility' (e.g., all ~18 tools).

Why it fails: Selection reliability degrades as the option count grows. The model misroutes among similar tools and uses tools outside its role.

instead Scope each agent to the 4-5 tools its role needs via AgentDefinition.tools / allowedTools. Let the coordinator hold the full picture.

avoid
Giving a synthesis agent the entire web-search toolset so it can verify facts without round trips.

Why it fails: Over-provisioning reintroduces cross-specialization misuse: the synthesis agent starts doing search work, breaking separation of concerns.

instead Add one narrow verify_fact tool for the common simple checks (the ~85% case), and keep complex verifications routed through the coordinator to the search specialist.

avoid
Trying to force an ordered multi-tool sequence in a single request via tool_choice.

Why it fails: Forced tool_choice only guarantees the first/one tool call; it cannot express 'A then B then C' in one turn.

instead Force the first tool (e.g., extract_metadata), execute it, then make a follow-up request for the remaining steps.

avoid
Leaving tool_choice on auto when the workflow must produce a tool call (e.g., a schema-based extraction).

Why it fails: With auto the model may return conversational text and skip the tool, so downstream parsing gets prose instead of structured data.

instead Set tool_choice: any to guarantee some tool is called, or force the specific extraction tool by name.

Worked example: Multi-agent research system: cutting synthesis round trips without over-provisioning

You run the Scenario 3 research system: a coordinator delegates to a web-search agent, a document-analysis agent, and a synthesis agent. Testing shows the synthesis agent constantly needs to check a fact (a date, a name, a statistic) while combining findings. Today it hands control back to the coordinator, which invokes the web-search agent, then re-invokes synthesis with the result. That adds 2-3 round trips per task and pushes latency up ~40%. Your evals show 85% of these are simple fact lookups; 15% need deeper investigation.

Wrong turn 1 — give the synthesis agent the full web-search toolset so it can verify anything itself. This kills the round trips but violates least privilege: the synthesis agent now has 15+ tools and starts running open-ended searches instead of synthesizing. Selection quality drops and separation of concerns is gone.

Wrong turn 2 — batch all verification needs and send them to search at the end. Synthesis steps often depend on an earlier verified fact, so batching creates blocking dependencies and can produce a report built on an unverified claim.

The scoped fix — give the synthesis agent one narrow verify_fact tool for the simple 85%, and keep the coordinator path for the complex 15%:

synthesis_agent = AgentDefinition(
    description="Combines findings from other agents into a cited report.",
    prompt=SYNTHESIS_SYSTEM_PROMPT,
    # Scoped: report-writing plus ONE narrow cross-role tool.
    tools=["write_report", "verify_fact"],
)

web_search_agent = AgentDefinition(
    description="Runs web research and loads document sources.",
    prompt=SEARCH_SYSTEM_PROMPT,
    tools=["web_search", "load_document"],  # load_document validates the URL is a doc source
)

verify_fact handles the quick lookups inline; anything ambiguous or requiring real investigation still delegates through the coordinator to web_search. You get the latency win for the common case and preserve reliability for the hard case.

Where tool_choice fits. In the document-analysis step you want metadata extracted before any enrichment tool runs. On the first request set tool_choice: {"type": "tool", "name": "extract_metadata"} to guarantee that runs first; execute it, return the result, then issue a follow-up request (with tool_choice: auto or any) so the model proceeds to enrichment. If you instead need to guarantee the extraction agent never replies in prose, set tool_choice: any.

Exam tips

  • Roughly 4-5 tools per agent is the working guideline; around 18 tools significantly degrades selection reliability. The fix is scoping, not a bolt-on router.
  • tool_choice auto = model may return text; any = must call some tool (model picks); {"type":"tool","name":...} = must call that specific tool.
  • Forced tool_choice only guarantees the FIRST tool call. Enforce ordered sequences with follow-up turns, not one request.
  • A synthesis agent needing frequent simple checks should get one scoped verify_fact tool, NOT the full web-search toolset; complex cases route through the coordinator.
  • Distribution (which tools an agent has, via AgentDefinition.tools / allowedTools) and tool_choice (what the model must do per request) are separate levers; tool_choice is a Messages API parameter.
  • Replace a generic fetch_url with a constrained load_document that validates the URL, so misuse is prevented in code rather than by a prompt instruction.
Official exam objectives for 2.3
Knowledge of
  • The principle that giving an agent access to too many tools (e.g., 18 instead of 4-5) degrades tool selection reliability by increasing decision complexity
  • Why agents with tools outside their specialization tend to misuse them (e.g., a synthesis agent attempting web searches)
  • Scoped tool access: giving agents only the tools needed for their role, with limited cross-role tools for specific high-frequency needs
  • tool_choice configuration options: "auto", "any", and forced tool selection ({"type": "tool", "name": "..."})
Skills in
  • Restricting each subagent's tool set to those relevant to its role, preventing cross-specialization misuse
  • Replacing generic tools with constrained alternatives (e.g., replacing fetch_url with load_document that validates document URLs)
  • Providing scoped cross-role tools for high-frequency needs (e.g., a verify_fact tool for the synthesis agent) while routing complex cases through the coordinator
  • Using tool_choice forced selection to ensure a specific tool is called first (e.g., forcing extract_metadata before enrichment tools), then processing subsequent steps in follow-up turns
  • Setting tool_choice: "any" to guarantee the model calls a tool rather than returning conversational text

Flashcards from this lesson

Roughly how many tools per agent before selection reliability starts to break down?

Aim for about 4-5 tools per agent. Around 18 tools significantly degrades selection because the model must weigh too many similar options.

Difference between tool_choice: "any" and forced tool selection?

any = the model must call one of the tools but chooses which (no text-only reply). Forced {"type":"tool","name":"X"} = the model must call that specific named tool.

A synthesis agent constantly needs simple fact checks and it is adding latency. Best fix?

Give it one narrow, scoped verify_fact tool for the common simple checks (~85%), and keep complex verifications routed through the coordinator to the search agent. Do not hand it the full web-search toolset.

Can tool_choice force an ordered sequence like 'call A, then B' in one request?

No. Forced tool_choice only guarantees the first/one tool call. Enforce ordering by forcing the first tool, executing it, then issuing a follow-up request for later steps.

When should you set tool_choice: "any"?

When you must guarantee the model calls a tool rather than returning conversational text, e.g., to force schema-based structured output when the exact tool can vary.

In the Agent SDK, how do you restrict which tools a subagent can use?

Via the tools field of that subagent's AgentDefinition (Claude Code uses allowedTools / disallowedTools). This is separate from tool_choice, which is a per-request Messages API parameter.

Why replace a generic fetch_url with a constrained load_document?

The constrained tool validates that the URL is a document source, preventing misuse in code rather than relying on a prompt instruction the model may not obey.

Study all flashcards with spaced repetition