Agent代码审查与批量修复流水线

代码审查与批量修复流水线

系列第 8 篇 · 前置:第 1 篇第 2 篇第 3 篇第 4 篇第 5 篇第 6 篇第 7 篇

第 5 篇讲了审查验证模式:多维度查→去重→逐个验证。这篇把它工程化:确认的问题自动分类,简单的直接修、跑测试验证,修坏了回退;复杂的只报告。

这是系列的最后一篇正文,会用到前面所有知识:parallel、pipeline、schema、haiku 分层、错误处理。


一、整体流程

markdown 复制代码
四维度并行审查(Bug/安全/性能/风格)
        ↓
      去重(纯JS)
        ↓
   逐个对抗验证(pipeline)
        ↓
   确认的问题分类
    ├── 简单问题(格式/命名/明显笔误)→ 自动修复 → 跑测试 → 失败回退
    └── 复杂问题(逻辑/架构/安全)   → 写进报告,人来处理
        ↓
   生成审查报告

和第 5 篇的区别:第 5 篇只做到"确认真问题",这篇接上"修"和"验"。


二、定义修复 Agent

yaml 复制代码
---
name: code-fixer
description: 修复简单的代码问题(格式、命名、明显笔误),只改指定问题,不重构。
tools: Read, Write, Bash
---

你是一个代码修复员。给你一个文件和一个具体问题,你只修这个问题,不改其他任何东西。

规则:
1. 只修指定的问题,不要顺手重构
2. 修完说明改了哪几行
3. 如果问题涉及逻辑改动(不是简单笔误),不要修,返回"SKIP: 需要人工确认"
4. 不要修改测试文件

给它 Read、Write、Bash(跑测试用),但 Prompt 里严格限制只改指定问题。


三、完整 Workflow

javascript 复制代码
export const meta = {
  name: 'code-review-fix',
  description: '四维度审查 → 验证 → 自动修复简单问题 → 测试验证 → 报告',
  phases: [
    { title: '四维审查' },
    { title: '验证问题' },
    { title: '自动修复' },
    { title: '生成报告' },
  ],
}

const TARGET = args.target || 'src/'
const TEST_CMD = args.testCmd || 'npm test'

// ===== 阶段1:四维度并行审查 =====
phase('四维审查')
log(`审查目标:${TARGET}`)

const DIMENSIONS = [
  { key: 'bugs', prompt: '查逻辑错误、空指针、await缺失、条件判断错误' },
  { key: 'security', prompt: '查注入风险、硬编码密钥、权限缺失' },
  { key: 'performance', prompt: '查不必要的串行、内存泄漏、重复计算' },
  { key: 'style', prompt: '查命名不一致、未使用变量、缺少注释的复杂逻辑' },
]

const allFindings = await parallel(
  DIMENSIONS.map(d => () =>
    agent(
      `审查 ${TARGET}。${d.prompt}。
       每条问题输出:文件路径、行号、问题描述、是否简单可修(true/false)。`,
      {
        label: `审查:${d.key}`,
        phase: '四维审查',
        model: 'haiku',
        schema: {
          type: 'object',
          properties: {
            issues: {
              type: 'array',
              items: {
                type: 'object',
                properties: {
                  file: { type: 'string' },
                  line: { type: 'number' },
                  description: { type: 'string' },
                  autoFixable: { type: 'boolean' },
                },
                required: ['file', 'description', 'autoFixable'],
              },
            },
          },
          required: ['issues'],
        },
      }
    ).then(result => result.issues.map(i => ({ ...i, dimension: d.key })))
  )
)

// 去重(纯JS)
const seen = new Set()
const unique = allFindings.flat().filter(i => {
  const key = `${i.file}:${i.description.slice(0, 50)}`
  if (seen.has(key)) return false
  seen.add(key)
  return true
})

log(`发现 ${allFindings.flat().length} 条,去重后 ${unique.length} 条`)

// ===== 阶段2:对抗验证 =====
phase('验证问题')

const verified = await pipeline(
  unique,
  (issue) => agent(
    `读 ${issue.file}。有人报告第${issue.line || '?'}行有问题:
     "${issue.description}"

     请验证。读文件确认。
     - 确实是问题 → 输出 CONFIRMED
     - 误报 → 输出 FALSE
     - 不确定 → 输出 FALSE(严格标准)`,
    { label: `验证:${issue.file}`, phase: '验证问题' }
  ).then(verdict => verdict.includes('CONFIRMED') ? issue : null)
)

const realIssues = verified.filter(Boolean)
const autoFixable = realIssues.filter(i => i.autoFixable)
const needHuman = realIssues.filter(i => !i.autoFixable)

log(`确认 ${realIssues.length} 条:${autoFixable.length} 条可自动修,${needHuman.length} 条需人工`)

// ===== 阶段3:自动修复 + 测试验证 =====
phase('自动修复')

const fixResults = []
for (const issue of autoFixable) {
  log(`修复:${issue.file} - ${issue.description.slice(0, 40)}`)

  const fix = await agent(
    `修复 ${issue.file} 中的问题:${issue.description}。只改这一处。`,
    { agentType: 'code-fixer', label: `修复:${issue.file}`, phase: '自动修复' }
  )

  if (fix.includes('SKIP')) {
    fixResults.push({ issue, status: 'skipped', reason: fix })
    needHuman.push(issue)
    continue
  }

  // 跑测试验证
  const test = await agent(
    `运行 ${TEST_CMD},告诉我测试是否通过。只报告通过/失败和失败原因。`,
    { label: '跑测试', phase: '自动修复' }
  )

  if (test.includes('失败') || test.includes('FAIL')) {
    // 回退:让Agent恢复文件
    await agent(
      `刚才修改 ${issue.file} 导致测试失败,请恢复这个文件到修改前的状态。
       失败原因:${test.slice(0, 300)}`,
      { label: '回退', phase: '自动修复' }
    )
    fixResults.push({ issue, status: 'reverted', reason: test.slice(0, 200) })
    needHuman.push(issue)
  } else {
    fixResults.push({ issue, status: 'fixed', detail: fix.slice(0, 200) })
  }
}

// ===== 阶段4:生成报告 =====
phase('生成报告')

const report = await agent(
  `生成代码审查报告。

   审查目标:${TARGET}

   自动修复结果:
   ${JSON.stringify(fixResults, null, 2)}

   需要人工处理的问题:
   ${JSON.stringify(needHuman, null, 2)}

   格式:
   1. 修复汇总(修了几个、回退几个、跳过几个)
   2. 需要人工处理的问题列表(文件、问题、建议)
   3. 总体评价`,
  { phase: '生成报告' }
)

return {
  target: TARGET,
  summary: {
    found: unique.length,
    confirmed: realIssues.length,
    autoFixed: fixResults.filter(r => r.status === 'fixed').length,
    reverted: fixResults.filter(r => r.status === 'reverted').length,
    needHuman: needHuman.length,
  },
  report,
}

四、关键设计

1. 为什么修复用 for 循环不用 pipeline

修复必须串行。两个 Agent 同时改同一个文件会冲突。而且每修一个要跑测试,测试失败要回退,有前后依赖。pipeline 适合各走各的,这里不行。

2. 为什么修完立刻跑测试

自动修复最大的风险是"修了一个问题,引入两个新问题"。每修一个就跑测试,一旦失败立刻回退,不会累积错误。比全修完再测安全得多。

3. 为什么回退让 Agent 做而不是 git checkout

两种方式都行。如果项目在 Git 管理下,更安全的做法是修之前先 commit,回退直接 git checkout。让 Agent 恢复文件是不依赖 Git 的方案,但不如 Git 可靠。建议:

javascript 复制代码
// 更安全的做法:修复前先提交
await agent('git add -A && git commit -m "checkpoint before auto-fix"')
// 回退
await agent(`git checkout ${issue.file}`)

4. 为什么 autoFixable 让审查 Agent 判断

审查 Agent 看了代码,它最清楚这个问题是"少了个等号"还是"架构有问题"。加一个 autoFixable 布尔字段,比在修复阶段再判断省一次 Agent 调用。

5. 安全边界

这个流程不适合直接在主分支跑。建议:

  • 新建分支跑
  • 修复前先 commit checkpoint
  • 自动修复的结果必须人工 review 后再合并
  • 安全问题(security 维度)一律不自动修,只报告

五、运行方式

bash 复制代码
# 审查 src 目录,用 npm test 验证
运行 workflows/code-review-fix.js,目标是 src/,测试命令是 npm test

# 审查单个文件
运行 workflows/code-review-fix.js,目标是 lib/utils.js,测试命令是 npm test

跑完你会得到:

  • 自动修复了几个、回退了几个
  • 需要人工处理的问题列表
  • 完整报告

六、从这个系列学到了什么

8篇下来,核心就三件事:

1. 定义 Agent 就是定义岗位

name、description、tools、Prompt。description 决定它什么时候被调用,tools 决定它能做什么,Prompt 决定它怎么做。权限收窄、规则具体、给示例,这三条做到了 Agent 就靠谱。

2. Workflow 就是用代码调度 Agent

四样 JS 走天下:await agent()、模板字符串、parallelpipeline。需要所有人结果用 parallel,各干各的用 pipeline,不知道跑多少轮用 while。能 JS 处理的别派 Agent,找问题用 haiku。

3. 工程化的关键是验证和回退

单个 Agent 写得再好也会出错。多维度查、交叉验证、修完跑测试、失败回退,这些机制比"把 Prompt 写得更完美"可靠得多。


小结

sql 复制代码
代码审查流水线 = 查 → 去重 → 验证 → 分类 → 修 → 测 → 回退

简单问题自动修,复杂问题交给人
每修一个跑一次测试,失败立刻回退
在独立分支跑,修复前commit checkpoint
相关推荐
桃西西呀15 分钟前
上下文窗口都卷到 100 万了,大模型为什么还在为"位置"发愁?
人工智能·llm·ai编程
深蓝AI30 分钟前
Mem0 实战:给 AI 应用加上长期记忆,从 Hello World 到生产用法
agent
AI效率君39 分钟前
Deer‑Flow 2.0 + Go‑MCP‑Server(add加法工具)保姆级完整教程
人工智能·agent
昭昭日月明42 分钟前
LangChain 生态:从链到代理,开发者需要掌握的三大核心
python·langchain·agent
程序员天天困1 小时前
向量检索不准怎么办:混合检索与 Rerank 重排序召回优化实战
后端·python·ai编程
Csvn1 小时前
第 12 章 并行化 Parallelization
人工智能·aigc·agent
乘风gg2 小时前
企业级 AI Coding 的 Harness 工程实战:8 个 Skill 串起全链路
前端·ai编程·claude
苏灿烤鱼2 小时前
当 AI Agent 遇见真实科学环境:深度拆解 Scientific Agent Skills,把"聊天机器人"变成"AI 科学家"
python·开源·agent