基于Hermes的GitHub PR自动审查系统搭建实践

基于Hermes的GitHub PR自动审查系统搭建实践 1. 项目概述与设计思路1.1 为什么我要做一套基于 Hermes 的 PR 自动审查先说个背景。做技术 Leader 或者核心维护者之后每天最花时间的事往往不是写代码而是埋在 GitHub 的 Pull Request 列表里。小团队还好但凡项目上了规模PR 一多每个都要人肉过一遍逻辑、风格、潜在 bug时间根本不够用。我见过不少团队的做法是让 CI 跑一遍测试、Lint 一下剩下的全靠 reviewer 肉眼扫。测试和 Lint 能拦住语法和低级错误但拦不住“这段逻辑明显写错了但是编译能过”这种问题更拦不住“这个写法风格跟项目整体不一致”的隐性债务。所以当我接触到 Hermes 这个能本地部署、自带 Agent 能力的智能体框架时第一个想法就是能不能让它去读 PR 的 diff像一个人工 reviewer 一样输出结构化的评审意见这个想法拆解下来不复杂用 GitHub API 拉取 PR 的变更内容把 diff 送给大模型分析再让智能体根据预设的评审规则输出结论。但实际操作起来细节远比想象中多。这篇文章就把我从零搭起这套 Hermes GitHub PR 自动评审的完整思路、踩坑过程、以及最终落地可用的配置写出来给想搞同类自动化工具的同学一个可直接参考的样本。简单说清楚这套系统是什么它是运行在你自己的服务器或本机上的一套自动化服务当 GitHub 仓库里有新的 PR 被打开或更新时Hermes 会自动读取这个 PR 的修改内容结合项目设定的评审标准比如代码风格规范、常见错误模式、安全红线等生成一份带具体行号和修改建议的评论直接发回 PR 对话流里。它适合谁用适合手里有几个活跃仓库的开发者、维护者也适合需要在代码合入前做多道质量把关的团队。它能解决的核心问题就一句话把 review 的第一道过滤工作交给 AI让人去处理真正需要人判断的部分。1.2 技术方案选型为什么用 Hermes 而不是直接调 API刚开始很多人会问我直接写个脚本拿 GitHub API 把 diff 拉下来然后往大模型 API 里一丢让它返回评论不也能达到类似效果吗确实能但有一个巨大区别那是“一个脚本”而 Hermes 给的是“一个完整的 Agent 运行环境”。直接调 API 的脚本方式所有逻辑都得自己写死在代码里。比如“如果 PR 改动超过 500 行就不评审了”“如果是依赖升级 PR 就给个简单提示就行”“如果评审者评论过就不重复评论”这类规则每加一条都要改代码、重新部署。而 Hermes 这类 Agent 框架的价值在于它允许你用自然语言定义工作流然后让框架去规划执行步骤、调用工具、管理上下文。这在应对需求经常变的场景里优势非常明显——改一套规则只需改提示词不用改代码。而且 Hermes 本身已经内置了不少实用组件比如分支式任务规划、子 Agent 调用、工具注册等能力。我这次的实际做法是用 Hermes Agent 作为大脑注册了两个自定义工具——一个拉取 PR 信息和 diff一个向 PR 提交评论。然后写了一条工作流规则接收 GitHub Webhook 事件解析出 PR 编号拉取 diff让大模型按评审框架逐项分析最后把结果作为评论提交回 PR。这套结构的好处是以后想扩展能力比如自动打标签、自动指派 reviewer、把评审结果同步到钉钉/飞书只需新增工具和修改提示词主流程完全不用动。对于长期维护的需求这比写死脚本可维护性高得多。2. 核心细节解析与实操要点2.1 评审关注维度要让 AI 看什么做自动评审之前第一件事不是写代码而是想清楚你要让 AI 在一份 diff 里重点看什么。如果没有明确维度大模型很容易给出“这段代码很好”之类的废话或者东一句西一句完全没有重点。我根据自己的经验把评审维度定成了五类写在了系统提示词里强制 Hermes 按这个框架输出维度关注点输出要求逻辑正确性边界条件、空指针、循环退出、异常分支必须指向具体行说明触发场景代码风格一致性命名、缩进、是否跟项目现有写法一致给出建议改法性能隐患多层循环、重复查询、大数据量下的性能风险说明影响范围安全红线注入风险、敏感信息硬编码、越权问题最高优先级必须明说可维护性函数过长、重复代码、缺少注释、可读性问题给出重构方向这五个维度写清楚之后Hermes 生成的评审意见就很接近于一个中级工程师的 review 水平了。有一点要注意不要让它一次输出所有维度的问题。diff 一大一次性全部分析上下文窗口很容易撑爆而且输出质量会明显下降。实际做法是让 Hermes 先根据 diff 的整体规模和修改文件数做一个判断——如果改动文件少于 5 个且改动行数小于 300才走完整五维评审如果改动较大就只挑关键文件做深度分析或者只做安全红线检查。这个“分级评审”的思路很关键它避免了一个常见问题机器人对一个 2000 行的 PR 输出一篇 5000 字的论文式 review人根本看不完。评审意见也需要聚焦才有价值。2.2 Hermes 在这个流程里的角色编排我实际用的架构是Hermes 作为运行在 Docker 里的独立服务监听 GitHub Webhook每收到一个 PR 事件就触发一条 Agent 任务Agent 按预先写好的 Workflow 规则依次执行“提取 PR 元数据 - 拉取完整 diff - 分块分析 - 汇总意见 - 提交评论”。这个流程里 Hermes 最核心的两个能力是“任务规划”和“工具调用”。比如说当它拿到的 diff 超过了自己上下文窗口能处理的范围时它不会傻傻地尝试把全部 diff 一次性塞进来而是会自己规划先读文件列表挑出优先级最高的文件然后逐个文件分析。这个行为可以靠提示词引导需要用多步推理时分步处理每步只关注当前文件。另外有一个很实用的细节我把“是否已经评审过这个 PR 的当前 commit”作为状态存在本地 SQLite 里。这样每次 PR 更新 commit 后才触发新的评审避免在对话流里刷屏。Hermes 的持久化能力让我可以直接把状态存在它的数据目录里不用额外引入复杂的存储组件。工具层面我注册了两个自定义工具# 简化示意工具1拉取 PR diff def get_pr_diff(repo: str, pr_number: int) - dict: 调用 GitHub API 获取 PR 元信息和 .diff 内容 # repo: owner/name # 返回 { title, descriptions, changed_files, additions, deletions, diff } pass # 简化示意工具2提交 PR 评论 def post_pr_comment(repo: str, pr_number: int, body: str) - bool: 把评审结果提交为 PR 评论 pass这里要特别提醒GitHub API 获取 diff 有两个方式一个是用 REST API 的GET /repos/{owner}/{repo}/pulls/{pull_number}拿到基础信息后再去逐个取文件的 patch 内容另一个是直接在请求头加Accept: application/vnd.github.v3.diff一步拿到整个 PR 的合并 diff。后者简单直接适合分析但要注意拿到的 diff 是纯文本没有提交人、文件归属等结构化信息。我的做法是两者同时用——用 v3.diff 头拉全文给 AI 分析用标准 REST 响应拿结构化元数据做记录。2.3 提示词设计一套能直接用的评审框架聊到自动评审提示词是灵魂。我踩过不少坑总结下来最有效的系统提示词结构是三层角色设定、评审规则、输出格式。角色设定要让 Hermes 明白自己的身份。我给它的设定是“你是项目团队的资深代码评审专家负责在新代码合入前发现逻辑缺陷、安全隐患和可维护性问题。你的意见直接影响到代码质量要专业、客观、有依据。”评审规则就是上面说的五个维度但要用更详细的自然语言展开。比如“逻辑正确性”这一段我会写要特别关注边界条件、空值处理、并发场景、异常路径发现了问题必须说明触发条件不能只给结论。输出格式我用的是结构化 Markdown 模板## 评审结果概览 - 结论需要修改 / 可以合入 / 存在阻塞问题 - 重点问题数X 个次要问题数Y 个 ## 阻塞问题必须修改 - [ ] 文件路径:行号 **问题描述** [触发条件/场景分析]修改建议 ## 建议优化 - [ ] 文件路径:行号 **问题描述**修改建议为什么强调格式因为大模型自由发挥时什么都写得出来但有格式约束后输出质量非常稳定。尤其“结论”那一行我用它做后续自动化的判断依据——比如“存在阻塞问题”的时候就自动添加request-changes标签这样人在处理 PR 列表时一眼就能看出优先级。还有一个非常实用的技巧给 Hermes 喂“好例子”。我在提示词末尾附了一段示例——给定一份小 diff比如一个简单的 Java 方法展示什么叫“好的评审意见”。一段意见里既有定位文件和行号又有逻辑推理为什么这里有 bug还有可执行的建议改成什么样。模型会模仿这个范式的输出效果比抽象描述好得多。3. 实操过程与核心环节实现3.1 环境搭建Hermes 部署与初始化我先说环境。Hermes 可以装在本机也可以装服务器我的推荐是装在一台小内存 VPS 或者家里/公司的常驻机器上因为它要持续监听 Webhook所以不能像笔记本一样随时关机。配置上CPU 两颗就够内存建议至少 4GB因为除了 Hermes 本身后面还要跑一些缓存服务。存储 20GB 足够。安装 Hermes 我用的是 Docker 方式最省心依赖不会污染本机。Docker Compose 配置文件大致如下services: hermes: image: hermes-agent/hermes:latest container_name: hermes restart: always ports: - 8080:8080 volumes: - ./hermes-data:/app/data environment: - LLM_PROVIDERopenai_compatible - LLM_BASE_URLhttps://api.deepseek.com/v1 - LLM_API_KEY${DEEPSEEK_API_KEY} - LLM_MODELdeepseek-chat - GITHUB_TOKEN${GITHUB_TOKEN}这里我用的是兼容 OpenAI 协议的接口模型选择上我建议用 DeepSeek 这类性价比高的模型。为什么因为代码评审要对整个 diff 做大段上下文推理大模型的每 token 成本会被放大如果全部用最贵的旗舰模型一个活跃仓库一个月跑下来的 API 费用会很可观。DeepSeek 这类模型的代码理解能力够用成本低一个数量级实测在评审场景下质量差距不明显。注意环境变量里的GITHUB_TOKEN必须是一个有repo权限的 Personal Access Token这样 Hermes 才有权限读取私有仓库的 PR 内容并提交评论。如果是公开仓库换成public_repo权限就够。启动后第一次进入 Hermes 需要做基础配置确认模型连接是否正常、注册自定义工具、加载工作流规则。这个过程在 Hermes 的管理界面里操作整体像在填表格不涉及写代码基本半小时能搞定。3.2 构建 PR 评审工作流接下来是核心配置一个可运行的评审工作流。Hermes 支持用自然语言定义工作流我实际写的规则浓缩后是这么一段当收到 GitHubpull_request事件时执行。第一步提取事件中的仓库名和 PR 编号。第二步调用get_pr_diff工具获取 PR 基础信息和完整 diff。第三步如果 PR 标题或变更文件中包含requirements、*.lock、*.min.*只做安全红线检查其他维度跳过。第四步如果 diff 超过 800 行按文件拆分成多个子任务逐个分析每个子任务只关注当前文件的变更。第五步汇总所有分析结果按输出模板整理成一份 Markdown 评审意见。第六步调用post_pr_comment工具把评审结果发回 PR。第七步记录本次评审的 commit SHA防止重复触发。这七步流程里第四步是最容易被忽略但又最关键的。大模型的上下文窗口虽然越做越大但把几千行的 diff 一次性丢进去它容易“看后面的忘前面的”而且输出质量显著下降。拆分成多个子任务后每个子任务专注一个文件的 diff上下文长度可控分析质量明显提升。代价是会多消耗一些 token换来的是更精准的评审这个交易很划算。子任务的设计思路是这样的主 Agent 做任务分解负责调度和汇总子 Agent 专门负责某一两个文件的分析最后主 Agent 拿着所有子 Agent 的分析结果统一去重、分级、套模板。Hermes 天然支持这种多轮调度不需要额外开发。3.3 配置 GitHub Webhook 接入工作流在 Hermes 里配置完成之后剩下就是让它能收到 GitHub 事件。这一步逻辑不复杂但配置上有几个容易踩的坑。首先要在 GitHub 仓库的 Settings - Webhooks 里新增一个 webhookPayload URL 填 Hermes 服务的地址加上/webhook/github这个路径Content type 选application/json事件类型选Let me select individual events然后勾上Pull requests和Pull request reviews。Secret 可以填一个随机字符串Hermes 端配置相同的 Secret 做签名校验防止别人伪造请求。我第一次配的时候踩过一个坑内网环境的 Hermes 服务地址是局域网 IPGitHub 的 webhook 是公网主动访问根本到不了内网。如果遇到同样的场景需要借助内网穿透工具把 Hermes 的 8080 端口暴露到公网上。这属于网络基础设施问题每个团队的网络环境不同处理方式也不同这里不展开只提醒有这个坑。Webhook 配好之后可以先去 GitHub 上任意提一个测试 PR看 Hermes 日志里有没有收到事件、工作流有没有被正确触发。第一次跑通通常是最难的因为中间任何一环出错都不会有直观提示只能看日志慢慢排查。日志里看到event received说明 webhook 没问题看到workflow triggered说明规则匹配成功看到tool call: get_pr_diff说明 Agent 已经开始工作了。3.4 评审效果的实际表现我用这个系统试跑了大概两周覆盖三个不同技术栈的仓库一个 Java 后端、一个 Python 数据管道、一个 TypeScript 前端整体效果可以分几点说。首先是“能发现的真问题”阻塞类问题主要集中在这几类——空指针/None 检查缺失、循环内重复调用外部接口、资源没有正确关闭、鉴权逻辑只在白名单里更新了文档没更新代码。这些都属于“测试过了但人不会仔细看”的典型问题AI 反而能稳定发现因为它的注意力不会被几十处同类修改分散。其次是“误报问题也真实存在”最突出的两类误报是命名建议过度干预比如非要把userInfo改成userProfile纯属没事找事和设计风格冲突比如把 Command 模式的调用改写成策略模式AI 把两种不同的设计倾向混淆了。这个问题在提示词里加了一句“非明显问题不要提出优先关注 bug 类问题风格建议只提影响阅读的部分”之后误报率降了一大截。最后是“速度与成本”一次中等规模的 PR20 个文件600 行 diff全流程跑完大概需要两到三分钟主要是大模型推理耗时。成本方面用 DeepSeek 的话这样一个 PR 的分析成本大致在两三毛钱人民币非常低。如果换更贵的模型效果会有提升但成本可能变成二十到三十块这个性价比差异值得每个团队根据自己预算权衡。4. 常见问题与排查技巧实录4.1 上下文窗口爆掉的场景与处理这是跑评审工具第一个会遇到的问题。PR 的 diff 文件少则几十行多则几千行一旦超过模型的上下文限制调用就会直接报错。我的处理思路分成两层。第一层是控制输入不把整个 diff 作为纯文本一股脑塞进去而是先让 Hermes 读文件列表结合文件树做一次“重要性排序”优先处理核心业务代码跳过自动生成的代码、第三方库引入、配置文件。第二层是拆分上下文超过 800 行的 diff 直接走子 Agent 逐文件分析每个子 Agent 只拿到单个文件 diff最后主 Agent 拿着汇总结果再做一轮去重和优先级判定。如果是特别极端的超大 PR比如一次重构改了上百个文件我还会在流程里加一个上限只评审按改动行数排序的前 15 个文件其他文件跳过并且在评审结论里注明“本次仅重点审查了 X 个核心文件其他变更请人工关注”。与其硬啃一个又长又水的全量评审不如聚焦核心文件的深度分析。4.2 评论质量不稳定、时好时坏的应对我在试运行初期遇到过一种很不爽的情况同一个类型的问题这个 PR 里能发现那个 PR 里就漏了。后来排查下来问题出在提示词里的“优先级描述”不够清晰大模型在“系统性缺陷”和“个别小问题”之间的取舍标准飘忽不定。解决办法是给评审规则里的每个维度加上“必须/禁止”的强化约束。比如安全类的规则我明确写“如果发现任何疑似安全风险必须输出即使不确定也输出并标注存疑”而风格类规则我写“非明显影响可读性时禁止输出”。同时把维度优先级做成显式数字排序安全 逻辑 性能 可维护性 风格。这样做之后输出的稳定性提升了非常明显。还有一个我摸索出来的技巧在输出格式里要求 AI“先给结论再给论据”。也就是在它真正逐文件分析之前先用一两句话概括整体判断比如“本次变更的核心是重构了用户认证模块逻辑复杂度中等主要风险集中在新加的 token 刷新机制”再系统地列出具体问题。强制先写结论会让模型在后续分析时更聚焦不容易跑偏。4.3 关于模型 API 的网络与服务稳定性实际部署中还有一个容易忽略的运维问题大模型 API 调用并不总是稳定的偶尔会出现超时、限流或者服务端 5xx。一旦发生整个评审流程就会卡住而 GitHub 那边的 PR 可能已经更新了好几个 commit事件顺序错乱后再次触发就变得很混乱。我的方案是给 Hermes 的调用层加上重试机制超时 30 秒就重试连续失败 3 次后转入失败队列由定时任务在十分钟后重新投入。同时在工作流规则里要求拿到一个事件后先去查本地 SQLite 状态表如果发现当前 PR 的当前 commit SHA 已经被处理过直接丢弃避免重复评论。还有一个实际遇到过的问题模型对某个文件 diff 的响应里编造了不存在的行号。比如实际文件只有 80 行它评论里写了第 95 行。这种错误虽然不常发生但在自动化流程里一旦出现就很不专业。我在后处理环节加了校验逻辑用正则从评论里提取所有声称的行号跟实际 diff 的行号集合比对超出范围的行号直接删除该条评论。处理之后评论的可用性明显提高人看起来也更可信。4.4 权限与安全控制最后聊一个安全细节。给 Hermes 配置的 GitHub Token 权限要根据使用场景尽量收敛。如果只做评审完全不需要repo权限只要public_repo加pull_requests: write就够了。不要图省事直接给一个完整 repo 权限的 token万一 Hermes 服务被攻破或者配置泄露攻击者拿到的是你整个仓库的写权限代价太大。Token 的管理建议走环境变量注入而不是直接写死在容器的编译文件里。如果是单机部署可以放在独立的.env文件里并把该文件加入.gitignore。另外在 Hermes 的日志里注意观察有没有打印出 token 的明文——我见过一些第三方组件会把请求头里的 Authorization 打印出来这是非常大的隐患。Webhook 的 Secret 校验也要启用。GitHub 发送请求时会带一个签名Hermes 端可以验证这个签名的确来自 GitHub能有效过滤掉恶意伪造的 webhook 请求。虽然这不能完全杜绝攻击但配合最小权限 Token整套系统暴露的攻击面已经大幅缩小。5. 我的实操经验与后续扩展建议这套系统从想到做到稳定跑了两个星期最让我惊喜的是它带来的“流程重构”效应。以前 PR 上来第一件事是人肉扫一遍 diff扫完才能判断要不要深入看。现在机器人先扫人在评论区看到的是已经分好等级、标好定位的评审意见心理负担小很多。尤其是那种几百行看着很大的 PR有了一份结构化的自动评审意见打底人reviewer 可以更快进入状态效率提升非常明显。但我也想给准备“抄作业”的人说句实话自动化评审不会取代人工 review它能做的是把人从“找茬”中解放出来让人去做更有价值的设计和协调判断。它提供的意见里能直接照做的可能占七成剩下三成需要人综合上下文去判断——比如一个看似糟糕的写法其实是为了兼容某个历史数据格式的故意妥协。所以这套系统最理想的使用方式是把它当作“第一轮 reviewer”而不是“最终裁决者”。最后分享一个后续可以扩展的方向把评审数据存下来做趋势分析。我现在已经在本地记录了每次评审发现的问题数量、类型分布、所属模块运行一段时间之后回看会非常直观地发现哪个模块的代码质量最差、哪类问题出现频率最高。这种数据驱动的代码质量管理一旦跑起来就再也回不去了。有同样需求的同学建议从一开始就把“评审历史持久化”放进设计里别等数据攒了一批才想起没有分析字段。