用 AI Agent 在 GitHub PR 上实现自动化 Code Review
2026/9/17 7:49:44 网站建设 项目流程

很多人一听到“自动化代码评审”,第一反应就是CI里的静态检查或者SonarQube那套扫描规则。但今天我要聊的Hermes,不太一样。它定位是在GitHub PR上直接执行的自动化Code Review Agent,核心能力不是挑出你没加分号,而是像一位有经验的同事那样,去理解你这次改动解决什么问题、在哪里可能翻车、哪里还有边界情况没考虑,然后把结论和疑问直接写到PR评论里。

这个项目解决的是研发流程里最耗时、最容易被敷衍的环节——人工Review。尤其是当你维护的项目有一定规模,或者团队分布在多个时区,等一个人来Review可能比写代码还久。Hermes这种Agent可以7x24小时响应,第一时间对PR给出初评意见,帮维护者过滤掉明显有问题的提交,也帮作者在提交前发现自己没注意到的漏洞。适合谁参考?想给开源项目做自动把关的维护者,或者企业内部想建设代码评审辅助体系的团队,又或者你跟我一样,纯粹是好奇大模型能不能真的当个“AI同事”,这篇都能给你一个可落地的参考。

1. 内容整体设计与思路拆解

1.1 为什么选择“Agent”而不是一堆脚本

早期我也尝试过用GitHub Action挂些Lint工具,再配合几个简单的正则规则去扫代码。效果不能说没有,但总感觉不够“聪明”。比如一个PR删了一行关键的错误处理,静态检查完全看不出问题;再比如调用某个废弃API,编译时根本不会报错,但运行时就是会出幺蛾子。这些问题的共同点是:需要上下文理解,而不是文本匹配。这正是Agent类应用比传统脚本更有价值的地方。

Hermes的设计核心,是把大模型的能力当作“评审员”,而把GitHub的API和事件流当作“通信管道”。它不是简单的“触发-执行-返回结果”,而是一个带有感知和决策的循环:

  • 感知:接收GitHub Webhook推送的PR事件,拉取PR的元信息(标题、描述、改动文件列表、Diff内容、评论等)。
  • 决策:根据配置的规则和历史对话,决定这次评审要看什么、从哪里入手。
  • 执行:调用代码分析的逻辑(比如解析Diff、跑静态分析、提取关键函数),生成评审意见。
  • 反馈:把结构化的评审结果以评论形式发回PR,必要时还能更新状态标签(比如request-changes)。

有了这层循环,Hermes才能真正做到“因为它知道你在改什么,才知道该提醒什么”。比如你改了一个公共函数,它知道要去搜调用方是否受影响;你加了一个新依赖,它会去检查License和已知的安全漏洞。这种能力,脚本很难覆盖。

1.2 整体架构形态与关键模块

Hermes本身是用Python写的,底层调用大模型API来做语义理解。整体架构上,我更愿意把它理解成三层:

接入层:负责跟GitHub交互。包括处理Webhook签名验证、调用REST API和GraphQL API拉取数据、管理Rating Limit。这层做不好,后面全白搭——比如不处理重试和限流,PR一多,API直接给你的应用“断粮”。

理解层:这是核心,也是跟普通CI最不一样的地方。它要把PR的Diff转化成大模型能高效理解的摘要,把整个仓库的结构(比如哪些文件改了会影响哪些模块)也一并送过去。怎么组织Prompt(提示词)在这一层非常关键。不是把Diff全文塞给模型就完事了,那样既有Token浪费,模型也容易迷失在细节里。要把Diff按文件、按Hunk切碎,再附上变更说明、关联Issue上下文,让模型去“精读”。

执行层:负责把模型的分析结果转化成具体的GitHub操作,比如创建评论、提交Review、添加Label。这一层要考虑权限控制,哪些操作是自动执行的,哪些需要等待人工确认。

从实际部署来看,我的建议是直接以Docker容器方式跑在服务器上,或者挂在Kubernetes集群里,通过GitHub App的方式跟仓库关联。直接用个人Token做测试可以,但不适合长期用,原因我后文会细说。

1.3 方案选型的取舍

在“自动化代码评审”这个需求上,业界其实有几种做法:用现成的CodeRabbit、Sourcery这类SaaS服务,自己写GitHub Action,或者用Hermes这类自托管Agent。我的选型逻辑是:

  • SaaS服务简单,但代码会经过第三方服务器,对于很多公司,尤其是做硬件、做金融、做医疗的公司,这是合规红线。而且你没法深度定制它的评审逻辑。
  • GitHub Action更适合做固定流程,比如“每次PR都要跑mypy”“都要跑测试”。但Action是无状态的,很难跨多次评论保持上下文,不适合做复杂的多轮交互评审。
  • Hermes这种自托管的Agent,代码在自己手里,规则自己定,数据不出内网,同时有状态管理,可以做多轮对话、追问作者、根据更新重新审查。代价是要自己维护一套服务,复杂度确实更高,但带来的可控性是前两种方案给不了的。

正因为它可控,所以在企业内部落地、在开源项目里做维护助手,Hermes的边际效用是递增的。用久了,你会发现它越来越像团队里的“虚拟成员”,而不是一个冷冰冰的脚本。

2. 实操过程与核心环节实现

2.1 本地部署与最小复现

先说我建议的启动方式。Hermes官方文档里挂了一个Docker镜像,这是起步最顺的路。你得先在服务器上装好Docker和Docker Compose,然后写一个简单的docker-compose.yml

version: "3.8" services: hermes: image: hermes-agent/hermes:latest container_name: hermes-review ports: - "8080:8080" environment: - HERMES_MODE=production - HERMES_GITHUB_APP_ID=12345 - HERMES_GITHUB_PRIVATE_KEY_PATH=/run/secrets/github_private_key - HERMES_MODEL_PROVIDER=deepseek - HERMES_MODEL_NAME=deepseek-chat - HERMES_MODEL_API_KEY=${DEEPSEEK_API_KEY} volumes: - ./config:/app/config - ./secrets:/run/secrets restart: unless-stopped

这里面有几个字段我得重点说明。HERMES_MODEL_PROVIDER是模型供应商,Hermes做了抽象层,可以接DeepSeek、OpenAI兼容接口或者其他开源模型的API。HERMES_GITHUB_APP_IDHERMES_GITHUB_PRIVATE_KEY_PATH是GitHub App的凭证,后续创建App时会用到。

启动容器后,Hermes会监听/webhook路径。你需要把它暴露到公网,或者在GitHub上用Smee这类工具做内网穿透调试。这一步能不能走通,决定了整套系统能不能双向往来。

2.2 创建一个GitHub App

要让Hermes以“机器人”身份出现在你的仓库里,最标准的做法是创建一 个GitHub App,而不是用个人访问令牌。区别在哪?个人令牌的权限是跟着人走的,万一你的Token泄露,别人就拥有了你账号的所有权限;而GitHub App的权限是细粒度的,可以只给它“读取PR”“写入评论”这两个权限,风险面小很多。

创建过程大概是:

  1. 进入GitHub账号的Settings -> Developer settings -> GitHub Apps,点击“New GitHub App”。

  2. 填名称,比如hermes-reviewer;填写Webhook URL,就是你部署Hermes的那台服务器的公网地址,后面记得加/webhook;Webhook secret自己生成一段随机字符串。

  3. 在“Permissions”里,需要给这几个权限:

    • Pull requests: Read & write(让它能读取PR内容和发表评论)
    • Checks: Read & write(如果后续要写Check Run状态,这个必须有)
    • Issues: Read & write(如果要让它根据PR关联Issue,或者修改Issue标签,就需要这个)
    • Contents: Read(让它能拉取仓库代码内容来生成上下文)
  4. 生成私钥文件下载到本地,这个私钥就是docker-compose.yml里用的github_private_key

  5. 安装App到目标仓库。

这里有一个容易踩的坑:Webhook secret一定要配。如果不配,任何知道你Webhook地址的人都可以伪造请求、消耗你的模型配额、甚至给你的PR乱打标签。配好之后,Hermes会用HMAC算法校验每次请求的签名,来源不对的一律拒绝。

2.3 配置第一个Review规则

Hermes的核心可玩性在config.yml文件里。这是我见过最像“给Agent写说明书”的地方。它的语法定义了三件事:什么时候触发(triggers)、在什么条件下生效(conditions)、具体做什么(actions)。

举个我自己在用的最小配置:

rules: - name: "security-sensitive-files" triggers: - event: "pull_request" action: "opened" - event: "pull_request" action: "synchronize" conditions: - condition: "changed_files_include" patterns: - "auth/**" - "payment/**" - "server/security/**" actions: - action: "request_review" message: | 检测到本次改动涉及安全关键模块(auth / payment / security)。 请确认: 1. 是否有完善的输入校验? 2. 是否对权限变更做了日志记录? 3. 是否需要更新安全设计文档? - action: "add_label" label: "needs-security-review"

这条规则会拦截所有涉及安全相关目录的PR,自动打一个needs-security-review标签,并评论一段清单,提醒作者和后续Reviewer。有意思的是,conditions里的changed_files_include不仅支持路径通配,还支持diff_content的正则匹配。比如你想检查“不允许直接拼接SQL”这种模式:

rules: - name: "sql-injection-check" triggers: - event: "pull_request" action: "opened" - event: "pull_request" action: "synchronize" conditions: - condition: "diff_contains" pattern: "execute\\s*\\(.*\\$" flag: "SQL拼接风险" actions: - action: "comment" message: | 检测到疑似SQL语句拼接,请改用参数化查询,避免注入风险。 示例: - 错误:`cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")` - 正确:`cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))`

看到这你就能明白,Hermes不是只靠大模型瞎猜,它也支持确定性规则来做第一层过滤。大模型的优势在于理解模糊语义,正则的优势在于精确命中,两者结合,才是完整的评审体系。

2.4 给大模型配一套Review指南

除了规则引擎,Hermes还允许你通过REVIEW.md文件(放在仓库根目录)来指导模型的行为。这个文件的逻辑,相当于你在给新人写团队的风格指南。我举个实际例子:

# Code Review Guidelines ## 沟通风格 - 使用中文回复,语气专业、直接,不要过度礼貌。 - 每条评论必须指出具体问题所在,不能只说“这里需要改进”。 ## 重点关注 1. 逻辑错误:例如数组越界、空指针、错误的条件分支。 2. 并发问题:是否有共享状态被多线程读写,是否缺锁或原子操作。 3. 错误处理:异常被吞掉、返回值未检查、常见失败路径未覆盖。 4. 性能陷阱:在循环里执行了查询、N+1查询、不必要的大型对象拷贝。 5. 兼容性:是否破坏了公共API的向后兼容性。 ## 输出格式 对于每个问题,使用如下格式: ### 问题描述(文件名+行号) **严重级别**:可选的 [P0/P1/P2] **具体原因**:说明为什么这是一个问题。 **修改建议**:给出可执行的修复方案,必要时附代码片段。

这份指南会作为System Prompt的一部分,和每次PR的Diff一起提交给模型。如果你发现模型评论的质量不稳定,先别急着换大模型,先检查指南是不是写得太空。模型很吃“具体指令”这一套,你告诉它“给出具体行号和修复代码”,它就会认真很多。

2.5 模型的参数选择与Prompt构造

Hermes底层默认用的是DeepSeek的模型接口,这也是最近社区里比较主流的选择。我实测下来,在代码评审这个场景,模型的参数设置跟普通聊天有区别:

  • **temperature(温度)**要调低,建议0.1到0.2。评审需要的是稳定性和确定性,不需要创造性。温度太高,同样一段代码,它今天说好、明天说坏,你没法用。
  • max_tokens要设得够大,因为一次评论可能要覆盖多个文件多个问题。设小了,评论被截断,体验很不好。
  • top_p可以保持默认0.9左右,不用刻意调整。

Prompt的构造上,我强烈建议把“仓库上下文”和“Diff内容”分开。仓库上下文包括:根目录的README摘要、项目技术栈、关键目录结构;Diff内容则按文件分组。这样模型既知道这个项目是干嘛的,又能聚焦在具体改动上。

再说一个细节:Hermes会对Diff做“超长截断”策略。PR动辄上千行,一次全塞给模型不现实,Token费用也吃不消。默认策略是只把每个文件的头部和关键变动部分提取出来,如果文件太多,优先处理在REVIEW.md里指定的高关注目录。这就要求你在配置config.yml时,把max_diff_size这类参数设好,让Agent知道你的项目重点在哪里。

3. 功能进阶与场景玩法

3.1 用“提问”方式做深层次逻辑审查

单独的PR注释是“一次性的”,但代码评审本质是“多轮对话”。你在Review时经常遇到这种情况:某个PR逻辑绕了三层,你第一遍没看懂,于是写评论问作者“这里为什么不用XX方案?”作者答了之后你可能还会追问。Hermes同样支持这种追问。

当作者在PR里回复Hermes的评论,比如“这个改动是因为老接口废弃了”,Hermes会带着这层上下文重新审视代码。实测中,这种多轮讨论比第一次生成的意见更有价值,因为模型掌握了更多隐藏信息,能做出更准确的判断。我遇到过的情况是:第一轮模型报出一个“疑似错误使用API”的警告,作者解释说是兼容旧数据的字段映射。模型读取上下文后,自动把评论降级为“建议添加注释”,并且在更新后的PR上确认代码没有逻辑问题。这种“越用越懂”的感觉,是普通规则引擎完全做不到的。

3.2 和GitHub Actions的配合

Hermes不是要取代你现有的CI流水线,而是弥补“人性化”的部分。一个成熟的自动化评审体系,应该让机器做机器擅长的事,让模型做模型擅长的事。

我的建议是把Hermes作为“最后一道闸门”。具体流程:

  1. PR打开后,先跑GitHub Actions里的构建、单测、Lint。
  2. 这些机械检查通过后,Hermes再上场做语义级评审。
  3. 如果Hermes给的结果是REQUEST_CHANGES,作者修改后重新push,触发新的审查。

因为Single流程是串联的,所以要确保Hermes只在CI通过后才介入,避免模型在一堆构建错误里浪费时间。你可以通过GitHub Actions里的一个Job来调用Hermes的Webhook API,也可以直接在Hermes的规则里配置skip_if_checks_pending: true

3.3 多仓库接入与权限隔离

如果你管理的是一个组织下的多个仓库,每个仓库可能有不同的评审规范。Hermes支持按仓库加载不同的配置。目录结构大概是:

config/ base.yml # 全局默认配置 repo-awesome-project.yml # 仓库专属配置

config/base.yml里可以声明哪些规则是全局生效的(比如禁止提交密钥、禁止TODO),在仓库专属配置里再叠加特定模块的规则。这样,既保证了团队底线不会垮,又能让每个仓库有自己的风格。

部署层面,我建议给不同等级的仓库分配不同的Access Token。比如内部核心仓库用高权限的App,公开Demo仓库用只读权限的App。这样即使某个仓库被恶意提PR,攻击者也影响不了其他仓库。

4. 常见问题与排查技巧实录

4.1 不触发:Webhook收不到事件

这是最先遇到的问题,也是最常见的。如果你发现Hermes完全没有反应,优先按这个顺序排查:

  1. Webhook是不是内网地址:GitHub无法从公网访问你的localhost。本地调试可以用smee把GitHub事件转发到本地,但长期用一定得有公网地址。
  2. Webhook Secret校验:Hermes日志会有类似signature verification failed的报错,说明GitHub和Hermes两侧的Secret不一致。
  3. 事件有没有订阅:回到GitHub App设置页,在“Subscribe to events”里必须勾选Pull request。我见过有人只配置了权限,忘了订阅事件,结果Webhook完全不来。

4.2 评论乱码或格式错乱

Hermes评论的默认格式是Markdown。如果你发现代码块没有正确渲染,检查两件事:模型返回的文本里是否有多余的转义字符;config.yml里有没有设置comment_style: markdown。另外,模型偶尔会自己造一些不存在的文件名和行号,这就是幻觉。在REVIEW.md里强约束“每一条评论必须基于提供的diff,不得自行编造”能缓解一大部分。

4.3 API Rate Limit被耗尽

GitHub的REST API限制是每小时5000次请求,V4 GraphQL是单独的5000点。Hermes的每一次事件处理,可能要调用好几个API:拉PR详情、拉文件列表、拉Diff内容、发评论。如果仓库PR量大,很容易撞限。

我的建议是给Hermes的GitHub App配置更高等级的Plan,同时从代码层面尽量减少API调用次数:能用GraphQL合并的查询,就不要发多次REST请求;能用Webhook事件里自带的payload数据,就不要额外去拉。

4.4 模型评审质量忽高忽低

这是使用中最大的挫败感来源。明明昨天评论质量很高,今天同一个代码,模型给出的意见却偏了。我排查后总结出三个原因:

  1. Diff摘要策略:PR的Diff太长,被Hermes的截断策略切掉了一部分,模型没看到关键逻辑,凭片段脑补了。
  2. System Prompt冲突REVIEW.md里要求互相矛盾,比如前面说“保持简洁”,后面又要求“每条必须带代码片段”,模型只能随机挑一个执行。
  3. 模型本身波动:大模型是概率性的,相同输入也可能有不同的输出。所以一定要把温度调到最低,并且在架构上加入“重试机制”——如果模型输出格式不符合要求(比如JSON解析失败),自动重新调用一次。

4.5 PR频繁更新导致重复评论

当作者根据建议改了代码,push了新commit,Hermes如果又重新评论一份新的建议,很容易产生噪音。GitHub的Review机制本身有“thread”的概念。Hermes在评论时尽量复用已有的评论线程:先看这条评论针对的代码行是否已经有一个thread了,有就追加,没有才新建。如果你发现自己收到的评论总是刷屏,可以检查config.yml里的dedup_mode设置,有几个选项:off(不去重)、file(按文件去重)、hunk(按代码块去重)。我推荐用hunk,既保留了对新问题的讨论,又不会没完没了重复旧结论。

4.6 私钥和凭证管理不当

GitHub App的私钥是敏感资产。如果你把它直接提交进仓库,别人拿到后就能以你的App身份读取仓库代码、发表评论。强烈建议放在单独的secrets/目录,加.gitignore,并且在服务器上用环境变量传递。Hermes默认会检查私钥文件的权限,如果权限大于0600,它会直接拒绝启动,这是比较贴心的设计。

5. 实用建议与个人体会

整套系统从搭建到现在跑了大半年,我最大的感触是:Hermes真正的价值不在于替代人,而在于帮人把时间花在更值得的地方。以前Review一堆PR,我至少有一小半时间在看“这个函数为什么要改名”“这个注释是不是写错了”这类的琐碎问题,真正需要深入推敲的逻辑问题反而被挤掉。现在Hermes先筛一遍,我每次打开PR,看到的是它标注出来的“P0:这里可能有空指针风险”“P1:这条SQL建议参数化”,效率提升不是一点半点。

给准备上手的朋友三个建议:

第一,先用小仓库试几天。不要一上来就给核心仓库配上,你会发现它有很多需要调教的地方。先在Demo仓库跑通闭环,看看它的评论风格、准确率,再把规则体系调顺,最后才上核心仓库。

第二,配置别贪多。规则越多,误报率越高,作者和Reviewer都会累。我建议第一批只要三条规则:安全检查、提交信息规范、TODO标记清理。跑一段时间,看团队的反馈,再加下一批。

第三,REVIEW.md当成活的团队文档。每隔一两周,根据模型出的“昏招”去补充约束。比如有一段时间模型老是在类型标注上吹毛求疵,我就在指南里加了一句:“类型标注建议只针对新增函数,对旧代码不做强制要求。”加完这句话,误报率立刻降下来了。模型能不能变聪明,很大程度上取决于你喂给它的规则是否清晰。

自动化代码评审这条路,远没有到“全自动”,但已经能实打实地减轻负担。Hermes这种Agent让我看到了一个方向:用大模型去理解意图,用规则去兜底,用工程手段去管理流程,三者叠加,比任何单方面努力都靠谱。如果你也想给自己项目找个靠谱的“AI同事”,这个工具值得投入一下午试试。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询