~ / tutoriais /programmatic-tool-calling $ _

Programmatic tool calling: deixe o agente escrever o código em vez de chamar tool a tool

Lucas Souza Lucas Souza 11 min de leitura Tutoriais
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_execution precisa 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 via tool_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 o expires_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í.

Lucas Souza
Lucas Souza

{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
Tutoriais

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.

· 11 min
Tool calling na prática: como o agente decide chamar uma ferramenta
Tutoriais

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.

· 13 min
Anatomia de um Agent Harness: state, tool execution, feedback loops e guardrails
Tutoriais

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.

· 14 min
Roadmap AI Engineer em 90 dias: do dev backend ao primeiro agente em produção
Tutoriais

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.

· 11 min

VirguIA

beer & code assistant

conectando…

Não foi possível iniciar o chat agora.

tocando