Volley / Templates / LLM tool use
AI agents template
LLM tool calling sequence diagram
Function calling from your app's side. You send a tool definition, the model replies with a tool_use block, your app runs the tool, and a tool_result goes back to get the final answer.
Click any arrow in the editor to see its request and response as a table or the raw body. Change the hosts, ids and fields to match your integration, then share a link or embed it in your README.
Step by step
- Your app sends the question with a tool.
POST /v1/messageswithmodel,max_tokens,messagesand atoolslist where each tool has aname,descriptionandinput_schema. - The model asks for the tool. The response has
stop_reason: "tool_use"and atool_useblock with anid, the tool name and itsinput. - Your app runs the tool, here a call to a weather API.
- Your app sends the result back. A second
POST /v1/messageswith the full conversation, the assistant turn, and a user turn holding atool_resultblock with the matchingtool_use_id. - The model answers in text with
stop_reason: "end_turn".
Easy to get wrong
- The API is stateless. Each request carries the whole conversation, including the assistant's
tool_useturn. - The model can ask for several tools in one response. Return a
tool_resultfor everytool_useblock. - Loop on
stop_reason. The answer is not final until it isend_turn.
The source
The whole diagram is this plain text. Copy it into your repo, or open it in the editor.
llm-tool-use.volley
title: LLM tool use with the Claude Messages API
autonumber
order: User, App, Claude API, Weather API
User -> App: What's the weather in San Francisco?
App -> Claude API: POST /v1/messages
in: Request with a tool
```http
POST /v1/messages HTTP/1.1
Host: api.anthropic.com
Content-Type: application/json
x-api-key: <redacted>
anthropic-version: 2023-06-01
{
"model": "claude-sonnet-5",
"max_tokens": 1024,
"tools": [
{
"name": "get_weather",
"description": "Get the current weather for a city",
"input_schema": {
"type": "object",
"properties": {
"location": { "type": "string", "description": "City and state, like San Francisco, CA" },
"unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
},
"required": ["location"]
}
}
],
"messages": [{ "role": "user", "content": "What's the weather in San Francisco?" }]
}
```
Claude API --> App: 200 OK
out: Tool use
```json
{
"id": "msg_01Aq9w938a90dw8q",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-5",
"content": [
{ "type": "text", "text": "I'll check the current weather in San Francisco." },
{ "type": "tool_use", "id": "toolu_01A09q90qw90lq917835lq9", "name": "get_weather", "input": { "location": "San Francisco, CA", "unit": "fahrenheit" } }
],
"stop_reason": "tool_use"
}
```
note: The model does not call the tool. It returns a `tool_use` block, and your app runs it.
=: {fas-cloud-sun} Your app runs the tool
App -> Weather API: GET /v1/current?city=San+Francisco&units=imperial
Weather API --> App: 200 OK
out: Weather
```json
{ "city": "San Francisco", "temp_f": 61, "conditions": "Fog", "wind_mph": 12 }
```
App -> Claude API: POST /v1/messages
in: Request with the tool result
```json
{
"model": "claude-sonnet-5",
"max_tokens": 1024,
"tools": [{ "name": "get_weather", "description": "Get the current weather for a city", "input_schema": { "type": "object", "properties": { "location": { "type": "string" } }, "required": ["location"] } }],
"messages": [
{ "role": "user", "content": "What's the weather in San Francisco?" },
{
"role": "assistant",
"content": [
{ "type": "text", "text": "I'll check the current weather in San Francisco." },
{ "type": "tool_use", "id": "toolu_01A09q90qw90lq917835lq9", "name": "get_weather", "input": { "location": "San Francisco, CA", "unit": "fahrenheit" } }
]
},
{
"role": "user",
"content": [
{ "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "61°F, fog, wind 12 mph" }
]
}
]
}
```
note: Send the whole conversation again, including the assistant turn with its `tool_use` block. The `tool_result` goes in the next user message and its `tool_use_id` must match.
Claude API --> App: 200 OK
out: Final answer
```json
{
"id": "msg_01Bx3k7Lm2Np4Qr5",
"type": "message",
"role": "assistant",
"content": [{ "type": "text", "text": "It's 61°F and foggy in San Francisco, with wind around 12 mph." }],
"stop_reason": "end_turn"
}
```
App --> User: It's 61°F and foggy, with wind around 12 mph.
note: Loop while `stop_reason` is `tool_use`. Stop when it is `end_turn`.