Hermes GitHub PR 审查 —— 自动化代码评审做了这么多年研发我越来越觉得Code Review是整个研发流程里最容易被低估、也最容易被敷衍过去的环节。代码评审软件大家都会用但真正认真做Review的团队少之又少很多时候PR挂了三天没人理合并之前草草看一眼就点了Approve出了线上故障才知道当初的评审漏了什么。我自己也带过团队试过各种手段去推Review文化最后发现光靠自觉是真的不行得靠工具把这件事变成流水线上自然而然的一环。所以当我看到GitHub PR自动化审查这个方向时立刻就被吸引了而Hermes这个项目恰好把这件事做得相当顺手。这篇文章就围绕Hermes来写讲清楚它到底解决什么问题、怎么部署落地、规则怎么配、以及我在实际使用中踩过的坑。如果你正在为团队Review效率发愁或者只是好奇自动化代码评审能做到什么程度这篇应该能给你一套可以直接拿去用的方案。1. 先说清楚Hermes到底在帮我们干什么1.1 传统Code Review的痛在哪里在展开Hermes之前先聊聊我看到的真实痛点。很多人觉得Code Review就是“拉个PR、叫同事看一眼、点个同意”但实际执行起来往往是一地鸡毛。PR堆积成山是最常见的问题。业务开发节奏一快PR一多负责Review的人根本看不过来。每个人手上都有自己的一摊活儿能抽出时间给别人的PR提意见已经不错了更别说逐行看逻辑、想边界条件。于是PR要么长时间无人问津要么就是临上线前被催着草草合并评审质量形同虚设。然后是Review质量参差不齐。有人认真有人敷衍有人只对代码风格提意见真正危险的业务逻辑问题反而没人发现。我见过不少团队PR评论里讨论得热火朝天但全是在讨论变量命名和缩进核心的事务处理、异常分支、安全问题完全没人留意。这不能全怪个人人脑确实不适合做这种高强度的重复性检查。还有一类痛点是新人和团队的成长断层。新人提交的代码往往带着大量基础性问题比如没做空指针判断、异常被吞掉、事务边界不对。这些问题对资深工程师来说一眼就能看出来但团队里不可能每时每刻都有资深的人在旁边盯着。结果就是新人反复犯同样的错资深的人反复给同样的意见两边都累。1.2 Hermes的定位不是替代人而是先兜底Hermes解决的就是上面这些场景里“最机械、最重复”的那部分。它本质上是一个常驻服务监听GitHub仓库的PR事件拿到PR的改动内容之后按照配置好的规则进行审查然后把发现的问题以评论的形式发回PR页面。有人一听“自动化代码评审”就觉得是要用AI替代人工评审我觉得这个理解有偏差。Hermes真正适合干的是“兜底”和“初审”这两件事。代码合并之前先让Hermes过一遍把那些明显的低级错误、规范问题、安全隐患挑出来给人留出精力去看真正需要人判断的东西——架构是否合理、业务逻辑是否完备、方案有没有更好的选择。这样人工Review的负担能减少一多半评审质量反而更集中。从使用场景来说它适合三类人。个人开发者可以通过Hermes给自己的开源项目加一道自动检查的关卡中小团队可以在GitHub上快速搭起一套自动化评审流水线不需要采购昂贵的商业方案对工具链敏感的技术团队也能基于Hermes二次开发把团队自己的规范沉淀成规则。1.3 Hermes的工作流程速览Hermes的完整工作流程可以用一条线串起来PR事件产生 - Webhook推送到Hermes服务 - Hermes拉取PR元数据和Diff - 根据规则和模型生成审查意见 - 评论回帖到PR - 状态汇总。前两步是接入层的活负责把GitHub和Hermes连接起来中间两步是核心决定了审查效果的上限最后两步是输出层保证审查意见能真正触达开发者。我后面会把这几个环节逐个拆开讲。2. 整体架构与关键设计取舍2.1 事件驱动为什么选Webhook而不是轮询Hermes和GitHub通信的方案我觉得轮询和Webhook其实都可行但实际落地时Webhook是明显更优的选择。轮询的意思就是Hermes每隔一段时间调一次GitHub API看看有没有新的PR或者是PR有没有更新。这个实现看起来简单但资源浪费很严重尤其是在仓库多、PR频繁的情况下大量请求打过去只是在确认“没有新事件”而且很容易撞上GitHub的API限流。Webhook是反过来的GitHub主动把事件推给Hermes。有PR开了有PR更新了有PR被评论了GitHub都会往你配的地址发一个事件。这种模式实时性极高PR一提交几秒钟内审查就能触发同时没有无效请求不会白白消耗API额度实现上也干净很多服务起来后只需要等待回调。我把Webhook的工作流拆开给你看开发者在GitHub上创建或更新PR。GitHub根据仓库配置的Webhook地址把pull_request事件推送到Hermes服务。Hermes收到事件后先做合法性校验确认这个事件确实是GitHub发来的。根据事件类型分发处理opened事件触发全量审查synchronize事件触发增量审查。2.2 审查引擎LLM判断为主规则引擎兜底Hermes的审查引擎是怎么设计的我自己的实践是LLM为主、规则为辅。这个搭配不是拍脑袋想的而是两类工具的特性决定的。规则引擎适合做“确定性检查”比如禁止某个依赖版本、强制Logger格式、不允许输出调试代码。这些检查结果应该是100%确定的碰了就报没碰就不报不需要讨论。规则引擎跑起来快结果稳定谁都不会有异议。LLM适合做“语义理解型检查”比如这段代码的异常处理是否合理、这个并发场景有没有数据竞争、这个接口的参数校验是不是漏了。这类问题没有唯一正确答案需要一定程度的推理能力。用传统静态检查工具很难写规则但LLM可以给出相当接近人审的判断。两条腿走路的好处是确定性检查不依赖模型稳定性极高而语义检查虽然模型输出有波动但正因为有模型兜底很多静态分析发现不了的问题也能被捞出来。2.3 回帖机制怎么避免刷屏和噪音自动化评审最容易翻车的点就是噪音太多。一个PR被机器人刷了三十条评论开发者点开一眼扫过去发现一半是“建议使用const”这种无关痛痒的意见后面就会形成“机器人说啥都无视”的条件反射整个工具就废了。Hermes在回帖上做了一个值得表扬的设计评论聚合。不是每个问题单独发一条评论而是把一次审查的所有发现汇总成一条结构化评论按严重程度排序分成“必须修改”和“建议优化”两类。格式长这样审查发现 3 个问题其中严重 1 个、建议 2 个。严重问题src/user_service.go:45未关闭数据库连接存在连接泄漏风险。建议优化src/util.go:12建议使用errors.Is判断错误类型。src/api.go:88重复代码较多可考虑抽取公共函数。这样开发者一打开PR就能看到全部意见有疑问可以展开讨论毫无疑问可以快速处理。关键是机器不要反复去人那样只会让人烦躁。真正的自动化评审应该像一个不说话但一直干活的同事最后给你一份干净的检查报告。3. 从0到1把Hermes跑起来3.1 环境准备与依赖清单这部分我直接按我自己成功部署过的环境来写照着做基本不会踩空。需要准备的东西主要有一台能访问外网的服务器或本地开发机Linux/macOS都行安装了Docker和Docker Compose一个GitHub账号并且对要接入的仓库有管理员权限如果要用LLM审查能力准备一个可用的模型API KeyGit和基本的命令行操作能力。用量需求上Hermes本身很轻1核2G的机器就能跑起来适合个人项目。如果仓库很多、PR很频繁建议2核4G起步。存储上不需要数据库配置和状态都可以存在文件里这块负担很小。依赖清单也一并列出来Docker 20.10Node.js 18源码运行时需要Git 2.30Python 3.9部分辅助脚本需要YAML配置文件的语法基础3.2 创建GitHub App并配置权限Hermes和GitHub打交道推荐的方式是注册一个GitHub App而不是用个人Token。原因很明显GitHub App的权限是细粒度的可以只授予这个仓库的读取权限安全边界清晰个人Token是账号级权限一旦泄漏等于整个账号沦陷。创建步骤我手把手写一遍。先到GitHub页面依次进入Settings - Developer settings - GitHub Apps点“New GitHub App”。GitHub App的名称可以随便起建议叫得有意义比如hermes-bot。在权限配置里仓库权限需要打开Pull requests的读写权限和Metadata的只读权限。Webhook这里要填Hermes服务的公网地址事件类型勾选Pull requests即可。创建完成后系统会生成一个App ID这个要保存好后面配置要用。私钥的处理要特别说一下。创建GitHub App时可以生成私钥下载后是一个.pem文件。这个文件的保管一定要严格建议放到单独的目录并加上权限限制绝对不要提交到代码仓库里。3.3 本地运行与调试我建议第一次跑Hermes先在本地起一个调试实例不要直接上服务器。原因很简单本地能让你快速看到日志和报错调试效率高得多。配置文件的格式是YAML核心内容如下github: app_id: 12345 private_key_path: /path/to/private-key.pem webhook_secret: your-webhook-secret repo: owner/repo server: port: 8080 llm: provider: openai api_key: sk-xxxx model: gpt-4o-mini rules: - name: no-debug-log pattern: console\\.log|print\\( level: warning message: 请移除调试日志拿到配置文件后用源码方式运行就简单了。npm install装依赖npm run start启动服务然后用curl发一个模拟事件测试是否能正确响应。这一步的要点是先把服务跑通再谈效果调优。3.4 用Docker部署到服务器本地验证没问题后部署到服务器就直接上Docker。Docker的好处不止是免环境问题更重要的是升级回滚都很方便。我给的docker-compose.yml配置是这样的version: 3 services: hermes: image: hermes-review:latest container_name: hermes restart: always ports: - 8080:8080 volumes: - ./config.yaml:/app/config.yaml - ./private-key.pem:/app/private-key.pem environment: - LOG_LEVELinfo部署时有一个细节容易踩坑Webhook地址必须是公网可访问的。GitHub的Webhook投递机制决定了它没法主动访问你内网的服务。如果你没有公网服务器可以先把服务部署到一台有公网IP的云主机上做测试。这个我在第6章会展开讲。4. 核心玩法规则配置与Prompt调优4.1 配置文件逐项拆解Hermes的配置文件是使用体验最核心的部分。配置项设计得清晰基本做到了“看到字段名就知道是什么意思”。我逐个过一遍常用项。github.app_id和github.private_key_path是用来标识GitHub App身份和签名的一个是固定ID一个是密钥文件路径。github.webhook_secret是Webhook的校验密钥GitHub推送事件时会带一个签名头Hermes拿这个密钥验证事件确实来自GitHub防止伪造请求。server.port是Hermes自己的监听端口默认8080即可。llm.provider和llm.api_key指定模型服务商和密钥model选你惯用的模型。rules是规则列表每条规则包含名称name、匹配模式pattern、严重级别level和提示信息message。这里可以用正则表达式匹配的是代码中的文本内容。比如我想拦截调试用的日志输出就写pattern: console\\.log|print\\(级别设为warning命中后Hermes会自动在PR评论里提示。4.2 自定义规则从团队规范到机器检查团队规范落地成机器规则这步做得好能大幅提升Review效率。我整理过一套常用规则你可以直接参考。规则名正则/匹配方式级别作用禁止明文密钥AKIA[0-9A-Z]{16}critical防止云厂商密钥泄漏禁止调试日志console\.log|print\(warning清理调试残留禁止TODO遗留TODO|FIXMEwarning提醒未完成任务禁止大文件提交文件大小1MBcritical防止资源文件进仓库禁止内网IP10\.|172\.(1[6-9]|2[0-9]|3[01])\.critical防止内网地址泄漏比如禁止明文密钥这一条我之前在一个项目里真实遇到过有同事把AWS的AccessKey直接提交到了PR里还好当时用了Hermes的类似规则在合并前拦住了不然一旦密钥泄漏到公开仓库损失不可估量。这条规则建议每个团队都配上正则拿过去直接用就行。大文件提交那条也很有用。有些团队的仓库里会出现几个上百MB的二进制文件一提交PR整个仓库的体积就失控了。通过规则在PR阶段直接拦截比事后再用BFG清理历史要省事太多。4.3 LLM服务选型与Prompt模板设计规则引擎处理的是“死问题”LLM处理的是“活问题”。这块是拉开体验差距的地方我详细说说怎么配效果更好。模型选型上如果追求性价比和速度gpt-4o-mini这类轻量模型在大部分常见代码审查场景下已经很能打了。如果要做深度审查尤其是复杂的并发、架构层面的问题可以考虑更强的模型。关键是模型一定要支持比较长的上下文至少能覆盖一个PR的主要改动。Prompt模板是决定审查质量的重中之重。我调整过很多版稳定好用的模板大概是这样的你是一位资深代码审查专家请审查以下PR的代码修改。 要求 1. 重点关注逻辑错误、边界条件、异常处理、安全问题 2. 忽略纯粹的代码风格问题已有规则检查 3. 每条意见必须指出具体文件和行号 4. 按严重程度区分“必须修改”和“建议优化” 代码变更 {DIFF_CONTENT}这个模板有两个关键点。一是加了“忽略纯粹的代码风格问题”这句话因为风格检查用规则引擎就够了LLM只需要专注它擅长的事二是要求输出必须带行号没有行号的审查意见等于废话开发者找不到在哪改情绪先起来一半。4.4 本地调试审查效果的姿势配置规则和Prompt之后建议在正式接PR前先拿历史PR练手。方法很简单找个上个月已经合并的没问题的PR手动把Diff内容喂给Hermes跑一遍看它输出什么意见。如果发现它输出了一堆“这行代码缩进不对”“这个变量名起得不好”之类的废话不用怀疑是Prompt没有约束好回到模板里强化“只关注逻辑与异常”的指令。如果发现该抓的严重问题没抓到可以针对性补充规则或者调整Prompt让模型更关注某个方向。4.5 建议的“人工复核”机制自动审查再强也不能完全没人管。我给团队定的流程是Hermes出意见后PR作者逐条确认能改的立刻改不能改的要回复原因合并前最后一位人工Reviewer需要确认Hermes的意见都被处理完了。这样既保留了自动化带来的效率也保留了人的最终判断。5. 与已有工作流的融合5.1 接入GitHub ActionsHermes除了以常驻服务的形态运行还可以和GitHub Actions配合让审查能力直接嵌入CI流水线。两种方式定位不同Webhook模式适合持续监听、主动推送Actions模式适合提交时同步跑一轮把结果作为构建流程的一环。最简单的做法是在仓库里加一个.github/workflows/review.yml文件Trigger设置为pull_request事件name: hermes-review on: pull_request: types: [opened, synchronize] jobs: review: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkoutv4 - name: Run hermes review run: docker run --rm -v $PWD:/repo hermes-review:latest review --path/repo这种模式适合那种不想常驻服务的团队PR一提交CI就把审查跑一遍结果同步到PR评论里。缺点是每次都要冷启动容器速度比常驻服务慢一点但胜在架构简单、不占常驻资源。5.2 配合Status Check和分支保护如果想让Hermes的审查意见有“强制力”可以和GitHub的分支保护规则配合。GitHub的Status Check机制允许你规定某些检查必须通过才能合并PR。把Hermes的审查结果上报为一个Check Run未通过时PR的合并按钮直接是灰的门槛就立起来了。配置方式是在仓库的Settings - Branches - Add rule里把“Require status checks to pass before merging”打开然后把你Hermes上报的那个Check名字加进去。这样项目Owner可以明确看到“Hermes的检查没通过这个PR不能合并”。这个约束非常有用它把“建议”变成了“流程的一部分”而不是可看可不看的评论。结合我自己带团队的经验分支保护规则一定要设。没有这个强制门槛再好的工具都可能被人绕过。人都是趋利避害的上线压力一大什么流程都能跳。5.3 多仓库和团队落地如果团队有多个仓库都要接入Hermes可以在配置里列出多个仓库Hermes会把所有监听关系管理起来。repo: owner/repo-a单仓库模式。repos: owner/repo-a, owner/repo-b多仓库模式。每个仓库可以配置不同的规则集。比如前端仓库可以关闭某些针对后端的规则加上依赖体积检查后端仓库则加强安全相关的规则。这种精细化控制很实用一套服务管所有仓库但规则可以按项目独立开。团队推行的时候我建议先挑一个不怎么重要的辅助仓库试点跑一两个迭代把规则和Prompt调到稳定再全面推开。这样团队对工具的接受度会高很多不至于一上来就被噪音淹没导致抵触情绪。6. 使用过程中的常见问题与排查经验6.1 Webhook收不到事件或一直超时这是我在接入Hermes时遇到的最多的一类问题。现象是GitHub的Webhook投递记录里全是失败或超时Hermes这边压根没反应。排查思路要按顺序来。先看GitHub仓库的Settings - Webhooks - Recent Deliveries这里能看到每次投递的请求和响应详情。如果Response显示超时先检查你的服务器防火墙和安全组有没有放行GitHub的出口IP。很多云服务商的默认策略只放行80和443端口8080这种自定义端口是不通的。最常见的解决方式是在Webhook配置里把Payload URL默认设为https://your-domain.com/webhook利用Nginx或Caddy做一层反向代理把外部443端口的请求转发到内部8080端口。这样既解决了端口放行问题也能顺便把Webhook地址变成HTTPS的更安全。6.2 PR提交后一直转圈Hermes没反应如果Webhook投递显示成功但Hermes没执行要先看Hermes的运行日志。建议日志级别设置为debug能够看到事件进来后的完整处理链路。如果是事件都进不来检查Webhook的Secret配置是否一致如果事件进来了但没反应大概率是GitHub App的权限配置不对导致Hermes拉取PR内容和Diff时被拒绝。我之前就踩过这个坑。GitHub App的权限是分层级的只有Pull requests: Read权限才能拉取PR的Diff。如果权限只给了Metadata: ReadHermes能收到事件但拿不到Diff内容等于白搭。6.3 PR冲突或Rebase后审查结果不准自动化审查还有一个天然局限它审查的是PR当前的状态。如果PR刚提交时没有冲突但后来主分支更新导致PR出现冲突那原来的Diff就不再准确Hermes基于旧Diff给出的意见可能就失效了。解决办法也很简单手动触发一次新的审查。最直接的方式是让PR作者执行一次git rebase main并强制推送这会触发synchronize事件Hermes就会重新跑一遍。如果你不想让开发者手动操作也可以在Webhook处理逻辑里对每次synchronize事件都重新拉取最新Diff丢掉之前的审查结果。6.4 模型服务不可用或响应异常LLM审查依赖模型服务模型服务一旦不可用Hermes就瘫了一半。解决这个问题一个方案是配置模型API的超时时间和重试次数另一个是在模型不可用时降级为只跑规则引擎至少保证确定性问题还能被发现。响应异常也很常见有时候模型输出的内容不是合法JSON导致Hermes解析失败。我的处理方式是在调用模型之后加一个“结果清洗”步骤把模型输出中非结构化内容过滤掉只保留符合预期格式的审查意见。这个动作不需要很复杂但能显著提升稳定性。6.5 遇到Failed to read private key这类报错这个报错在第一次部署时很容易踩中。原因是私钥文件的权限过大Hermes出于安全考虑拒绝读取。解决方案是执行chmod 600 private-key.pem把文件权限改为仅Owner可读写。这个问题虽然小但卡住过不少人。6.6 常见问题速查表问题现象可能原因解决方式Webhook投递超时防火墙未放行端口配置反向代理使用443端口Hermes收不到事件Webhook Secret不一致对比两边Secret配置收到事件但未审查GitHub App权限不足补充Pull requests的读权限审查内容为空Diff拉取失败检查私钥与权限模型输出解析失败模型返回非结构化内容加入结果清洗步骤私钥读取失败文件权限过大chmod 600 private-key.pem7. 我的总结与进阶建议把Hermes这一套跑通之后我的实际感受是自动化的意义不只是提效而是把标准立住。人工评审可能今天严格明天宽松但机器规则一旦定下来每次PR都一视同仁。团队里新来的同事提交代码时Hermes的评论就像一位不说话的老前辈在提醒他们这个项目有这些规矩请遵守。这种潜移默化的影响比在评审会议上强调一百遍规范都有效。如果你想让Hermes再进一步有两个方向值得探索。一个方向是让审查结果和内部的知识库打通。团队可能有一些非公开的经验和规范把这些内容喂给模型让它带着团队特有的上下文去审查效果会精进不少。另一个方向是统计审查数据比如规定时间内问题密度、各类问题的占比趋势这些数据能帮你判断团队代码质量是在变好还是变差规则是否需要调整。最后说一句我真正想强调的自动化审查的目的是把人从重复劳动里解放出来而不是替代人的判断。代码审查里最有价值的那部分——架构方案的权衡、产品逻辑的验证、长期可维护性的考量——终究需要人来完成。让机器去查漏让人去思考这才是我认为最理想的工作方式。