[AI_TOOLS_LOG]// 2026.04.16 // 11 分钟阅读

给飞书 Review 接了个 Argue Bot

#AI#FEISHU#AUTOMATION#CODE-REVIEW

这篇想讲的,不是“我嫌 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 Argue Bot 的飞书工作流图

私人群里的对话大概是这样的:

私人群对话示意

它大概就是这样一条链路:

  • 研发群里出现 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 队列、消息编辑和归档逻辑——难的不是把命令跑起来,而是把这些边角处理都做到位,收拾到足够贴合自己真实工作流的程度。

SX
Written by sunxu

Android 工程师,写代码也写字。

© 2026 sunxu · CC BY-NC 4.0转载请注明原文链接,不可商用