Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 54

Parsing Test Results for Quality Assurance

Recommended resources

Olá! Bem-vindo de volta à nossa jornada para construir um agente de codificação autônomo.

Na lição anterior, você configurou o pipeline de CI para executar testes de unidade, estabelecendo um portão de qualidade crucial para validar a lógica do código gerado. Atualmente, o pipeline nos informa se os testes falharam (através de um código de saída diferente de zero), mas para que nosso agente se autocorrija de forma inteligente, ele precisa saber por que eles falharam.

Nesta lição, vamos implementar o mecanismo de feedback. O nosso objetivo é implementar um processo para analisar os resultados dos testes e determinar se o código gerado atende aos padrões de qualidade. Você aprenderá a extrair insights detalhados de arquivos de resultados de teste para fornecer ao seu agente o contexto necessário para identificar e corrigir seus próprios erros. Este é o passo que transforma o agente de um simples gerador de código em um solucionador de problemas iterativo.

1. Além dos Códigos de Saída: A Necessidade de Resultados Estruturados

Um simples "passou" ou "falhou" não é suficiente para a auto-correção. Um agente inteligente precisa de respostas para perguntas como:

  • Qual teste específico falhou?
  • Qual era o resultado esperado e qual foi o resultado real?
  • Em qual linha de código a falha ocorreu?

Felizmente, as ferramentas de teste modernas podem gerar relatórios detalhados em formatos de máquina. Os mais comuns para o seu stack são:

  • TRX (.trx) para .NET: Um formato XML detalhado que pode ser gerado pelo dotnet test com o argumento --logger "trx;LogFileName=test-results.trx".
  • JUnit XML (.xml): Um formato XML que se tornou o padrão de fato no mercado, suportado por inúmeras ferramentas, incluindo o Jest (o executor de testes comum em projetos React) através de reporters como jest-junit.

Ambos os formatos estruturam as informações de maneira semelhante, contendo elementos para suítes de teste, casos de teste individuais, e, mais importante, nós <failure> ou <error> que contêm a mensagem de erro e o stack trace. É a análise programática desses arquivos que alimentará nosso ciclo de feedback.


2. O Padrão "LLM in a Loop" para Auto-Correção

A ideia de um agente que melhora seu próprio trabalho com base em feedback é um padrão de design poderoso, frequentemente chamado de "LLM in a Loop". Em vez de uma interação única, o agente entra em um ciclo de geração e avaliação até que um padrão de qualidade seja atingido.

LLM in a Loop: Automate feedback with evals

O vídeo 'LLM in a Loop: Automate feedback with evals' de Shaw Talebi oferece uma excelente introdução teórica a este conceito fundamental.

Assista a estas duas seções principais para entender a base do que estamos construindo: 00:00:00 - 02:11: Esta parte introduz a motivação principal. Assim como um humano refina um prompt em uma conversa com o ChatGPT, podemos automatizar esse processo de refinamento para o nosso agente. 02:11 - 02:48: Aqui, o vídeo apresenta um exemplo concreto que se alinha perfeitamente com nosso objetivo: um agente de codificação escreve código, e o feedback para o loop é baseado na aprovação ou reprovação dos testes de unidade.


3. Implementando a Verificação de Qualidade

Agora que entendemos o padrão, como o implementamos na prática? Nosso processo de verificação de qualidade será baseado em regras, o método mais direto e confiável.

Passo 1: Definindo a Avaliação Baseada em Regras

Vamos usar o mesmo vídeo para categorizar nosso método de avaliação.

LLM in a Loop: Automate feedback with evals

Para construir o loop, precisamos de uma forma automática de avaliar a saída do agente. Vamos retornar ao vídeo de Shaw Talebi para entender que tipo de avaliação estamos usando.

Concentre-se nestes segmentos: 04:35 - 05:29: Apresenta três tipos de avaliações. Nosso foco será no primeiro tipo: avaliações baseadas em regras (rule-based evals). 05:29 - 07:12: Detalha o que são as avaliações baseadas em regras. Preste atenção especial aos 'testes binários', como a verificação de erros. É exatamente isso que faremos: analisar um arquivo de resultado de teste para obter uma métrica de 'passou/falhou' para cada caso de teste.

Em nosso cenário, a "regra" é simples: todos os testes de unidade devem passar. Se algum falhar, a avaliação falha, e o ciclo de correção é acionado.

Passo 2: Um Blueprint Prático para o Ciclo de Correção

O padrão de implementação para este ciclo é notavelmente consistente entre diferentes linguagens e frameworks.

Code Generation and Validation Workflow
Este diagrama ilustra o fluxo que estamos construindo. Uma pergunta (ou tarefa do Jira) inicia a geração de código. O código passa por verificações (em nosso caso, testes de unidade). Falhas nessas verificações geram um feedback que alimenta a próxima tentativa de geração, criando um ciclo de melhoria iterativa.

O artigo a seguir, embora focado em Python e LangGraph, fornece um excelente blueprint arquitetural que podemos adaptar.

LangGraph: Building Self-Correcting RAG Agent for Code Generation

O artigo 'LangGraph: Building Self-Correcting RAG Agent for Code Generation' detalha um blueprint prático para este ciclo de auto-correção. Os conceitos são universais e se aplicam diretamente ao nosso projeto.

Leia as seguintes seções para entender os componentes-chave: 'The Self-Correcting Agent’s Blueprint': Esta seção introduz o ciclo com três nós principais: Generate (Gerar), Check Code (Verificar Código) e Reflect (Refletir). Este é o nosso padrão central. A descrição do nó code_check (dentro da seção 'Nodes (The Logic)'): Este é o coração da lição. O exemplo usa exec() dentro de um bloco try-except. Para o nosso agente, o code_check não usaria exec(), mas sim executaria o comando de teste (ex: dotnet test) e, em seguida, analisaria o arquivo de resultado (TRX/JUnit). Note como ele captura a exceção, define uma flag de error e salva a mensagem de erro. É exatamente assim que você processaria um teste falho. A descrição da aresta condicional should_continue (dentro de 'Edges (The Control Flow Loop)'): Esta é a lógica de decisão. A função verifica a flag error e um contador de iterações para decidir se o ciclo deve parar ou continuar. Essa lógica é vital para evitar loops infinitos.

O seu orquestrador de agente (seja um script em Python, C# ou uma app Forge) implementará essa lógica:

  1. Chamar o nó Generate: Invocar o LLM (via Rovo ou outra API) para gerar o código.
  2. Chamar o nó Check Code:
    • Executar o pipeline de CI ou um script local que roda os testes.
    • Analisar o arquivo test-results.trx ou junit.xml resultante.
    • Se houver falhas, extrair os detalhes (nome do teste, mensagem, stack trace).
    • Retornar um estado indicando "falha" e os detalhes do erro.
  3. Avaliar com should_continue:
    • Se o estado for "sucesso", o trabalho está concluído.
    • Se for "falha", mas o limite de tentativas não foi atingido, continuar para o próximo passo.
    • Se o limite de tentativas foi atingido, parar e sinalizar para revisão humana.
  4. Chamar o nó Reflect / Generate: Formatar os detalhes do erro em um novo prompt e chamar o LLM novamente, reiniciando o ciclo.

4. Construindo o Prompt de Feedback

A qualidade da auto-correção depende diretamente da qualidade do feedback. Depois de analisar o arquivo de resultados, você deve construir um prompt claro e informativo.

Exemplo de Prompt de Feedback:

O código gerado falhou na verificação de qualidade. O(s) seguinte(s) teste(s) de unidade falhou(aram):

Caso de Teste: Test_CalculateTotalPrice_WithDiscount
Mensagem de Erro: Assert.AreEqual failed. Expected: <90.00>. Actual: <100.00>.
Stack Trace:
at Tests.OrderServiceTests.Test_CalculateTotalPrice_WithDiscount() in C:\\...\\OrderServiceTests.cs:line 45

Tarefa: Analise o teste que falhou, o requisito original da tarefa do Jira e o código que você gerou. Forneça uma versão corrigida do método CalculateTotalPrice que satisfaça o teste.

Este prompt fornece ao LLM todo o contexto necessário para entender o erro e propor uma solução direcionada.


5. Visão Holística: Agentes de Teste End-to-End

Os princípios que discutimos para testes de unidade podem ser estendidos para validações mais complexas, como testes de ponta a ponta (E2E), que simulam a jornada de um usuário real.

This One Command Makes Coding Agents Find All Their Mistakes (Use it Now)

Para ampliar nossa perspectiva, este vídeo de Cole Medin demonstra um poderoso agente 'autocurável' (self-healing) que realiza um fluxo de trabalho de validação completo, incluindo testes E2E.

Assista a estes segmentos para ver nossas ideias em ação em uma escala maior: 05:28 - 08:36: Observe como o agente percorre iterativamente as jornadas do usuário, verifica seu trabalho e até corrige problemas bloqueantes antes de testar novamente. Este é o nosso ciclo 'Generate-Check-Reflect' em um cenário do mundo real. 08:36 - 09:26: Preste muita atenção ao relatório final estruturado. O agente não apenas para; ele comunica o que foi corrigido e quais problemas permanecem. Seu agente pode gerar relatórios semelhantes a partir dos resultados de teste analisados. 16:07 - 17:01: Mostra o resultado final de uma execução, categorizando claramente os problemas corrigidos versus os restantes. Essa saída estruturada é o objetivo do nosso processo de análise — é o que torna o trabalho do agente auditável e acionável.

Uma ressalva importante aqui é o risco de "Reward Hacking", um conceito discutido no vídeo de Shaw Talebi (seção de 23:03 a 25:22). Se os testes forem fracos, o agente pode aprender a "enganá-los" (passar nos testes sem realmente corrigir o problema subjacente). Isso reforça a importância de ter uma suíte de testes robusta e bem escrita, um ponto que abordamos na lição anterior com o Mutation Testing.


Conclusão

Nesta lição, você aprendeu a fechar o ciclo de feedback do seu agente. Em vez de apenas saber que algo deu errado, agora você tem um plano para descobrir exatamente o quê, por que e como comunicar isso de volta ao agente para que ele possa se corrigir.

Principais Pontos:

  • A auto-correção eficaz exige a análise de resultados de teste estruturados (como TRX e JUnit XML), não apenas a verificação de códigos de saída.
  • O padrão "Generate-Check-Reflect" forma o núcleo de um agente de codificação autônomo e iterativo.
  • O processo envolve executar testes, analisar os arquivos de log para extrair detalhes de falhas e usar um roteador condicional para controlar o fluxo do loop.
  • A construção de um prompt de feedback detalhado é crucial para guiar o LLM na correção do erro.
  • A qualidade da auto-correção está diretamente ligada à qualidade da sua suíte de testes.

Com os três portões de qualidade — linting, build e testes — e um mecanismo para analisar os resultados, seu agente agora tem um sistema de QA robusto. Ele pode gerar código, verificar sua conformidade, sintaxe, e agora, sua correção lógica.

Na próxima lição, avançaremos para a última etapa de garantia de qualidade deste módulo: "Validar scripts de migração de banco de dados gerados para compatibilidade de sintaxe com MariaDB". Isso abordará um requisito específico e crítico do seu projeto: garantir que as alterações propostas no banco de dados sejam seguras e válidas.