夜雨聆风学习资料网

ARTICLE · 1027904

3.2万星的AI评审工具,最值钱的部分跟AI无关

3.2万星的AI评审工具,最值钱的部分跟AI无关

周一早上我在翻 GitHub 趋势榜,看到一个叫 open-code-review 的项目,阿里的,今年5月才建仓,4个月涨到 3.2 万星。

我第一反应是"又一个套壳"。

过去一年这种东西我看得太多了:写段 prompt,接个模型 API,外面包一层命令行,README 里写满"智能""颠覆""10倍效率"。所以我本来是抱着挑刺的心态把它 clone 下来的。

结果读了两个文件夹,我在工位上坐了半天没动。

不是因为它的 AI 有多强——恰恰相反。是因为它几乎把所有要紧的活儿,都交给了"不智能"的代码。

它的 README 里有一句话,架构是「确定性流水线 + LLM Agent」。我第一遍看的时候完全没当回事,"确定性"这三个字太像场面话了。直到我打开源码。

它不信 AI,而且信得很有章法

这个工具干的事很简单:读你的 git diff,让 AI 把问题逐行标出来。

听起来就是个 prompt 工程。但它解决的是三个具体到不能再具体的问题——这三个问题,凡是让 AI 做过代码评审的人都遇到过:

  • 覆盖不完整:改动文件一多,AI 就开始偷懒,只挑几个文件看,剩下的提都不提
  • 位置漂移:AI 说"第 120 行有并发问题",你翻到 120 行,那里是一句日志
  • 质量不稳定:改一个标点,同一个文件两次评审的结论能差出十万八千里

我看完代码才明白,它对付这三个问题的办法,不是把 prompt 写得更花哨,而是在 AI 外面砌了一圈墙

第一堵墙:覆盖率是"封存"的,不是靠自觉的

这是我在 internal/agent/agent.go 里看到的一段,我盯着看了很久:

// registerCoverage freezes the coverage denominator// before any reuse or concurrent dispatchfunc(a *Agent) registerCoverage(diffs []model.Diff) error {    for _, d := range diffs {        if d.IsDeleted { continue }        if err := b.RegisterSelected(a.coverageItem(d)); err != nil {            return err        }    }    return b.SealSelected()   // 封存}

注意最后那个 SealSelected()——封存

它的意思是:在任何一个 AI 调用发生之前,这次评审"应该覆盖哪些文件"这份清单就被定死、封存了。等评审结束,系统拿最后的执行结果去对这份清单,任何一个登记在册、却没有被标记为"已处理"的文件,会被自动判定为失败

这句话你品一下:AI 不可能偷偷跳过某个文件然后蒙混过去。漏了就是漏了,系统会把它揪出来。

我当时第一个念头不是"这个技术设计真巧",而是——我们团队的任务分配,恰恰缺这个

我们每周一的评审会也是定清单的,七八个模块分下去,谁做哪块写得清清楚楚。但到周五核对的时候,靠的是什么?靠我问"你那块怎么样了",靠大家自己说。没人主动说"我这周其实没动"。清单是定了,但没有封存,也没有自动对账。

后来我做了一件事:把我们组的需求排期表加了一列状态,每周五由我直接对着表点,没标完成的一律先算没完成,不问你为什么。就改这一个动作,第一次点完,有两个我以为早就做完的东西,其实卡了三天没人吭声。

这不是什么高明管理,就是把"靠自觉"换成了"靠对账"。

第二堵墙:给 AI 的接口,窄到不能再窄

评审的第一步是把改动分组成"一次看一批"。这个分组动作它也交给 AI 了——因为哪些文件语义相关,确实需要判断。

但它给 AI 的接口窄得让我意外。这是分组请求的数据结构:

type groupingResponse struct {    Label string `json:”label”`    Files []int  `json:”files”`  // 序号,不是文件路径}

代码注释里写得很直白:序号只花几个 token,路径要花一整串

为什么要抠这几个 token?因为模型输出是有长度上限的。文件一多,如果让它吐路径,输出到一半就被截断,整批分组直接报废,只能退化成"每个文件单独跑一遍"——成本翻十几倍。

所以它做了两件事:

一是让模型只回报序号,输出量降一个数量级,从根本上避免截断;

二是模型拿到的只有文件元数据,不含 diff 内容——分组这件事只需要知道"这是什么文件",不需要看几百行代码。

我看到这里才反应过来,过去我用 AI 的方式有多糙。我经常把一整个模块的代码丢过去,说"你看看有什么问题"。输入塞得满满当当,输出要它吐一大段自然语言。

它这套做法反过来:让 AI 干判断,但把它能看到的、要它说的,都压到最小。

判断需要上下文,但不需要全部上下文。这个分寸感,才是真功夫。

第三堵墙:可以帮 AI 改错,但绝不替它背书

这是全文我最想讲的一段,在 internal/tool/comment_args_repair.go。

模型的输出偶尔会坏——本来该是一个 JSON 数组,它给你吐成一个字符串,少套了一层转义。这种时候标准做法是报错重试。但这个项目写了两百多行代码来确定性地修复它,逐字节扫描,判断一个引号到底是字符串的结束符、还是正文里没转义的内容。

到这里都还正常。真正让我坐直的是修复之后的处理:

if !repairedCommentsAcceptable(entries, s) {    return nil, nil   // 放弃修复,保留原始报错}if hasSuspectTruncation(entries) {    return nil, nil   // 放弃修复,保留原始报错}return entries, &CommentRepair{EscapedChars: escaped}

修完了,还要过两道验收:每一条评论内容不能为空、不能出现 schema 里没有的字段、条数不能少于原文里 "content" 出现的次数;任何一条文本里引号数量是奇数,就判定"这个值可能被截断了",整批拒绝。

而且代码注释里写了一句我认为是全文最重的话:

Such a batch is refused outright rather than partially recovered.(这样的批次会被直接拒绝,而不是做部分恢复。)

它宁可让模型重发一遍,也不接受一个"能解析、但可能是错的"结果。

理由也写在注释里:被截断的 existing_code 匹配不上任何一行真实代码,后面所有确定性的定位手段都会失效,AI 只能靠猜行号——那还不如让模型带着完整的锚点重来一次。

我读到这里停下来想了很久。这跟我带团队时踩过的坑,一模一样。

组里交上来的方案,格式不对、漏了小节、数据来源没标——这些"格式层面"的问题,我现在会让 AI 先帮着过一遍,统一格式、补全字段,这没什么不好,省时间。

但我犯过的错误是:改完格式之后,就默认内容也是对的。

有一次一份调研材料,AI 帮着把结构理得很漂亮,标题工整、分点清晰,我扫了一眼就往上交了。结果里面一个关键数字引错了来源。格式修得越漂亮,越容易让人放松警惕——那两份"验收检查"(条数对不对、有没有被截断),我省掉了。

现在的规矩是:**格式可以让 AI 修,修完的内容必须重新验一遍原始出处。**这不是不信任人,这是承认——漂亮的排版会掩盖内容的窟窿。

它甚至主动放弃了一部分正确率

README 里有一组数据,来自它们的 AACR-Bench 基准:50 个热门开源仓库、200 个真实 PR、10 种编程语言、80 多位资深工程师交叉标注、1,505 条基准问题。

在同一套底层模型下跟通用 Agent 比:

  • 精确率(Precision)和 F1 明显更高
  • token 消耗大约只有 1/9
  • 但召回率(Recall)更低

注意最后一条——它的召回率更低,而且是故意这么设计的

代码里没写这句话,但 README 写得很清楚:这是"'宁精勿噪'的有意取舍"。

翻译成人话:它宁可漏掉一些问题,也绝不多报一堆假问题。因为评审工具一旦开始误报,用不了两周就没人看它的结论了——发出去的每一个假警报,都在消耗别人对你的信任额度

这个逻辑我在管理上太熟了。团队里那个每次都说"出大事了"的人,你真到出事那天反而不信他。

**信号的密度,决定了信号的价值。**少发一条不确定的结论,比多发十条"可能是问题"的提示,有用得多。

我用完之后改的三件事

读完代码我做了三件事,都在自己组里,不大,但立竿见影:

第一,把"覆盖率"显性化。凡是我分下去的任务,清单先落表,每周五我对表点,不看理由只看状态。漏了的自动暴露,不用等人汇报。

第二,给 AI 的输入做减法。以前是"你看下整个模块",现在是"你只看这个文件里这个函数的改动"。输入越窄、要它输出的东西越结构化,结论反而越稳。

第三,给 AI 的结论加一道"验收"岗。凡是 AI 参与产出的东西,我要求标注清楚"哪些是 AI 给的、哪些是人核过的"。格式可以 AI 修,事实性内容必须回到源头验一次。

这三件事没有一件是技术活。它们全是流程活

这才是这个项目真正教我的东西:它的门槛根本不在"用了哪个模型",而在于它花了两百多行代码去修一个引号,写了一段"封存覆盖率"的逻辑去堵住 AI 偷懒的口子——它把力气全花在给 AI 砌墙上了

我们大多数人(包括一年前的我)用 AI 的方式,是使劲把模型往强里用。而它反过来,把模型能自由发挥的地方压到最小,把不能出错的地方全部换成死代码。

真正难的不是让 AI 变聪明,是给它的聪明划一条线。


这个项目叫 alibaba/open-code-review,Apache-2.0 开源,装了就能用。感兴趣的可以去 GitHub 搜。也提醒一句:它是 CLI 工具,要配自己的模型接口,不是开箱即用的 SaaS。

我把这次读源码整理的"给 AI 划边界的检查清单"(我们组现在在用的那版,含任务清单模板和 AI 产出验收表)整理成了一份文档。在公众号后台回复「边界」就能领。

如果你也正在团队里推 AI,欢迎留言说说——你给 AI 划的第一条线是什么?

相关学习资料

返回首页浏览学习资料