O executor de ferramentas lida com o loop agêntico, o encapsulamento de erros e a segurança de tipos para que você não precise fazer isso. Quando você precisar de aprovação com humano no loop, logging personalizado ou execução condicional, use o loop manual em vez disso.
Em vez de lidar manualmente com chamadas de ferramentas, resultados de ferramentas e gerenciamento de conversas, o executor de ferramentas automaticamente:
Defina ferramentas usando os helpers do SDK e, em seguida, use o executor de ferramentas para executá-las.
Dependendo da assinatura de ferramenta do SDK, uma ferramenta retorna seu resultado como uma string ou como blocos de conteúdo (blocos de texto, imagem ou documento), portanto uma ferramenta pode retornar resultados multimodais. Uma string retornada se torna um único bloco de conteúdo de texto. Para retornar dados estruturados, como um objeto JSON ou um número, codifique-os como uma string primeiro.
Use o decorador @beta_tool para definir ferramentas com type hints e docstrings.
import json
from anthropic import Anthropic, beta_tool
client = Anthropic()
@beta_tool
def get_weather(location: str, unit: str = "fahrenheit") -> str:
"""Get the current weather in a given location.
Args:
location: The city and state, e.g. San Francisco, CA
unit: Temperature unit, either 'celsius' or 'fahrenheit'
"""
return json.dumps({"temperature": "20°C", "condition": "Sunny"})
@beta_tool
def calculate_sum(a: int, b: int) -> str:
"""Add two numbers together.
Args:
a: First number
b: Second number
"""
return str(a + b)
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[get_weather, calculate_sum],
messages=[
{
"role": "user",
"content": "What's the weather like in Paris? Also, what's 15 + 27?",
}
],
)
for message in runner:
print(message)O decorador @beta_tool inspeciona os argumentos da função e a docstring para derivar o esquema JSON para você.
O executor de ferramentas é um iterável que produz mensagens de Claude. A cada iteração, o executor verifica se Claude solicitou um uso de ferramentas. Se sim, ele executa a ferramenta e envia o resultado de volta para Claude automaticamente, e então produz a próxima mensagem de Claude para continuar seu loop.
Você pode encerrar o loop em qualquer iteração com uma instrução break. O executor faz o loop até que Claude retorne uma mensagem sem um uso de ferramentas, ou até atingir max_iterations se você o definir.
Se você não precisar de mensagens intermediárias, pode obter a mensagem final diretamente:
Use runner.until_done() para obter a mensagem final.
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[get_weather, calculate_sum],
messages=[
{
"role": "user",
"content": "What's the weather like in Paris? Also, what's 15 + 27?",
}
],
)
final_message = runner.until_done()
for block in final_message.content:
if block.type == "text":
print(block.text)Dentro do loop, você pode ler cada mensagem de resposta e modificar o estado do executor antes da próxima chamada de API. Cada iteração segue este ciclo de vida:
Por padrão, o executor gerencia o estado da conversa para você: após cada turno de chamada de ferramenta, ele anexa a mensagem do assistente e quaisquer resultados de ferramentas ao seu próprio histórico de mensagens. Você assume o histórico de mensagens quando quer repetir um turno (descartar a resposta e reenviar), injetar uma mensagem de acompanhamento ou construir o resultado da ferramenta você mesmo.
Você assume o controle modificando as mensagens do executor de dentro do corpo do loop. O método exato depende do SDK. Consulte as abas por linguagem a seguir.
Quando você assume o controle em uma iteração, o executor não anexa a mensagem do assistente nem os resultados de ferramentas daquele turno. Você se torna responsável por manter a conversa válida: anexe a mensagem do assistente e um resultado de ferramenta você mesmo (se quiser que o turno conte), modifique o estado condicionalmente para que o loop ainda possa ser encerrado quando não houver chamadas de ferramentas, e passe max_iterations para limitar o loop. Todos os sete SDKs suportam max_iterations.
Use generate_tool_call_response() para inspecionar ou calcular o resultado da ferramenta. Chamar append_messages() dentro do loop informa ao executor que você está gerenciando o histórico por conta própria, então inclua a mensagem do assistente e o resultado da ferramenta no que você anexar.
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
max_iterations=10,
tools=[get_weather],
messages=[{"role": "user", "content": "What's the weather in San Francisco?"}],
)
for message in runner:
tool_response = runner.generate_tool_call_response()
if tool_response is not None:
# append_messages() marca o estado como modificado, então o runner pula o
# append automático nesta iteração. Faça o append da mensagem do assistente
# e do tool result você mesmo, além de qualquer follow-up.
runner.append_messages(
message,
tool_response,
{"role": "user", "content": "Please be concise."},
)
# Quando não há chamada de ferramenta, deixe o estado intacto para o loop sair.Para alterar parâmetros de requisição como max_tokens sem assumir o histórico de mensagens, use set_messages_params(). O executor ainda anexa a mensagem do assistente e o resultado da ferramenta automaticamente.
for message in runner:
runner.set_messages_params(lambda params: {**params, "max_tokens": 2048})Para tarefas agênticas de longa duração, os executores de ferramentas de Python, TypeScript e Ruby suportam compactação automática, que gera resumos quando o uso de tokens excede um limite para que a conversa possa continuar além dos limites da "context window" (janela de contexto). Todos os três SDKs descontinuaram essa opção do lado do cliente em favor da edição de contexto do lado do servidor, que está disponível em todos os SDKs. Os executores de ferramentas de Go, Java, C# e PHP não incluem compactação do lado do cliente.
Quando uma ferramenta lança uma exceção, o executor de ferramentas a captura e retorna o erro para Claude como um resultado de ferramenta com is_error: true. O resultado da ferramenta carrega a mensagem da exceção (em Python, seu tipo e mensagem), não o stack trace completo.
O que o SDK registra em log é específico de cada linguagem. O SDK Python registra a exceção completa, incluindo seu stack trace, por meio do módulo padrão logging sempre que uma ferramenta lança uma exceção não tratada. Os SDKs Python, TypeScript e Java leem a variável de ambiente ANTHROPIC_LOG para ativar o logging do SDK, que inclui detalhes de requisição e resposta:
# Registra log no nível info
export ANTHROPIC_LOG=info
# Registra log no nível debug para uma saída mais detalhada
export ANTHROPIC_LOG=debugOs SDKs Go, Ruby, C# e PHP não leem ANTHROPIC_LOG. Fora do Python, nenhum SDK registra em log uma ferramenta que falhou: para ver por que uma ferramenta falhou, capture e registre a exceção dentro da função da ferramenta antes de retornar ou relançá-la.
Por padrão, erros de ferramentas são passados de volta para Claude, que pode então responder apropriadamente. No entanto, você pode querer detectar erros e tratá-los de forma diferente, por exemplo, para interromper a execução antecipadamente ou implementar tratamento de erros personalizado.
Nos SDKs Python e TypeScript, use o método de resposta de ferramenta (generate_tool_call_response() em Python, generateToolResponse() em TypeScript) para interceptar resultados de ferramentas e verificar erros antes que sejam enviados para Claude. Os outros SDKs não expõem esse hook. Suas abas descrevem a alternativa mais próxima:
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[my_tool],
messages=[{"role": "user", "content": "Run my_tool with the query 'hello'."}],
)
for message in runner:
tool_response = runner.generate_tool_call_response()
if tool_response is not None:
# tool_response é um dict: {"role": "user", "content": [...]}
# Verifica se algum resultado de ferramenta tem um erro
for block in tool_response["content"]:
if block.get("is_error"):
# Opção 1: Lançar uma exceção para interromper o loop
raise RuntimeError(f"Tool failed: {json.dumps(block['content'])}")
# Opção 2: Registrar em log e continuar (deixar o Claude lidar com isso)
# logger.error(f"Tool error: {json.dumps(block['content'])}")
# Processa a mensagem normalmente
print(message.content)Você pode modificar resultados de ferramentas antes que sejam enviados de volta para Claude. Isso é útil para adicionar metadados como cache_control para habilitar o cache de prompt em resultados de ferramentas, ou para transformar a saída da ferramenta.
Nos SDKs Python e TypeScript, use o método de resposta de ferramenta para obter o resultado da ferramenta e, em seguida, modifique-o antes que o executor prossiga. Se você anexa explicitamente o resultado modificado ou o muta no local depende do SDK. Consulte os comentários de código em cada aba.
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[search_documents],
messages=[
{
"role": "user",
"content": "Search for information about the climate of San Francisco",
}
],
)
for message in runner:
tool_response = runner.generate_tool_call_response()
if tool_response is not None:
# tool_response é um dict: {"role": "user", "content": [...]}
# Modifica o resultado da ferramenta para adicionar controle de cache
for block in tool_response["content"]:
if block["type"] == "tool_result":
# Adiciona cache_control para armazenar em cache este resultado de ferramenta
block["cache_control"] = {"type": "ephemeral"}
# Anexa a resposta modificada (isso evita o anexo automático da original)
runner.append_messages(message, tool_response)
print(message.content)Habilite o streaming para processar a resposta de cada turno de forma incremental. Cada iteração produz um objeto de stream que você pode iterar para obter eventos.
Defina stream=True e use get_final_message() para obter a mensagem acumulada.
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[calculate_sum],
messages=[{"role": "user", "content": "What is 15 + 27?"}],
stream=True,
)
# Ao fazer streaming, o runner retorna BetaMessageStream
for message_stream in runner:
for event in message_stream:
print("event:", event)
print("message:", message_stream.get_final_message())
print(runner.until_done())Imponha conformidade com JSON Schema nas entradas de ferramentas de Claude com amostragem restrita por gramática.
Analise blocos tool_use, formate respostas tool_result e trate erros com is_error.
Habilite, formate e desabilite chamadas paralelas de ferramentas, com orientações sobre histórico de mensagens e solução de problemas.
Especifique esquemas de ferramentas, escreva descrições eficazes e controle quando Claude chama suas ferramentas.
Was this page helpful?