Agents & Tools Interview Prep

Course Content

Agents & Tools Interview Prep

6 sections · 40 lessons

What is the purpose of the tool_choice parameter, and how do you use it?


Same four modes, two APIsautoautonormal agent turnsanyrequiredroutermust dispatchtype tool, nametype function, nameforced extractionnonenonefinal answer turnAnthropicOpenAIUse it forModel decidesMust call oneMust call thisNo toolsSome newest models reject the two forced modes; use auto, strict, and a prompt instruction.
Forcing is for single decisions; leave it on for a whole conversation and the agent can never simply answer.

What you need to know

The modes

AnthropicOpenAIBehaviourTypical use
{"type": "auto"}"auto"Model chooses text or toolsNormal agent turns
{"type": "any"}"required"Must call at least one toolA router that must always dispatch
{"type": "tool", "name": "x"}{"type": "function", "name": "x"}Must call tool xForced structured extraction
{"type": "none"}"none"Tools visible but not callableFinal "write the answer" turn

OpenAI also offers {"type": "allowed_tools", ...} to limit the model to a subset of the declared tools for one turn.

Parallel calls are a separate switch

By default, a model may return several tool calls in one turn. To limit it to at most one:

  • Anthropic: add "disable_parallel_tool_use": true inside tool_choice.
  • OpenAI: set parallel_tool_calls: false on the request.

Use this when your tools are not safe to run together — for example two writes to the same booking.

Forced tool use and the newest models

As of 2026, some of the newest Claude models (for example Claude Opus 5.5) reject any and named-tool tool_choice with a 400 error. On those models:

  • Use auto and say plainly in the prompt which tool to call.
  • Keep strict: true on the tool so arguments stay schema-valid.
  • If you forced a tool only to get JSON back, use structured outputs (output_config.format) instead.
  • Check that a call was actually made, and retry once if not.

This is a good example of why the model name belongs in config and the harness should not assume every model supports every option.

Python
def call_router(messages):    resp = llm.call(messages, ROUTE_TOOLS,                    tool_choice=llm.force_any_or_auto())  # "any" if the model supports it    calls = [b for b in resp.content if b.type == "tool_use"]    if not calls:        raise NoRouteChosen(resp)   # retry once, then fall back to a default route    return calls[0]

force_any_or_auto() lives in the llm wrapper, next to the model name, so a model upgrade changes one file.

A real-life example

A GitHub triage bot uses tool choice at three points:

  1. Routing — every new issue must be classified as bug, feature, question or spam. The classifier turn uses a single classify_issue tool with an enum, forced (on a model that supports forcing) so the output is always a structured label.
  2. Investigation — normal agent turns with auto, so the model can search issues, read CI logs or ask for more information.
  3. Final comment — after 6 investigation steps, the harness sends one last turn with tool_choice: none, forcing the model to write the comment from what it has instead of starting another search.

When the team tried a newer model for step 1, requests failed with a 400. They switched that route to auto with "Call classify_issue exactly once" in the prompt, kept strict: true, and added a check-and-retry. Classification accuracy stayed the same.

Follow-up questions to expect

  • "Why not force a tool on every turn?" — Then the model can never answer in text or ask a clarifying question, so the conversation cannot end naturally.
  • "How do you get guaranteed JSON without tool choice?" — Structured outputs: pass a JSON Schema as the response format; the reply itself is constrained to it.
  • "Does forcing a tool affect quality?" — Forcing can skip the model's usual reasoning text before the call; for hard decisions, keep auto and guide it in the prompt.