Trocar Agente por Chain (Replace Agent with Chain) é uma refatoração de IA para sistemas com LLM, do grupo Movendo controle. Quando o caminho é sempre o mesmo, fixar a ordem das etapas no código.
Um agente com ferramentas decide a cada volta o que fazer, mas o caminho é sempre o mesmo. Ele custa mais, demora mais e às vezes pula um passo. É o smell Agente Onde Bastava uma Chain.
A triagem de currículos da Empresa extrai dados, confere requisitos obrigatórios, pontua e grava no ATS. Os traces de uma semana mostram a mesma sequência em 98% das execuções: extract_resume, check_requirements, score_candidate, save_to_ats. Nas outras 2%, o modelo gravou antes de pontuar, ou pulou a checagem. Cada currículo pagou quatro voltas de “o que faço agora?” para chegar a um caminho que o código já conhecia.
O post “Building effective agents” da Anthropic (dezembro de 2024) recomenda workflows com passos fixos quando o caminho é previsível, e reserva o agente para quando o modelo precisa escolher. Esta refatoração é essa troca. O destino é Encadeamento de Prompts.
Solução
Quando o caminho é sempre igual, fixe a ordem dos passos no código. Cada passo vira uma chamada com um prompt focado ou uma função comum, e a saída de um alimenta o próximo.
Antes e depois
-agent = Agent(- system="Você processa currículos recebidos. Use as ferramentas para "- "extrair dados, checar requisitos, pontuar e gravar no ATS.",- tools=[extract_resume, check_requirements, score_candidate, save_to_ats],-)-agent.run(resume_pdf)+def process_resume(resume_pdf, job):+ data = llm_parse(EXTRACT_PROMPT, resume_pdf, schema=ResumeData) # 1+ reqs = check_requirements(data, job.requirements) # 2. código+ if not reqs.mandatory_ok:+ return ats.save(data, status="nao_atende", reasons=reqs.missing)+ score = llm_parse(SCORE_PROMPT, data, job, schema=Score) # 3+ return ats.save(data, status="triado", score=score) # 4
Antes: o agente escolhe a ordem a cada volta.
flowchart TD
IN(["1. Currículo"]):::io --> A(["2. Agente decide o próximo passo"]):::llm
A --> T1["extrair"]:::tool
A --> T2["checar"]:::tool
A --> T3["pontuar"]:::tool
A --> T4["gravar"]:::tool
T1 --> A
T2 --> A
T3 --> A
Depois: a ordem está no código.
flowchart LR
IN(["1. Currículo"]):::io --> E(["2. Extrair"]):::llm
E --> C["3. Checar requisitos"]:::tool
C --> D{"4. Atende?"}
D -->|sim| S(["5. Pontuar"]):::llm
D -->|não| G[("6. Gravar no ATS")]:::store
S --> G
O currículo chega.
Uma chamada focada extrai os dados num schema.
Os requisitos obrigatórios são checados em código, sem modelo.
Uma condição simples decide se vale pontuar.
Só os currículos que atendem passam pela pontuação.
Todos são gravados, com status e motivo.
Exemplo trabalhado
Um currículo de 8 páginas. No agente, cada volta reenvia o histórico: a extração, o resultado da checagem, a pontuação. São quatro chamadas de decisão mais as ferramentas, com o PDF ecoando no contexto. Se check_requirements for uma ferramenta que o modelo “escolhe” chamar, ele pode não chamar.
Na chain, a extração é uma chamada com EXTRACT_PROMPT e schema ResumeData. A checagem é uma função: diploma obrigatório, registro no conselho, localização. Sem diploma, o código grava nao_atende e não pontua. Não existe volta em que o modelo “esqueça” esse if.
Suponha, só para ver a ordem de grandeza, 4 mil tokens de contexto por volta do agente e 4 voltas. A chain faz 2 chamadas ao modelo (extrair e pontuar) com prompts curtos, e zero chamadas nos currículos que falham a regra. Qualidade da extração e da pontuação continua medida por eval, agora por passo.
Por que funciona
Num agente, cada volta é uma chamada ao modelo para decidir o próximo passo, com o histórico inteiro reenviado. Se o próximo passo é sempre o mesmo, essas decisões são custo e risco sem benefício: o modelo pode pular a checagem de requisitos ou gravar antes de pontuar.
Na chain, o código decide a ordem. Cada chamada ao modelo faz uma coisa só, com um prompt curto e uma saída tipada, e pode ser testada sozinha. Passos que não precisam de modelo (checar requisitos, validar CNPJ, somar valores de uma NF-e) viram código comum.
A chain é mais barata, mais rápida e mais previsível. O agente vale quando o caminho muda de caso para caso: pesquisar até achar, navegar num portal desconhecido, decidir entre dez ferramentas conforme o ticket.
Passo a passo seguro
Meça. Rode o eval do agente e guarde qualidade, custo por item, latência e a sequência de ferramentas de cada execução.
Olhe as sequências. Se quase todas as execuções chamam as mesmas ferramentas na mesma ordem, a chain é o desenho certo. Agrupe os 2% restantes: são erro, ou um tipo de entrada de verdade diferente?
Liste os passos e as dependências entre eles.
Escreva um prompt focado por passo que precise de modelo, com saída estruturada.
Troque por código os passos que são regras exatas.
Ligue os passos em ordem, com as condições explícitas (o “se não atende, grava e para”).
Trate as exceções reais: se uma fração pequena dos casos precisa de um caminho diferente, crie um desvio em código ou mande para uma pessoa. Se a entrada é que muda o caminho (status vs. nota fiscal), um roteador na frente escolhe a chain certa.
Meça de novo. Qualidade igual ou melhor, custo e latência menores. Confira em especial os casos que o agente pulava.
Erro comum: chain que esquece de passar contexto
No agente, a pontuação via o PDF inteiro porque estava no histórico. Na chain, o passo 3 só vê o que você passou. Se SCORE_PROMPT receber só o schema extraído e o job pedir “experiência com NF-e descrita nas linhas 40 a 80”, a pontuação fica cega. Passe o trecho, não conte com memória de volta anterior.
Riscos
Caso que precisava de flexibilidade. Algum tipo de entrada pode depender da decisão dinâmica do agente. O eval com casos variados mostra. Currículo em imagem, currículo de outra língua, pacote com dois PDFs: se isso existe, desenhe o desvio; não volte o fluxo principal a agente.
Chain rígida demais. Se novos casos começam a exigir ramos e loops, talvez a tarefa tenha mudado. Reavalie. Um ou dois if ainda são chain. Um loop em que o modelo escolhe a próxima ferramenta já é agente de novo.
Perda do contexto entre passos. No agente, tudo estava no histórico. Na chain, passe explicitamente o que cada passo precisa.
Desafio
Este agente responde perguntas sobre o status de pedidos. O trace mostra que, em todas as execuções, ele chama find_order, depois get_tracking, e responde. Como fica a chain?
order = find_order(customer_id, hint=extract_hint(message)) # extrair a pista com uma chamada pequena ou regexif order is None: return ask("Qual o número do pedido?")tracking = get_tracking(order.id) # código, sem modeloreturn llm(REPLY_PROMPT, message, order, tracking) # uma chamada para redigir
get_invoice nunca aparece nos traces de status; se perguntas de nota fiscal existirem, elas vão para outra rota, decidida por um Roteamento na entrada.
Teste seu entendimento
Perguntas rápidas
O que é Trocar Agente por Chain?
Trocar Agente por Chain (Replace Agent with Chain) é uma refatoração de IA para sistemas com LLM, do grupo Movendo controle. Quando o caminho é sempre o mesmo, fixar a ordem das etapas no código.