Programmatic tool calling: deixe o agente escrever o código em vez de chamar tool a tool
Você monta um agente, pluga uns MCPs, e na primeira tarefa séria ele precisa: buscar 20 funcionários, puxar os gastos de cada um, comparar com o limite e te dizer quem estourou. Doze, quinze, vinte chamadas de tool. Cada uma é um turno do modelo. Cada turno volta com o resultado inteiro entrando no contexto. No fim, o agente leu centenas de kilobytes de dado bruto só pra te responder uma linha: "três pessoas passaram do orçamento".
Caro. Lento. E o contexto entope no meio do caminho.
A ideia que está mudando isso tem nome: programmatic tool calling. Em vez de chamar uma tool de cada vez, o agente escreve um pequeno programa que orquestra todas as chamadas, processa o resultado ali mesmo e devolve pro modelo só a resposta final. Neste post você vai entender o padrão, ver o código de como isso funciona na prática (com a API da Anthropic e com o Code Mode da Cloudflare), e saber quando vale a pena trocar a arquitetura do seu agente.
TL;DR
- O que é: padrão onde o LLM escreve código que chama as tools (em loop, em paralelo, com filtro), em vez de chamar tool a tool via round-trip do modelo.
- Stack/Modelos: Claude (API com
code_execution), Cloudflare Code Mode, ou implementação própria com sandbox. Conceito vale pra qualquer modelo bom de código. - Custo/Acesso: disponível na Claude API, Claude Platform na AWS e Microsoft Foundry. Cobrança junto com o code execution.
- Por que importa: Cloudflare reporta queda de 1,17 milhão de tokens para ~1.000 no acesso a 2.500 endpoints — 99,9% menos contexto.
O contexto: por que chamar tool a tool é caro
O fluxo clássico de tool use é uma conversa de ida e volta. O modelo decide chamar uma tool, você executa, devolve o resultado, o modelo lê, decide a próxima. Funciona lindamente pra uma chamada. Começa a doer em três. Vira tragédia em doze.
Dois custos se acumulam.
O primeiro é a definição das tools. Todo schema de toda tool entra no contexto logo de cara, antes mesmo de o agente fazer qualquer coisa. Um servidor MCP gordo pode despejar dezenas de milhares de tokens só de descrição de função. A Anthropic mostrou um caso onde carregar tudo de uma vez custava 150.000 tokens — e que, deixando o agente descobrir só as ferramentas que precisa, caiu pra 2.000 tokens, uma economia de 98,7%.
O segundo é o resultado intermediário. Cada retorno de tool trafega pelo contexto, e em workflows encadeados ele trafega mais de uma vez — o output de uma chamada vira o input da próxima, e o modelo relê tudo no meio. No exemplo da Anthropic, transcrever uma reunião de vendas de 2 horas e jogar entre Google Drive e Salesforce significava processar 50.000 tokens a mais, só de dado passando de um lado pro outro.
Some os dois e você tem a conta real: chamar 10 tools direto consome cerca de 10x mais tokens do que chamar as mesmas 10 dentro de um código que devolve só o resumo.
Isso não é hype. É a física do round-trip.
A virada: o agente escreve o código
A sacada do programmatic tool calling — ou "code mode", como ficou conhecido — é simples de enunciar e poderosa na prática: dê ao modelo uma ferramenta de "executar código" e exponha as tools como funções que esse código pode chamar. O modelo então escreve um script que faz o loop, o filtro, o paralelo, a condicional — tudo o que código sabe fazer — e só o resultado final volta pro contexto.
Por que isso funciona tão bem? Porque o modelo é muito melhor escrevendo código do que enfileirando tool calls. Como a Cloudflare colocou: os LLMs viram milhões de linhas de TypeScript real, e só exemplos artificiais e contrived de tool-calling. Você está pedindo pro modelo fazer o que ele mais treinou.
E não é achismo de marketing. O paper CodeAct (ICML 2024) mostrou que consolidar as ações do agente num espaço único de código executável dá até 20% mais taxa de sucesso que as alternativas baseadas em JSON. Nos benchmarks de busca agêntica como BrowseComp e DeepSearchQA, a Anthropic relata que adicionar programmatic tool calling foi o fator que destravou a performance dos agentes.
Pré-requisitos
Pra acompanhar a parte de código:
- [ ] Chave da Claude API (o
code_executionprecisa estar habilitado na conta). - [ ] Modelo compatível: Opus 4.8/4.7/4.6/4.5 ou Sonnet 4.6/4.5, via
code_execution_20260120. - [ ] Noção de tool use tradicional — se isso aqui é novidade, vale ler a doc de tool use antes.
- [ ] Pra testar o Code Mode: conta Cloudflare com Workers.
Disponível na Claude API, na Claude Platform na AWS e na Microsoft Foundry. Ainda não no Bedrock nem no Vertex.
Mão na massa: programmatic tool calling na Claude API
Passo 1: marque a tool como chamável por código
A diferença de uma definição normal é um campo só: allowed_callers. Você adiciona o code_execution na lista de tools e marca a sua tool de negócio como invocável de dentro do código.
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
messages=[{
"role": "user",
"content": "Consulte o faturamento das regiões Oeste, Leste e Centro e me diga qual teve a maior receita",
}],
tools=[
{"type": "code_execution_20260120", "name": "code_execution"},
{
"name": "query_database",
"description": "Executa uma query SQL no banco de vendas. Retorna uma lista de linhas como objetos JSON.",
"input_schema": {
"type": "object",
"properties": {
"sql": {"type": "string", "description": "Query SQL a executar"}
},
"required": ["sql"],
},
"allowed_callers": ["code_execution_20260120"],
},
],
)
O allowed_callers aceita três valores: ["direct"] (só o modelo chama, é o default), ["code_execution_20260120"] (só de dentro do código) ou os dois. A doc recomenda escolher um — misturar confunde o modelo na hora de decidir o caminho.
Passo 2: o modelo escreve o código
Aqui mora a mágica. Em vez de te devolver três tool_use em sequência, o Claude escreve um único bloco de código que chama a tool em loop e processa o resultado:
# código que o PRÓPRIO Claude gera e roda no sandbox
regions = ["Oeste", "Leste", "Centro", "Norte", "Sul"]
results = {}
for region in regions:
data = await query_database(f"<sql para {region}>")
results[region] = sum(row["revenue"] for row in data)
top_region = max(results.items(), key=lambda x: x[1])
print(f"Região líder: {top_region[0]} com R${top_region[1]:,} de receita")
Repare no await. As suas tools viram funções assíncronas automaticamente, o que deixa o modelo paralelizar chamadas quando elas não dependem uma da outra. Cinco regiões, um turno do modelo — não cinco.
Passo 3: os dados ficam fora do contexto
Esse é o ponto que muda a conta de custo. Quando o código chama query_database, o code execution pausa, a API te devolve um tool_use, você responde com o resultado, e o código continua de onde parou. O resultado bruto da query — que pode ser 847 linhas de dado — fica no sandbox. Nunca entra no contexto do modelo.
O que volta pro Claude é só o stdout:
Região líder: Oeste com R$45,000 de receita
Uma linha. Não as 847. Os resultados intermediários não contam no seu uso de tokens de entrada e saída — só o output final do código e a resposta do Claude. É essa a diferença entre "três pessoas estouraram o orçamento" custar uma linha ou custar a planilha inteira.
Passo 4: filtre, decida, termine cedo
Como é código de verdade, o modelo ganha o que tool-calling puro nunca teve: controle de fluxo. Pode filtrar antes de devolver:
logs = await fetch_logs(server_id)
errors = [log for log in logs if "ERROR" in log]
print(f"{len(errors)} erros encontrados")
for error in errors[-10:]: # só os 10 últimos voltam pro contexto
print(error)
Pode parar assim que achar o que procura, sem varrer o resto:
for endpoint in endpoints:
status = await check_health(endpoint)
if status == "healthy":
print(f"Endpoint saudável: {endpoint}")
break # para aqui, não checa os outros
Isso é o que o tool-calling tradicional não consegue fazer sem queimar um turno de modelo por iteração.
O mesmo padrão no Code Mode da Cloudflare
A Cloudflare empacotou a mesma ideia de um jeito diferente. O @cloudflare/codemode converte suas tools em uma API TypeScript tipada, dá ao modelo uma única tool de "escrever código", e roda o código gerado num sandbox isolado de Worker. As chamadas de tool são despachadas de volta pro host via Workers RPC, e só o resultado final volta.
O número que eles publicaram é o argumento mais forte do padrão inteiro: o custo de contexto pra interagir com mais de 2.500 endpoints de API caiu de 1,17 milhão de tokens pra cerca de 1.000 — uma redução de ~99,9%. E esse custo é fixo: não importa se a API tem 10 ou 10.000 endpoints, o footprint não explode.
A parte de segurança também é levada a sério: o código roda com fetch() e connect() externos bloqueados por padrão (globalOutbound: null), então o código gerado só conversa com o mundo através das tools que você expôs. Sandbox de verdade, não confiança cega.
Limitações e onde você vai se queimar
Esse padrão não é bala de prata. Onde ele cobra o preço:
- Tool call simples não compensa. Pra uma chamada única e rápida, o overhead de subir o code execution é maior que o ganho. A própria doc lista isso como caso ruim de uso — programmatic tool calling brilha em workflows com 3+ chamadas dependentes, processamento de dado grande ou operações em lote.
- Você está executando código gerado por LLM. Se rodar fora de um sandbox, isso é um vetor de injeção. Resultado de tool volta como string e pode conter comando executável. Rode em container isolado, sem egress de rede, e valide o que entra. A opção gerenciada da Anthropic e o Worker da Cloudflare já fazem isso por você — implementação caseira é por sua conta e risco.
- Tem incompatibilidades. Na Claude API, programmatic tool calling não roda com structured outputs (
strict: true), não dá pra forçar viatool_choice, e tools vindas de um MCP connector não podem ser chamadas por código. - Container expira. Ele vive enquanto a tarefa roda, mas tem timeout de inatividade (~4,5 min). Se a sua tool demora pra responder, o código pode tomar
TimeoutError. Monitore oexpires_at.
FAQ rápido
Isso substitui o MCP? Não. É uma forma melhor de consumir MCP. As tools continuam sendo MCP; muda que o agente as orquestra por código em vez de uma a uma. A própria Cloudflare chama o Code Mode de "a melhor forma de usar MCP".
Funciona com qualquer modelo? O conceito sim — qualquer modelo decente de código se beneficia. Mas o suporte nativo na Claude API exige code_execution_20260120 (Opus 4.5+ ou Sonnet 4.5+). Fora isso, você implementa o sandbox por conta própria.
É só economia de token ou tem ganho de qualidade? Os dois. Menos token e menos latência, sim — mas os benchmarks (BrowseComp, DeepSearchQA, CodeAct) mostram também mais acerto, porque o modelo raciocina sobre composição de ferramentas no terreno em que ele é mais forte: código.
Preciso reescrever meu agente do zero? Não. Na Claude API é adicionar allowed_callers nas tools certas e ligar o code_execution. O resto do seu fluxo continua igual.
Conclusão
O ponto não é "código é mais legal que JSON". O ponto é arquitetural: quando o agente orquestra tools por código, os dados pesados ficam onde devem ficar — fora do contexto — e o modelo só lê a conclusão. É a diferença entre um agente que aguenta uma tarefa real de produção e um que entope o contexto na terceira chamada.
E é exatamente esse tipo de decisão — onde o dado mora, quando o modelo precisa ler, como você desenha o agente pra não estourar custo e latência — que separa o "fiz um agente no fim de semana" do "coloquei um agente em produção". É a mesma régua que discutimos em Anatomia de um Agent Harness: a engenharia em volta do modelo é o que aguenta produção. E é sobre isso o Workshop Arquitetando Soluções de IA: arquitetar software com agentes de IA na prática, com as decisões de engenharia na mesa, não slide motivacional.
O próximo passo é olhar suas tools com outro olho. Toda vez que você vir um agente fazendo a mesma chamada em loop, ou puxando um dataset enorme só pra responder uma linha, é candidato a virar código. Comece por aí.
{AI Engineer} — apaixonado por Laravel, arquitetura de software e construir produtos com impacto. Compartilho aqui tutoriais, descobertas e reflexões sobre o dia a dia de engenharia.
Você também pode gostar
Programmatic Tool Calling: por que executar suas ferramentas em código é o futuro do agente
Function calling clássico vai virar legado. Programmatic tool calling do Claude troca o loop turno-a-turno por código Python no sandbox: 37% menos tokens, paralelismo nativo via asyncio.gather e composição em um único script. A gente compara latência, tokens, debug, e fecha com um agente que escreve o próprio orquestrador.
Tool calling na prática: como o agente decide chamar uma ferramenta
Anatomia do loop ReAct e do tool calling: quando o agente decide buscar/agir vs. responder direto, com design de tools (contratos, schemas, idempotência) e um exemplo de tool de busca em banco no Laravel via Claude API.
Anatomia de um Agent Harness: state, tool execution, feedback loops e guardrails
Harness é o software que envolve o LLM e separa um demo bonito de um agente que aguenta produção. Quebro a anatomia em cinco peças obrigatórias: estado persistente, roteador de ferramentas, validação de I/O, loop de raciocínio e limites de segurança. É o mapa mental que abre a série de posts sobre engenharia de agentes.
Roadmap AI Engineer em 90 dias: do dev backend ao primeiro agente em produção
Caminho real de 13 semanas para dev backend experiente virar AI engineer aplicada. Tool use, harness próprio, RAG, memória, evals e um projeto fim-a-fim que cabe no portfólio. Sem refazer fundamentos, sem detour por framework da moda. Entregáveis por semana e foco no que recrutador olha de verdade.