先说结论:这个标题拆开来看,其实藏着四层信息——Hermes是执行体,GitHub PR是落点,自动化代码评审是业务目标,而前面"审查"两个字则决定了它的核心动作不是"帮人写代码",而是"在代码合入之前替团队把关"。如果你正在维护一个多人协作的仓库,每天有一堆 PR 等着被 review,但又不想让每一次评审都变成排队等人工,那这篇文章要聊的东西就非常适合你。
我最早接触 Hermes 这套自动化评审方案时,心里其实没抱太大期望。毕竟团队的代码评审问题很典型:小改动没人看,大改动看不过来,关键 bug 全靠半夜被线上报警打醒。后来我尝试把 Hermes 接到 GitHub 的 PR 事件流里,让它在每次 PR 打开或更新时自动拉取 diff,按约定规则做一轮 AI 初评,再把结果以评论和建议的形式回写到 PR 页面。跑了两周之后我发现,它的价值不在"替代人",而在帮人省掉最耗精力的那部分判断成本——比如这次改动动了哪些文件、有没有明显的边界条件漏处理、新增代码是否和现有接口语义一致。下面我就把整套思路、配置方法和我实际踩过的坑完整写出来,给想在自己的仓库里落地这套流程的朋友做个参考。
1. Hermes 到底是什么,以及它解决什么问题
1.1 核心定位:PR 审查版"自动巡检"
Hermes 本质上是一个基于大语言模型的代码审查代理。它可以是一个独立服务,也可以被封装成 GitHub Actions 里的一个 job,不管哪种形态,它做的事情都是同一个流程:监听 PR 事件、拉取代码差异、调用模型分析、再把结构化结论写回 PR。
很多人第一次听到"AI 审查代码"时,会下意识联想到 lint 工具或者 SonarQube 这类静态检查。这里我先把边界说清楚:lint 检查的是"代码是否符合语法规则和风格规范",SonarQube 检查的是"代码里有多少坏味道和重复片段",而 Hermes 这种模型驱动的审查 Agent 要做的是对"代码变更的语义"做评估。它不会因为少了一个空格而打断你,但会因为你在改支付金额计算逻辑时漏掉了精度处理而提出疑问。这个差异决定了它在审查体系里的位置是偏上层的"思考型检查",而不是偏底层的"规则型扫描"。
1.2 一个 PR 里,Hermes 到底在看什么
要理解它的能力边界,得先知道一次审查的输入是什么。最基础的是 PR 的完整 diff,包括新增文件、删除文件、修改文件的上下文行。其次还有配套的元数据:commit message、修改涉及到的函数边界、是否改了公共接口、有没有删除关键错误处理分支。Hermes 内部会把这些信息结合成一个带上下文的 prompt 送去给模型解析。
我实际使用下来,Hermes 对下面几类问题最敏感:
- 改动破坏了既有调用契约:例如把一个函数的返回类型从可空改成了不可空,但调用方没有同步处理。
- 错误处理被吞掉或绕过:新增代码里 catch 之后什么都没做,返回值异常时也没走兜底逻辑。
- 并发与状态一致性隐患:多个协程或线程里同时读写同一个字段,而又没有加锁也没有使用原子操作。
- 只覆盖了 happy path:路径分支上明显存在空指针、越界访问、文件不存在等边界场景。
- 与仓库现有模式不一致:项目里统一用某个工具库处理日志,新代码却自己拼字符串输出。
这里要注意的是,上面这些问题它不一定每次都能 100% 命中,但如果提示词和评审规则设计得合理,它能非常稳定地把这些问题中最值得人工关注的那一部分挑出来。
1.3 为什么不是"换个 lint 工具"这么简单
我团队里最开始也有人问:既然要自动化,为什么不干脆把 lint 规则开严一点?原因很简单,规则型工具没有跨文件、跨模块的全局视角。一个 PR 可能只改了十行代码,但影响的是一个服务所有入口的请求转发逻辑。静态检查只会看这十行是不是格式整齐,而 Hermes 会结合仓库里的周边代码去判断这十行放进来之后,原有逻辑是否还能闭环。
另一个原因是机器人判断的粒度不同。Hermes 的审查输出可以按"阻塞性问题 / 建议修改 / 纯疑问"三个级别分类,还能直接生成可点击的 GitHub review suggestion。这就让它不只是"报错",而是能参与到 reviewer 和 author 的对话上下文里,而不是像传统 lint 一样在 CI 里直接红色失败。这也是我把这项能力定位成"自动巡检"而非"质量门禁"的原因:它可以巡视,可以提醒,但最终拍板应该还是人。
2. 让 Hermes 接入 GitHub PR 的完整设计思路
2.1 两种接入姿势:GitHub App 与 Actions 工作流
落地 Hermes 时,首先要想清楚接入方式。我实践中比较推荐的是以 GitHub Actions 工作流为入口跑 Hermes,仓库根目录放一个.github/workflows/pr-review.yml,每次 PR 事件产生时触发执行。这种方式的好处是配置透明、对仓库侵入小,普通成员也能通过改 workflow 文件调整流程,不需要额外维护一台常驻服务器。
GitHub App 方案则更适合那些要跨多个仓库统一做审查规则、消息需要异步推送、甚至想在看板里汇总审查结果的大型团队。App 方式需要自己部署回调服务,好在 Hermes 如果提供 CLI 子命令,也能被外部服务调用。小团队起步阶段我不建议一上来就搞 App,先跑通 Actions 版,把规则沉淀下来,后续如果出现了"几十个仓库都要用同一套配置"的需求,再迁移到 App 架构也不迟。
2.2 Hermes 的执行链路:事件到结果落回 PR
一次完整的审查事件流大致是下面这样:
- 开发者提交 PR 或往已有 PR 推送新 commit。
- GitHub 根据 workflow 配置触发
pull_request事件。 - Hermes 使用
actions/checkout拉取目标分支与合并基准之间的代码。 - Hermes 调用 GitHub API 获取当前 PR 的
.diff数据。 - 后端接入的模型对 diff 和上下文进行推理。
- Hermes 把结论拆成"摘要评论 + 行级评论 + 审查结论"三种形态,通过 GitHub API 写回 PR。
- 人工 reviewer 后续在 PR 页面看到结果,可以直接回复或补充。
这个链路里最容易出问题的地方在第 5 步到第 6 步之间。模型返回的结果如果是纯自然语言,没有结构化字段,Hermes 就不知道哪条评论该放在哪个文件的哪一行。所以我在配置时都会要求 Hermes 使用 JSON 模式输出,再在内部把 JSON 解析成一个个审查评论,这条路走通之后,整个过程才谈得上"自动化"。
2.3 权限模型与 Token 设计,千万别省这一步
接入过程中最容易被忽略的是权限。Hermes 要读取 PR 信息,需要contents: read权限;要把评论发到 PR 页面,需要pull-requests: write权限;如果你想让它通过 commit 状态接口来标记"审查中/审查完成",还需要checks: write或statuses: write。
在 Actions 里用的 token 通常是仓库自动生成的${{ secrets.GITHUB_TOKEN }},它的生命周期跟着 workflow 跑,不会在账号里长期暴露。但有一点要注意:如果你给 Hermes 配的是个人访问令牌,而且这个 token 属于某个同事的账号,一旦那个同事离职或者关闭了 token,整个自动化流程就会瞬间失效。要么用机器人账号的 token,要么直接用 GITHUB_TOKEN,不要把人肉账号绑定在基建任务上。
3. 关键细节:审查规则的设定与提示词设计
3.1 先写好"角色 + 规则 + 边界"三段式提示词
Hermes 的审查质量,说实话,取决于你对它的"期望描述"。我最终沉淀出来的提示词模板可以拆成三段,第一段是角色定义,让它知道自己是个资深 reviewer;第二段是项目规则,告诉它当前仓库优先级最高的审查维度;第三段是边界清单,明确告诉它哪些东西不要提。
实际示例大致是这样:
你是一个资深后端开发,负责审查 PR。你熟悉项目的技术栈和业务背景。 请在审查时优先关注以下问题: 1. 正确性风险:内存泄漏、并发竞争、异常返回、空值处理。 2. 可维护性:不合理命名、重复逻辑、错误注释。 3. 安全风险:用户输入未校验、敏感信息进入日志。 不要报告以下内容: 1. 纯代码风格问题,例如空格、行长度。 2. 与本次改动无关的历史问题。 3. 基于臆测的潜在风险,除非能给出明确触发路径。这样做的原因是模型如果没有边界约束,很容易把一批"风格偏好"当成问题提出来,导致真正重要的 bug 被淹没在噪音里。我试过一版没加边界清单的 prompt,结果一次 PR 生成 47 条评论,其中 30 条都是"建议把单引号改成双引号"之类的废话。加了边界清单后,评论数量降到 12 条,有效信息密度明显上升。
3.2 diff 提取策略:不是所有文件都值得喂给模型
很多人以为喂给模型的上下文越多越准确,实际上不是这样。一次改动 5000 行的巨型 PR,如果把完整 diff 直接丢进去,且不说 token 成本,模型也容易在超长上下文里"迷失重点",给出一个非常笼统的平均意见。
我采用的策略是先过滤,再分组。Hermes 在拿到 PR 的变更文件列表后,先把明显不需要审查的文件剔除掉,比如package-lock.json、vendor目录、生成器产物、纯静态资源文件。剩余的文件再按变更难度分成两组:结构性改动和普通业务改动。结构性改动比如接口定义、数据库字段、通信协议,这些优先进入模型上下文;普通业务改动可以用摘要模式或者只抽取关键函数。这个流程看起来简单,但处理完后再送审,模型给出有针对性意见的比例会提高不少。
另外我会在 workflow 中设置:
- name: Setup Hermes uses: your-registry/hermes-action@v1 with: diff-strategy: filtered include-globs: | src/** tests/** exclude-globs: | generated/** vendor/** *.lockexclude-globs这个参数在大型仓库里必须配。之前我按默认配置跑一次 monorepo,光生成的.pb.go文件就占了几千行 diff,严重挤占了模型的注意力配额。
3.3 审查结果的粒度:摘要评论,行级评论,别混着发
Hermes 支持把结论通过三种方式展示:PR 顶部的整体摘要、代码 diff 里的行级评论、以及 review 结束时的总结批注。如果你的团队刚开始用 AI 审查,我强烈建议先只开"整体摘要 + 指定数量的行级评论",不要一上来就让它在每个文件每行都发言。
我设定过一套参数:
report: mode: combined summary: true inline: enabled: true max_comments: 16 min_confidence: 0.8 global: max_comments: 8max_comments设得太大会刷屏,设得太小则可能漏掉从后往前看的人真正需要的重要提醒。16 这个数是我用了大半月的经验值,它不仅控制住了评论数量,还能保证最重要的问题不会因为排在后面而被丢弃。如果模型输出的问题超过 16 条,我会让它总结在摘要里,而不是所有都往文件行上贴。
4. 从零跑通一条 Hermes 自动审查流水线
4.1 先搭一个最小可用的 GitHub Actions workflow
前文讲了很多思路,这里直接给一个能跑通的最小配置。我在仓库里用到的pr-review.yml长这样:
name: Hermes Code Review on: pull_request: types: [opened, synchronize, reopened] issue_comment: types: [created] permissions: contents: read pull-requests: write jobs: hermes-review: if: contains(github.event.comment.body, '/hermes') || github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Run Hermes review uses: your-registry/hermes-github-action@v1 with: github-token: ${{ secrets.GITHUB_TOKEN }} model: deepseek-hermes api-key: ${{ secrets.HERMES_LLM_API_KEY }} config-path: .github/hermes.yaml这里有一个设计小细节值得说明:issue_comment加上if条件,是为了支持团队成员在 PR 里手动输入/hermes来触发重新审查。为什么要这样做?因为很多 PR 在收到 review 意见后,作者会修改代码。虽然synchronize事件能自动触发一次新审查,但如果在讨论过程中有人提了个建议,作者只改了一行,你觉得没必要再全量审一次,那么手动命令触发就能很好地控制节奏,避免每次讨论都引来一轮 AI 刷屏。
4.2 Hermes 核心配置逐项解释
工作流指定了.github/hermes.yaml,里面的内容我大概是这样配的:
review: trigger: on_open: true on_sync: true on_comment: "/hermes" path: exclude: - "*.md" - "docs/**" - "generated/**" llm: temperature: 0.2 max_retries: 3 output: summary: true inline: true max_comments: 16 generate_suggestion: true blocking: labels: - "blocking"这个配置里有几个关键参数我挑出来说。temperature: 0.2是降低模型输出的随机性,代码评审这种场合不需要创造性发挥,越稳定越好,我试过把 temperature 调到 0.8,它居然给出了两个互相矛盾的建议。generate_suggestion: true是让 Hermes 对每一处行级问题生成一个 GitHub 可一键应用的 code suggestion,这会大幅降低开发者修改问题的成本。blocking.labels表示它给 PR 打上"blocking"标签的标准,这直接影响 CI 里是否设置 label 校验。
4.3 改完代码后的增量重审,必须处理旧评论
一个真实场景是:开发者看到 Hermes 提了几条 line comment,自己改完代码并 push 了新 commit。此时如果只触发一轮新审查,PR 页面上会同时保留旧的过时评论和新评论,很容易把看 review 的人搞糊涂。
Hermes 的机制是:收到新的审查请求后,先查当前 PR 上已经存在哪些机器人评论,把对应的旧 inline comment 标记为 outdated,或者根据配置直接删除。这个动作需要额外调用 GitHub GraphQL API,建议你一定要开启这个选项,否则评论累积两周后,PR 页面看起来会像一个没人打理的论坛帖子。配置里可以这样打开:
review: cleanup: outdated_comments: true outdated_summary: true4.4 一次真实 PR 的审查结果长什么样
下面是我实际见到的一次输出,一个改动是给用户积分接口增加了缓存逻辑。Hermes 给出的摘要评论大概是这个级别:
本次改动整体思路清晰,核心为引入本地缓存以降低数据库压力。需要注意以下几点:
- 缓存 key 仅由用户 id 拼接,未包含积分类型字段,会导致不同类型积分互相覆盖。
- 当缓存未命中回源数据库时,缺少并发控制,可能出现缓存穿透,建议在回源逻辑上增加单飞或分布式锁。
- 过期时间设置较短,建议结合业务指标观察命中率。
三条信息里,第二条是没有跑代码时也很容易漏掉的高价值提醒。如果这是一个两三百行的 PR,人工 reviewer 很可能在 review 时只注意到功能流程顺不顺,但很难马上想到缓存穿透这个点。Hermes 在这里更像一个能提前帮你把边界场景想一遍的辅助大脑。
5. 我跑 Hermes 时踩过的 7 个坑与排查记录
5.1 Review 评论没有出现,bot 像睡着了一样
第一个遇到的问题是 workflow 明明执行成功,但 PR 页面没有任何评论。排查后发现,问题出在 workflow 里的permissions配在了 job 级别,而 Actions 默认的GITHUB_TOKEN是只读的,导致 Hermes 调用 GitHub API 创建评论时没有权限。
解决方案很直接,把permissions提升到 workflow 顶层并显式声明pull-requests: write。同时记得避免使用过于宽泛的permissions: write-all,最好按最小权限给,以免安全扫描工具报警。
5.2 PR diff 太大,模型上下文被截断
另一个高频坑是 PR 改动太大。默认的模型上下文窗口有限,如果一次 PR diff 超过模型窗口,Hermes 要么报错,要么只审到一半,结果会出现"后半部分文件完全没有评论"的情况。
处理方式我在前面提过:配置diff-strategy为filtered或sampled。我后来还把 workflow 里加了文件数量判断,如果单次 PR 变更文件超过 30 个,就跳过自动审查,只在摘要中提示"PR 过大,建议人工 review"。这比硬撑着让模型吞下一大堆半截上下文靠谱得多。
5.3 行级评论落在错误的代码行
这类问题非常影响体验。明明 diff 显示某行有改动,评论却贴到了另一个相似函数附近。原因是 diff 上下文里的行号计算有偏差,Hermes 内部在把模型输出映射回 GitHub line 时,没有正确识别新文件行号。这个问题在很多 AI review 工具里都存在。
排查以后,我会在构造请求前先把 diff 文件的行号映射表拉取下来,确保传给模型的输入本身带上"新文件行号"字段,并要求模型在 JSON 输出里引用行号而不是只写代码片段。只要提示词里明确写"每条问题必须包含 exact_line 字段",评论错位的问题基本能消失。
5.4 同一问题被重复评论,翻来覆去刷屏
当 PR 里同一个函数被修改了多次,Hermes 每轮都可能针对当前版本提出相同的隐患。比如第一次 review 时,它发现某函数缺少空值校验并提出了修改,开发者还没改,只是去改了另一个文件,于是新一轮 review 又对同一个空值校验问题重复评论。
对策是在 Hermes 的规则引擎里加一个相似度去重模块。每轮审查前,先把历史评论里的标题和行号提取出来,计算与计划生成问题的相似度,如果相似度超过一定阈值,就丢弃这条新评论。这个去重功能一开始让我觉得它不聪明,但实际却挽救了 PR 页面的阅读体验。
5.5 提示词写得太宽泛,审查结果全是正确的废话
早期我把提示词写成"请检查这个PR的正确性和代码质量",Hermes 的输出大多是"建议完善单元测试""建议优化性能"这种放之四海皆准的废话。后来我把项目里常见的 Bug 类型和反面案例写进规则里,比如"本仓库历史 issue 中出现过金额精度丢失,请重点检查改动是否涉及精度转换",审查效果才有质的提升。
提醒所有想用通用大模型做自动 review 的人,不要指望模型自动理解你项目的业务坑。这些坑不写进提示词,它不知道,也不可能猜得到。
5.6 并行审查多个 PR 导致结果互相覆盖
当团队同时开了四五个 PR,Hermes 服务如果是自己部署的,没有做并发队列控制,可能会出现在进程里同时跑多个 review 请求,最后写回结果时用的是同一个全局变量,导致评论写到了不在审查范围内的另一个 PR 上。
排查这个问题比较费劲,因为现象像是评论"随机漂移"。最终解决方法是把每次 review 的上下文封装成独立对象,并发处理时用 pull request ID 作为唯一隔离标识,所有写操作都从该上下文中取值。在实际生产环境里,这个并发设计比想象中重要得多。
5.7 模型判断"阻塞问题"准确率不高,乱打标签
Hermes 如果直接给 PR 设置request changes状态,一旦模型判断失误会很影响开发体验。这也是我建议团队在引入初期不要开启"自动请求变更"的原因。
比较好的折中是使用 label 而不是官方 request changes 状态,让 Hermes 添加blocking标签,表示"这里有几个问题需要人工确认",然后再配合分支保护规则,只有 maintainer 确认后才允许合入。这样既保留了强制校验入口,又给了人最终裁判权。
6. 团队落地 Hermes 后的一些个人经验
6.1 先在建议模式跑上一周,再决定要不要收严
如果你们团队从没有用过 AI 代码审查,我会特别强调:开始的 7 天到 14 天,Hermes 统一跑在"建议模式",它只发评论不建议,不阻塞,不打标签。这样做主要有两个好处。
第一,开发者不会产生被机器否定的抵触感。人是有情绪的,突然有个 bot 在每个 PR 上都留言"这里有风险",团队很容易产生反感。先用建议模式让大家看到它确实能发现真问题,信任感建立起来之后,再慢慢打开更严格的开关。
第二,你有机会根据实际准确率调整规则。如果模型在某些文件类型上总出错,也就是误报率偏高,那就需要把这类文件加进 exclude 名单。盲盒式的上架规则只会让团队更混乱。
6.2 人机分工:AI 看低级错误,人看架构与业务意图
在一次项目回顾会上,我们团队形成了一个很明确的共识:Hermes 的评论可以作为开发者的"第一轮自查清单",但不能替代正式 reviewer。具体分工是机器负责性价比高的重复劳动,比如变量作用域理解、空指针风险、错误处理缺失、资源泄漏;人则聚焦在架构决策、业务方案、接口设计、跨模块影响这些机器没有全局思考能力的层面。
这个分工落地后,团队的迭代节奏明显快了不少。开发者在提交 PR 前会先跑到 Hermes 结果,把基础问题清理掉,reviewer 打开 PR 时看到的已经不是满屏低级错误,而是真正需要讨论的架构问题。
6.3 控制成本要从 prompt 长度和模型档位下手
只要按 API 调用次数计费,AI 审查就有成本。代码评审不是一个低频率动作,每次 PR 的每次 commit 都可能触发消耗。控制成本有几个思路:第一,过滤掉低价值文件,别为 lock 文件和生成的代码浪费 token;第二,采用令牌桶限流,同一 PR 在短时间内多次 commit 时,不每次都触发全量审查,而是合并成一次延迟审查;第三,根据仓库重要性,选择不同档位的模型,重要业务模块用小而强的专用模型,普通文档和测试代码可以用便宜的模型做粗粒度检查。
6.4 后续扩展:让 Hermes 不只是"审代码"
最后说一个我准备往下做的方向。Hermes 的审查能力如果做得足够模块化,可以进一步接风险卡片、自动化测试建议、甚至安全扫描联动。比如 Hermes 识别出某个改动修改了用户登录接口,自动触发对应模块的集成测试;或者识别出一个涉及 PII 数据的改动,然后往 PR 上挂一个"隐私影响提示"的卡片。这些能力目前在配置层面都已经能通过写自定义规则和 webhook 完成,只是需要团队一点点去积累和打磨规则库。
我自己的经验是,自动化代码评审这类工具,最重要的不是 AI 模型本身有多强,而是团队的规则积累和反馈闭环能不能转起来。Hermes 给了这套流程一个很适合延伸的载体,但它不会替你定义什么叫"好的代码"。把标准想清楚、写进规则、持续迭代,比换一个更强的模型要重要得多。