如果你维护的仓库一周有三四十个 PR,作为核心 reviewer 的你很难每个都认真读一遍 diff。我们团队大约十个人,维护几个内部仓库,PR 一多就只能靠两个老员工轮流顶着看,Review 积压、低级问题漏到主干、规范讨论反复拉扯,这些痛我猜很多团队都有共鸣。上个月我们做了个调整:把一个叫 Hermes 的智能体挂进了 GitHub PR 流程里,让它先于人类完成一轮自动化代码评审。
Hermes 在这个场景里的定位不是替代人,也不是又一个 lint 工具。它收到 GitHub 的 PR 事件后,会主动拉取代码、读取 diff、对照 PR 描述分析变更逻辑,再把可疑点按优先级写成行内评论和汇总意见,通过 GitHub API 回写到 PR 讨论里。也就是说,当开发者打开一个 PR 时,里面已经有了一份由机器生成的、带代码位置引用和修改建议的初筛报告。
这篇文章不是产品介绍,是一次完整的落地复盘。我会把这样的链路选型思路、部署细节、规则与提示词怎么调、真实 PR 里踩过的三个大坑、以及误报和成本控制方法都摊开讲。如果你是那种"Reviewer 已经满负荷、PR 队列经常积压、想引入 AI 又怕误报"的维护者,这篇文章值得看完。
1. 先说结论:我为什么决定把 PR 初筛交给 Agent
1.1 人工 Review 的舒适区与真实盲区
先说一个可能不好听但对现状很真实的现象:在大多数中小团队里,代码评审并不是技术问题,而是时间分配问题。Reviewer 被迫在自己开发任务和别人的 PR 之间来回切换,真正能静下心逐行读代码的时间非常有限。最终的结果是:架构级别的、大方向的讨论基本都能被覆盖,但很多数据校验边界、错误处理分支、资源释放这类细节问题,恰恰最容易在"差不多看了"的状态下漏掉。
这种场景里,人工 Review 的舒适区其实是"设计评审"和"经验判断",而不是机械性的检查。需要人反复确认的东西,往往并不是新的业务逻辑本身,而是那些通用规则:新增的路径是否覆盖了空参数、数据库查询是否走了索引、异常情况下资源会不会泄漏、日志会不会把敏感字段打出来。这些规则每一轮都问一遍,人很快就会疲劳,而机器不会。
1.2 自动化代码评审的三个层级
在做方案调研的时候,我习惯把代码质量相关的自动化能力分成三个层级来理解,这样不容易被"AI 会自动 review"这种概念带偏。
| 层级 | 典型工具 | 特点 | 它能发现什么 |
|---|---|---|---|
| 静态规则引擎 | Ruff、ESLint、SonarQube | 秒级反馈、结果稳定、可解释 | 格式问题、未用变量、明显反模式 |
| 测试与 CI | Pytest、Jest、GitHub Actions | 验证行为正确性,但只能验证已覆盖路径 | 功能回归、接口契约变化 |
| Agent 语义评审 | Hermes 这一类智能体 | 能理解变更意图,跨文件推断上下文 | 逻辑漏洞、边界缺失、一致性偏差、安全隐患 |
这里有个很容易踩的误区:团队如果已经上了 lint 和单测,就以为"自动化代码评审"已经做完了。但静态规则是没法知道这个 PR 的语义上下文到底是什么的,它处理不了"这个分支条件在 3 个调用方里行为不一致"这类问题。单测可以在代码写好之后验证结果对不对,但没法在代码还没跑起来之前告诉作者哪里可能会错。Hermes 这种 agent 补的恰好是语义理解这一层。
1.3 我眼里的角色定位:“助理评审员”,不是“自动批准机器人”
很多团队引入 AI 评审时,最担心的不是它没用,而是它乱说话、刷屏、挡流程。所以我们从第一天就定了一个原则:Hermes 的所有评审意见都只是建议,不参与 approve,更不允许阻塞合并。
它的实际产出是这几类东西:一是 PR 级别的一段 summary,讲清楚这个变更大概在做什么;二是针对 diff 中具体行代码的评论,每条评论都要求给出文件、行号、问题类型和修改建议;三是一个"需人工确认"清单,专门放那些模型自己也拿不准、但代码里看起来不合常理的疑点。人在打开 PR 时,看到的不再是一块白板,而是一张已经标注过的初稿。这才是 Agent 参与代码评审最舒服的状态。
2. 链路选型:GitHub App、Webhook 与 Actions,我最终选了哪条路
2.1 把 GitHub 和 Hermes 接起来,主流方式其实只有三种
所有 GitHub 之上的自动化,本质都是在回答一个问题:代码仓库里发生了什么事,你怎么知道,你又凭什么去回写结果。落到具体实现上,常见的就是下表三条路。
| 接入方式 | 触发机制 | 权限模型 | 部署成本 | 适合场景 |
|---|---|---|---|---|
| GitHub App + Webhook 事件驱动 | GitHub 主动推送事件到自建服务 | App 安装级授权,可精确限仓库 | 需要一台公网可达服务器 | 长时任务、需要跨 PR 缓存状态 |
| GitHub Actions + workflow | YAML 定义事件触发 CI 任务 | Actions token,随 workflow 生命周期 | 基本零运维 | 短任务、依赖官方生态 |
| 定时调用 GitHub API 轮询 | 自己控制节奏 | PAT 或 App token | 简单但浪费 | 无法开 Webhook 的网络环境 |
从触发时效和可控制性综合来看,Webhook 事件驱动是最符合"自动化代码评审"这个场景的。PR 创建、提交新 commit、被请求 review 这些动作,GitHub 都会在秒级把事件推给服务端。Hermes 不需要反复拉取,也不会因为轮询太频繁而被 API rate limit 卡住。
2.2 我采用的模式:GitHub App 只授予最低必要权限
我注册的是一个 GitHub App,而不用普通的 Personal Access Token。原因是 App 能按"安装到哪个组织/仓库"做授权,权限范围也拆得非常细,比一把梭的 token 安全很多。
GitHub App 创建时,Payload URL 填成 Hermes 服务的 Webhook 地址,例如https://review.example.com/webhook/github;Webhook secret 用openssl rand -hex 32生成一串随机值,这个值会用于之后校验每次请求的来源。Permissions 里只需要三项:
| 权限 | 级别 | 用途 |
|---|---|---|
| Contents | Read-only | 拉取仓库代码来分析 diff 上下文 |
| Pull requests | Read & write | 读取 PR 信息,并提交 review 评论 |
| Metadata | Read-only | 获取仓库基础元数据(GitHub 强制要求) |
Subscribe to events 里勾上 Pull requests 一项就够了。这样 GitHub 只会在 PR 的 opened、synchronize、reopened 等时刻通知我们,不会把 issue、push、star 之类无关事件也倒进来。
2.3 为什么没有直接用 GitHub Actions 写完整个评审任务
我们前期确实做过一个 Actions 版原型,但很快就放弃了。最大的问题是代码评审这个任务本身不适合放在 CI 容器里短跑。一次认真一点的评审,要读取 PR 描述、拉取 refs/pull/ /head、分析 diff、可能还要读几个相关文件的局部实现,最后再调用大模型 API 生成意见。整个链路在模型推理比较慢或者网络波动时,很容易超过 Actions 单任务的超时上限,而且工作流的日志也不适合长时间审查跨多个 commit 的状态。
Actions 的优势是完全不需要维护服务器,这在很多轻量任务里很香。但是代码评审需要"记忆":这个 PR 上一次评审到了哪个 commit、哪些评论已经发过了、哪些规则已经被开发者标记为误报。这些状态放在长驻服务里很自然,放在每次冷启动的容器里就非常别扭。另外,Hermes 本身带调度逻辑,长驻服务也方便本地调试,开发时可以直接在本机跑起来对着测试事件调。
所以在整个系统里,GitHub Actions 仍然承担单元测试和静态检查,而 Hermes 作为一个独立的 Webhook 服务在旁边跑。各干各的,谁也不把谁拖垮。
3. 部署与配置:从空仓库到跑通第一次 PR 评审
3.1 运行时环境与依赖安装
Hermes 服务的部署形态是:一台 4 核 8G 的 Linux 服务器,前面挂 Nginx 做 TLS 终结和请求转发,后面跑 Hermes runtime。模型推理走外部 API,所以本地不需要 GPU,硬件压力很小。不过这里有个容易被忽略的点:Hermes 同时需要访问 GitHub API 和模型 API,网络时延必须稳定,否则拉代码和调模型都会频繁超时。建议选一台对 GitHub 网络链路相对畅通的节点,部署前先用curl -I https://api.github.com确认一下。
环境方面,我比较推荐用 conda 隔离出一套干净的 Python 运行时,避免污染服务器系统 Python:
conda create -n hermes python=3.10 -y conda activate hermes pip install -U pip pip install hermes-agent不同版本的 Hermes 发行包入口名可能有差异,有的叫hermes,有的叫hermes-agent,安装后先执行hermes --version确认一下。如果你服务器的 conda 配置文件里自定义过软件源通道,最好确认相关依赖都来自同一个稳定通道,别在生产机上进行通道混合实验,否则很容易遇到"上次能装上这次装不上"的依赖解析问题。
3.2 服务配置文件里的几个关键项
Hermes 的配置我拆成了两部分:一部分是运行时参数,比如监听端口、日志级别、并发 worker 数;另一部分是密钥和外部 API 地址,