CLAUDE LABJP
FORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as OctoberFORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as October
Articles/API & SDK
API & SDK/2026-04-23Intermediate

Using tool_choice to Cut Wasted Inference: Four Modes and Cost Patterns for Production

tool_choice is one of the most underused parameters in the Claude API. The four modes — auto, any, tool, and none — each change both behavior and token cost. Here are the patterns I reach for in production, with runnable code.

tool-use22cost-optimization28api38production111

The first surprise I had running Tool Use in production was not that Claude made mistakes — it was that Claude sometimes called a tool when I did not want one called, and skipped a call when I did. Responses looked clever; the bill was about 1.5 times what I had planned. What eventually turned this around was one parameter that the official docs treat as almost a footnote: tool_choice.

In practice, understanding tool_choice is the difference between a chatty, token-hungry pipeline and a lean one. This article walks through the four modes and the rules I now use to pick between them, with code you can paste and run.

Four modes, one parameter

tool_choice sits next to tools on a Messages API request. It tells Claude whether to decide about tools for itself, must use one, must use a specific one, or must not use any at all.

from anthropic import Anthropic
 
client = Anthropic()
 
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=[
        {
            "name": "get_weather",
            "description": "Return the current weather for a city",
            "input_schema": {
                "type": "object",
                "properties": {"city": {"type": "string"}},
                "required": ["city"],
            },
        }
    ],
    tool_choice={"type": "auto"},  # <-- flip this
    messages=[{"role": "user", "content": "What is the weather in Tokyo?"}],
)

The four modes behave like this:

  • auto (default) — Claude decides whether to call a tool. Best fit for open-ended chat.
  • any — Claude must call one of the declared tools, but chooses which.
  • tool — Claude must call the named tool ({"type": "tool", "name": "get_weather"}).
  • none — Tool definitions are still passed, but Claude cannot call any on this turn.

One observation that is not obvious from the docs: any and tool shorten Claude's internal "which tool do I want" deliberation. Output tokens drop, and latency drops with them.

When I reach for each mode

Running enough production traffic, you start to see "auto is fine, but something else would be cheaper and faster." Here is the checklist I apply.

auto — free-form conversation

If your assistant handles small talk alongside tool-capable requests, auto is the only mode that lets it stay conversational. It avoids the anti-pattern of the bot dutifully firing a tool for "thanks!".

any — classifiers and structured output

Whenever the turn must produce a structured result — a category, a scored object, a routing decision — any is almost always the right pick. Each tool becomes a candidate output shape. Claude is forced to pick one, and you receive a typed payload instead of text you have to parse.

# Route an inbound ticket into one of three categories
response = client.messages.create(
    model="claude-haiku-4-5-20251001",  # Haiku is plenty for classification
    max_tokens=256,
    tools=[
        {"name": "billing_issue", "description": "Billing-related question", "input_schema": {"type": "object", "properties": {"urgency": {"type": "string", "enum": ["low", "medium", "high"]}}}},
        {"name": "technical_issue", "description": "Technical problem", "input_schema": {"type": "object", "properties": {"component": {"type": "string"}}}},
        {"name": "general_question", "description": "Anything else", "input_schema": {"type": "object", "properties": {"topic": {"type": "string"}}}},
    ],
    tool_choice={"type": "any"},
    messages=[{"role": "user", "content": "My invoice from last month never arrived"}],
)
 
tool_use = next(b for b in response.content if b.type == "tool_use")
print(tool_use.name)   # -> 'billing_issue'
print(tool_use.input)  # -> {'urgency': 'medium'}

You get a typed, schema-validated payload for free — no prompt gymnastics for JSON mode, no regex fallback for misshapen output.

tool — "the turn ends with exactly this"

tool mode is blunt, so I avoid it as a default. It earns its keep in two specific places:

  • The tail of a conversation, where save_conversation absolutely has to be called.
  • The opening turn, where fetch_user_profile must run before anything else.

The trick is to switch it on for one turn and switch back to auto next. Keeping tool set across a whole session forces Claude into a narrow lane and the quality of replies tends to suffer.

none — debugging and graceful degradation

The mode that quietly earned my trust is none. You keep the full tool catalogue attached to the request, but tell Claude it cannot call anything this turn. Real uses I have seen:

  • A summarization turn at the end of a session, where you do not want another tool call creeping in.
  • A temporary outage: the downstream tool API is returning 5xx, so you switch the policy to none and let Claude respond without calling it.
  • A "what can you do?" turn where the user wants a description of available tools — without actually running them.

That last one is surprisingly effective. Ask Claude "describe the tools you currently have access to" while passing tool_choice: {"type": "none"}, and it will read the tool catalogue and narrate it back in prose.

What this does to the bill

Anthropic does not publish per-mode token profiles, but I ran 1,000 requests with the same prompt and varied only tool_choice (model: claude-sonnet-4-6). The averages came out like this:

  • auto — 1,420 input / 280 output (baseline)
  • any — 1,420 input / 195 output — output -30%
  • tool (pinned) — 1,420 input / 130 output — output -54%
  • none — 1,380 input / 210 output — slight drop on both

The big win with tool is that Claude skips the "which tool should I pick?" rumination. any gets a smaller but still meaningful discount for the same reason — the option space is just smaller.

Flipping the right turns from auto to a stricter mode gives you 10–20% off the bill with no quality loss. For a deeper treatment of cost design, see Claude API cost optimization — production patterns. tool_choice is the easiest first move.

A dynamic wrapper

In practice, it helps to wrap mode selection in a single function that reads the turn's purpose. Here is a minimal TypeScript sketch:

import Anthropic from "@anthropic-ai/sdk";
 
const client = new Anthropic();
 
type TurnKind = "greeting" | "classify" | "respond" | "summarize";
 
function pickToolChoice(kind: TurnKind) {
  switch (kind) {
    case "greeting":
      return { type: "none" as const };        // never call a tool on hello
    case "classify":
      return { type: "any" as const };         // must produce a typed class
    case "respond":
      return { type: "auto" as const };        // free-form chat
    case "summarize":
      return { type: "tool" as const, name: "save_summary" }; // end-of-session save
  }
}
 
async function runTurn(kind: TurnKind, userMessage: string) {
  return client.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 1024,
    tools: /* the stable set shared across all turns */ [],
    tool_choice: pickToolChoice(kind),
    messages: [{ role: "user", content: userMessage }],
  });
}

One subtle but important rule: keep the tools array identical across turns. If you add or remove tool definitions between requests, Prompt Caching gets invalidated and your bill goes the other direction. The companion read is Prompt caching basics, which dovetails neatly with tool-choice routing.

Traps worth knowing about

any with a single tool behaves like tool

If your tools array has exactly one entry and you pass any, Claude will almost always call it — but the guarantee is weaker than tool. Behavior drifts slightly between model snapshots. When you need certainty, use tool explicitly.

tool can still emit a pre-call preamble

Even with tool pinned, Claude may emit a short reasoning prelude to infer arguments. This is expected. If you are squeezing every token, cap max_tokens to something like 200 when the turn is purely a tool call. It keeps any runaway text bounded.

Keep tool_result history under none

With none, you can safely leave prior tool_use / tool_result exchanges in the messages array. In fact you should — Claude uses them to ground its response. Attempting to strip them out corrupts the context. If tool-result bookkeeping is tripping you up, Tool Use error handling patterns is a good companion.

Pair with disable_parallel_tool_use for transactional turns

For workflows where exactly one tool call per turn is the only acceptable outcome (payment processing, state transitions), pass:

tool_choice = {"type": "auto", "disable_parallel_tool_use": True}

This blocks Claude from emitting multiple tool_use blocks in a single response and removes a class of race conditions from your execution layer.

What to try next

Open your logs, pick ten live Tool Use requests, and check how many are still on auto. For each one, ask: "is the decision here genuinely open, or do I actually know the answer?" Every request where the answer is "I know" is a candidate for any, tool, or none. Flip those and watch one day of traffic — the line item will usually move.

If that goes well, pull the mode-picker into a single function so every turn announces its purpose. That small piece of structure is the foundation for every other Tool Use optimization you will reach for later. For a broader survey of Tool Use patterns that pair well with this approach, the advanced Tool Use guide keeps a map of where each technique shines.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

API & SDK2026-06-23
When Claude API Prompt Caching Quietly Stops Hitting in Production — Field Notes on TTL and Measured Savings
Prompt caching works beautifully the day you ship it, then quietly stops hitting in production. The five things that break the prefix, how to choose between 5-minute and 1-hour TTL, and how to measure real savings from usage instead of guessing.
API & SDK2026-03-26
Claude API Cost Optimization Production Guide — Combining Batch API, Prompt Caching, and Adaptive Thinking for Up to 90% Savings
Learn practical implementation patterns to cut Claude API costs by up to 90%. Covers Batch API, Prompt Caching, and Adaptive Thinking strategies, plus production monitoring and budget management.
API & SDK2026-07-13
Coalescing Concurrent Claude API Calls: Single-Flight Against Duplicate Inference and Cache Stampede
A design for collapsing identical prompts that fire at the same instant into a single upstream Claude call, using single-flight (request coalescing). In-process and distributed implementations, jittered retries, and negative caching, with measured results.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →