ENZH
和 AI 讨论这篇文章
ChatGPTClaude

审代码这活,我也交给 agent team 了

📊 幻灯片

四个 AI 审查员并行审代码四个 AI 审查员并行审代码

上一篇讲的是构建:十个任务拆给五个 AI,按 DAG 分三波调度,Mio 的多模态输入、增强 onboarding 和 selfie 生成,一个 session 全部落地。但构建完其实活只干了一半——五个并行 agent 产出了 81 个 commit,横跨三层架构,代码能跑,typecheck 也全过,可是能跑只能说明它没写崩,扛不扛得住是另一回事,中间还差一轮认真的 review。所以这篇讲的就是另一半:代码审查、修 bug、发版本,用的还是同一套 agent team 的模式,只是干的活完全不同。


这个 session 是从一次崩溃恢复开始的,context 已经被压缩过一轮。所以第一步不是接着干活,是先重新确认状态:

比 origin 领先 38 个 commit
TypeScript: 0 errors

基线没什么问题。但扫 repo 状态的时候顺手扫出来一个 bug:{custom_story} 这个占位符泄漏到 LLM prompt 里了。五个人格配置文件里都留着这种死掉的模板占位符,本来应该在 onboarding 阶段被替换掉,结果替换逻辑根本没处理它,于是它就原封不动地出现在发给模型的 system prompt 里。这种 bug 麻烦就麻烦在它是「能跑」的:模型看到这段乱码会直接忽略,照常回复,功能上什么都没坏,但每条消息都在白白浪费 token,而且真有人去检查 prompt 的话,看到一个裸的 {custom_story} 挂在里面,还是挺尴尬的。修起来很小,不过这也正是发布前要做 review 的原因:这类东西你不主动去查,它永远不会自己冒出来。


四个专业 reviewer,各看各的

我跟 claude code 说了一句:"ok do a full review with agent team of the implementations." 它就启动了四个专业的审查 agent,各管一个领域:

  1. Media reviewer——transcribe、vision、process、selfie、reference-images、file-download 这一摊。
  2. Onboarding reviewer——状态机、命令、预设配置、schema。
  3. Pipeline reviewer——server 的 index.ts、router、system-prompt、agent loop。
  4. Security auditor——API key、输入验证、路径穿越、SSRF、prompt 注入、成本滥用。

为什么要分专业?其实跟人类团队一个道理:同一个文件,安全专家和功能 reviewer 看到的东西是不一样的。通用 reviewer 盯的是代码本身写得对不对;security auditor 不太管这个,它整个心思都在攻击面上,在找哪些地方能被人钻进去。四份报告大概五分钟内全部回来了,汇总是这样:

同一份代码,通用审查员盯正确性、安全审查员盯攻击面,专业分工才能各自发现对方漏掉的 bug同一份代码,通用审查员盯正确性、安全审查员盯攻击面,专业分工才能各自发现对方漏掉的 bug

审查员结论CRITICALHIGHMEDIUM
MediaWARNING0410
PipelineBLOCK246
OnboardingWARNING047+
SecurityBLOCK245

两个 BLOCK 加两个 WARNING,这个状态是不能发布的。四个 CRITICAL 具体是这些:

  • 成本归因缺失。processMedia()userId 可用之前就被调用了,媒体处理的成本没法归到正确的用户头上。
  • 打字指示器泄漏。消息批次为空的时候 clearInterval 没被调用,bot 会一直显示「正在输入...」。
  • HTTP API 路径穿越。/api/agents 这个端点收一个 presetId 参数,直接拼进了文件路径,没有任何验证,很经典的目录穿越漏洞。
  • bot token 泄漏到下载 URL。Telegram 的文件下载 URL 本身就带着 bot token,下载出错的时候,这个 URL 连着 token 可能一起被打进错误日志。

HIGH 大概有十个,四份报告去重之后是:引用图片的缓存没有上限(这条三个 reviewer 分别都标了);selfie 和 media 操作没有超时;生成端点没有限流;.replace() 里的 $ 符号会造成模板注入;item.size 是 undefined 的时候文件下载没有大小上限;没有 MIME 类型验证;超时之后 about_user 被设成空字符串,把验证绕过去了;/reonboard 在 onboarding 进行中的时候有竞态条件;bubble transform 里出现 NaN 的 token 计数;成本追踪静默失败,.catch(() => {}) 把错误直接吞了。

这里面有些问题,一个认真的通用 reviewer 也能找到。但路径穿越和 bot token 泄漏这种,是 security auditor 专门去探攻击面才探出来的;成本归因那个,是 pipeline reviewer 顺着数据流追出来的——那条数据流横跨好几个模块,不专门顺着追根本注意不到。所以分专业这个成本我觉得花得挺值。


三个 fixer,严格按文件分

拿到审查结果之后,启动了三个修复 agent。分工严格按文件所有权来:

  • Security fixer,管 agents.ts、file-download.ts、onboarding.ts、process.ts。路径穿越:加 preset ID 白名单验证。bot token 泄漏:把原始错误换成通用错误信息。模板注入:用 split/join 换掉 .replace()。MIME 验证:给 audio、image、video 各加类型白名单。
  • Pipeline fixer,管 index.ts、loop.ts、reference-images.ts。打字指示器:在空批次的路径上补 clearInterval。成本归因:把 Telegram user ID 传进 processMedia()。NaN token:在合成事件里替换成 0。selfie 超时:加 30 秒的 AbortController。缓存上限:最多 10 条,最旧的先淘汰。成本日志:用实际的错误日志换掉 .catch(() => {})
  • Onboarding fixer,管 onboarding.ts、process.ts、commands.ts。超时默认值:设成「用户未填写自我介绍」而不是空字符串。reonboard 竞态:启动新会话前先调 clearOnboardingState()。下载后大小检查:Telegram 不给文件大小的时候,下载完再验一次。Promise.allSettled:单个媒体失败不再把全部结果带崩。

这里有个点值得说一下:没有任何两个 agent 编辑同一个文件。上一篇里,文件所有权在构建阶段防的是合并冲突,修 bug 这边是同一个原则——分工按文件分,一个文件永远只有一个 agent 在动,三个 agent 同时改代码也不会互相踩脚。

修复按文件所有权分工,一个文件只有一个 agent 在动,三个修复员并行改代码也互不踩脚修复按文件所有权分工,一个文件只有一个 agent 在动,三个修复员并行改代码也互不踩脚

第四个 agent 是文档更新员,和修复同步跑,把 CLAUDE.md、API.md、SCHEMA.md、TECHNICAL.md、DATA-FLOWS.md、CONVENTIONS.md 和 TODO.md 全部更新了一遍。文档漂移是真实存在的问题,趁改动还热乎的时候修,比过阵子发现文档全过期了再补便宜得多。


changelog 和发布:机械活直接扔给 agent

所有修复提交之后,我又说了一句:"let's also add a changelog thing." claude code 并行启动了两个 changelog agent:一个管 v0.0.1,分析前 39 个 commit(2 月 26 日上午 10 点 PST 之前),也就是基础构建阶段;另一个管 v0.0.2,分析后面那 81 个 commit,也就是上一篇的三功能冲刺,加上这一轮所有的审查修复。两个 agent 各写各的部分,合并成一份 CHANGELOG.md,然后:

git tag v0.0.1 <commit-hash>
git tag v0.0.2
gh release create v0.0.1 --notes-file ...
gh release create v0.0.2 --notes-file ...

两个版本、两个 tag、两个 GitHub release。这种活纯机械,不需要什么判断,说实话也没人想手动做,扔给 agent 跑就完了。


最后一步是把经验存下来。往项目的 CLAUDE.md 里加了两样东西:一个 "Releases & Versioning" 章节,把 changelog 和打 tag 的工作流记录下来;还有一条规则,"Always use doc-updater subagent for documentation updates"。流程上的改进这种东西,不记下来就没了,下次还会撞上同样的摩擦。CLAUDE.md 就是这个项目的记忆,写进去的东西跨 session 持久化,context 被压缩之后还在,崩溃恢复之后也还在,反正写进去就丢不了。VM 那篇里讲过,长 session 里崩溃恢复是常态,所以往 CLAUDE.md 里编码得越多,context 重置的时候丢的就越少。


整个从审查到发布的周期,拆开是五个阶段、总共十一个 agent,全部在一个 claude code session 里跑完。具体是:

  1. 审查前清理(1 个 agent,手动修复)
  2. 并行代码审查(4 个专业 reviewer)
  3. 并行修复(3 个 fixer + 1 个文档更新员)
  4. changelog + 发布(2 个 changelog agent)
  5. 流程改进(把经验编码进 CLAUDE.md)

这种审查修复的周期,后来我又跑了几轮。有几条习惯是能直接列出来的:

  1. reviewer 可以分专业。security auditor 和 pipeline reviewer 在同一个文件里能找到不同的 bug,通用审查会漏掉领域特定的问题。
  2. fixer 要有严格的文件所有权。不让两个 agent 编辑同一个文件;分工按文件分,不按 issue 分——两个 issue 落在同一个文件上,就分给同一个 fixer。
  3. 文档更新和修复同步跑。并行挂一个文档更新 agent 几乎没有额外成本,但能防住文档漂移。
  4. 仪式性的活可以全自动。changelog、tag、release,这些机械任务不需要人的判断。
  5. 审查过程里学到的东西,session 结束前写进 CLAUDE.md。

上一篇讲的是 agent team 怎么构建:分解计划、调度依赖、五个 agent 并行写代码。这篇的审查、修复、发布,用的还是那几样东西——任务分解、文件所有权、并行执行,没有一样是新的。反正现在写代码的已经不是人了,审代码的也不是,人去做的是 high-level 的决策。这个 session 里我拢共就给了两句指令,一句开审查,一句要 changelog,剩下的活都是 agent 在跑,后面几轮基本也还是这个跑法。

和 AI 讨论这篇文章
ChatGPTClaude

订阅更新

新文章发布时发到你的邮箱,不发别的。


© Xingfan Xia 2024 - 2026 · CC BY-NC 4.0