写这篇东西之前我刚刚处理完一个被 Hermes 拦下来的问题 PR。事情的背景很直白我维护的仓库长期被 GitHub 上的 PR 队列压得喘不过气于是接入了自动化代码评审工具 Hermes让每个 PR 合入前都先过一遍机器审查。这套组合拳打下来效果确实明显值得把从选型、部署到调优的全过程都展开聊聊。如果你也被代码评审拖得筋疲力尽或者团队正在为PR 堆积如山、评审标准全凭个人感觉而头疼那这篇文章正好适合你。我会从 Hermes 的核心机制讲起再带你把部署接入 GitHub 的每一步走完最后把我踩过的坑、调过的参数、以及如何把机器审查调成团队自己人的经验全部分享出来。1. 为什么要把 PR 审查交给自动化1.1 我遇到的实际评审困境先说个真实场景。之前我参与维护的一个后端服务仓库高峰期同时有二十多个待审 PR。代码评审这件事听起来简单真做起来非常耗神你打开一个 PR先要理解它改了什么再逐个文件看 diff还要在脑袋里模拟业务上下文判断边界条件有没有漏。一个改动面比较大的 PR认真看完能花掉一个下午而且看到最后几个文件的时候注意力早就开始下滑。更麻烦的是评审标准不统一。有人特别关注命名规范有人只盯着业务逻辑还有人习惯性地在格式问题上纠缠半天。结果就是一个 PR 是否通过很大程度上取决于轮到谁审而不是代码本身的质量。有一回一个定时任务模块的重构 PR改了二十多个文件前后三个同事各看了一遍愣是没人发现一个边界条件漏判上线第二天凌晨任务就崩了。这类问题不是靠加强责任心能解决的。人工评审的瓶颈在注意力、精力和标准一致性而这些恰恰是机器擅长的领域。我当时就想着一定要引入一个能够理解代码语义、而不是只会跑静态检查的工具于是开始留意 Hermes 这类自动化代码评审 Agent。1.2 自动化评审和人工评审的边界划分使用 Hermes 的前提是想清楚一个原则自动化评审不是要取代人而是要把人力从低水平重复劳动里解放出来。我自己的分工方式是这样的评审维度适合交给 Hermes必须保留人工代码规范与风格统一性完全适合配合团队规则可以逐项核对不需要常见缺陷模式空指针、资源未关闭、越界很擅长模型能识别典型 bug 模式涉及业务深层语义的缺陷仍需人确认变更影响范围分析能通过上下文读取相关文件比人一次看十几个文件更全跨模块架构影响的最终判断安全风险能识别常见注入、权限缺失模式需要结合业务场景做最终确认架构合理性、技术选型不擅长它的判断偏通用正确必须由有经验的工程师把关产品需求与业务语义不擅长必须由需求方和开发者共同确认实操下来Hermes 最适合承担的是第一轮评审员的角色。PR 一到它先做全量检查把明显的 bug 隐患、规范问题、边界遗漏统统揪出来人只需要看它指出的问题和少数它看不懂的地方。这个模式把单个 PR 的评审时间压缩了大概一半以上而且不会再出现连续看五个 PR 之后漏掉显而易见的问题这种情况。2. Hermes 的核心机制与工作链路2.1 从 GitHub 事件到审查报告的完整链路Hermes 能自动干活本质上是因为它把接收事件、拉取变更、理解代码、产出结论这几个环节串成了一条自动化链路。以我部署的版本为例一个 PR 从提交到收到评论大致经历这么几步第一步是事件触发。Hermes 以 GitHub App 的身份接入仓库后会订阅相关的事件。最常见的是pull_request事件里的opened状态新 PR 创建和synchronize状态PR 分支有新提交。这两个事件覆盖了日常 95% 的评审需求。第二步是拉取变更数据。事件触发后Hermes 会调用 GitHub API 获取该 PR 的元信息标题、描述、修改了哪些文件、diff 内容是什么。大文件多文件会走分页处理把全部变更信息拉全。第三步是上下文收集。只把 diff 丢给模型是不够的Hermes 会进一步读取变更涉及的源文件内容、同目录相关文件以及可能被调用到的接口定义把这些内容一并纳入分析范围。这一步很像人看 PR 时要打开旁边的文件看看上下文的动作。第四步是并行分析。Hermes 内部有多个针对不同关注点的分析模块可以同时检查 bug 模式、性能问题、安全风险、规范符合度。每个模块独立工作产出各自的发现。第五步是结果聚合与发布。各个模块的发现会被汇总去重按严重级别排序然后以 review comment 和 summary 的形式发回到 PR 页面。整个过程通常几十秒内完成具体耗时取决于 PR 大小和所用模型的速度。这个链路设计得好不好关键在于前面几步是否稳定。我自己踩过的一个坑是事件订阅不完整导致只配了opened忘了synchronize结果作者后续修改推送后 Hermes 完全不理等于只审了初稿。2.2 skill 机制从内置能力到团队自定义规则Hermes 有一个比较实用的设计审查能力按技能拆分每个技能可以独立启用、关闭和配置。默认会带一批通用技能大致覆盖这些方向缺陷检测自动寻找空指针、资源未释放、数组越界、错误处理缺失等典型编程错误。安全审查识别 SQL 注入、命令注入、硬编码密码、越权调用等风险。性能分析发现重复查询、循环内创建对象、无必要的大对象复制等性能隐患。规范检查对照常用语言的最佳实践和代码风格提出建议。这有点像给代码评审配了一个全科医生内科、外科、皮肤科各有一个专科医生在同时会诊。实际运行时每个技能其实就是一套独立的提示词模板加规则参数针对同一个 PR 的同一批数据做分析。更关键的是团队自定义规则。我们团队在项目里放了自定义规则文件用自然语言写规范Hermes 会把这些规则注入到分析过程中。比如我们有一条日期处理必须使用统一工具类禁止直接 new Date()的规范手工评审时经常被忽略写进规则后几乎每一条违规都会被自动标记出来。这个机制让自动评审从通用水平变成了懂团队习惯的评审员价值提升非常明显。2.3 为什么不能只给模型看 diff刚开始用 Hermes 的时候我也动过直接拿 diff 调接口的念头后来发现效果差很多。真正跑通以后才理解只看 diff 有三个严重问题。第一个问题是上下文缺失。一段代码删了几行为什么要删它和周边代码的关系是什么这些问题只看 diff 回答不了。比如一个函数从同步改成异步diff 里可能只有几行变化但不看函数体本身和调用方就判断不出是否遗漏了调用处的适配。Hermes 的做法是主动读取变更文件和相关文件的完整内容相当于给模型补上审阅者应该翻看的资料。第二个问题是跨文件影响无法追踪。改了一个公共方法的签名到底会影响多少调用方这需要对整个项目结构有一定感知。Hermes 在上下文收集阶段会读取可能受影响的关联文件从而发现这个改动会破坏三处调用这类问题。第三个问题是语义理解需要全局信息。命名是否合理、错误处理是否与项目惯例一致这些判断依赖项目整体的风格信息。只看 diff 会让模型产生只见树木不见森林的偏差。当然上下文读得越多token 消耗也越大。所以 Hermes 的做法是有节制的它不会把整个仓库都塞给模型而是以变更文件为中心向外扩展读取关联文件并设置一个合理的上下文上限。这个平衡点很关键后面讲成本控制的时候我会展开说。3. 部署 Hermes 并与 GitHub 对接的完整实操3.1 用 Docker Compose 部署 Hermes 服务部署方式上我选择的方案是 Docker Compose 单机部署。这样做的原因很实际Hermes 本质上是一个常驻的 Web 服务需要接收 GitHub 的 Webhook、调用模型 API、回写审查结果用 Docker 封装后环境一致性最好升级回滚也方便。以我实际部署的目录结构为例服务端就是一套很常规的配置。项目中包含一个docker-compose.yml内容大致是这样version: 3.8 services: hermes-agent: image: hermes-agent:latest restart: unless-stopped env_file: - .env volumes: - ./config:/app/config - ./data:/app/data ports: - 8080:8080.env 文件里放的是各种密钥和运行参数包括模型服务的 API Key、模型名称、GitHub App 的 ID、私钥路径、Webhook 校验 Secret 等。我这里要特别强调一句这些敏感信息千万不要直接写进 compose 文件并提交到仓库里。我用的是 env_file 方式加载.env 文件加入 .gitignore最大程度避免密钥泄露。Windows 环境部署需要注意的点不太一样。我自己在 Windows 机器上调试时主要卡在路径和网络代理上。路径方面Windows 的挂载路径写法与 Linux 不同需要把./config写成带盘符的完整路径。网络方面需要确保部署机器能正常访问 GitHub API 和所用的模型服务接口否则会出现Webhook 能收到、但拉 diff 失败这种让人摸不着头脑的问题。我是把整个服务放到一台 Linux 服务器上才彻底消停的建议长期使用也这么做。3.2 创建 GitHub App权限与 Webhook 是关键步骤Hermes 与 GitHub 的对接方式我强烈建议使用 GitHub App 而不是 Personal Access Token。原因有三点GitHub App 有细粒度的权限控制可以按仓库授权能随时吊销它按事件订阅推送不需要轮询而且它的身份是独立的审计日志里能看到是她在操作不会和开发者本人账号混在一起。创建 GitHub App 的路径在账户 Settings 的 Developer settings 里填表的时候有几个关键项不能填错。权限Permissions方面按最小化原则配置Pull requestsRead and write因为 Hermes 要读 PR 信息和写审查评论。ContentsRead only因为要读取仓库文件内容做上下文分析。ChecksRead and write如果需要把审查结果写入 check run 的话。Webhook 事件订阅方面我勾选的是pull_request、issue_comment和pull_request_review。issue_comment用来支持在评论里 hermes 重新审查这类交互命令。创建完成后会生成一个私钥文件.pem这个文件要下载下来放到服务器的config目录里。同时还要在 App 设置页把 Webhook URL 配置成 Hermes 服务的公网地址比如https://your-domain.com/webhook/github并设置一个足够长的随机字符串作为 Webhook Secret后面 Hermes 会用这个 Secret 校验每个请求的签名防止伪造请求打进来。最后一步是安装 App 到目标仓库。安装完成后会生成一个 Installation ID这个 ID 在配置文件里要用到。我最初就栽在这个 ID 上忘了记录 Installation ID导致 Hermes 调用 API 时一直报 401排查了半天才发现是这里漏了。3.3 配置审查规则与触发策略服务跑起来之后剩下的核心工作就是调配置文件。我用的配置文件格式是 YAML结构大致如下github: app_id: 123456 installation_id: 987654 private_key_path: /app/config/private-key.pem webhook_secret: your-random-webhook-secret model: provider: deepseek api_key_env: HERMES_MODEL_API_KEY model_name: deepseek-chat temperature: 0.2 review: triggers: - pull_request.opened - pull_request.synchronize ignore_paths: - *.lock - package-lock.json - dist/** - docs/** max_files_per_review: 50 comment_on_empty: false逐个解释一下关键项。app_id和installation_id是 GitHub App 的身份凭证相关项填错任何一个都会导致 API 调用失败。private_key_path指向前面下载的私钥文件建议放到只有服务账户能访问的路径。model这一段是模型配置我用的是 DeepSeek 的 APItemperature有意调低到了 0.2因为代码审查是严谨任务不希望模型发挥太多创造力。ignore_paths很有用。像 lock 文件、构建产物、自动生成的文档这些内容人工评审时也不会仔细看不如直接跳过既省 token 又减少噪音。max_files_per_review是单次审查的文件数上限超过这个数字的巨型 PRHermes 会拒绝自动审查并提示拆分 PR这个设置可以避免模型分析质量下降。comment_on_empty我设置成 false意思是没发现问题时不发评论减少噪音——默认是 true那时候每个 PR 都会收到一条未发现问题的评论看多了也挺烦的。还有一个重要的策略参数是只在哪些情况下触发。我把triggers限定为 PR 创建和分支更新两个事件没有开启定时重新审查。因为定时触发会让一批老 PR 反复消耗配额而大部分情况下 PR 作者还在改 bug审了也是白审。4. 一次完整 PR 审查的实战复盘4.1 从提交 PR 到评审完成的时间线说一个实际项目的例子。我们团队近期做了一个登录模块改造要新增验证码登录功能涉及 3 个新文件和 8 个修改文件。PR 提交之后我在 GitHub 上看到 Hermes 的活动轨迹大致是这样的时间点事件T0 秒GitHub Webhook 推送到 Hermes 服务T1 秒Hermes 向 GitHub API 发出请求拉取 PR 元信息和文件变更列表T3 秒获取全部 diff 内容读取相关源文件做上下文补全T6 秒多个技能模块并行分析调用模型接口T20 秒结果聚合完成通过 API 创建 review 评论T22 秒PR 页面刷新后可以看到审查意见整个流程大约 22 秒比我人工打开 PR、读一遍描述的时间还短。这个耗时里最长的部分是模型推理占了 14 秒左右GitHub API 请求只占了几秒因为前后端对接口的请求耗时都不高。大一点的 PR 时间会更长。比如我之前测试过一个改动 40 个文件的 PRHermes 花了将近两分钟才出结论。这个时间虽然比小 PR 长但仍是可以接受的因为如果是人工评审两个小时都未必能看完。4.2 审查结果怎么读、怎么用Hermes 的审查结果分两部分行内评论和总体总结。行内评论会直接挂在对应代码行下面内容一般是指出问题所在位置、解释为什么有问题、给出修改建议。它的行内评论质量通常不错能做到这行代码第 47 行的判空逻辑遗漏了空列表场景这里直接拼接 SQL 存在注入风险建议改用参数化查询这种具体程度而不是空泛地说这段代码似乎有问题。总体总结则是一段结构化的描述包含变更概览、发现的问题清单、按严重级别分类的统计以及需要优先处理的几项建议。严重级别我自己理解为四个档位Blocker会导致编译失败、接口异常、数据错误等必须修复的问题。Major潜在空指针、鉴权缺失、资源未关闭等大概率会在特定场景下出问题。Minor代码风格、命名不统一、重复代码等不紧急但值得改进的点。Nit拼写错误、格式不一致等无伤大雅的小问题。实操中我的处理原则是Blocker 和 Major 必须逐个确认Minor 可以批量看一遍Nit 直接忽略。一次审查报告里如果只有 Minor 和 Nit 级别的问题那这个 PR 基本可以直接过了如果出现 Blocker 或很多 Major就要把作者叫回来认真改。4.3 把 Hermes 调成团队自己人工具用了一段时间之后最值得投入精力的事情就是微调它的审查标准。默认的通用规则能覆盖大众问题但每个团队都有自己的编码习惯和禁忌这些必须通过规则配置注入进去。我们在项目根目录维护了一个规则文件里面用自然语言写团队规范。举个例子我们团队有一条硬性规定所有新增的外部输入参数必须做合法性校验。这条规则写进 Hermes 后它真的会在新的 API 接口代码里检查是否存在参数校验逻辑一旦缺失就标记为 Major 问题。还有一次我们把禁止在循环中调用远程接口的规则加进去之后 Hermes 在好几个 PR 里都准确识别出了循环体内调用 Redis 的问题这是以前人工评审经常漏掉的点。调优过程不是一次性的。我建议每隔一到两周回看一次审查记录把那些机器没抓到的历史事故补充进规则同时把频繁误报的规则降级或删除。这种持续迭代比一上来就追求大而全的规则集有效得多。5. 常见问题与排查技巧实录5.1 API 调用与 GitHub 接入类问题实际运行期间我整理了一份高频问题速查表遇到问题先看一眼能省不少事症状最可能的原因排查与解决Webhook 完全收不到事件Webhook URL 不通或者 Secret 校验失败先到 GitHub App 的 Recent Deliveries 里看最近的投递记录有 200 说明到了服务端再查服务端日志里签名校验是否通过调用 GitHub API 返回 401私钥过期、App ID 填错、Installation ID 不对重新生成私钥、核对三个配置项是否一一对应返回 403 或 404App 没有安装到目标仓库或权限不足确认 App 已安装且配置了对应仓库的读取权限模型接口超时模型服务响应慢或超时时间设得太短在配置文件里把超时时间放宽到 60 秒以上并加上指数退避重试审查评论发出去了但 PR 状态没更新Checks API 权限缺失或未配置 check run 上报给 App 加上 Checks Read and write 权限并在配置里开启状态上报有一个细节特别值得注意GitHub App 的私钥文件无法直接查看有效期但它是可以更换的。每次重新生成私钥后旧的就会立刻失效。如果突然遇到 401先想想最近是不是换过密钥。5.2 误报多、审查质量不足怎么办误报是 LLM 类审查工具最常见的槽点。Hermes 用了一段时间后也会出现一些强行提意见的情况例如把合法的递归调用当成死循环风险或者把日常命名风格差异当成规范问题。团队对这种评论容忍度很低看多了会产生机器又在瞎说的抵触情绪。针对误报我的处理思路是分层治理。先给特定目录配置忽略规则比如测试目录、示例代码目录这些地方的误报率本来就高。再调整严重级别映射让模型在不确定时默认给 Minor 而不是 Major避免把小事放大。还可以把团队规则文件里那些模糊表述改得更精确比如把合理处理错误改成新增接口必须显式处理参数校验异常模型就更容易对齐。漏报的问题则更隐蔽。出现漏报通常是因为规则没有覆盖或者上下文信息不足。我会观察一段时间内线上出现的事故凡是跟代码缺陷相关的逐一对照 Hermes 的审查记录找出它没抓到的那类问题然后把应对规则补进去。这个方法比较笨但确实有效而且随着规则持续累积漏报率会逐步降下来。5.3 性能与成本控制自动化审查不是免费的主要成本在模型 API 调用。我之前粗略统计过一次中型 PR改动 15 个文件、diff 大约 800 行、上下文文件 6 个的消耗单次审查的输入 token 大约 12000输出 token 大约 1500。按照常见模型 API 的价格折算一次审查的成本在几分钱这个量级。但如果仓库每天有几十个 PR积少成多一个月也是一笔值得关注的开销。降低成本我做了三件事。第一把ignore_paths配全lock 文件、生成代码这类无意义内容全部跳过。第二启用增量分析逻辑当 PR 的 base commit 没有变化时只分析新增的 diff 部分不做重复的全量分析。第三合理设置max_files_per_review超过阈值的超大 PR 让作者拆分后再审避免一次性把一个超大项目半壁江山都塞给模型。但有一条反向经验也重要不要为了省 token 把上下文裁剪得太狠。我试过把模型配置改成只送 diff、不送上下文文件结果是省了一半 token但误判率明显上升反而浪费了更多人时间去复核。成本和质量之间要找一个平衡点现在这个配置是我用下来性价比最高的。6. 几点实操体会这套 Hermes 自动化代码评审跑通之后我最大的感受是它把团队代码评审的下限拉高了很多。以前 PR 质量完全看评审人当时的状态现在不管谁提交 PR机器都会先认认真真过一遍——哪怕它还做不到完美至少那些常规的低级错误和团队规范问题基本不会再溜过去了。我个人在实践中的建议是不要把 Hermes 的结果当作最终结论要把它定位成需要人工确认的预审意见。Blocker 级别的问题可以放心让作者改Major 级别的问题建议人工瞄一眼再决定Minor 和 Nit 就随它去。同时规则文件要持续迭代把它当成一个活文档来维护每发生一次线上事故、每发现一次漏报都回来补规则。最后再分享一个提升团队接受度的小技巧让 Hermes 在评论总结里加一句我可能误报请人工确认后再处理。这句话看起来很简单但对安抚开发者情绪非常有效。大家知道机器只是个助手反而愿意认真看它的意见如果它表现得全知全能一旦出现误报信誉就会立刻崩掉。把这个定位摆正自动化评审才能真正变成一个团队愿意长期依赖的工具。