夜里十一点,我打开 GitHub 的 PR 列表,一排 pull request 挂着 changes requested,点进去却发现根本没有一条有效评论。这种状态持续了一个多月后,我决定把 Hermes 接进来做自动化代码评审。让机器先把每一条 PR 完整读一遍,把明确的问题直接标在 diff 上,人工 reviewer 只需要在机器意见之上做判断,而不是重新干一遍体力活。这篇博文就围绕 Hermes 在 GitHub PR 审查上的落地过程来写,包含部署、接入、规则设计、实测复盘和踩坑记录,适合那些团队规模不大、review 经常靠催的小型研发团队,也适合想给开源仓库找个“0 号 reviewer”的维护者。
1. 为什么我把 PR 审查交给 Hermes
1.1 一个让 reviewer 崩溃的凌晨
我们团队三个人轮流当 reviewer,听起来是够用的配置,实际上所有 PR 都堆积在“待 review”里没人碰。原因很典型:上午改完的 PR,下午还没人看;下午点开一个 PR,刚把上下文想起来,又被即时通讯里的问题打断;到了晚上终于有整块时间,却发现这个 PR 改动了十几个文件,自己负责的模块只占其中一小块。
真正让我下决心接 Hermes 的,是一次凌晨的线上事故。后端同学重构了用户登录逻辑,PR 里明确写了“登录失败时新增重试机制”,reviewer 看到重试逻辑没问题就点了 approve,却没人发现重试过程里没有超时控制。线上流量一上来,超时任务直接堆积,把数据库连接池打穿。这不是某个人的粗心,而是人工 review 天然存在盲区:注意力优先放在“这次改动的核心逻辑”,没人系统性地扫一遍“边界条件、超时、并发、资源释放”这些老问题。
1.2 Hermes 在 PR 评审里扮演的角色
Hermes 不是一个普通的 lint 工具,lint 只能抓格式和固定规则,比如缩进、未使用变量、明显语法错误。而我需要的是能看懂 diff、理解代码逻辑的“语义级审查”,Hermes 这类大模型驱动的 agent 正好干这个。
按我的理解,Hermes 是一个消息驱动的 agent 框架:它监听 GitHub 上的事件,把 pull_request、issue_comment 这些事件转成具体任务,再调用底层大模型做推理,最后通过 skill 机制调 GitHub API 把评审意见写回 PR。整个过程里,Hermes 更像一个“0 号 reviewer”——它一定先看,给出第一轮评估,人工 reviewer 再在它的基础之上做决策和最终把关。
这个定位非常重要。自动化代码评审的合理目标从来不是“替代人”,而是把人类从“扫雷”里解放出来。机器负责把低层次的、重复性的问题全部捞出来,人负责判断业务边界和做最终决策。团队逐步习惯这套流程之后,等于每个 PR 在合入之前都至少经过了两道独立检查:一道机器的,一道人的。
1.3 适合什么团队
我梳理了一下,以下场景接 Hermes 收益最大:
- 团队小,没有专职代码评审人,review 全靠抽空。
- 开源项目维护者,PR 积压严重,需要快速了解外部贡献者的改动质量。
- 跨语言、多仓库团队,统一由同一个 agent 规则把关。
- 团队有一堆公共代码规范和已知坑,想把它们固化到评审流程里。
反过来,如果你的项目处于强安全审计环境,或者对“机器自动评论”这件事本身非常敏感,建议先只让它生成内部报告,不要直接 post 到 PR 评论区。合规和信任是两回事,工具可以很先进,但流程要稳。
2. Hermes 的工作链路:从 GitHub 事件到评审意见的完整流转
2.1 Hermes 是什么
市面叫 Hermes 的名字不少,我这里说的是 hermes-agent 这个方向的智能体服务。它最核心的设计是“事件驱动 + 技能扩展”:GitHub 推来一个事件,Hermes 决定调用哪些技能,例如抓取 PR 信息、读取指定文件、提交 review,最后把大模型的推理结果组装成 GitHub API 能识别的格式写回去。
命名上也能看出来,Hermes 在希腊神话里是信使,这个项目的定位就是事件与执行之间的桥。你不用为每一个仓库写一套定制代码,只要配置好一个通用规则,它就能在不同仓库里复用得很好。
2.2 完整事件链路
以下链路是我基于自己部署的版本整理的,具体事件名和字段可能因版本略有差异,但整体思路一致:
- 开发者在 GitHub 上提交 PR 或 push 新 commit,产生 pull_request 事件。
- GitHub Webhook 把事件推送到 Hermes 服务。
- Hermes 校验签名,确认事件来源是 GitHub,防止伪造请求。
- Hermes 调用 GitHub API,拉取 PR 的元信息、commit 列表、diff 内容。
- 服务端组装上下文:diff、PR 描述、仓库规则文件、忽略路径列表。
- 大模型基于上下文进行推理,输出结构化评审结果。
- Hermes 通过 GitHub API 把结果作为 review 提交到 PR,或写入行内评论。
这条链路里最容易出问题的不是第 1 步也不是第 7 步,而是第 5 步的上下文组装。模型本身看不到仓库全貌,你给它什么它就只能评什么。给少了,它会瞎猜;给多了,它会发散。上下文组装质量直接决定评审水不水。
2.3 三种接入方式对比
我实际试过 Webhook、GitHub App、GitHub Actions 三种方式,各有适用场景。
| 接入方式 | 自建要求 | 适合场景 | 主要缺点 |
|---|---|---|---|
| Webhook | 需要一台常驻服务器,暴露 HTTP 端口 | 团队自建 Hermes,长期沉淀规则 | 多一个服务要维护 |
| GitHub App | 需要生成私钥并配置权限 | 想精细控制权限、覆盖多个仓库 | 配置稍复杂 |
| GitHub Actions | 不需要自建服务,走 GitHub 自带执行器 | 单个仓库快速试用 | 受执行时间限制,每次跑要带模型 Key |
我个人最后选了 Webhook + 常驻 Docker 容器的方式,因为我不想让每次 PR 审查都等待 Actions 执行器排队,也不想把模型 API Key 塞进仓库的 Secrets 里反复轮换。
3. 环境准备与 GitHub 接入:我踩过的配置点
3.1 用 Docker 部署 Hermes
在服务器上部署 Hermes 其实不复杂,我用 Docker 容器跑,一条命令就能拉起来:
docker run -d \ --name hermes-review \ -p 8080:8080 \ -e HERMES_GITHUB_WEBHOOK_SECRET=your_webhook_secret \ -e LLM_PROVIDER=deepseek \ -e LLM_API_KEY=sk-xxxx \ -e LLM_MODEL=deepseek-chat \ -e REVIEW_RULES_PATH=/app/rules/review.yaml \ -v $PWD/review.yaml:/app/rules/review.yaml \ hermes-agent/hermes:latest这里的HERMES_GITHUB_WEBHOOK_SECRET是 GitHub Webhook 里配的密钥,两边必须完全一样。LLM_PROVIDER和LLM_API_KEY决定用哪个模型做推理,我选的是 DeepSeek,因为它的上下文窗口大,面对大 diff 时不容易截断。容器名和镜像名只是示例,具体以你实际拿到的安装包为准。
启动之后先访问http://localhost:8080/health确认服务状态,再回 GitHub 页面用 “Redeliver” 按钮补发一次 webhook,看 Hermes 日志里是否打印出事件接收记录。这一步能一次性验证网络、签名、API Key 三条链路是否都是通的。
3.2 Webhook 配置步骤
GitHub 侧的配置路径是:仓库 Settings → Webhooks → Add webhook。需要填四样东西:
- Payload URL:填 Hermes 服务接收 GitHub 事件的地址,例如
http://your-host:8080/webhook/github。 - Content type:必须选
application/json。 - Secret:填与
HERMES_GITHUB_WEBHOOK_SECRET相同的随机字符串。 - Events:选择 “Let me select individual events”,至少勾选
pull_request,如果希望它响应评论和 review 对话,再勾pull_request_review_comment和issue_comment。
配置完成后,GitHub 会立刻发一条ping事件。如果 Hermes 日志里能看到 ping 且不报 403,说明签名验证已经通过。很多配置问题都出在 secret 不一致上,这个坑我踩过不止一次。
3.3 用 GitHub Actions 快速验证
如果你想先不动服务器,也可以用 GitHub Actions 快速跑通一遍。大致 workflow 长这样:
name: Hermes Auto Review on: pull_request: types: [opened, synchronize, reopened] permissions: contents: read pull-requests: write jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Hermes Review env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} LLM_PROVIDER: deepseek LLM_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }} LLM_MODEL: deepseek-chat run: | docker run --rm \ -e GITHUB_TOKEN \ -e LLM_PROVIDER \ -e LLM_API_KEY \ -e LLM_MODEL \ -v ${{ github.workspace }}:/repo \ hermes-agent/hermes:latest review \ --repo ${{ github.repository }} \ --pr ${{ github.event.pull_request.number }}注意pull-requests: write权限必须要给,否则 Hermes 有模型推理结果也写不回 PR。具体 CLI 子命令名以你使用的版本为准,至少先跑hermes-agent/hermes:latest help看一眼再改。
3.4 配套的 Hermes Studio 管理面板
我比较喜欢 Hermes Studio 这个自带的管理界面。它能看到事件队列、每次评审耗时、模型原始输出,甚至能查看“被过滤掉的评论草稿”。平时我不会直接在 Studio 里写 prompt,但排查问题时它是第一去处。比如某个 PR 没有自动评论,我打开 Studio 就能看到是事件没推过来、权限不够,还是模型返回了NO_ISSUE。没有这个面板,遇到“静默失败”会让你非常痛苦。
4. 让评审有“业务感”的规则集与提示词设计
4.1 先定义“要查什么”
很多人在接自动化代码评审时的第一个失误,就是让模型“自由发挥”。自由发挥的结果不是没有评论,而是评论灌水——每条看起来都对,但没有一条值得改。正确的做法是先定义检查维度。
| 检查维度 | 要覆盖的问题 | 典型例子 |
|---|---|---|
| 安全 | 注入、硬编码密钥、越权、危险反序列化 | 用字符串拼接 SQL |
| 正确性 | 空指针、并发、资源未释放、错误被吞 | 异常分支没有关闭句柄 |
| 性能 | 不必要的循环、大对象拷贝、N+1 查询 | 循环里重复请求数据库 |
| 可维护性 | 命名、重复代码、函数过重 | 一个函数写了四百行 |
| 一致性 | 是否违反仓库已有的编码规范 | 新代码用了旧的废弃 API |
这些维度不是每个 PR 都要全量覆盖,也不是每一条都同等重要。安全问题的优先级永远最高,风格问题排在最后。
4.2 一套能直接抄的 review 提示词
我目前在用的提示词核心部分长这样,你可以直接拿去做基准版本:
你是一位严谨的资深代码评审专家。 你正在审查一个 GitHub PR,请基于 diff 和仓库上下文输出评审意见。 执行要求: 1. 只报告能明确指向具体代码行的问题,禁止空泛的“建议优化”。 2. 按严重级别输出:blocker / warning / suggestion。 3. 每个问题必须包含文件、行号、问题描述和修复建议。 4. 优先检查安全、正确性、性能问题,最后才是风格。 5. 如果同一个根因导致多处问题,合并为一条,不要刷屏。 6. 如果 diff 里没有值得提的问题,只回复 NO_ISSUE,不要硬凑。 7. 对你不确定的问题,标记“需要确认”,不要武断下结论。 输出格式: ### Blocker - 文件:行号 - 问题描述 - 修复建议 ### Warning ... ### Suggestion ...提示词里最关键的是第 6 条。没有这一条,模型会倾向于给每一个 PR 都挑出点东西来证明自己“工作过”,这会产生大量噪音。允许它说“没问题”,反而会让真正的问题更突出。
4.3 给 Hermes 喂仓库上下文
模型对业务的理解程度取决于你喂了多少上下文。我建议至少配置三类内容:
第一是仓库级信息,比如 README、架构说明、约定的技术栈;第二是 PR 本身的描述和关联 issue,里面通常有改动背景;第三是忽略清单,比如.reviewignore,把 lock 文件、生成的代码、第三方 vendor 目录全部排除掉。
我还额外建了一个REVIEW_RULES.md,里面写团队已经公认的约定,例如“项目禁止使用全局可变状态”“对外的 HTTP 接口必须显式设置超时”。这些规则看起来是给代码库写的,实际上是在给模型写提示词。模型每轮都会被注入这些内容,评论自然更有业务感。
5. 实测效果:误报、漏报与真发现的界限
5.1 一个典型 PR 的评审结果
有一次后端提交了一个“用户注册失败重试逻辑”的 PR。Hermes 的评审输入是 300 行 diff,最后输出了四条意见:
- blocker:重试发送请求时没有设置超时时间,失败请求可能长期占用连接资源。
- warning:指数退避没有加随机抖动,多个客户端失败后会同步重试,形成踩踏。
- warning:错误日志里缺少 trace_id,线上排查时无法关联链路。
- suggestion:重试最多尝试 5 次,建议把次数抽成配置项。
这个结果让团队挺惊讶。前两条意见是人工 review 大概率能看出来的,但第三条 trace_id 的问题往往要等到线上出故障才会意识到。真正让我确定这套方案可用的是另一件事:作者根据 Hermes 的意见改完以后,人类 reviewer 再看 PR 时,只说了一句“没问题”,整个 review 周期从两小时压缩到了二十分钟。
5.2 抽样 20 个 PR 后的数据
我连续抽样了 20 个 PR,统计了 Hermes 意见与人工复核结果的差异:
| 指标 | 数值 |
|---|---|
| Hermes 提出的问题总数 | 49 |
| 人工确认是真问题的数量 | 37 |
| 误报数量 | 12 |
| 人工额外发现但 Hermes 漏掉的问题 | 5 |
按这个粗样本算,Hermes 的精确率大约是 75.5%,召回率约 88%。样本不大,别当成通用结论。但趋势很明显:它抓重复性问题很稳,误报主要集中在“看不到历史背景”的场景里。
5.3 误报和漏报的典型来源
误报的常见来源是模型只知道当前 diff,不知道历史背景。比如它建议“把 A 函数抽到公共模块”,但团队上个季度已经做过一次抽象,业务后来决定保持重复。这类误报不是模型笨,是上下文组装缺了东西。
漏报则大多来自跨文件问题。Hermes 通常聚焦在 diff 本身,如果问题发生在“调用方没感知到签名变化”这种跨文件场景,单看文件 diff 很难发现。应对办法是让 Hermes 在评论里多使用“需要确认”这类不确定标记,同时保留人工 reviewer 的独立判断。机器不是万能的,但它的主要价值是把低垂的问题先摘掉。
6. 部署后容易掉的坑与调优方向
6.1 事件与权限的坑
我在接入过程中踩过四个比较深的坑,值得单独记录。
第一个是 Webhook 签名不匹配。GitHub 会拿 secret 给请求体加签名,Hermes 也会验一次。两边只要有一个字符不一样,请求就会被拒绝,而且 GitHub 页面看请求记录全绿,因为事件是推送成功的,只是服务端没有接受。这种问题看服务端日志最快。
第二个是 GitHub App 的权限配置。有一个仓库我始终拉不到 diff,查了半天才发现是 App 的Contents: Read权限没开。权限不足的表现非常隐蔽,GitHub API 不会直接说“没权限”,而是返回一个看起来像文件不存在的结果。
第三个是评论写错端口。行内 review 必须调用POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews接口,把 comments 放在数组里传;如果图省事走issues/{number}/comments,会变成普通评论,代码行上没有任何标记。我只用普通评论跑了一周,导致团队成员要在评论区和文件之间来回翻,体验很差。
第四个是评论洪泛。大 PR 一次可以触发二三十条评论,直接淹没整个讨论串。解决办法是在规则里限制单次最多提 8 条意见,并且把低优先级意见合并进总结,而不是逐条发。
6.2 模型参数与上下文限制
模型的temperature参数对评审质量影响很大。我一开始用默认值 0.7,结果模型开始“过度发挥”,给出很多富有创意但与代码无关的建议。调到 0.2 以后,输出稳定了很多,基本围绕 diff 本身说话。
另一个限制是 diff 大小。改动超过 1000 行的 PR,直接整包丢给模型,既容易超时也容易丢上下文。我的处理策略是:先跑一个git diff --stat,按文件拆分评审,每个文件只提取 diff 中前 800 行的内容;如果单文件超过这个阈值,先生成一个文件级摘要,再让模型基于摘要挑重点文件阅读。这样单个文件的问题不会因为上下文过长而被忽略。
6.3 后续可以扩展的方向
Hermes 接进 PR 审查流程之后,还能往几个方向延伸。我自己正在做的是给 PR 自动打风险标签:根据 Hermes 输出的 blocker 数量,自动标记review/high-risk、review/ok,再配合分支保护规则,高风险 PR 必须有两个人工 approve 才能合入。
下一步我打算让它做 release note 生成,把所有合并的 PR 按改动类别汇总,省去发版前人工整理的时间。至于 issue 自动分类、定时巡检长尾 PR,这些都不需要改 Hermes 主程序,只要在事件规则里加对应的技能配置就能做。
最后分享一个我自己的体会:不要把 Hermes 的第一步目标定为完全替代人工 review。我现在的流程是 Hermes 先评,作者根据机器意见自改,再由人类 reviewer 看 Hermes 的评论和剩余 diff。走过三轮之后,团队里的 PR 平均 review 时间从一天半降到了半天。自动化代码评审的价值不在炫技,而在把每个人从第一遍扫描里解放出来。给 Hermes 一点项目背景,它会比大多数人想象中靠谱;但给它一条干净的规则,它才会稳定地靠谱。