CodeGym /Cursos /ChatGPT Apps /Processos multietapas: auto-orquestração pelo modelo e co...

Processos multietapas: auto-orquestração pelo modelo e controle de ciclos

ChatGPT Apps
Nível 12 , Lição 3
Disponível

1. O que é um run multietapas e em que ele difere de uma solicitação “única”

Quando você trabalhava apenas com o ChatGPT App e MCP tools, o fluxo era bem linear: chegou a solicitação do usuário → o GPT decidiu chamar uma ou mais ferramentas → você deu a resposta ao usuário. Isso ainda pode ser considerado “um passo lógico”, mesmo que dentro da ferramenta você fizesse algo mais complexo.

Para um agente, run é objetivo + série de etapas. Não pensamos mais em “um prompt — uma resposta”, e sim encaramos a tarefa como um mini-projeto que o agente conduz do início ao fim.

Podemos ver a diferença assim:

Tipo de interação O que o modelo faz Onde fica a lógica
Chamada comum de ferramenta no ChatGPT App Decide se deve chamar a ferramenta, preenche os argumentos, compõe a resposta com base no resultado A lógica de negócio principal e a sequência de ações — em uma única ferramenta ou no backend
Run de agente (Agents SDK) Planeja várias etapas, decide quando e qual tool chamar, analisa resultados intermediários, pode revisar o plano A lógica “de como chegar ao objetivo” fica parcialmente na instrução de sistema do agente e parcialmente “na cabeça” do modelo

Ponto importante: você não precisa entregar o planejamento completamente ao modelo. Normalmente sai um híbrido: você codifica rigidamente as grandes fases do roteiro (por exemplo, “primeiro coletar requisitos, depois escolher presentes, depois preparar o cartão”), e dentro de cada fase permite que o agente use suas ferramentas com bastante liberdade.

Mini analogia

Uma chamada única de ferramenta é como chamar um entregador: “pegue um documento e traga ao escritório”.

Um run agente multietapas é como um assistente pessoal: “Prepare um presente para um colega para o aniversário: descubra do que ele gosta, selecione algumas opções, verifique a entrega e junte tudo em uma apresentação bonita”. O assistente decide quais ações tomar ao longo do caminho.

Mais adiante na aula veremos também como esses runs multietapas se encaixam no stack já conhecido Apps SDK → MCP → backend, para que, para o ChatGPT e para o widget, a lógica do agente pareça uma ferramenta MCP comum e bem definida.

2. Como o modelo planeja as etapas: visão de alto nível

Em termos do Agents SDK, cada run é convenientemente visto como uma tríade:

  1. Goal (objetivo): descrição textual da tarefa, que entra nas instruções system/user do agente.
  2. Tools: conjunto de ferramentas disponíveis com boas descrições e JSON Schema.
  3. State: histórico de etapas e estado estruturado que você mantém externamente (BD, Redis, o que for).

Em seguida funciona o ciclo de run conhecido: o modelo observa o objetivo e as ferramentas disponíveis e, a cada etapa, decide:

  • “Agora tenho informações suficientes — posso fornecer o resultado final ao usuário”;
  • ou “Preciso chamar a ferramenta X com tais argumentos”;
  • ou “Recebi o resultado da ferramenta, agora preciso interpretá-lo, filtrá-lo e, possivelmente, chamar outra ferramenta”.

No nível de pseudocódigo, a ideia é assim (lembrete: é um modelo mental, não uma API real):

while (!done && steps < MAX_STEPS) {
  const modelResponse = await callModel({
    system: agentPolicy,
    messages: history,
    tools,
  });

  if (modelResponse.type === "tool_call") {
    const toolResult = await callTool(modelResponse.toolName, modelResponse.args);
    history.push({ role: "tool", content: toolResult });
  } else {
    // resposta final
    done = true;
    return modelResponse.content;
  }

  steps++;
}

No Agents SDK real, todo esse ciclo já está implementado e “escondido” dentro da biblioteca. Você descreve o agente de forma declarativa, e o SDK coloca modelo e ferramentas para rodar em ciclo até obter a resposta final ou atingir os limites de etapas/tempo.

A tarefa do arquiteto é:

  • formular o goal e a instrução de sistema de modo que o modelo planeje etapas razoáveis;
  • montar um conjunto de ferramentas sem sobreposição de significado;
  • definir limites de etapas e tempo;
  • pensar em quais etapas podem ser paralelas.

Quando temos objetivo, ferramentas e uma visão do estado, a próxima pergunta é — por quais etapas chegar a esse objetivo. Nem todas as etapas são iguais: algumas são estritamente sequenciais, outras podem ser paralelizadas.

3. Etapas sequenciais e paralelas

Agora que temos um entendimento básico do ciclo de run do agente, é importante entender quais tipos de etapas existem dentro desse processo. No workflow do agente há dois tipos principais: sequenciais e paralelas.

Etapas sequenciais

É quando o resultado da etapa A é criticamente necessário para a etapa B. Por exemplo, no nosso GiftGenius didático:

  1. Primeiro é preciso entender quem é o destinatário do presente: colega, parente, idade, interesses.
  2. Depois selecionar um conjunto de candidatos via a tool search_gifts.
  3. Em seguida filtrar conforme o orçamento e restrições.
  4. Depois formatar cartões bonitos para o widget.
  5. E só então, talvez, sugerir ir ao checkout.

Cada etapa seguinte depende dos dados da anterior; por isso, a execução é estritamente sequencial.

Em pseudocódigo do comportamento do agente, isso pode parecer um “plano interno” do modelo:

1. Perguntar ao usuário sobre o destinatário e o orçamento
2. Chamar a tool search_gifts(profile, budget)
3. Chamar a tool filter_by_constraints(gifts, constraints)
4. Montar a lista final e a descrição

O modelo não escreve uma lista dessas em código, mas podemos induzi-lo a essa estrutura por meio de instruções de sistema, exemplos de diálogo e descrição das ferramentas.

Etapas paralelas

Às vezes, as etapas podem ser executadas de forma independente. Por exemplo, queremos comparar propostas de presentes de três lojas ao mesmo tempo:

  • search_gifts_amazon
  • search_gifts_etsy
  • search_gifts_local_store

Do ponto de vista do agente, são três chamadas independentes de ferramentas, que podem ser executadas em paralelo para reduzir o tempo total de resposta.

No Agents SDK (e, em geral, nos frameworks modernos de agentes) geralmente há suporte embutido a chamadas paralelas de ferramentas, caso o modelo proponha várias chamadas de uma vez em uma etapa. O cenário canônico: o modelo descreve na resposta uma lista dessas chamadas, o SDK as executa de forma concorrente, coleta os resultados e os insere como um conjunto de mensagens tool para a próxima etapa do modelo.

Do ponto de vista de planejamento, fica assim:

// Passo do agente: o modelo decidiu chamar três ferramentas
const calls = [
  { name: "search_gifts_amazon", args: {...} },
  { name: "search_gifts_etsy", args: {...} },
  { name: "search_gifts_local_store", args: {...} },
];

const results = await Promise.all(
  calls.map(c => callTool(c.name, c.args))
);

// Em seguida, todos os resultados são adicionados ao contexto antes do próximo passo do modelo

Se você já escreveu frontend em JS/TS, já se deparou com a ideia de solicitações paralelas: por exemplo, quando usa Promise.all para disparar vários fetch() ao mesmo tempo. Agora a mesma ideia aparece dentro do ciclo de run do agente, só que a decisão do que exatamente pode ser executado em paralelo é tomada em grande parte pelo próprio modelo.

4. Exemplo de workflow para GiftGenius: etapas, objetivos e ferramentas

Na seção sobre etapas sequenciais, já dividimos intuitivamente o comportamento do GiftGenius em fases. Agora vamos formalizar esse mesmo cenário multietapas como um workflow de agente: vamos descrever o objetivo, as etapas e vinculá-las às ferramentas e à configuração do agente. Ainda não vamos nos prender a uma API específica do Agents SDK; vamos descrever a estrutura e adicionar um pouco de TypeScript “condicional” para fixar.

Objetivo (goal)

Que o objetivo seja:

Ajudar o usuário a selecionar de 3 a 5 opções de presente para um destinatário específico, considerando o orçamento, as ocasiões e as restrições de entrega, e fornecer uma lista estruturada de cartões de presentes para o widget GiftGenius.

Etapas principais

Vamos descrever a versão mínima com 4 etapas:

  1. Esclarecimento do contexto do destinatário
    Objetivo: coletar informações sobre quem vai receber o presente (idade, gênero, interesses, relação com quem presenteia), além do orçamento e da data do evento.
    Ferramentas: possivelmente, nenhuma ferramenta — apenas diálogo modelo ↔ usuário.
  2. Busca e triagem inicial de presentes
    Objetivo: obter uma amostra “bruta” de presentes.
    Ferramentas: search_gifts(profile, budget) — tool que consulta nosso catálogo/sistema de busca e retorna uma lista de candidatos.
  3. Filtragem e ordenação
    Objetivo: descartar opções inadequadas (sem entrega para a região, fora do orçamento, restrições inadequadas) e ordenar por relevância.
    Ferramentas: filter_and_score_gifts(candidates, constraints) — ferramenta pura e idempotente.
  4. Formatação do resultado para o widget
    Objetivo: trazer os dados para um formato conveniente para o UI: título, descrição curta, imagem, preço, CTA.
    Ferramentas: format_gift_cards(gifts) — pode ser tanto uma ferramenta de código (geração de estrutura) quanto uma ferramenta LLM (textos estéticos).

Como isso pode parecer na configuração do agente

Vamos supor que temos um construtor de agentes (pseudocódigo):

import { createAgent } from "@acme/agents-sdk";
import { tools } from "./gift-tools";

export const giftAgent = createAgent({
  name: "gift-guru",
  system: `
    Você é o agente GiftGenius e ajuda a escolher presentes.
    Objetivo: sugerir 3–5 opções que possam realmente ser compradas,
    considerando o perfil do destinatário, o orçamento e as restrições de entrega.
    Primeiro esclareça os detalhes importantes, depois use as ferramentas de busca e filtragem.
    Não chame ferramentas se ainda não souber o orçamento ou os interesses principais.
    Encerre o trabalho quando tiver uma lista clara de cartões de presentes.
  `,
  tools, // aqui estarão search_gifts, filter_and_score_gifts, format_gift_cards
  maxSteps: 12,
  timeoutMs: 15000,
});

Observe alguns detalhes:

  • Na instrução de sistema, dizemos explicitamente que o agente deve primeiro esclarecer os detalhes e só então chamar as ferramentas de busca. Isso reduz o risco de o modelo começar a acionar ferramentas com contexto muito vago.
  • Limitamos maxSteps para o agente não cair em loops infinitos.
  • O timeoutMs é necessário para que todo o run não leve a vida inteira do usuário.

5. Auto-orquestração pelo modelo: o que “deixar a critério do modelo” e o que fixar rigidamente

O agente é um equilíbrio entre a liberdade do modelo e a estrutura rígida que você define.

Se der liberdade demais ao modelo e não definir limites, você terá um “caos criativo”: chamadas de tool desnecessárias, etapas repetidas, loops não óbvios. Se, ao contrário, você codificar tudo rigidamente no backend como um autômato finito, o modelo vira apenas um decorador de texto, e não um executor inteligente de tarefas.

O que normalmente se deixa para o modelo

No contexto do GiftGenius e cenários semelhantes, é razoável confiar ao modelo:

  • a formulação das perguntas ao usuário (como esclarecer interesses, como perguntar sobre o orçamento de forma adequada);
  • a decisão sobre quando há informações suficientes para iniciar a busca;
  • a escolha de quais ferramentas usar dentro de uma fase (por exemplo, qual tool de busca de loja usar, se houver várias);
  • a geração de textos de descrições, explicações e comparações.

O que é melhor fixar rigidamente

Por outro lado, vale fixar antecipadamente:

  • as grandes fases do roteiro (“Coleta de informações” → “Busca” → “Filtragem” → “Formatação” → “Final”);
  • os limites de etapas e tempo;
  • as condições em que o agente deve “parar” e dizer honestamente ao usuário que a tarefa é insolúvel (por exemplo, se o orçamento é 5 dólares, mas é necessário um gadget eletrônico caro com entrega para amanhã);
  • a política de idempotência das ferramentas e as estratégias de tentativas (retry).

Exemplo híbrido: fases como estado, detalhamento pelo modelo

Você pode criar no state do agente um campo phase, que assumirá valores "collect_profile" | "search" | "filter" | "format" | "done". Então seu backend (ou o próprio Agents SDK, se ele suportar um state machine personalizado) controlará quais ferramentas estão disponíveis em cada fase.

Pseudocódigo:

type Phase = "collect_profile" | "search" | "filter" | "format" | "done";

interface GiftAgentState {
  phase: Phase;
  profile?: UserProfile;
  candidates?: GiftCandidate[];
  finalGifts?: GiftCard[];
}

A instrução de sistema para o agente pode incluir uma breve descrição das fases, e você, no código, limitará a lista de tools exibidas ao modelo dependendo da fase atual. Esse é um exemplo de tool gating, que é detalhado no módulo sobre workflow.

6. Controle de loops infinitos e repetições inúteis

Se der ao agente um ciclo de run sem controle, cedo ou tarde ele vai se comportar como um estudante na véspera do prazo: “esclarecendo e reescrevendo” infinitamente para evitar entregar o trabalho. Nossa tarefa é não deixá-lo travar.

Há três fontes típicas de loops infinitos:

  1. O modelo não tem certeza da resposta e continua reformulando a mesma solicitação à ferramenta com mudanças insignificantes.
  2. A ferramenta retorna consistentemente erro ou resultado vazio, e o agente insiste em “tentar de novo”.
  3. O agente fica preso entre duas ferramentas, chamando uma e depois a outra, sem avançar rumo à resposta final.

Limite de etapas (maxSteps)

O mecanismo mais simples e obrigatório é limitar a quantidade de etapas. Na maioria das implementações do Agents SDK, você pode indicar maxSteps ao iniciar o run ou na configuração do agente. Assim que o limite é atingido, o SDK encerra o run com um status especial (por exemplo, aborted_by_max_steps). Depois, você decide como mostrar isso ao usuário.

No GiftGenius, podemos considerar que uma seleção de presentes apropriada cabe em cerca de 10 etapas (alguns esclarecimentos, algumas buscas, filtragem, formatação). Definimos, por exemplo, 12–15 etapas com folga e tratamos cuidadosamente a situação quando o limite é atingido:

const run = await giftAgent.run({
  input: userGoal,
  maxSteps: 12, // sobrescrevemos o padrão
});

if (run.status === "max_steps_exceeded") {
  // Mostramos uma mensagem honesta ao usuário
}

Limite de tempo (timeout)

Às vezes o problema não é a quantidade de etapas, mas a duração total. As ferramentas podem ser lentas, a rede — instável. Por isso é útil definir timeoutMs tanto no nível de cada chamada de tool quanto no nível de todo o run.

Por exemplo, você pode decidir que:

  • cada chamada a um API externo (busca de presentes no parceiro) não deve levar mais que 3–5 segundos;
  • todo o run de seleção de presentes deve caber em 15 segundos.

Se o timeout disparar, você encerra o run com cuidado, possivelmente mostrando ao usuário um resultado parcial e uma explicação honesta de que “parte das fontes não respondeu a tempo”.

Detecção de repetições

Um padrão mais avançado (e útil) é detectar chamadas repetidas de ferramentas com os mesmos argumentos. Se você observar que o agente já chamou três vezes seguidas search_gifts(profile, budget) com os mesmos parâmetros, é sinal de que ele travou.

Você pode adicionar ao state um contador de chamadas por chave (toolName, argsHash) e, se o contador passar de um limiar, então:

  • interromper o run e retornar ao usuário um erro compreensível;
  • ou injetar uma instrução adicional ao modelo: “você já tentou chamar essa ferramenta três vezes com os mesmos parâmetros; tente mudar a estratégia ou pergunte ao usuário”.

Pseudocódigo:

function shouldAbortToolCall(toolName: string, args: unknown, state: GiftAgentState) {
  const key = `${toolName}:${hashArgs(args)}`;
  const count = state.toolCallCounts[key] ?? 0;

  if (count >= 3) return true;

  state.toolCallCounts[key] = count + 1;
  return false;
}

Onde hashArgs é qualquer função determinística de serialização dos argumentos (por exemplo, JSON.stringify com ordenação de chaves).

7. Critérios claros de conclusão da tarefa

Uma das diferenças-chave entre um agente “brincadeira” e um agente de produção é ter critérios claros de conclusão. Sem isso, o modelo pode largar a tarefa cedo demais (“aqui estão alguns presentes, se virem”) ou, ao contrário, continuar melhorando o resultado infinitamente.

No GiftGenius, podemos definir uma regra simples:

  • O agente se encerra quando tem de 3 a 5 presentes com os campos preenchidos: id, title, shortDescription, price, imageUrl, purchaseUrl, e que passaram pela filtragem de orçamento e entrega.
  • Se após no máximo N tentativas de busca e filtragem houver menos de 3 presentes adequados, o agente informa honestamente ao usuário que não foi possível encontrar nada decente e sugere ampliar o orçamento ou afrouxar as restrições.

Esses critérios podem ser codificados diretamente na instrução de sistema do agente e/ou na verificação do resultado após o run.

Exemplo de verificação de resultado após o run:

if (run.status === "completed") {
  const gifts = run.output.gifts; // suponha que nosso agente retorne um JSON estruturado

  if (!gifts || gifts.length < 3) {
    // O agente "concluiu", mas o resultado é fraco — podemos:
    // 1) mostrar uma explicação honesta,
    // 2) sugerir que o usuário altere as condições.
  } else {
    // Tudo ok — mostramos o widget com os presentes
  }
}

É importante não esperar do modelo um entendimento “mágico” de sucesso de negócio. Você, como desenvolvedor, deve formular explicitamente as condições de um resultado “satisfatório” e verificá-las.

8. Onde exatamente fica a orquestração: agente, backend, widget

Já comentamos que a orquestração pode morar em diferentes níveis: no agente, no backend, no widget.

Do ponto de vista dos processos multietapas, a lógica é aproximadamente esta.

Agente (Agents SDK) responde pelo workflow “mental”:

  • como dividir o objetivo em etapas;
  • quais ferramentas chamar e em que ordem;
  • quais perguntas adicionais fazer ao usuário.

Backend normalmente fornece:

  • a implementação das ferramentas (busca, filtro, commerce etc.);
  • armazenamento de estado e checkpoints;
  • restrições rígidas de negócio (limites de orçamento, permissões, disponibilidade por região).

Widget (Apps SDK) gerencia:

  • a exibição do progresso (stepper, barra de progresso, “etapa 2 de 4”);
  • os formulários de entrada;
  • detalhes de UX, como botões desabilitados quando nem todos os dados estão preenchidos.

Uma boa prática é pensar assim: o agente dirige o trabalho das ferramentas e o diálogo, e o widget de UI dirige a experiência visual do usuário. Eles se comunicam por meio de dados estruturados (ToolOutput, output do run do agente).

9. Miniexemplo de código: executando o agente multietapas GiftGenius a partir de uma ferramenta MCP

Agora, como prometido no início da aula, vamos conectar o novo conceito ao stack já conhecido Apps SDK → MCP → backend e mostrar um pequeno exemplo de como uma ferramenta MCP pode chamar um run de agente.

Suponha que no seu app/mcp/route.ts exista a tool run_gift_workflow, que:

  • recebe a solicitação textual do usuário (o objetivo dele);
  • inicia o agente giftAgent;
  • retorna o resultado estruturado para o widget.

O código está simplificado e é apenas ilustrativo, mas dá uma ideia da integração:

// app/mcp/route.ts
import { server } from "@modelcontextprotocol/sdk/server";
import { z } from "zod";
import { giftAgent } from "@/agents/giftAgent";

server.registerTool(
  "run_gift_workflow",
  {
    title: "Selecionar presentes",
    description: "Inicia o agente multietapas de seleção de presentes",
    inputSchema: {
      userGoal: z
        .string()
        .describe("Objetivo do usuário, por exemplo: quero um presente para um colega até US$ 50"),
    },
  },
  async ({ userGoal }) => { 		
    const run = await giftAgent.run({		// aqui executamos o agente por 12 etapas e timeout de 15 s
      input: userGoal,
      maxSteps: 12,
      timeoutMs: 15000,
    });

    return {
      status: run.status,
      gifts: run.output?.gifts ?? [],
      debug: run.debugInfo, // pode remover depois
    };
  }
);

Depois, o ChatGPT App pode chamar esse MCP-tool como qualquer outro, e seu widget GiftGenius pode construir o UI com base em gifts. Você obteve um workflow multietapas “por baixo do capô”, enquanto externamente tudo parece uma única tool bem comportada para o ChatGPT.

10. Erros típicos no design de processos multietapas

Erro nº 1: “Deixe o modelo se virar, eu só vou dar todas as ferramentas”.
Quando o agente tem acesso a uma dezena de tools com sobreposição de significado, sem uma instrução de sistema e fases claras, o modelo começa a se perder: chama a mesma coisa de maneiras diferentes, duplica solicitações, entra em loops. É melhor investir tempo no design: dividir o roteiro em fases, limitar a lista de ferramentas dentro de cada fase e declarar explicitamente a estratégia no prompt de sistema.

Erro nº 2: Ausência de limites de etapas e tempo.
Se você não definir maxSteps e timeout, em produção você rapidamente terá runs “perdidos” que consomem recursos enquanto os usuários não veem nada. Limites não são “opcional”, são higiene básica. Ao mesmo tempo, é importante tratar de forma sensata as situações de estouro de limites, e não simplesmente cair num 500 silencioso.

Erro nº 3: Não há critérios explícitos de conclusão.
O modelo encerra o run quando acha que já “basta”, mas a sua noção de “basta” pode estar longe dos requisitos de negócio. Se você não formalizar os critérios de sucesso (quantos presentes, quais campos, quais filtros foram aprovados) e não verificá-los, terá um UX instável: hoje cinco ótimas opções, amanhã uma “mais ou menos” e três duplicatas.

Erro nº 4: Não rastrear chamadas repetidas de ferramentas.
O agente pode ficar preso no padrão “recebeu erro → reformulou a solicitação mudando 2 palavras → chamou a mesma ferramenta de novo”. Se você não rastrear chamadas repetidas por (toolName, args), esses loops passarão despercebidos até que você olhe os logs e se assuste. Contadores simples e hash dos argumentos ajudam muito.

Erro nº 5: Misturar orquestração e implementação da lógica de negócio em uma única ferramenta.
Às vezes tentam esconder um workflow inteiro dentro de um único MCP-tool ou função do agente: busca, filtro, formatação e tomada de decisão. O agente perde o sentido — o modelo não consegue controlar o processo etapa a etapa; você perde transparência e a possibilidade de reutilizar partes do roteiro. É melhor extrair etapas separadas em tools independentes e dar ao agente a composição delas.

Erro nº 6: Ausência de ligação com estado e checkpoints.
Um processo multietapas sem salvar estado intermediário e checkpoints vira um monólito frágil: se algo cair no meio, o usuário precisa começar tudo de novo. Isso é especialmente crítico em cenários em que o usuário vai e volta entre etapas ou retorna depois de um tempo. Use um state store, armazene a fase, o perfil, os candidatos e permita que o agente continue do ponto certo.

Erro nº 7: Ignorar a camada de UX.
Às vezes os desenvolvedores se empolgam com o workflow interno do agente e esquecem que o usuário vê apenas o widget e as mensagens no chat. Se o UI não mostrar progresso claro, status como “procurando presentes…”, “filtrando opções…”, o usuário vai achar que o app “travou” ou “não está fazendo nada”, mesmo que o agente esteja orquestrando um processo complexo. Ao planejar um run multietapas, pense desde já em como ele aparecerá na interface.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION