这篇想讲的,不是“我嫌 review 麻烦,所以让 AI 替我回复”。
真实情况正好相反。
我们组里的这套 review,本身就是认真设计过的。里面既有领导自己的规则,也有组内不同成员一起补的规范。像资源格式、依赖、线程、内存、日志、序列化、commit message 这些东西,都被整理成了比较明确的检查项。
所以我对这套东西的态度一直不是“绕过去”,而是:
它本来就有价值,我只是想把它接得更适合我自己的工作流。
先说清楚:这不是本地第一轮 review
这篇写的是提交以后的那一轮 review。
也就是:
- MR 提上去
- 飞书里收到 review 报告
- 然后我再决定怎么处理
我本地那一轮其实是另外一回事。像 pre-commit、Claude Code 本地 review、包括我自己现在在做的 memory 串联,属于更靠前的流程。那部分我后面会单独再写。
所以这篇不要把它理解成“我用 bot 替代了第一轮 review”。
更准确的说法是:
我给提交后的飞书 review,又补了一层 argue bot。
为什么还要再补这一层
因为提交后的那一轮 review,天然有一个限制:
它能看到 diff、commit、MR 描述,也能按规范逐条检查;但它不知道我当时本地的开发背景,也不知道一些更细的设计考量。
这会带来一个很常见的结果:
- 有些问题确实很准,而且是阻断级别
- 有些问题方向没错,但优先级没那么高
- 还有一些问题,在我自己的上下文里其实并不成立
这也是我为什么会去做 argue bot。
不是为了和 review 对着干,而是为了补上这一层:
规范型 review 很强,但它不总知道我当时为什么这么写。
我对这套 review 的基本态度
如果 CI/CD 阶段的 review 和我本地那套 review 都认为某个问题确实存在,而且严重到阻断,那我一般不会犹豫,直接修。
如果只是一些没那么致命的问题,比如 commit message 不规范,那我更多会把它当成一次反馈:
- 这次先记下来
- 下次提交时注意
- 再顺手去调整我自己的 commit skill
所以这整件事在我这里更像一个持续优化过程。
不是说 review 提意见,我就一定要反驳;也不是说 AI 替我 argue 了,我就一定不改。
很多时候,真正发生的是:
- 规范在推动我修正习惯
- 我的本地工具链也在反过来适配这些规范
最后大家是在互相成就,而不是互相对抗。
我其实并不排斥看 review 报告
这一点也得说清楚。
我做这个 bot,不是因为我懒得看 review 报告。
相反,就算不是我自己的需求,只要是同事那边的东西,我平时也会去翻 review 报告。因为那里面经常能看到:
- 组里当前最在意什么
- 哪些问题会被重复提出来
- 哪些规范其实值得内化到自己平时的开发里
所以 review 报告对我来说,本来就是一个学习入口。
而且这种“看别人报告”本身就能暴露出很多组内还在反复出现的问题,比如:
- 生产代码里还带着
Log.e(TAG, "...") - 提交里混进了
http://192.168.x.x:3030/xxx.html这种 debug URL - 大段注释代码没删干净
commit message还是fix bug这种模糊写法
这些东西单看一条 report 也许只是一个提醒,但看多了以后,你会很清楚团队到底还在哪些地方不够稳。
我自己其实也会把这些信息继续往组内流程里推,看看哪些能靠规范、哪些能靠工具、哪些能靠 skill 再往前收一层。
我真正想解决的,不是“不要看报告”,而是:
当报告很长、问题很多、来源又混着 reviewer 和 CI/CD 规则时,我想先有一层更贴近我自己工作流的判断。
这张图更接近它真实在干的事
整条链路:
私人群里的对话大概是这样的:
它大概就是这样一条链路:
- 研发群里出现 review 报告
- bot 只监听,不在公共群发言
- 它把确认消息发到我的私人群
- 我回复
全部、我的或者不要 - 如果有需要,我再顺手指定
claude或codex - bot 去拉文档、做 argue、生成总结,再把结果回写到私人群
这套设计里,我最在意的有三点:
- 公共群只监听,不污染频道
- 最终要不要处理,决定权还在我手里
- bot 给我的不是原报告搬运,而是处理后的判断结果
为什么我做了 全部 / 我的 / 不要
我做 全部 / 我的 / 不要,不只是为了“范围控制”,更直接的原因其实是额度。
因为我的 token 不是无限的。
如果额度很充足,那我当然更愿意直接看 全部。但真实情况往往不是这样,所以我平时会按阶段来选:
- 有必要的时候,用
我的 - 一般情况直接忽略,或者回复
不要 - 真觉得这轮值得全量跑,再用
全部
也就是说,这不是一个优雅的产品设计题,而是一个很现实的额度分配题。
它解决的是:
在 token 有限的前提下,我把分析量优先留给最值得看的部分。
双引擎就是为了互相兜底
Claude 和 Codex 这两个引擎,我都接了。
原因其实很简单:
- 看我当前哪个引擎余量更多
- 如果
Claude Code碰到5h limit,那就切Codex - 反过来也一样
- 偶尔哪个模型状态不太对,或者明显降智了,我也会顺手换另一个
所以对我来说,这两个引擎主要就是互相兜底。
这也是为什么我会在确认消息里支持直接写:
全部 codex我的 claude
哪个当下更合适,我就先用哪个。
真正让它能长期跑的,是这些细碎的工程处理
这套东西如果只是“监听一下飞书,然后调一下 AI”,其实很快就会变成一次性 demo。
它现在能比较稳定地跑,靠的是这些看起来不那么显眼的处理:
doc token去重,避免同一份报告反复处理commit sha过滤,避免重复 review 浪费 token- 同时支持
thread回复和reply回复 pending.json存等待确认的条目7天不回自动过期,30天后清掉 rejected- 状态消息尽量原地编辑,不在私人群刷一堆日志
其中 sha 和 doc token 过滤对我尤其重要。因为一旦重复触发,烧掉的不是一条消息,而是实打实的 token。
Argue 归档我一开始其实是按目录设计的。
我原本想的是直接按日期归类,比如:
2026 / 04 / 16 / xxx 文档
这样后面回头翻会更顺。
但我实际试下来以后,发现自己没有写入特定飞书文件夹的权限。所以后面我才退一步,改成在标题上做文章,类似:
Argue|2026-04-16|xxx feature
这样即使文档没法落到我预期的目录里,至少标题还是统一的,后面搜起来也比较顺。
实现上还是那些东西:lark-cli 负责飞书 API,Claude CLI 和 Codex CLI 负责 argue,外面包一层轮询、去重、pending 队列、消息编辑和归档逻辑——难的不是把命令跑起来,而是把这些边角处理都做到位,收拾到足够贴合自己真实工作流的程度。