十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用Hermes智能体打造GitHub PR自动评审:从原理到落地实践

用Hermes智能体打造GitHub PR自动评审:从原理到落地实践 最近我把团队代码评审的流程重做了一遍核心变化是把 Hermes 智能体接进了 GitHub PR 流程。跑了一段时间之后效果比我预想的好不少——不是因为它能替代人而是因为它把评审这件事的“最低水位”抬高了。自动化代码评审这个话题圈里聊了很多年但真正落地到“每个 PR 都有 AI 意见而且大家愿意看、愿意改”其实没那么容易。文章里我把自己搭建 Hermes GitHub PR 自动审查这套流程的完整思路、配置细节、核心代码和踩坑经验都整理了出来。内容适合正在做团队研发效能建设的人、折腾过 GitHub Actions 但没玩过智能体的朋友以及想知道“AI 审代码到底怎么用才算落地”的读者。1. 为什么把代码评审交给自动化流程很多人一听到“AI 评审 PR”第一反应就是这东西靠谱吗能比我同事看得明白我一开始也是这么想的。但实际把人工评审的账算清楚之后你会发现真正的问题不是“AI 行不行”而是“人已经顶不住了”。1.1 人工评审的困境在哪在团队协作里PR Review 本来是质量保障最重要的一环。但实际做起来大家都知道这事儿特别容易被挤压。项目节奏一紧评审就变成“先合进去再说”等出了问题再回头补锅。我统计过自己团队的情况一个不到十人的研发小组每天大概产生 15 到 20 个 PR其中真正需要仔细看的核心改动可能只有三四个但剩下那些小改动、依赖升级、重命名、格式调整又不得不看——因为你不看就不知道里面有没有夹带私货。这种“低信息密度但必须过目”的评审对资深工程师的时间消耗特别大。上下文切换成本才是真正的隐形杀手。你正在写自己的模块切出去看一个 PR看完再切回来重新进入状态至少要十几分钟。一天切个几次有效工作时间就所剩无几了。更麻烦的是不同人的评审标准不一样。有的同事对命名极其敏感但对并发问题毫无感觉有人只看功能逻辑完全不管异常兜底。团队规范写在文档里是一回事执行起来完全是另一回事。这就导致 PR 评审变成一个既耗时间、又难统一还容易得罪人的活。1.2 传统静态检查和智能体的本质区别传统静态检查工具比如 ESLint、RuboCop、SonarQube能做很多事但它们本质上是“规则匹配”。规范里没写到的逻辑问题、跨文件的副作用、命名习惯的演变甚至“这段代码其实可以复用已有的工具函数”这类需要理解业务上下文的意见传统工具完全给不出来。我曾经试过把 SonarQube 的规则调到很严格结果团队里怨声载道因为大量误报把有效信号淹没了。后来把规则放宽又回到“查不出啥问题”的状态。静态检查的死穴就在这里它不理解代码在做什么只检查代码长什么样。Hermes 走的路线不一样。它是所谓的“智能体”做事情的方式更像一个评审者先读 PR 的完整 diff再结合关联的 Issue 描述、仓库的贡献规范、甚至相关文件的当前版本综合判断之后再输出结构化意见。它不只会说“这个地方有个文件没关闭”也能说“这个函数命名容易让人误解建议改成 XXX理由是基于现有模块里同类操作的命名习惯”。这块的价值不在于替代资深工程师而在于把人从 80% 机械性、重复性的评审动作里解放出来。人只需要看 AI 标记出来的“高风险区域”和最终的结论然后把精力放在真正需要判断力的地方。2. Hermes 自动评审的核心机制要把 Hermes 接到 GitHub PR 上你首先得理解它评审时内部是怎么工作的。我拆成三个关键环节来讲这决定了后面你配置规则和调优质量的方向。2.1 Patch 解析与上下文重建PR 评审的第一步是把 diff 变成智能体能理解的语言。diff 本身是行级别的文本差异但光有差异没有上下文别说智能体人也没法评。Hermes 的做法通常是先通过 GitHub API 获取 PR 的 files changed 列表然后把每个文件的 diff 连同文件路径、变更行号、被修改函数所在的作用域等信息一起打包。这里有个细节很关键——它不只是把 diff 喂给模型而是会主动拉取变更涉及的相关文件片段构建一个“上下文包”。举个例子一个 PR 改了user_service.py里的某个方法同时改了user_repository.py里的查询逻辑。如果只看 diffAI 只能看到两个文件各自改了啥但 Hermes 会尝试理解这两个改动之间的调用关系然后判断“查询条件变了但调用方的处理逻辑没跟上”这种跨文件问题。实践中我发现上下文窗口不是越大越好。把整个仓库都塞进去模型反而抓不住重点而且响应时间会变得不可接受。合理的做法是只提取变更文件的相邻内容、相关函数定义、以及 import 关系链路上的必要信息。上下文控制在合理范围内评审质量是最高的。2.2 确定性规则与语义评审的双层设计真正好用的自动评审系统不能只靠 AI。我的经验是把它设计成两层第一层是确定性规则由传统的静态检查工具承担直接在 CI 阶段跑。比如 Python 项目用 Ruff mypy前端项目用 ESLint TypeScript 检查。这一层负责的是“铁律”类问题语法错误、明显未使用的变量、类型不匹配、安全漏洞的已知模式等。确定性规则的优势是快、准、无幻觉缺点是不会变通。第二层才是 Hermes 的语义评审。它处理的是需要理解意图的问题这个 PR 的修改跟描述的目标是否一致、是否有遗漏的边界条件、是否有更简洁的实现方式、是否引入了潜在的性能隐患、命名和现有代码风格是否协调。两层配合之后你会得到一个很好的效果分工确定性规则管底线AI 管“人味”的部分。如果只依赖 AI你会发现它偶尔会一本正经地胡说八道如果只依赖规则你又永远得不到业务层面的意见。双层设计互相兜底是目前最稳妥的架构。2.3 评审意见如何做到“可执行”AI 评审最大的坑是给出一堆正确的废话。比如“请确保代码质量”“建议提升代码可读性”——这种意见谁看了都不会改。所以我在接 Hermes 的时候对输出格式做了强制要求每条评审意见必须包含四个要素——问题所在的文件与行号、问题类型、具体原因说明、以及修改建议。甚至可以要求 AI 直接给出建议的代码片段。GitHub 的 review comment API 天然支持行级评论这正好匹配这种格式。我要求 Hermes 给每个问题按严重程度分级Block必须修否则影响合并、Important强烈建议修、Suggestion可选优化。这样开发者在看评论时可以先处理 Block 级别的其余快速浏览效率高很多。3. 从零搭建一套 Hermes 自动评审流程下面进入实操。我以团队内部常见的架构为例GitHub 仓库 GitHub Actions 作为触发和调度层 Hermes 智能体作为评审执行层 GitHub API 作为结果回写通道。3.1 前置准备与安装部署首先要把 Hermes 跑起来。假设你用的是 Python 环境项目本身依赖较少安装步骤大致如下# 使用你实际获取到的分发渠道拉取 Hermes 项目 git clone https://github.com/your-org/hermes.git cd hermes python -m venv .venv source .venv/bin/activate pip install -e .安装完成后检查一下版本是否正常hermes --version同时需要准备一个 GitHub Token。这里我建议不要用个人访问令牌挂在本地而是创建一个专属的 GitHub App 或者用仓库的 Actions secret 来管理。个人 Token 容易过期而且权限范围不好控制。实践中我用的是 GitHub Actions 的内置 GITHUB_TOKEN它在 workflow 运行期间自动注入仓库配置好权限即可省去很多 token 管理的麻烦。模型侧的配置也需要提前确认好。Hermes 的底层模型可以通过配置文件指定我这边用的是团队已有的模型服务只要求它支持较长的上下文输入至少 32K token因为在处理大型 PR 的时候上下文不够会比较痛苦。配置项大致如下# config.yaml model: provider: your-provider name: your-model temperature: 0.2 max_tokens: 4096temperature 我固定在 0.2 左右。代码评审跟创意写作不一样需要的是稳定和准确温度太高会带来不必要的随机性。3.2 用 GitHub Actions 完成触发编排在哪个环节触发评审直接决定了整个流程的体验。我的选择是当 PR 被打开、或者有新 commit 推送到 PR 分支、或者 PR 标题/描述发生变更时触发。这三个事件覆盖了绝大多数需要重新评审的场景。对应的 workflow 文件写起来并不复杂name: hermes-pr-review on: pull_request: types: [opened, synchronize, edited] permissions: contents: read pull-requests: write checks: write jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - name: Run Hermes review env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} REPO_NAME: ${{ github.repository }} run: | hermes review \ --repo $REPO_NAME \ --pr $PR_NUMBER \ --token $GITHUB_TOKEN注意permissions这一项。很多人的 workflow 跑不通问题就出在默认权限不足特别是写 comment 这一步。pull-requests: write必须显式声明否则 Hermes 把评审结果写回 PR 时会直接 403。3.3 评审规则与提示词模板的设计Hermes 的评审不是裸奔式的“随便看看”而是有一套可配置的规则体系。你可以单独准备一个.hermes/rules.md文件放在仓库根目录Hermes 每次评审前会自动读取它作为评审依据。我自己的规则文件大概长这样# 评审规则 1. 安全优先新增的外部输入必须做验证禁止拼接执行危险命令。 2. 一致性命名风格必须与当前代码库保持一致不要混用多种风格。 3. 异常处理新增的 IO 操作、网络调用必须有超时和异常兜底。 4. 性能注意循环内禁止提交数据库查询或远程调用。 5. 可读性单个函数不要超过 80 行超过则建议拆分。 6. 破坏性变更涉及对外接口的变更必须在 PR 描述中说明兼容性处理。提示词模板的作用更大。我踩过的坑是如果提示词里只写“请审查这个 PR”Hermes 会输出一堆泛泛而谈的话。后来我把提示词改成了明确的任务框架效果立刻不一样。核心结构如下你是一个资深代码审查者。请审查 PR #{pr_number} 的变更内容。 评审要求 - 先阅读 PR 描述理解变更意图。 - 对比变更前后逻辑识别行为差异。 - 只输出真实存在的问题不要夸奖代码不要泛泛而谈。 - 每条意见包含文件路径、行号、严重级别、原因和建议。 - 如果无法确认问题不要臆测标注“不确定”并说明需要人工复核。这个“无法确认就说不确定”的约束特别重要。它能有效减少 AI 的幻觉式评论——那些言之凿凿实则误导的意见比没有意见更伤人。4. 实操核心环节的技术实现有了 workflow 和配置之后真正干活的逻辑在 Hermes 内部。下面我拆开几个核心环节讲清楚每一步是怎么实现的、参数怎么选的。4.1 获取 PR 信息与 diff 数据Hermes 拿到 repo 名和 PR 号之后第一步是通过 GitHub API 拉数据。核心调用逻辑如下from github import Github def fetch_pr_context(github_token: str, repo_name: str, pr_number: int): gh Github(github_token) repo gh.get_repo(repo_name) pr repo.get_pull(pr_number) files pr.get_files() diff_data [] for f in files: diff_data.append({ filename: f.filename, status: f.status, additions: f.additions, deletions: f.deletions, patch: f.patch, }) return { title: pr.title, body: pr.body, diff: diff_data, }注意这里我只取每个文件的patch字段没有取整个文件内容。原因前面说过控制上下文。但如果某个文件改动特别大patch 可能被截断GitHub API 会返回截断标记。处理方式是当检测到 patch 以截断标记结尾时再单独调用 contents API 拉取该文件的实际内容并提取变更行周边的代码片段。if f.patch and f.patch.endswith(...): content repo.get_contents(f.filename, refpr.head.sha).decoded_content # 结合 patch 中的行号信息提取变更行附近的上下文这段逻辑是评审质量的分水岭。很多 PR 评得不准就是因为模型只看到了被截断的 diff完全不知道函数全貌。4.2 构建评审请求并执行有了上下文之后Hermes 会把 diff、PR 描述、仓库规则、提示词模板组合成一次推理请求。我这边做了一个小优化对大 diff 做分块评审。一个超过 800 行的 PR我会按文件维度拆成多个子任务分别评审最后再汇总。这样能避免模型在长上下文里“顾头不顾尾”也能并行处理显著缩短等待时间。分块之后的执行逻辑类似def run_review(pr_context: dict, rules: str) - list[dict]: chunks split_by_file(pr_context[diff], max_chunk_size800) results [] for chunk in chunks: prompt build_prompt( pr_titlepr_context[title], pr_bodypr_context[body], diffchunk, rulesrules, ) raw llm_chat(prompt, temperature0.2) results.extend(parse_structured_comments(raw)) return resultsparse_structured_comments这步我会要求模型返回 JSON 格式而不是自由文本。通过输出约束把评审意见变成结构化数据后续无论是写入 GitHub 还是做统计都方便得多。4.3 评审结果回写与增量去重拿到结构化意见之后下一步是回写到 PR 上。GitHub 支持两种方式一种是整体评论另一种是行级评论。行级评论的体验最好因为开发者可以直接在对应代码行看到问题。实现行级评论时有一个前置条件评论必须有position或line参数而且这个 position 是相对于 PR 的 diff 的。一个常见的坑是AI 返回的行号是文件里的绝对行号直接传给 API 会报错。我在这上面翻过车后来处理方式是根据每个文件的 patch 内容先建一个“diff 行号 ↔ 文件行号”的映射表再提交评论时换算回来。def post_inline_comments(gh, repo_name, pr_number, comments, diff_line_mapping): pr gh.get_repo(repo_name).get_pull(pr_number) for comment in comments: try: position diff_line_mapping.get(comment[filename], {}).get(comment[line]) if position is None: continue pr.create_review_comment( bodycomment[body], commit_idpr.head.sha, pathcomment[filename], lineposition, ) except Exception as e: logger.warning(fpost comment failed: {e})增量去重是另一个必须处理的细节。PR 每次有新的 commit 推送workflow 都会重新跑一遍评审。如果不做去重同一个问题会被重复评论三四次开发者的 GitHub 通知会变成灾难。我的方案是每次跑评审之前先拉取该 PR 现有的 review comments提取其中的“指纹”问题文件 行号 问题类型再从新结果里过滤掉已存在的指纹。同时对于已经被开发者标记为“已解决”的评论也做到不重复提出同类问题。existing pr.get_review_comments() existing_keys { (c.path, c.line, c.body.split(|)[0]) for c in existing } new_comments [ c for c in new_results if (c[filename], c[line], c[type]) not in existing_keys ]这套逻辑跑稳之后用户体验发生了质的飞跃每个 commit 推送后只会看到针对新增改动的评审而不是几十条重复刷屏。5. 常见问题排查与调优建议自动评审系统上线初期一定会遇到各种幺蛾子。下面这些问题是我们在实际使用中最常碰到的每条都是我踩过坑之后总结出来的处理办法。5.1 高频问题速查表现象可能原因解决办法workflow 运行失败报 403GitHub Token 权限不足检查permissions.pull-requests是否设为 writeHermes 没有输出任何评论diff 被截断或没有映射到行号检查大文件 content 拉取逻辑确认 diff 映射表是否正常评论重复刷屏缺少增量去重参照上文指纹去重方案评论位置不对position 使用了文件绝对行号先做 diff 行号与文件行号的换算AI 意见太水、太泛提示词约束不足强制输出 JSON 结构化格式增加“不要夸奖”等负向约束评审耗时过长PR 过大或模型上下文处理慢按文件分块并行评审设置单块行数上限误报率高规则文件与仓库实际情况不符定期根据开发者的 feedback 更新规则5.2 评审质量怎么一步步调好上线第一阶段别急着追求“AI 能发现所有问题”。我的做法是先跑两周“观察模式”Hermes 照常评审但只把结果发给固定的几位核心开发者不直接对全员开放。核心开发者把每条评论标注为“有效”“无效”“误报”每周汇总一次数据用这些标注去迭代规则和提示词。两周之后你会发现误报集中在某几类要么是仓库里有大量历史遗留代码本来就不符合规则AI 只是照实指出要么是某些业务场景需要特殊豁免但规则文件里没写明。把这两类情况补充进规则文件误报率能很快降到可接受的范围。另一个重要调优点是“置信度”。我给 Hermes 加了一条后处理逻辑问题越严重的判断越要求它给出充分的代码级证据。如果一个评论没有具体行号和修改建议我会把它降级为 Suggestion而不是 Block。这个兜底策略有效减少了 AI “语出惊人”带来的干扰。5.3 几条实战心得跑了大半年 Hermes 自动评审我最大的体会是这个东西的定位不是“裁判”而是“第一道防线”。以前我们的流程是代码写得差不多交给同事看同事忙不过来就拖到上线前通宵补看。现在有了 HermesPR 一提交五分钟内就有初步评审结果。很多低级问题——漏了异常处理、参数校验不严、明显不一致的命名——在开发者自己还没切走注意力的时候就被标记出来了修复成本极低。我还强烈建议把 Hermes 的评审历史做一个简单的数据面板。每周统计一下AI 评出了多少问题多少被开发者接受并修改哪些模块的 AI 误报率最高。这些数据比任何代码规范文档都真实能直接反映团队代码的薄弱环节在哪。比如我统计后发现我们团队在 API 参数校验这块的问题占比最高后来单独做了个专项培训效果立竿见影。最后分享一个我在调优过程中发现的小技巧把 Hermes 的评审结论和开发者的实际修改做对比。当开发者没有采纳某条 AI 意见并合并了 PR 时把这条意见保留到一个“未采纳”列表里。每隔一段时间回看这些未采纳的意见你会发现两类价值——一类是规则确实不合理需要调整另一类是开发者漏看了这说明 AI 的意见没有被认真对待需要考虑把严重级别提得更高或者在合并前加一道强制确认流程。这个“人机互证”的闭环才是自动化评审持续产生价值的真正动力。
返回列表