~ / tutoriais /agent-improvement-loop-melhora-proprio-codigo $ _

Agent improvement loop: o ciclo que faz o agente melhorar o próprio código

Lucas Souza Lucas Souza 8 min de leitura Tutoriais
Agent improvement loop: o ciclo que faz o agente melhorar o próprio código

O pulo do gato não é o agente acertar de primeira. Isso qualquer modelo grande faz num caso fácil. O pulo do gato é o agente perceber que errou, medir o tamanho do erro e se corrigir sozinho — sem você revisando log atrás de log no domingo à noite.

Isso tem nome: agent improvement loop. É o ciclo de gera, testa, avalia e corrige que a OpenAI formalizou no cookbook do Agents SDK e que a Anthropic descreve como evaluator-optimizer. Não é mágica. É engenharia de loop.

Neste tutorial você vai montar o esqueleto desse loop: rodar o agente, capturar o que aconteceu, avaliar a execução com checagens duras e um juiz, e fechar o ciclo com uma correção verificada. No fim, você tem um agente que melhora medindo, não chutando.

TL;DR

  • O que é: um ciclo de auto-melhoria de agente — gera (roda), testa (captura traces), avalia (evals), corrige (aplica e verifica) — e repete até não sobrar regressão.
  • Stack/Modelos: Python, OpenAI Agents SDK (ou Claude Agent SDK), um modelo forte para o agente, um modelo para o juiz. Vale com qualquer provider.
  • Custo/Acesso: o SDK é open-source; você paga as chamadas de API do agente + do juiz. O loop completo do cookbook roda em ~20 min com os defaults.
  • Link útil: Build an Agent Improvement Loop with Traces, Evals, and Codex.

O contexto — por que o agent improvement loop importa agora

Até pouco tempo atrás, melhorar um agente era um ritual manual e triste. Você lia o trace de uma conversa que deu errado, achava no olho que o problema era o prompt, mexia numa frase, rodava de novo, torcia. Sem número. Sem garantia de que o ajuste não quebrou outros dez casos que funcionavam.

O agent improvement loop troca o "torcer" por um flywheel. A OpenAI organiza esse flywheel em quatro estágios encadeados: traces mostram o que aconteceu, feedback (humano e de modelo) explica o que importou, evals transformam essas expectativas em teste reutilizável, e a etapa de otimização ranqueia as mudanças no harness e entrega um handoff pro Codex implementar. O ponto-chave: a evidência de cada rodada vira entrada da próxima. O loop aprende.

A Anthropic chega no mesmo lugar por outro caminho. No padrão evaluator-optimizer, um LLM gera a resposta e um segundo LLM critica e devolve feedback, repetindo até passar. A regra de quando usar é honesta: "funciona melhor quando você tem critério de avaliação claro e quando o refinamento iterativo agrega valor mensurável". Sem critério claro, você só está rodando o modelo duas vezes e pagando dobrado.

E isso não é papo de slide. O MLflow descreve o mesmo loop em seis passos — configurar tracing, rodar, achar problema nos traces, quantificar com juízes, corrigir o código e verificar, repetir. E tem número de pesquisa: o paper LLMloop, com cinco loops de auto-refinamento (corrigir compilação, qualidade estática, falhas de teste), levou o pass@10 de código gerado de 76,2% para 90,2%. A diferença entre "gerou e rezou" e "gerou, testou e corrigiu".

Pré-requisitos

Antes de montar o loop, você precisa de:

  • [ ] Um agente que já roda (nem que seja um loop de tool calling cru — veja como criar um agente do zero).
  • [ ] Python 3.11+ e o openai-agents SDK (pip install openai-agents).
  • [ ] Uma chave de API com acesso a um modelo forte para o agente e outro para o juiz.
  • [ ] O mais importante: um punhado de casos de teste com resposta esperada. Não precisa de mil. Comece com 10 falhas reais que você já viu em produção. Esse é o seu golden set, e sem ele o loop não tem norte.

Se você ainda não tem evals de verdade, pare aqui e monte primeiro. Já escrevemos o passo a passo em como montar evals honestos. O loop de auto-melhoria é tão bom quanto o critério que mede "bom".

Mão na massa — os quatro estágios do loop

O loop tem quatro engrenagens. Vou mostrar cada uma com código, e depois fechar o ciclo.

Passo 1: Gera — rode o agente capturando o trace

Você não pode melhorar o que não mede. O primeiro passo é rodar o agente envolvendo a execução num trace, pra capturar não só a resposta final, mas toda a trajetória: quais tools chamou, em que ordem, com quais parâmetros.

from agents import Agent, Runner, trace

agent = Agent(
    name="suporte",
    instructions="Você responde dúvidas usando as tools disponíveis. "
                 "Sempre cite a fonte antes de afirmar um fato.",
    tools=[buscar_doc, abrir_ticket],
)

async def rodar_caso(caso):
    # trace() captura a trajetória inteira, não só o output final
    with trace(workflow_name="suporte-eval", group_id=caso["id"]):
        result = await Runner.run(agent, caso["pergunta"])
    return {
        "id": caso["id"],
        "pergunta": caso["pergunta"],
        "esperado": caso["esperado"],
        "resposta": result.final_output,
        "trajetoria": result.new_items,  # tool calls, em ordem
    }

O detalhe que separa amador de profissional: guardar trajetoria, não só resposta. Metade dos bugs de agente não está no texto final — está na sequência de tools. O agente respondeu certo, mas chamou a tool errada três vezes antes (e queimou tokens), ou inventou um fato sem chamar a busca. Sem o trace você nunca vê isso.

Passo 2: Testa — checagens duras primeiro

Antes de gastar um tostão com LLM-as-a-judge, aplique as checagens determinísticas. São baratas, rápidas e pegam os erros mais grosseiros. A OpenAI chama isso de code-based checks: validação de schema, exact-match, conformidade de formato, e — crucial pra agente — tool correctness.

def checagens_duras(caso):
    falhas = []

    # A tool de busca foi chamada antes de afirmar fato?
    tools_usadas = [t.name for t in caso["trajetoria"] if t.type == "tool_call"]
    if "buscar_doc" not in tools_usadas:
        falhas.append("respondeu sem buscar a fonte")

    # A resposta tem o formato que o contrato exige?
    if "fonte:" not in caso["resposta"].lower():
        falhas.append("não citou a fonte")

    return falhas

Se a checagem dura já reprova, nem chama o juiz. Você economiza e ainda ganha um sinal limpo: "esse caso falhou por tool errada", não um número difuso de 0 a 1.

Passo 3: Avalia — o juiz olha a trajetória, não só o texto

Para o que não tem resposta exata — tom, completude, se o raciocínio fez sentido — entra o LLM como juiz. E aqui vai o ponto que a maioria erra: o juiz não deve olhar só a resposta final. Ele avalia a trajetória inteira. Usou as tools certas, na ordem certa, com os parâmetros certos?

JUIZ_PROMPT = """Você avalia a execução de um agente de suporte.

Pergunta: {pergunta}
Resposta esperada: {esperado}
Resposta do agente: {resposta}
Tools chamadas (em ordem): {tools}

Avalie de 1 a 5 e responda em JSON:
{{"nota": <int>, "passou": <bool>, "motivo": "<frase curta e específica>"}}

Reprove (passou=false) se a resposta contradiz o esperado,
se inventou fato sem fonte, ou se a ordem de tools foi ilógica."""

async def juiz(caso):
    prompt = JUIZ_PROMPT.format(
        pergunta=caso["pergunta"],
        esperado=caso["esperado"],
        resposta=caso["resposta"],
        tools=[t.name for t in caso["trajetoria"] if t.type == "tool_call"],
    )
    veredito = await chamar_modelo_juiz(prompt)  # parse do JSON
    return veredito

Force o juiz a devolver um motivo curto e específico. "Resposta ruim" não conserta nada. "Afirmou o preço sem chamar buscar_doc" vira tarefa de correção. O juiz tem que produzir diagnóstico, não nota de prova.

Passo 4: Corrige — e verifica que a correção não quebrou nada

Aqui o loop fecha. Você junta as falhas das checagens duras e do juiz, e usa esse diagnóstico pra propor uma mudança no harness — geralmente no prompt, na descrição de uma tool, ou numa guardrail. A OpenAI deixa o Codex fazer isso de forma autônoma, gerando um codex_handoff.md com as mudanças ranqueadas. Você pode fazer manual no começo.

async def uma_iteracao(casos):
    resultados = [await rodar_caso(c) for c in casos]      # gera
    for r in resultados:
        r["falhas_duras"] = checagens_duras(r)             # testa
        r["veredito"] = await juiz(r)                      # avalia

    reprovados = [r for r in resultados
                  if r["falhas_duras"] or not r["veredito"]["passou"]]

    score = 1 - len(reprovados) / len(resultados)
    diagnostico = [f'{r["id"]}: {r["falhas_duras"]} / {r["veredito"]["motivo"]}'
                   for r in reprovados]
    return score, diagnostico

# o loop de verdade: corrige, roda de novo, só aceita se o score subir
score_antes, diagnostico = await uma_iteracao(golden_set)
# ... você (ou o Codex) aplica a mudança guiada pelo diagnostico ...
score_depois, _ = await uma_iteracao(golden_set)

if score_depois <= score_antes:
    print("regrediu ou empatou — reverte a mudança")

A trava que faz isso ser engenharia e não esperança: só aceite a mudança se o score subir no golden set inteiro. Consertar o caso 7 e quebrar o caso 2 não é melhoria, é troca de bug. É exatamente o tipo de regressão silenciosa que o loop manual no olho deixa passar — e que o MLflow resume bem: a graça é construir "uma suíte de scorers que pega regressões automaticamente".

Limitações e pontos de atenção

Esse loop não é piloto automático. Onde você se queima:

  • O juiz erra. LLM-as-a-judge tem viés — tende a gostar de resposta longa, do próprio estilo, e é manipulável. Calibre o juiz contra rótulos humanos antes de confiar nele pra aprovar mudança em produção. Trate o juiz como um eval que também precisa de eval.
  • Overfitting no golden set. Se você só otimiza pros 10 casos que tem, o agente fica ótimo neles e continua quebrando no resto. Rotacione e amplie o golden set com falhas novas de produção. Ele é vivo, não fixo.
  • Loop que custa caro. Cada iteração roda o agente + o juiz em todos os casos. Com golden set grande e modelo caro, a conta sobe rápido. Use checagem dura como primeiro filtro e reserve o juiz pro que sobrou.
  • Auto-correção sem freio vira loop infinito. Defina um número máximo de iterações e uma condição de parada clara: parou de melhorar, parou de rodar.

Esse bloco não é detalhe. É o que separa um agente que melhora de um agente que gira em falso queimando dinheiro.

FAQ rápido

Isso é a mesma coisa que fine-tuning? Não. Fine-tuning muda os pesos do modelo. O agent improvement loop melhora o harness em volta do modelo — prompt, tools, guardrails, política. É mais barato, mais rápido de iterar e você entende exatamente o que mudou. Na maioria dos casos de produto, mexer no harness resolve antes de precisar de fine-tuning.

Preciso do Codex ou de uma ferramenta específica? Não. O Codex automatiza o passo de aplicar a correção, mas o loop é agnóstico de ferramenta. Funciona com o OpenAI Agents SDK, com o Claude Agent SDK, com MLflow, ou com Python puro. A peça que importa é o critério de avaliação, não o vendor.

Quantos casos preciso no golden set pra começar? Comece com 10 a 20 falhas reais. Quantidade pequena de casos certos (que pegam dores reais) bate dataset gigante de casos genéricos. Cresça à medida que produção te entrega novos modos de falha.

Dá pra rodar o loop em produção, contínuo? Dá, e é o destino. Traces reais de produção viram casos novos, que viram evals, que disparam a próxima rodada de otimização. Esse é o flywheel completo. Só não solte a correção automática em produção sem um humano no portão até o juiz estar calibrado.

Conclusão

O agente que impressiona na demo acerta o caso fácil. O agente que aguenta produção é o que percebe que errou, mede o erro contra um critério honesto e fecha o loop com uma correção que não quebra o resto. Gera, testa, avalia, corrige. Repete.

Não é hype de "IA que se programa sozinha". É loop engineering: traces de verdade, evals que medem trajetória, e uma trava que só aceita mudança quando o número sobe. O modelo é a peça mais fácil. O loop em volta dele é o trabalho.

E o loop em volta do modelo é exatamente o harness — o ambiente que decide se o agente vive ou trava. Se você quer ver esse harness sendo construído do zero, do prompt até o agente rodando, é o que a gente vai montar ao vivo no Do Prompt ao Harness: construindo um agente de vendas: código na tela, decisão de arquitetura na mesa, sem slide motivacional. Se ainda tem dúvida do que é esse ambiente, comece por aqui e depois venha montar o seu.

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

VirguIA

beer & code assistant

conectando…

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

tocando