Skip to content
Tutorials13 min read

Revisão de Código no Estilo de PR do GitHub para Agentes de Programação de IA

Configure a anotação de revisão de código no estilo de PR do GitHub no Potato com comentários inline em diffs, avaliações de qualidade por arquivo e veredictos de aprovar ou rejeitar para a saída de agentes de programação.

Potato Team

Por que a Anotação de Revisão de Código Importa

A maioria dos benchmarks de agentes de programação reduz a avaliação a um binário: os testes passaram ou não? O SWE-bench reporta uma porcentagem de issues resolvidas. O HumanEval reporta pass@k. Essas métricas são úteis para rankings, mas inúteis para entender a qualidade do código.

Um agente pode passar em todos os testes e ainda assim escrever código que ninguém gostaria de manter, código com uma brecha de segurança, um caminho lento ou um estilo que briga com o resto da base de código. Um revisor humano solicitaria mudanças nesse PR mesmo com os testes verdes. Se você quer agentes que escrevam código que as pessoas realmente fazem merge, você precisa revisar o código, não apenas rodar os testes.

O schema de anotação code_review do Potato traz a experiência de revisão de PR do GitHub para dentro de uma ferramenta de anotação. Os anotadores veem diffs unificados com realce de sintaxe, clicam em linhas do diff para adicionar comentários inline, avaliam arquivos em algumas dimensões de qualidade e dão um veredicto de aprovar, solicitar mudanças ou apenas comentar, igual à revisão de um pull request real. Para a referência completa do schema, consulte a documentação de anotação de agentes de programação e o guia de avaliação de agentes.

Aqui está a interface de revisão de código no Potato, mostrando comentários inline em diffs e avaliações por arquivo:

Anotação de revisão de código com comentários inline em diffs e avaliações de arquivoInterface de revisão de código do Potato com comentários inline em diffs e avaliações de qualidade por arquivo


Visão Geral do Schema de Revisão de Código

O schema code_review tem três camadas:

  1. Comentários inline em diffs: os anotadores clicam em qualquer linha do diff para anexar um comentário categorizado (bug, estilo, desempenho, segurança, lógica, sugestão, pergunta)
  2. Avaliações por arquivo: cada arquivo modificado recebe avaliações independentes de correção (1-5) e qualidade de código (1-5)
  3. Veredicto geral: o anotador emite um veredicto final: aprovar, solicitar mudanças ou apenas comentar

Isso espelha uma revisão de código real, então parece natural para desenvolvedores, e a saída estruturada que ele produz mapeia diretamente para o treinamento de modelos de revisão de código.


CodingTraceDisplay: Como os Diffs São Renderizados

O componente CodingTraceDisplay renderiza traces de agentes de programação como uma sequência de chamadas de ferramentas e suas saídas, com tratamento especial para edições de arquivos. Quando o agente edita um arquivo, a exibição mostra um diff unificado com:

  • Linhas vermelhas: linhas deletadas (prefixadas com -)
  • Linhas verdes: linhas adicionadas (prefixadas com +)
  • Linhas cinza: linhas de contexto (inalteradas)
  • Números de linha: números de linha antigos e novos na margem
  • Realce de sintaxe: realce ciente da linguagem com base na extensão do arquivo
  • Clique para comentar: clicar em qualquer linha abre um formulário de comentário ancorado àquela linha

O diff é calculado automaticamente a partir das operações de edição do agente. Se o agente usou uma ferramenta de busca e substituição, o Potato reconstrói os estados antes/depois e gera o diff unificado.

Para agentes que produzem múltiplas edições de arquivo em um único trace (comum em correções de bugs do mundo real), cada arquivo recebe sua própria seção de diff recolhível, semelhante à aba "Files changed" do PR do GitHub.

O CodingTraceDisplay renderiza as mudanças de código com realce de sintaxe adequado:

Exibição de trace de programação com renderização de diff e árvore de arquivosCodingTraceDisplay renderizando diffs unificados com realce de sintaxe e uma barra lateral de árvore de arquivos


Categorias de Comentários

Quando um anotador clica em uma linha do diff para adicionar um comentário, ele seleciona uma categoria:

CategoriaCorDescriçãoExemplo
bugVermelhoO código tem um erro funcional"Isso vai lançar um NullPointerException se user for None"
styleAzulProblema de estilo ou convenção de código"O projeto usa snake_case para funções, não camelCase"
performanceLaranjaCódigo ineficiente"Isso consulta o banco de dados dentro de um loop; use uma consulta em lote"
securityRoxoVulnerabilidade de segurança"A entrada do usuário é passada diretamente para a consulta SQL sem sanitização"
logicAmareloProblema de lógica que pode não causar falha imediata"Esta condição deveria ser >= e não >, erro de um a mais no limite"
suggestionVerdeSugestão de melhoria, não um erro"Considere usar um context manager aqui para um gerenciamento de recursos mais limpo"
questionCinzaEsclarecimento necessário"Por que este import foi adicionado? Ele não parece ser usado"

Cada comentário também tem um corpo de texto livre onde o anotador explica o problema em detalhe, assim como ao escrever um comentário de PR real.


Avaliações por Arquivo

Depois de revisar o diff de cada arquivo, o anotador o avalia em duas dimensões:

Correção (1-5):

  • 1: não funciona, introduz novos bugs
  • 2: funciona parcialmente, tem problemas significativos
  • 3: funciona no caminho feliz, mas ignora casos extremos
  • 4: funciona corretamente com problemas menores
  • 5: totalmente correto, trata casos extremos apropriadamente

Qualidade de Código (1-5):

  • 1: insustentável, sem estrutura
  • 2: baixa qualidade, problemas significativos de estilo/design
  • 3: aceitável, segue convenções básicas
  • 4: boa qualidade, limpo e legível
  • 5: excelente, idiomático, bem documentado

Opções de Veredicto

Depois de revisar todos os arquivos, o anotador seleciona um de três veredictos:

  • Aprovar: o código está pronto para merge como está, ou apenas com mudanças triviais
  • Solicitar Mudanças: o código precisa de revisões significativas antes do merge
  • Apenas Comentar: fornecer feedback sem tomar uma decisão de merge

Isso mapeia diretamente para os três estados de revisão de PR do GitHub.


Configuração Passo a Passo

Passo 1: Converter Traces de Agentes de Programação

Os traces de agentes de programação vêm em muitos formatos. Aqui estão exemplos para três agentes populares.

Do Claude Code (exportação JSON):

bash
python -m potato.convert_traces \
  --input claude_code_sessions/ \
  --output data/code_traces.jsonl \
  --format claude_code

Do Aider (histórico de chat):

bash
python -m potato.convert_traces \
  --input aider_logs/ \
  --output data/code_traces.jsonl \
  --format aider

Do SWE-Agent (diretório de trajetórias):

bash
python -m potato.convert_traces \
  --input swe_agent_trajectories/ \
  --output data/code_traces.jsonl \
  --format swe_agent

O conversor produz um formato JSONL padronizado. Cada linha contém um trace com a tarefa, os passos do agente e os diffs dos arquivos:

json
{
  "trace_id": "swe_bench_123",
  "task": "Fix the TypeError in django/db/models/query.py when calling .values() on an empty QuerySet",
  "repo": "django/django",
  "base_commit": "a1b2c3d",
  "steps": [
    {
      "type": "thought",
      "content": "Let me look at the QuerySet.values() method to understand the TypeError."
    },
    {
      "type": "action",
      "tool": "search",
      "input": "def values",
      "file": "django/db/models/query.py"
    },
    {
      "type": "observation",
      "content": "Found at line 234: def values(self, *fields):\n    ..."
    },
    {
      "type": "action",
      "tool": "edit",
      "file": "django/db/models/query.py",
      "old_content": "    def values(self, *fields):\n        clone = self._clone()\n        clone.query.set_values(fields)",
      "new_content": "    def values(self, *fields):\n        clone = self._clone()\n        if not fields and not self.query.values_select:\n            return clone\n        clone.query.set_values(fields)"
    },
    {
      "type": "action",
      "tool": "edit",
      "file": "tests/queries/test_values.py",
      "old_content": "class ValuesTests(TestCase):",
      "new_content": "class ValuesTests(TestCase):\n    def test_empty_queryset_values(self):\n        \"\"\"Calling .values() on empty QuerySet should not raise TypeError.\"\"\"\n        qs = Author.objects.none()\n        result = list(qs.values())\n        self.assertEqual(result, [])"
    }
  ],
  "files_changed": [
    {
      "path": "django/db/models/query.py",
      "diff": "--- a/django/db/models/query.py\n+++ b/django/db/models/query.py\n@@ -234,6 +234,8 @@\n     def values(self, *fields):\n         clone = self._clone()\n+        if not fields and not self.query.values_select:\n+            return clone\n         clone.query.set_values(fields)"
    },
    {
      "path": "tests/queries/test_values.py",
      "diff": "--- a/tests/queries/test_values.py\n+++ b/tests/queries/test_values.py\n@@ -1,4 +1,10 @@\n class ValuesTests(TestCase):\n+    def test_empty_queryset_values(self):\n+        \"\"\"Calling .values() on empty QuerySet should not raise TypeError.\"\"\"\n+        qs = Author.objects.none()\n+        result = list(qs.values())\n+        self.assertEqual(result, [])"
    }
  ]
}

Passo 2: Configurar o Schema de Revisão de Código

Crie seu config.yaml:

yaml
annotation_task_name: "Coding Agent Code Review"
 
data_files:
  - "data/code_traces.jsonl"
 
item_properties:
  id_key: "trace_id"
  text_key: "task"
 
# Display coding agent traces with diff rendering
display:
  type: "coding_trace"
  trace_key: "steps"
  diff_key: "files_changed"
  syntax_highlighting: true
  show_line_numbers: true
  collapse_large_diffs: true
  max_uncollapsed_lines: 200
 
annotation_schemes:
  - annotation_type: "code_review"
    name: "review"
    description: "Review the agent's code changes as you would a GitHub PR"
 
    # Inline comment categories
    comment_categories:
      - name: "bug"
        label: "Bug"
        color: "#DC2626"
        description: "Functional error in the code"
      - name: "style"
        label: "Style"
        color: "#2563EB"
        description: "Code style or convention issue"
      - name: "performance"
        label: "Performance"
        color: "#EA580C"
        description: "Inefficient code or unnecessary computation"
      - name: "security"
        label: "Security"
        color: "#9333EA"
        description: "Security vulnerability or unsafe practice"
      - name: "logic"
        label: "Logic"
        color: "#CA8A04"
        description: "Logic issue that may not cause immediate failure"
      - name: "suggestion"
        label: "Suggestion"
        color: "#16A34A"
        description: "Improvement idea, not an error"
      - name: "question"
        label: "Question"
        color: "#6B7280"
        description: "Clarification needed"
 
    # File-level ratings
    file_ratings:
      - name: "correctness"
        label: "Correctness"
        scale: 5
        descriptions:
          1: "Does not work, introduces new bugs"
          2: "Partially works, has significant issues"
          3: "Works for happy path, misses edge cases"
          4: "Works correctly with minor issues"
          5: "Fully correct, handles edge cases"
      - name: "code_quality"
        label: "Code Quality"
        scale: 5
        descriptions:
          1: "Unmaintainable, no structure"
          2: "Poor quality, significant style issues"
          3: "Acceptable, follows basic conventions"
          4: "Good quality, clean and readable"
          5: "Excellent, idiomatic, well-documented"
 
    # Overall verdict
    verdict:
      options:
        - name: "approve"
          label: "Approve"
          color: "#16A34A"
          description: "Ready to merge as-is or with trivial changes"
        - name: "request_changes"
          label: "Request Changes"
          color: "#DC2626"
          description: "Needs significant revisions before merging"
        - name: "comment"
          label: "Comment Only"
          color: "#6B7280"
          description: "Providing feedback without a merge decision"
 
# Annotator settings
annotator_config:
  allow_back_navigation: true
 
# Output settings
output:
  path: "output/"
  format: "jsonl"

Passo 3: Iniciar o Servidor de Anotação

bash
potato start config.yaml -p 8000

Navegue até http://localhost:8000. Você verá o primeiro trace de agente de programação com a descrição da tarefa, os passos de raciocínio do agente e os diffs dos arquivos renderizados com realce de sintaxe.

Passo 4: O Fluxo de Trabalho do Anotador

Aqui está o fluxo de revisão típico:

  1. Leia a tarefa: entenda o que o agente foi solicitado a fazer (por exemplo, "Fix the TypeError in django/db/models/query.py")
  2. Revise o trace: percorra os passos de raciocínio do agente para entender sua abordagem
  3. Revise o diff de cada arquivo:
    • Leia o diff com realce de sintaxe
    • Clique em qualquer linha para adicionar um comentário inline
    • Selecione uma categoria de comentário (bug, estilo, desempenho, etc.)
    • Escreva o corpo do comentário explicando o problema
    • Avalie o arquivo em correção (1-5) e qualidade de código (1-5)
  4. Emita o veredicto: selecione aprovar, solicitar mudanças ou apenas comentar
  5. Envie: clique em "Submit" ou pressione Ctrl+Enter

Atalhos de teclado aceleram o fluxo de trabalho:

AtalhoAção
j / kNavegar entre arquivos
cAbrir comentário na linha selecionada
1-5Definir avaliação para a dimensão atual
aDefinir veredicto como aprovar
rDefinir veredicto como solicitar mudanças
Ctrl+EnterEnviar revisão

Formato de Exportação

Cada revisão enviada produz um objeto JSON estruturado:

json
{
  "trace_id": "swe_bench_123",
  "annotator": "reviewer_01",
  "timestamp": "2026-03-22T14:32:11Z",
  "review": {
    "inline_comments": [
      {
        "file": "django/db/models/query.py",
        "line": 236,
        "side": "right",
        "category": "logic",
        "body": "This early return skips set_values entirely, but if fields are provided later via .values('name'), the previous empty .values() call will have returned a clone that never went through set_values. Consider checking if this clone is still valid downstream."
      },
      {
        "file": "tests/queries/test_values.py",
        "line": 5,
        "side": "right",
        "category": "suggestion",
        "body": "Consider adding a test case for .values() followed by .values('name') to verify the chaining behavior after your fix."
      }
    ],
    "file_ratings": [
      {
        "file": "django/db/models/query.py",
        "correctness": 3,
        "code_quality": 4
      },
      {
        "file": "tests/queries/test_values.py",
        "correctness": 4,
        "code_quality": 4
      }
    ],
    "verdict": "request_changes"
  }
}

Esse formato estruturado é diretamente utilizável para treinar modelos de revisão de código e para análise agregada.


Análise: Trabalhando com Dados de Revisão

Carregando Revisões

python
import json
import pandas as pd
from pathlib import Path
 
reviews = []
for f in Path("output/").glob("*.jsonl"):
    with open(f) as fh:
        for line in fh:
            reviews.append(json.loads(line))
 
print(f"Loaded {len(reviews)} code reviews")

Distribuição das Categorias de Comentários

python
from collections import Counter
 
all_comments = []
for rev in reviews:
    for comment in rev["review"]["inline_comments"]:
        all_comments.append(comment)
 
category_counts = Counter(c["category"] for c in all_comments)
print("Comment categories:")
for cat, count in category_counts.most_common():
    print(f"  {cat}: {count}")

Avaliações Médias por Arquivo

python
ratings = []
for rev in reviews:
    for fr in rev["review"]["file_ratings"]:
        ratings.append(fr)
 
ratings_df = pd.DataFrame(ratings)
print("Average ratings by file:")
print(
    ratings_df.groupby("file")[["correctness", "code_quality"]]
    .mean()
    .round(2)
    .to_string()
)

Distribuição dos Veredictos

python
verdict_counts = Counter(rev["review"]["verdict"] for rev in reviews)
total = sum(verdict_counts.values())
print("Verdict distribution:")
for verdict, count in verdict_counts.most_common():
    print(f"  {verdict}: {count} ({count/total*100:.1f}%)")

Taxa de Bugs por Agente

Se seus traces incluem um campo agent, você pode comparar as taxas de bugs entre agentes:

python
agent_bugs = {}
for rev in reviews:
    agent = rev.get("agent", "unknown")
    bug_count = sum(
        1 for c in rev["review"]["inline_comments"]
        if c["category"] == "bug"
    )
    if agent not in agent_bugs:
        agent_bugs[agent] = []
    agent_bugs[agent].append(bug_count)
 
print("Average bugs per review by agent:")
for agent, bugs in sorted(agent_bugs.items()):
    print(f"  {agent}: {sum(bugs)/len(bugs):.2f} (n={len(bugs)})")

Casos de Uso

Treinando Modelos de Revisão de Código

Os comentários inline estruturados, as avaliações de arquivo e os veredictos da anotação de revisão de código do Potato são dados de treinamento ideais para modelos automatizados de revisão de código. Cada revisão fornece:

  • Feedback localizado vinculado a linhas específicas do diff
  • Problemas categorizados (bug vs. estilo vs. desempenho)
  • Sinais de qualidade em múltiplas granularidades (linha, arquivo, geral)

Esse é o formato de dados usado por ferramentas como CodeRabbit e o revisor de IA do Graphite, mas gerado por especialistas humanos em vez de destilado de um LLM.

Avaliando Agentes de Programação no SWE-bench

O SWE-bench diz se o agente resolveu a issue (os testes passam), mas não se o código pode ser mesclado. Ao rodar a anotação de revisão de código nas soluções do SWE-bench, você pode identificar agentes que resolvem issues com código limpo versus agentes que resolvem issues com gambiarras. Isso produz um ranking mais matizado que se correlaciona com a experiência real dos desenvolvedores.

Construindo Conjuntos de Dados de Qualidade de Código

Agregue dados de revisão de código de muitos traces para construir conjuntos de dados de problemas comuns de qualidade de código em código gerado por IA. Esses conjuntos de dados podem ser usados para:

  • Fazer fine-tuning de modelos de geração de código para evitar erros comuns
  • Construir linters específicos para padrões de código gerado por IA
  • Treinar classificadores que sinalizam problemas prováveis na saída do agente antes da revisão humana

Resumo

O schema code_review do Potato coloca o fluxo de trabalho de revisão de PR do GitHub dentro da avaliação de agentes. Os comentários inline, as avaliações de arquivo e os veredictos que você coleta fornecem dados estruturados de qualidade de código, o que é muito mais do que um resultado de teste de passou/falhou revela. Esses são os dados de que você precisa, seja para treinar um modelo de revisão de código, separar soluções limpas do SWE-bench das cheias de gambiarras, ou apenas estabelecer uma linha de base de qualidade para o seu agente.