Inteligência Artificial

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.

Do Caos à Produção: Como Orquestrar Agentes Determinísticos com Vercel AI SDK

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.

A abordagem ingênua vs. uma camada unificada
Um SDK por provedor
A abordagem ingênua

Parsing de stream na mão, tipagem fraca e trocar de provedor exige reescrever a lógica de negócio.

Uma API só
Uma camada unificada

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.

TS
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.

TS
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 forma

Se 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.

TS
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.

TS
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.

Matriz de estratégias de delegação
Ação pontual
Tool calling tradicional

Pouca exploração, baixa complexidade. Ex.: buscar o clima, calcular um frete.

Orquestração sequencial
Tool calling multi-step

Vários passos encadeados, mas ainda no contexto do agente principal.

Busca semântica
Embeddings & RAG

Muito dado para varrer, baixa complexidade de decisão. Recupere o relevante, não tudo.

Exploração profunda
Arquitetura de subagentes

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.

Arquitetura Final do Sistema de Orquestração chama para execução resumos convertidos dados validados integração envia resposta Orquestrador Principal Modelo forte que recebe pedidos e decide Ferramentas e Subagentes Modelos especializados ou mais baratos que executam tarefas Schema Zod Validação e tipagem segura dos dados em JSON Retorno ao Usuário Resposta em streaming com dados tipados SDK Universal Conector único atravessando provedores, modelos e segurança
Arquitetura Final do Sistema de Orquestração

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.