Do Caos à Produção: Como Orquestrar Agentes Determinísticos com Vercel AI SDK
Descubra como orquestrar agentes de IA de forma profissional, usando conectores universais, saídas tipadas com Zod e tool calling para sistemas reais.

Modelos de linguagem são probabilísticos. Software é determinístico. Quase tudo o que é difícil em colocar IA em produção mora na fenda entre essas duas frases.
Na demo, a fenda não aparece — há um humano no loop, lendo a resposta e perdoando as arestas. Em produção, o que vem depois do modelo é software: um banco que espera um número, uma função que espera um formato exato, uma UI que espera um campo que sempre existe. Texto livre não serve. O trabalho é de engenharia: fechar essa fenda sem fingir que o modelo virou determinístico.
Este artigo é a escada para fechá-la, degrau a degrau: um conector universal, saídas tipadas, tool calling e, quando o tool calling não basta, isolamento por subagentes. Uso o Vercel AI SDK como ferramenta concreta — mas o que importa são os padrões, não a marca.
O caos onde você começa
A primeira versão de qualquer feature de IA costuma nascer torta. Você instala o SDK de um provedor, escreve o parsing do stream na mão, reza para o modelo devolver um JSON válido e acopla a lógica de negócio a uma API específica. Aí o provedor lança um modelo melhor — ou cai — e você descobre que trocar significa reescrever tudo.
Cada provedor tem uma API diferente, um formato de stream diferente, um jeito diferente de pedir saída estruturada. O resultado é boilerplate descartável e lock-in: você fica preso ao primeiro fornecedor que escolheu, mesmo quando aparece um melhor.
Parsing de stream na mão, tipagem fraca e trocar de provedor exige reescrever a lógica de negócio.
O mesmo código invoca qualquer LLM, com stream e tipos consistentes. Trocar de modelo é trocar uma linha.
Por que juntar provedores na mão não escala.
O conector universal
O primeiro degrau é parar de falar com cada provedor na língua dele. Uma camada unificada — o Vercel AI SDK é a mais adotada no mundo JavaScript — abstrai as diferenças: a mesma função generateText fala com OpenAI, Anthropic, Google ou xAI, e trocar de modelo é mudar uma linha.
import { generateText } from "ai";import { anthropic } from "@ai-sdk/anthropic";// import { openai } from "@ai-sdk/openai"; // trocar de provedor = trocar 1 linhaconst { text } = await generateText({ model: anthropic("claude-sonnet-4-6"), prompt: "Resuma este relatório em três frases.",});Por cima disso vive o AI Gateway: um endpoint único que adiciona resiliência sem latência perceptível. Você referencia o modelo como uma string — anthropic/claude-sonnet-4.6 — e ganha fallback automático (se um provedor cai, outro assume), autenticação por OIDC (sem gerenciar chaves) e telemetria. O roteamento sai por volta de 20 ms.
Nada disso é mágica, e o AI SDK não é a única opção — Mastra e LangChain cobrem terreno parecido, e Cloudflare e a AWS disputam a mesma camada de integração. Mas o padrão é o que vale: uma interface agnóstica de provedor, para que a sua arquitetura não case com um único modelo.
Ordem a partir do caos: saídas estruturadas
Agora a fenda, concreta. Peça dados a um modelo em texto livre e você recebe algo como “Hum, deixe-me ver… o nome é João da Silva e acho que ele tem 30 anos…”. Bonito para um humano ler, inútil para o software consumir. O modelo é probabilístico; o if que vem depois é determinístico.
As funções generateObject e streamObject fecham isso. Você passa um schema Zod, e o SDK força o modelo a aderir àquela estrutura — tipada e validada de ponta a ponta. Não é “quase JSON”; é o objeto que você declarou.
import { generateObject } from "ai";import { anthropic } from "@ai-sdk/anthropic";import { z } from "zod";const { object } = await generateObject({ model: anthropic("claude-sonnet-4-6"), schema: z.object({ nome: z.string(), idade: z.number(), prioridade: z.enum(["baixa", "media", "alta"]), }), prompt: "Extraia os dados do cadastro: ...",});object.prioridade; // tipado e validado — o TypeScript conhece a formaSe você leu o artigo da Refinaria de Dados, isto é o contrato em ação: o schema é a fronteira entre a saída probabilística do modelo e o sistema tipado que a consome. Ideal para extração, classificação e UIs generativas.
Dando mãos à IA: tool calling
Um modelo, por mais esperto que seja, não tem agência. Ele não busca o clima de hoje, não consulta o saldo de um cliente no seu banco, não dispara um e-mail. Está preso na própria caixa, congelado no corte do treinamento, isolado do mundo real — e nenhum JSON limpo muda isso.
Tool calling resolve. O modelo não executa código; ele emite uma intenção (“chame buscarPedido com pedidoId=A-1042”). O SDK executa a sua função TypeScript, devolve o resultado ao modelo e repete o ciclo até a tarefa terminar.
Aqui mora a primeira atualização importante — e onde muito tutorial está desatualizado. No AI SDK 4, você controlava o loop com maxSteps. No AI SDK 5 (julho de 2025), isso saiu: o loop agora é controlado por stopWhen, e as ferramentas declaram inputSchema, não mais parameters.
import { generateText, tool, stepCountIs } from "ai";import { anthropic } from "@ai-sdk/anthropic";import { z } from "zod";const { text } = await generateText({ model: anthropic("claude-sonnet-4-6"), stopWhen: stepCountIs(5), // antes era `maxSteps: 5` tools: { buscarPedido: tool({ description: "Busca um pedido pelo ID", inputSchema: z.object({ pedidoId: z.string() }), // antes era `parameters` execute: async ({ pedidoId }) => db.pedidos.find(pedidoId), }), }, prompt: "Qual o status do pedido A-1042?",});O muro: colapso de contexto
Tool calling é excelente para ações pontuais. Mas quando a tarefa exige explorar muita informação — ler dezenas de arquivos, varrer um banco, percorrer logs — cada resultado de ferramenta volta inteiro para o contexto do agente principal. E aí três coisas acontecem ao mesmo tempo: o consumo de tokens explode, a latência dispara e o agente esquece a instrução original e perde a coerência.
É o paradoxo do tool calling ingênuo: quanto mais a ferramenta trabalha, mais lixo cognitivo ela despeja de volta no agente. A solução não é uma ferramenta melhor; é uma fronteira.
A fronteira agentic: isolamento por subagentes
Um subagente é um agente autônomo embrulhado como uma ferramenta. O agente principal o chama como chamaria qualquer tool — manda uma tarefa, recebe um resultado — mas o subagente roda com a própria janela de contexto, do zero. Ele faz o trabalho pesado isolado e devolve só um resumo focado.
O detalhe que fecha o argumento é o toModelOutput. Ele separa o que a ferramenta produz do que o modelo principal enxerga: o subagente pode queimar 100 mil tokens explorando, mas o orquestrador consome só o resumo de mil. O usuário acompanha todo o progresso em streaming; o modelo principal vê apenas o destilado. O contexto do agente principal fica limpo e coerente.
import { tool, generateText, stepCountIs } from "ai";import { anthropic } from "@ai-sdk/anthropic";import { z } from "zod";// Um subagente é um agente autônomo invocado como ferramenta.const pesquisaProfunda = tool({ description: "Pesquisa profunda e independente sobre um tópico", inputSchema: z.object({ tarefa: z.string() }), execute: async ({ tarefa }) => { // janela de contexto própria: queima 100k tokens explorando... const { text } = await generateText({ model: anthropic("claude-sonnet-4-6"), stopWhen: stepCountIs(20), tools: { /* buscar, ler, etc. */ }, prompt: `Investigue a fundo e resuma: ${tarefa}`, }); return text; }, // ...mas o orquestrador só vê o resumo de ~1k tokens toModelOutput: ({ output }) => ({ type: "text", value: output }),});É o padrão orquestrador-trabalhadores: um agente central divide a tarefa, os subagentes executam em paralelo e isolados, e o central sintetiza. Cada subagente começa com contexto limpo — é justamente isso que o deixa explorar à vontade sem inchar a conversa principal.
Escolhendo a arquitetura certa
Subagente não é resposta para tudo — eles adicionam latência e complexidade, e superengenharia é uma forma de falha tão real quanto a falta dela. O AI SDK deixa você compor todas as estratégias na mesma base; o trabalho é casar a arquitetura com a tarefa, olhando dois eixos: o volume de dados a explorar e a necessidade de independência.
Pouca exploração, baixa complexidade. Ex.: buscar o clima, calcular um frete.
Vários passos encadeados, mas ainda no contexto do agente principal.
Muito dado para varrer, baixa complexidade de decisão. Recupere o relevante, não tudo.
Muita exploração E independência: delegue para agentes isolados que devolvem resumos.
Escolha pelo volume de exploração e pela necessidade de independência.
Pondo em produção: resiliência e observabilidade
Arquiteturas multiagente quebram de formas que uma demo nunca mostra, e precisam de infraestrutura à altura. O AI Gateway e o parâmetro providerOptions.gateway gerenciam o caos operacional: fallback automático de modelo se um provedor falha (order, only, sort por custo, latência ou throughput), Zero Data Retention por chamada para privacidade, e autenticação OIDC que elimina o gerenciamento de chaves.
E há o custo invisível. Sistemas autônomos gastam em silêncio — um subagente que dispara vinte passos pode custar muito mais que o orquestrador. Por isso a observabilidade não é luxo: você precisa de rastreabilidade por função e por provedor, com custo segregado por modelo, métricas de token e latência de primeiro token (TTFT). Sem isso, você descobre a conta no fim do mês.
A arquitetura, montada
Junte os degraus e a peça final aparece: um orquestrador principal (um modelo forte) recebe o pedido e decide; ele chama ferramentas e subagentes especializados (talvez outros modelos, talvez mais baratos), que exploram isolados e devolvem resumos; os dados passam por um schema Zod e viram JSON tipado; e tudo volta para o usuário em streaming. Um SDK só, atravessando fronteiras de provedor, de modelo e de segurança.
O arco é esse: de APIs dispersas para um conector universal; de texto probabilístico para tipagem segura; de caixas de chat isoladas para sistemas com agência; de colapso de contexto para orquestração de subagentes. A engenharia de prompt frágil vira arquitetura de software.
E note o que não mudou no caminho: o modelo continua probabilístico. Você não o domou. Você construiu software determinístico em volta dele — um conector que não te prende, um schema que garante a forma, um loop que sabe parar, uma fronteira que protege o contexto. A inteligência é probabilística; a arquitetura, não. É aí, nessa fenda costurada com cuidado, que mora a diferença entre uma demo e um produto.
Escrito em junho de 2026. As referências de API — o controle de loop com stopWhen/stepCountIs (AI SDK 5, julho de 2025), ferramentas com inputSchema, o padrão de subagentes com toModelOutput e os recursos do AI Gateway (fallbacks, ZDR, OIDC, BYOK e observabilidade) — refletem o estado do Vercel AI SDK nessa data. O AI SDK não é a única forma de implementar esses padrões.


