Designing a Claude ApplicationTool use, the integration primitive
No narration yet
Module 2, Lesson 228 min

Tool use, the integration primitive

Tool use is how Claude stops being a text box and starts being an integration. It is also where most of the fiddly, testable detail lives, and where two things that sound like they belong together turn out to live in completely different places.

The loop, in five moves

You send tools, each with a name, a description, and an input_schema in JSON Schema. Claude replies with stop_reason: "tool_use" and one or more tool_use blocks. You execute. You append the assistant message verbatim, then a user message carrying tool_result blocks keyed by tool_use_id. You call again.

One turn of the loop, the part people get wrong
[
  { "role": "user", "content": "Weather in Exeter and Totnes?" },
  { "role": "assistant", "content": [
      { "type": "tool_use", "id": "tu_1", "name": "get_weather", "input": { "city": "Exeter" } },
      { "type": "tool_use", "id": "tu_2", "name": "get_weather", "input": { "city": "Totnes" } }
  ]},
  { "role": "user", "content": [
      { "type": "tool_result", "tool_use_id": "tu_1", "content": "17C, rain" },
      { "type": "tool_result", "tool_use_id": "tu_2", "content": "18C, cloud" }
  ]}
]

Parallel tool use is GA, so two calls in one assistant message is normal, not exotic. Both results go back in one user message.

The bit that feels wrong: results your own code produced go in a user message. You wrote the weather lookup, so surely you are not the user. But the roles here are not about authorship, they are about direction. Everything travelling into the model is the user side, whoever generated it, and once you read the roles as inbound and outbound rather than human and machine, tool_result stops looking misplaced.

description is not documentation. It is the only thing the model has to decide whether this tool is the right one, and a vague description is the most common cause of a model calling the wrong tool. Write it like a spec, not a comment.

tool_choice controls whether, not how

Four settings. auto lets the model decide. any forces a tool call but leaves the choice open. tool with a name forces one specific tool. none forbids tools this turn.

That is the whole job of tool_choice. It picks which tool runs. It has no opinion about schemas.

Strict tool use, and the flag placement question

Strict tool use is GA, no beta header required. It constrains the generated tool input to your schema rather than merely encouraging it.

Correct placement
"tools": [
  {
    "name": "create_ticket",
    "description": "Open a support ticket. Use only after the user confirms.",
    "input_schema": { "type": "object", "properties": { "title": { "type": "string" } }, "required": ["title"] },
    "strict": true
  }
]

Tools you do not have to write

A chunk of the tool surface is server-side and GA, meaning Anthropic runs it: web search, web fetch, code execution, tool search, memory, bash, and text editor.

Two cost notes that make good questions. Web search bills at 10 dollars per 1000 searches. Web fetch is free. So a design that scrapes a known URL should reach for fetch, and one that genuinely needs discovery pays for search.

Tool search deserves a specific mention: it exists because a large tool catalogue eats your context window before the conversation even starts. If your design has forty tools, the answer is not a bigger prompt.

Practice

Try it yourself

Recall

Where strict lives

One flag, one location, and the wrong location is the whole question.

Where does the strict flag for strict tool use go, and where does it emphatically not go, and is there anything it does not work with?

Quiz

Two tool calls in one turn

An assistant message comes back containing two tool_use blocks. What does the next request need?

Quiz

Spot the defect in this loop turn

A hand-rolled loop appends this after executing the tool. It does not work.

[
  { "role": "user", "content": "Weather in Exeter?" },
  { "role": "assistant", "content": [
      { "type": "tool_use", "id": "tu_1", "name": "get_weather", "input": { "city": "Exeter" } }
  ]},
  { "role": "assistant", "content": [
      { "type": "tool_result", "tool_use_id": "tu_1", "content": "17C, rain" }
  ]}
]
Quiz

Forcing a tool call

The requirement is that the model must call one of your tools on this turn and must not answer in prose. Which tool_choice do you set?

Quiz

Fill the blank without getting the level wrong

You want the generated tool input constrained to the schema rather than merely encouraged toward it. One line is missing.

{
  "tool_choice": { "type": "auto" },
  "tools": [
    {
      "name": "create_ticket",
      "description": "Open a support ticket. Use only after the user confirms.",
      "input_schema": { "type": "object", "properties": { "title": { "type": "string" } } },
      ___
    }
  ]
}
Check

Inventory what you do not have to build

List which of your planned tools already exist as server-side tools.

You should see

You have checked your tool list against the GA server-side tools (web search, web fetch, code execution, tool search, memory, bash, text editor) and removed any you were about to hand-implement, noting that web search bills at 10 dollars per 1000 searches while web fetch is free.