Hermes:基于大模型的自动化代码评审工具实践指南
先把结论放前面我自己在 GitHub 仓库上跑过一段时间的 Hermes它不只是一个 PR 辅助小玩具而是能把“开 PR → 读 diff → 给评论 → 挂状态”这整条链路交给自动化代码评审去执行的一整套方案。如果你还在靠人工逐条翻 Pull Request又被大量“看起来像人肉的机械检查”拖住Hermes 这套东西值得你花十分钟看完。它解决的核心问题其实很简单代码评审不应该把时间浪费在“这个变量没判空”“这里把调试日志提交上去了”“这个改动为什么没有对应测试”这类有明确标准、但人看多了就会漏的事情上。Hermes 会在大模型后端本地部署或走 API 都行的帮助下读取 PR 的变更内容、相关上下文然后按你预先定好的 review 规则输出结论。也就是说它能当你的第一轮 reviewer初筛一遍再交给你。这篇文章会从它的设计思路讲起完整过一遍部署、配置、接入 GitHub 的实操步骤最后把我踩过的坑和一些优化经验直接列出来。无论你是个人开源项目维护者还是三五个人的小团队想找个私有化方案都可以照着这份记录落地。需要说明的是Hermes 具体版本的命令名和配置文件字段可能稍有差异我写的是基于常见实践整理的思路实操时先跑一遍hermes --help确认当前版本不会有太大偏差。1. Hermes 到底解决了什么问题核心思路与设计拆解1.1 为什么我不太信纯人工 Review在搭 Hermes 之前我经历过很多次“PR 挂了两天没人理作者只好在群里挨个点名”的场景。人工评审最大的瓶颈不是看不懂代码而是上下文切换成本太高。你手头正写着 A 模块突然切去看 B 模块的一个 PR要把调用链、边界条件、历史改动原因全部捡回来脑子至少要热五分钟。一个项目只要活跃度稍微上来PR 在手里放几个小时反馈质量就会肉眼可见地下降。另一个更现实的问题是注意力衰减。一个 PR 有 400 行改动前 200 行你可能还认真看看到后面基本就在快速滑屏。像“新加的错误处理吞了异常”“临时调试代码没删干净”“Key 写死了”这类问题模型反而比人稳定因为它没有疲劳曲线。Hermes 真正替代的不是资深工程师的架构判断而是把那些 low-hanging fruit 全部兜住让人工 reviewer 集中精力看真正需要业务判断和设计决策的点。所以我的定位很明确Hermes 是个自动化的第一道评审防线而不是用来开除人工评审的借口。你仍然需要一个 senior 做最终把关但你不必再亲自干“机械巡查”的活儿。1.2 Hermes 的典型工作流从“开 PR”到“评审完成”Hermes 的完整链路看起来像这样实际跑起来非常顺开发者在 GitHub 上提交 PR此时 PR 处于 open 状态。GitHub 的 Webhook 事件推送pull_request和pull_request_review到 Hermes 服务。Hermes 调用 GitHub API 拉取本次 PR 的 diff、提交信息、关联的 issue、修改文件列表。Hermes 按规则从代码库中提取必要的上下文比如被调用函数的定义、改动文件的目录结构组装成适合大模型的 prompt。模型分析后输出结构化评审结果包括缺陷列表、修改建议和总体结论。Hermes 把结果写回 GitHub发 PR 评论、提交 review或在 Check 界面挂一个状态以辅助门禁。关键点在于第 4 步。早先也有人直接把整个 diff 一股脑丢给模型那样 token 消耗大回复也容易跑题。Hermes 更合理的做法是先做一次“代码变更摘要”只把有意义的上下文片段和疑似缺陷区放进去。比如一个文件只改了一行调用那么只需要把那行附近的函数签名一并拷进 prompt不需要把整个项目都塞进去。1.3 为什么私有化和本地模型是刚需代码评审这件事的敏感度往往被低估。把公司核心业务代码作为 prompt 发给第三方公开服务很多团队是不愿意的。Hermes 这类方案最大的好处是它天然支持两种模式如果只是用来审开源项目你可以直接接入 DeepSeek、OpenAI 这类远程 API开箱即用如果是公司内部仓库建议把模型部署在本地 GPU 机器或内网 API 网关后面让 diff 和代码上下文不出内网。我的建议是敏感项目一律走内网模型。现在的开源模型在代码理解上已经足够好用配合比较好的 prompt 约束效果并不比调用远程商用时差太多。Hermes 本身在这块做得比较灵活base_url 支持任意 OpenAI 兼容接口你甚至可以在同一条流水线里内网仓库走本地模型公开仓库走 DeepSeek按项目维度分开配置。这一点对大规模使用非常重要否则一个团队会为了“能不能上公共模型”争论很久。2. 动手搭一套 Hermes环境准备与 GitHub 侧配置2.1 运行环境一台能联网的 Linux 机器就够了先说你最关心的硬件问题。Hermes 本体其实是个 Python 服务对 CPU 要求不高最占资源的是模型推理。如果你打算让 Hermes 调用 DeepSeek 这类远程 API那随便一台 1 核 2G 的小机器都能跑得很稳本地只负责发请求和处理 GitHub Webhook。如果你想把模型私有化部署那就得准备一张显存稍大的 GPU 卡或者一台至少 16G 内存的 Mac/PC 用来跑量化模型。我这边目前的部署形态是Hermes 服务跑在一台 2C4G 的内网服务器上模型走 DeepSeek 的 API因为仓库本身包含外部开源依赖没有特别机密的内容。初始化环境用虚拟环境最省心# 创建独立环境避免污染系统 Python python -m venv ~/.venvs/hermes source ~/.venvs/hermes/bin/activate # 安装 Hermes 主程序不同版本的包名可能在 hermes 后面带后缀安装前先搜一下 pip install -U hermes hermes --help第一次运行hermes --help就能看到它下面有哪些子命令。正常情况下应包含init、review、server、config这几类init会在当前目录生成一份配置模板属于典型的“先跑通再改”设计。注意如果你是在 macOS 上用 Homebrew 装的 Python记得先确认 pip 指向的是当前虚拟环境执行which pip看一眼。环境不对往往会装到系统目录后面启动会各种找不到依赖。2.2 GitHub 侧身份用一个专门的 Bot别用个人 TokenHermes 要操作你的仓库必须在 GitHub 上有一个身份。最简单的办法是创建一个普通 GitHub 账号作为机器人账号然后给它生成一个具有repo权限的 Personal Access Token更规范的做法是注册一个 GitHub App把权限收紧到特定仓库。如果只是自己用推荐直接建 Bot 账号加 PAT一分钟搞定。如果团队共享GitHub App 更合适因为它的权限粒度非常细并且可以配置为“只对你指定的仓库开放”。不管用哪种Hermes 至少需要这几项权限读取代码和 PR 元数据pull_request: read、contents: read在 PR 上写评论和提交 reviewpull_request: write如果需要用 Check 状态当门禁还需要checks: write。我一开始图省事直接用了经典个人 Token权限给得很大。后来有一次 Token 被误提交到代码里虽然马上撤销了但那种事后冷汗的感觉实在不好受。现在新项目一律用 GitHub App用私钥在服务端自己签发 Token泄露风险小很多。2.3 让 Hermes 和 GitHub 握手配置仓库与启动服务安装完成后第一步是执行hermes config init生成一份hermes.toml也可能是.yaml看版本。下面是一份常用模型的配置示例[github] # 改成你自己的仓库范围org 级和单仓库都支持 repo your_org/your_repo # 注意这里不直接写 token而是从环境变量读防止误提交 token_env GITHUB_TOKEN [model] # Hermes 通过 OpenAI 兼容接口访问大模型 base_url https://api.deepseek.com/v1 model deepseek-chat api_key_env DEEPSEEK_API_KEY temperature 0.2 max_tokens 2048 [review] mode comment max_comments 8配置完成后启动服务# 启动 Webhook 监听服务默认监听 8080 端口 hermes server --listen 0.0.0.0:8080 # 如果想先调试可以直接对某个已有 PR 做一次评审 hermes review --repo your_org/your_repo --pr 123然后把 GitHub 仓库的 Webhook 地址指向http://你的服务器:8080/webhook勾选pull_request事件就行。不勾选push事件避免每次提交代码都触发评审导致评论太多。2.4 第一次验证用测试 PR 确认链路是通的所有按钮都搭好以后千万别直接拿正式分支试水。我在根目录下新建一个不痛不痒的分支改一行注释、加一个无关紧要的空函数然后提交一个标记为test-hermes的 PR。这样如果 Hermes 把整个 PR 的历史评论刷爆影响范围也足够小。跑完以后打开 PR 页面正常情况下你会看到 Hermes Bot 头像下方出现一条 review 或普通评论。如果什么都没有大概率是 Webhook 没触发或被服务器防火墙拦了。先用下面这条命令从服务器外部测一下端口通不通curl -I http://你的服务器IP:8080/health如果返回200再回 GitHub 的 Webhook 设置页面点“Recent Deliveries”查看最近一次请求有没有成功推送到你的服务器。GitHub 这边会显示 HTTP 状态码和响应体排查起来非常直观。这一步虽然简单但能帮你节省大量时间我建议无论多熟悉都先走一遍。3. 调教 Hermes评审规则与 Prompt 才是灵魂3.1 三种评审粒度Comment、Review 还是 Check 状态Hermes 一般支持三种评审粒度对应不同使用阶段comment普通 PR 评论模式。机器人把发现的问题一条条发出来不阻塞任何人最适合前期试跑。review以正式 Review 的形式提交作者能在 Files changed 页面看到比普通评论更像人工评审。check通过 Checks API 创建一个检查任务你可以指定它在什么条件下失败从而阻止合并。我的建议非常直接不要一上来就开check。先跑 1 到 2 周的review模式看看模型评论的准确率。如果 80% 以上的评论是真的该改的再考虑把“高严重级别问题”设置为 Check Failure作为门禁中的一道辅助。理由很简单模型判断不可能 100% 准确你要是把它的每条意见都当成强制项团队很快会恨死这个机器人。3.2 用规则文件控制“该看什么”和“不该看什么”很多人以为自动化评审就是靠模型自发找问题其实不是。模型的注意力完全由 prompt 和规则决定你不告诉它该关注什么它就会像刚入职的实习生一样四处乱看评论里全是空的。Hermes 的规则文件是最好的收敛手段。我平时会维护一份规则清单大致长这样[review.focus] # 只重点评审这里的文件路径其余文件最多给 summary include [server/**/*.py, web/src/**/*.ts] # 自动生成代码、锁文件和迁移脚本不参与行级评审 exclude [**/package-lock.json, **/migrations/*, **/*.pb.go] [review.rules] # 高优先级问题必查 security [hardcoded_secret, sql_injection, path_traversal] error_handling [swallowed_exception, unhandled_error] # 中优先级问题提示不强制 style [debug_print, magic_number] performance [large_loop_over_query, n_plus_one]配置文件的思路是把你要防的问题建模成规则门类然后让模型按这个门类去扫。你用模型不是为了让它自由发挥创造力而是让它做“一个知道这些规则的严谨工程师”。字段名可能因版本略不同但逻辑是一样的先定范围再定重点最后定输出方式。3.3 Prompt 设计把模型定位成“爱挑毛病但不能瞎说”的资深 reviewer如果底层大模型足够聪明prompt 可以写得很简单。但如果希望评审结果稳定就必须做结构化输出。我最常用的 prompt 大概长这样Hermes 的system_prompt配置里可直接丢进去你是一位有 10 年后端开发经验的资深 reviewer性格务实不喜欢说空话。 本次任务是评审一个 Pull Request。请仅针对以下方面提出意见 1. 可能导致线上故障或数据损坏的问题最高优先级。 2. 异常被吞掉、资源未关闭、并发边界错误。 3. 明显不合理的性能写法。 4. 明显违反仓库既有约定的风格问题。 要求 - 不要给泛泛而谈的建议例如“建议补充单元测试”这种没有上下文的话。 - 每条意见必须给出文件路径、大致行号、问题原因和可执行的修改方向。 - 如果你没有发现问题直接输出空列表不要硬凑内容。 - 对疑似问题使用询问语气例如“这里是否需要考虑 xxx”不要用断言语气。输出格式建议使用 JSON这样 Hermes 可以把结构化的结果转成 GitHub 评论格式还能为每条意见标记 severity。比如[ { file: server/src/handlers/user.py, line: 72, severity: high, message: 这里直接使用了用户传入的 file_path 拼接路径缺少 .. 过滤可能导致路径穿越。建议用 os.path.realpath 做归一化后检查前缀。 } ]模型是按概率生成文本的你不给格式它会自由发挥你给它一个固定格式它至少会在结构上保持稳定。Hermes 后续能不能把某条评论升级成 change request完全依赖这种结构化输出。如果评论字段乱成一团后续自动化能力都无从谈起。3.4 多仓库复用一份规则管住整个组织Hermes 很少只装在一个仓库里。你大概率会想让它在所有后端仓库里生效又不想在几十个仓库里重复维护同一份规则。这时可以在仓库根目录建立一个名为.hermes/的配置目录或者把配置放在单独的配置仓库中让 Hermes 在运行时按优先级合并配置。我目前的组织方式是公共规则维护在一个名为hermes-policies的仓库里里面保存了所有语言的 prompt、常见规则、屏蔽路径每个业务仓库只有一份很短的个性化配置覆盖自己专属的 ignore 路径和特殊约定。Hermes 启动时先拉公共配置再叠加仓库级配置后者的优先级更高。这样业务团队想限制“不许碰数据库迁移”只需要加两行不用 fork 整个规则库。这套做法的副作用是新人要看懂“机器人为什么这么评论”时可以直接查公共规则不需要翻邮箱里的历史讨论。所有 review 决策依据都是可追溯的这对团队规范建设有额外帮助。4. 把 Hermes 嵌进日常工作流手动触发、自动化调度与门禁4.1 手动触发用评论里的斜杠命令让机器人“再看一次”开发者的实际工作流往往是这样的早上开 PRHermes 扫了一遍提了 3 个问题开发者改完代码 push 新 commit发现 Hermes 依然把旧意见挂在上面这显然很烦。GitHub 的synchronize事件虽然能触发重新评审但有些团队更喜欢让作者主动控制时机。我的习惯是在 Hermes 里注册一个/hermes-recheck斜杠命令。作者提交新代码后在 PR 评论区输入这条命令Hermes 就会重新拉取最新 diff 再跑一轮。这一步实现了“按需评审”比每次 push 都自动评审少很多噪音。实现上就是让 Webhook 监听issue_comment事件如果评论内容以/hermes-recheck开头就优先于普通 PR 事件触发一轮 task。注意要加权限判断只有 PR 作者和仓库维护者的指令才生效否则任何人刷评论都可能让 Hermes 白白跑一次消耗 token。4.2 和 GitHub Actions 结合不部署独立服务也能用如果你不想维护一台常驻服务器Hermes 完全可以跑在 GitHub Actions 里。每次 PR 被打开或同步代码时Actions 拉一个装有 Hermes 的容器执行一次 review然后把结果写回仓库。下面是一份最小配置可以作为 workflow 的基础模板name: hermes-review on: pull_request: types: [opened, synchronize, labeled] jobs: review: if: contains(github.event.pull_request.labels.*.name, hermes) runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 with: fetch-depth: 0 - uses: actions/setup-pythonv5 with: python-version: 3.11 - run: pip install -U hermes - name: run hermes review env: GITHUB_TOKEN: ${{ secrets.HERMES_BOT_TOKEN }} DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }} run: | hermes review \ --repo ${{ github.repository }} \ --pr ${{ github.event.pull_request.number }} \ --output github注意 workflow 里并没有把 repo 通过 checkout 出来供 Hermes 阅读Hermes 自己会调用 GitHub API 拿代码内容。如果你希望它审代码时还能看到仓库里的文件夹层级和组织结构可以把当前 workspace 路径作为参数传进去Hermes 会优先读取本地文件再补充 API 拉不到的历史上下文。加if: contains(github.event.pull_request.labels.*.name, hermes)这行的意思是只有 PR 被贴上名为 hermes 的标签时才触发。这样做的好处很明显仓库默认不跑只有作者准备好才贴标签这能节省大量 CI 时间也避免小 PR 被机器人频繁骚扰。4.3 把 Hermes 变成“软门禁”高严重度才阻塞合并设置门禁需要非常克制。Hermes 本身不应该像单元测试那样跑挂就让 CI 全红因为模型本身是概率输出存在误报。我在实践里的做法是分两层普通意见只是 review comment只有那些标成high且符合特定规则的问题才会写成一个失败的 check run。例如Hermes 检测到 hardcoded secret、路径穿越这类明确定义的安全问题基本是铁板钉钉的这时候可以直接让 check 失败强制开发者处理而“这段代码性能可能有问题”这种需要上下文确认的意见尽量只作为评论出现留给作者和人工 reviewer 判断。实操建议先跑 3 到 5 个 PR把模型输出中你确认无误报的类型记录一下再把这些类型加进“高严重度”列表。不要凭感觉配置门禁规则否则第一天上线团队就会因为一堆似是而非的误报对你失去信任之后想再推行就难了。5. 我踩过的坑Hermes 常见问题与排查实录5.1 同一个 PR 收到一堆重复评论Webhook 重试没做幂等我上线第一个星期就遇到一个诡异问题每次开 PRHermes 会评论两到三条几乎相同的意见。一开始以为是模型抽风查了日志才发现是 GitHub Webhook 在超时后自动重试而 Hermes 每次都当作新事件处理。解决办法是在本地记录每次事件的delivery_id。GitHub 的每个 Webhook 请求头部都带一个唯一的X-GitHub-Delivery值把它存进 SQLite处理之前先查重。如果同一个 delivery_id 已经处理过直接返回 200 并跳过不再跑模型。同样地对于同一个 PR如果 commit SHA 没有变化也没有人工触发/hermes-recheck就没必要重新评审。这两层去重逻辑缺一不可前者防网络重试后者防重复 push 同一份代码。5.2 大型 PR 直接超时或 token 爆炸不做分块就等于烧钱有一次同事合并了两周的分支PR 一下改了 300 多个文件将近 2 万行。我直接让 Hermes 跑全量结果模型服务长时间不回复token 费用也肉眼可见地飙升。后来我把 Hermes 改成了分块评审模式按目录或按依赖关系把 diff 切成几块每块最多 600 行逐块分析最后再聚合成一份总结。如果 PR 实在太大正确策略其实是“拒绝评审”加“摘要模式”Hermes 只输出哪些文件改动量最大、哪些目录可能互相影响提示人工 reviewer 优先看哪几个文件。对于大 PR机器人再聪明也不可能完全替代人的上下文理解最好的价值是把高风险的改动区域标出来让人一进来就知道该看哪里。5.3 模型幻觉式评论别让它直接改代码大模型有两种典型幻觉一是把没问题的代码解读成有问题二是给出看起来正确的修改建议但实际是错的。我见过 Hermes 说某个变量“可能存在 None 引用”但读完整段代码发现上面已经判过空了。原因通常是上下文不够它没看到更靠前的保护条件。对策有两个。第一在 prompt 里明确要求“对不太确定的问题使用提问语气”把责任推回给作者确认。第二绝对不要开启任何“模型建议直接生成 commit”的功能。哪怕它在技术上能实现也不要让一个概率模型直接改代码。Hermes 的价值是提示风险和给方向不是代替人做修改。我自己对自动生成 patch 一直持保留态度如果真要试验也只能在专门的分支上跑。5.4 事件不触发先查 Webhook再看 Token 权限这个问题是最高频的求助类型。配置完 Hermes 后PR 事件像石沉大海。排查顺序我建议如下先打开 GitHub 仓库的 Settings → Webhooks找到刚才添加的 webhook点击 Recent Deliveries。如果最近没有请求记录说明事件根本没有推过来重看事件有没有勾选 pull_request。如果请求显示失败把 Response 里的日志贴到本地对照基本能看出是 404 还是 500。如果请求已经命中 Hermes 但机器人没发评论那就是 Token 权限问题。PAT 要确认勾选了repo权限GitHub App 要确认安装到了目标仓库并且 permissions 里pull_request是 write 而不是 read。这类问题 80% 都能在这两步里找到答案。不要一开始就深挖模型配置。5.5 常见问题速查表现象最可能的原因解决思路同一个 PR 评论多条重复Webhook 重试缺少幂等去重按 X-GitHub-Delivery 和 commit SHA 去重大 PR 超时/费用高diff 太大没有分块限制单次评审行数大 PR 进入摘要模式Hermes 评论“不存在的问题”模型没拿到足够上下文补充被调用函数的定义或 prompt 中要求询问语气Webhook 显示 404回调路径配置不对确认路径是 /webhook且服务器端口开放能收到事件但没评论Token 权限不够或 Bot 未安装检查 pull_request write / checks write 权限push 新 commit 后评论仍挂在旧 commit事件类型没监听 synchronizeworkflow 或 webhook 事件里增加 pull_request synchronize5.6 别把 Hermes 做成“唯一门禁”最后想单独说一件事自动化代码评审很容易走向另一个极端就是团队把所有评审责任甩给机器人认为只要 Hermes 没有意见代码就可以合并。这是危险的。任何基于大模型做 review 的工具本质上都是基于概率的辅助判断不是静态语义分析工具更不是人工结对评审的替代品。我会把 Hermes 定位成两个角色一个是“日常小扫帚”把明显该修掉的低级问题提前扫出来另一个是“上下文提醒器”当改动涉及某个目录时提醒一下“你动这里会影响 xxx 模块”。真正重要的设计评审、跨模块架构改动我仍然坚持要人工兜底。Hermes 让我的 PR 评审节奏明显轻快了但它也让我学会了另一件事越是好用的自动化越要有意识地限制它的决策权重。我实际运行了两个多月最值钱的体验不是它自动抓出了多少 bug而是它把“这个 PR 有没有明显问题”的初筛从人身上挪走了。我现在打开一个 PR先看 Hermes 的 high 级别意见再看自己关心模块的改动剩下的格式化、命名、明显边界问题基本可以放心交给它。如果团队里正好缺一个这样的“值守 reviewer”从评论模式开始跑打磨两周规则你会找到一个比较舒服的平衡点。