最近一段时间,我写代码的方式发生了很大变化。
以前一个功能需要自己逐个文件修改,现在很多时候只要把需求交给编码工具,它就能一次改完十几个甚至几十个文件。
速度确实快了。
但代码生成结束以后,新的问题也出现了:这些改动到底能不能合并?
文件少的时候,我还能从头到尾看一遍。改动一旦变大,Review 很容易变成快速浏览。接口看起来对,类型也能对上,测试可能还能通过,但一些真正危险的问题往往藏在更深的地方:
- 权限校验少了一层;
- 状态更新顺序不对;
- 金额字段用了浮点数;
- 某个失败分支没有回滚;
- 调用了一个实际上并不存在的 API;
- 从另一个模块复制来的代码,没有适配当前业务;
- 需求要求修改三条链路,最终只实现了其中两条。
这些问题并不一定是语法错误,编译器和普通的静态检查也不一定能发现。
我试过直接让模型做 Code Review。
结果通常有两个极端。
一种是给出很多建议,从变量命名、注释、函数长度一路说到架构设计。看起来很认真,但真正会影响合并的内容并不多。
另一种是模型检查了很久,最后告诉我“没有发现明显问题”。但我无法确认它究竟审完了没有,有没有因为上下文太大跳过文件,或者在中间已经超时。
对代码审查工具来说,漏报当然是问题,但另一个同样现实的问题是噪音。
如果一个工具每次都输出二三十条意见,其中大部分不需要处理,用不了几次,开发者就会开始忽略它。最后即使真正危险的问题出现,也很容易淹没在一堆普通建议中。
所以我做了 ReviewGate。
它的定位不是替代测试,也不是替代人工 Review,而是在代码合并之前增加一道质量闸口。
它只优先回答一个问题:
这次改动里,有没有值得暂停合并、先检查清楚的问题?
不追求把所有问题都说一遍
ReviewGate 默认从几个维度并行检查改动:
- 安全问题;
- 逻辑和边界条件;
- 性能问题;
- AI 生成代码里常见的错误假设;
- 项目自己的业务规则。
纯命名、格式和普通代码风格默认不检查。
不是因为这些完全不重要,而是它们更适合交给 linter、formatter 或团队规范。质量闸口如果被格式问题占满,真正危险的问题反而不容易被看见。
不同维度发现的问题会先合并去重,再交给独立的 Judge 重新验证。
高置信问题才会进入必须处理的区域,中低置信结果默认折叠。需要的时候仍然可以展开查看,但不会让它们直接阻塞合并。
最终只有三种结果:
BLOCK:发现了高置信问题,建议先处理;WARN:存在风险,或者审查没有完整完成;PASS:没有发现达到闸口阈值的问题。
这里我特意处理了一种情况:没有审完,不等于没有问题。
如果发生超时、上下文过大、部分任务失败,ReviewGate 不会给出 PASS,而是降级为 WARN。
我宁愿它保守地说“这次没有完整审完”,也不希望它在不确定的情况下告诉开发者“可以合并”。
业务规则比通用规范更重要
通用模型可以判断 SQL 注入、空值、错误处理和并发问题,但它并不知道每个项目自己的规则。
例如:
- 金额必须使用整数分;
- 用户资源访问必须校验
owner_id; - 已完成订单不能再次取消;
- 库存扣减必须和订单状态更新放在同一个事务;
- 管理员权限不能通过前端传入的角色字段判断。
这些规则通常散落在文档、代码和团队成员的经验里。
ReviewGate 可以把它们直接写进项目配置:
[business]
rules = [
"金额字段必须使用整数分,禁止使用 float",
"用户级资源访问必须校验 owner_id",
"已完成订单禁止回退到待支付状态",
]
之后每次 Review 都会检查这些规则。
对我来说,这部分比检查命名风格更有价值。因为真正容易造成线上事故的,往往不是代码写得不够漂亮,而是业务约束在某次改动中被绕过去了。
除了看代码,还可以检查需求有没有真正做完
缺陷审查只能判断代码本身有没有明显问题,但还有一类情况很难只靠 diff 判断:
需求写了五项,代码到底实现了几项?
ReviewGate 支持把需求文档、设计说明或者验收标准一起传进去:
reviewgate review \
--from main \
--to HEAD \
--intent docs/requirement.md
它会先把需求拆成一条条验收标准,然后逐项检查:
- 已满足;
- 缺失;
- 破坏了原有行为;
- 实现与要求不一致;
- 尚未核对。
如果有验收项没有检查完,同样不会直接给 PASS。
这对一次修改很多文件的任务比较有用,尤其是使用编码 Agent 完成功能时。代码可能写得没有明显错误,但实现范围未必完整。
误报不能只靠“下次忽略”
做 Review 工具绕不开误报。
模型换了,提示词变了,代码行号移动了,同一个问题可能反复出现。如果每次都让开发者重新判断,使用成本会越来越高。
ReviewGate 会给每条发现生成稳定指纹。
确认某条是误报后,可以把指纹写进仓库里的 .reviewgate/ignore:
# 这里是常量拼接,不存在注入风险,已人工确认
a3f2c1b09d4e
这个记录可以和代码一起提交,全队共享。
以后再次遇到同一问题,它不会继续阻塞,但仍然会以过滤状态保留,需要审计时可以重新展开。
我不太喜欢完全静默地删除结果。因为规则可能会变化,过去的判断也可能需要重新检查。折叠比彻底消失更稳妥。
它应该是一道闸,而不是另一个聊天窗口
ReviewGate 目前主要以 CLI 和 GitHub Action 运行。
在本地仓库里可以直接执行:
reviewgate review
检查当前分支相对主分支的改动:
reviewgate review --from main --to HEAD
在 CI 中,可以让高置信问题直接阻止合并:
reviewgate review --fail-on block
它不绑定具体模型,可以使用 OpenAI 兼容接口或 Anthropic 接口,也可以接 DeepSeek、Kimi、GLM、通义以及其他兼容服务。
我更希望它成为开发流程的一部分,而不是每次都要打开一个页面、复制代码、等待一段对话,再人工整理结果。
这个项目不解决什么
ReviewGate 不会替你证明代码一定正确。
它也不应该用来替代:
- 单元测试;
- 集成测试;
- 静态分析;
- 安全扫描;
- 人工代码审查;
- 上线后的监控和回滚机制。
它做的是这些工具之间仍然缺少的一层:
在改动准备合并时,基于本次 diff、周边代码、项目规则和需求意图,优先找出值得停下来检查的问题。
尤其是在 AI 大量参与编码以后,代码产出速度已经不再是唯一瓶颈。
接下来更麻烦的问题可能是:
我们生成了越来越多代码,但有没有足够可靠的方法决定,哪些代码可以进入主分支?
ReviewGate 是我对这个问题的一次尝试。
项目目前已经开源,支持 macOS、Linux 和 Windows,可以作为本地 CLI 使用,也可以接入 GitHub Actions。
它还远没有做到覆盖所有情况,但核心链路已经可以用于真实项目。我也在持续补充真实 PR、大改动、多语言代码和意图评审的测试记录。
仓库:
有兴趣可以拿自己的真实改动跑一下。
比起 Star,我现在更需要的是具体反馈:它找出的哪些问题确实有价值,哪些属于误报,哪些真正危险的问题它没有发现。