Tool Use: Letting the Model Call Your Code
With tool use (function calling), the model can ask your code to do things: look up an order, search your docs, check the weather. You define the tools; the model decides when to call them; your code runs them and returns results.
Defining a tool
tools = [{
"name": "get_track_progress",
"description": "Get the signed-in learner's progress on a learning track by its slug. "
"Use when the learner asks how far along they are.",
"input_schema": {
"type": "object",
"properties": {"track_slug": {"type": "string", "description": "e.g. python-programming"}},
"required": ["track_slug"],
"additionalProperties": False,
},
"strict": True, # guarantees inputs match the schema
}]
Clear names and descriptions matter: they are how the model decides which tool to use.
The tool loop
messages = [{"role": "user", "content": "How far am I in the Python track?"}]
while True:
response = client.messages.create(
model="claude-opus-5-5", max_tokens=16000, tools=tools, messages=messages,
)
if response.stop_reason != "tool_use":
break
messages.append({"role": "assistant", "content": response.content})
results = []
for block in response.content:
if block.type == "tool_use":
try:
output = run_tool(block.name, block.input, user=current_user)
results.append({"type": "tool_result", "tool_use_id": block.id, "content": output})
except Exception as exc:
results.append({"type": "tool_result", "tool_use_id": block.id,
"content": f"Error: {exc}", "is_error": True})
messages.append({"role": "user", "content": results}) # all results in ONE message
answer = "".join(b.text for b in response.content if b.type == "text")
Rules: append the assistant's full content (not just text), match each tool_result to its tool_use_id, and return all results from one turn together in a single user message.
The SDK tool runner
The Python SDK can run the loop for you (beta helper):
from anthropic import beta_tool
@beta_tool
def get_track_progress(track_slug: str) -> str:
"""Get the signed-in learner's progress on a learning track.
Args:
track_slug: The track slug, e.g. python-programming.
"""
return progress_summary(current_user, track_slug)
runner = client.beta.messages.tool_runner(
model="claude-opus-5-5",
max_tokens=16000,
tools=[get_track_progress],
messages=[{"role": "user", "content": "How far am I in the Python track?"}],
)
for message in runner:
final = message # the last message is the final answer
Tool safety
- The model chooses arguments; your code enforces permissions. Always use the signed-in user from the session, never a user ID supplied in tool input.
- Give read-only tools by default. Require human confirmation for anything that spends money, sends messages or deletes data.
- Validate inputs even with
strictschemas (ranges, ownership, existence). - Treat tool results that contain outside text (web pages, emails) as untrusted: they may include prompt-injection attempts.
- Cap the number of loop iterations to avoid runaway costs.
Exercise
Add two tools to your assistant: search_modules(query) over your learning modules and get_track_progress(track_slug). Ask questions that need both, and log each tool call with its arguments.
Check yourself
- Who actually executes a tool, the model or your code?
- Why must permissions come from the session, not tool input?
- How should results from multiple tool calls be returned?
Votre progression est enregistrée dans ce navigateur uniquement.
Envoyer pour relecture (10 points)