从零搭建Hermes:基于GitHub PR的AI自动化代码评审Agent实践

从零搭建Hermes:基于GitHub PR的AI自动化代码评审Agent实践 作为一个常年在一线写代码、也常年被 PR Review 卡住时间的人我太清楚“自动化代码评审”这件事的诱惑和陷阱了。团队里每天二三十个 PR每个人切换上下文的时间比写代码的时间还长Lint 和静态扫描工具又永远只盯着格式和低级错误。所以当 Hermes 这个 GitHub PR 自动审查 Agent 的项目落到我手上时我没有急着去调模型、写提示词而是先花了一周时间想明白到底什么样的自动化评审才值得一个开发团队真的去用、愿意去回、不会被五分钟一次的通知气得关掉它。这篇文章会把我从零搭建 Hermes 的完整过程讲清楚包括事件接入、diff 处理、上下文构建、提示词设计、评论回写、部署形态以及上线之后踩过的五个印象最深的坑。如果你想在自己的仓库里落地一套 AI 代码评审这篇文章应该能帮你省掉大量试错成本。1. 为什么写 Hermes人工 Review 的三个真实痛点1.1 团队 Review 的日常不是在看代码是在抢时间我当时所在的业务小组平均每天活跃 PR 大概接近 30 个。看起来不多但如果每一个 PR 都要有两个人以上认真读一遍根本不现实。我们当时用的是“谁提交谁指定 reviewer”的方式结果就是技术骨干基本半天都在看 PR剩下半天才能写需求新来的同学则更愿意挑格式、命名、小毛病来提意见反而把真正有风险的逻辑改动放过去了。这个问题本质上不是态度问题是成本问题。人从一段完整的开发状态切到另一段陌生的 diff光是把那几处修改放到更大的背景下想明白就至少需要十几分钟。你还要自己去点开文件、翻看调用链、回忆之前的约束。切回来以后可能又要十几分钟才能回神。一天下来大量时间都耗在这种切换上代码质量和开发效率两头都受损。1.2 现有自动化工具解决不了什么用过的自动化工具其实不少。ESLint、SonarQube、CodeClimate 这些能帮你守住代码风格、控制圈复杂度、扫出明显的漏洞模式但你让它回答“这次改动会不会影响另一个模块的线上行为”它就无能为力了。它连这次改动在业务上想干什么都不知道。后来又试过几种基于规则的审查机器人它们把“数组越界、空指针、硬编码密码、忘记处理异常”这类模式总结成模板去匹配。好处是可解释、好部署坏处是误报率奇高模式匹配不看上下文凡是出现JSON.parse就提示你处理 try/catch不管你是不是已经包在 try 里。团队用了一个月群里全是机器人的 真正的 review 体验反而更差。1.3 Hermes 的定位不让 AI 替代人而是让人省出时间所以做 Hermes 的时候我给自己定的原则是它不能停留在“规则匹配”和“lint 报告”这个层面而应该像一个初级但勤奋的资深工程师先把 PR 读一遍把低级问题、明显风险、可疑逻辑找出来给每个人留下有依据的评论而人只需要在它筛选后的结果里做二次判断。这不是替代人的 code review而是把所有重复劳动前置到机器人身上。我把它命名为 Hermes取希腊神话里信使神的意思——它不产出最终结论它负责替人把信息跑起来。后面我会把它如何接收 GitHub 事件、如何处理 diff、如何组织评审结论、如何回写评论以及我在生产环境中踩过的坑全部展开。如果你也想在自己的项目里搭一套自动化代码评审应该能得到一套可以直接上手的思路。2. Hermes 的架构拆解一次 PR 从事件到评论的完整旅程2.1 触发与采集GitHub App 还是 Webhook第一件要做的事是想清楚怎么让 Hermes 知道“有新 PR 或新 commit”。GitHub 官方推荐的方式是注册一个 GitHub App订阅pull_request、issue_comment、pull_request_review_comment这些事件。事件发生时GitHub 会把包含完整信息的 payload 推送到你指定的回调地址。我也见过用 GitHub Actions 做的轻量方案但这里我选择 GitHub App 的原因有几个App 事件比 Actions 丰富得多拿到的 payload 里带了action、pull_request、repository等字段想触发的时候触发不想触发的时候可以不触发App 有独立身份评论时不会占用某个同事的账号权限控制也更干净。回调地址收到事件以后第一件事不是直接开始分析而是做一个很不起眼但必须做的判断事件是opened、是synchronize新 commit 被推送、还是review_requested。不同事件后续处理逻辑完全不同。比如synchronize事件如果每次都全量重跑整个 PR一个开发到一半的分支会把你整个任务队列打满所以 Hermes 只对最新一轮 diff 做增量评审历史结论保留原样。2.2 队列与任务编排异步化是避免 Webhook 超时的底线接着是最容易被新手忽略的一步——队列。GitHub Webhook 本质上是一次 HTTP POST如果你在里面同步等待大模型分析完、再调用 GitHub API 写完评论这个请求很可能 10 秒都回不去。GitHub 对 webhook 的响应有超时预期超时后会判你投递失败并不断重试最后就出现“同一份评论发好几次”的诡异现象。Hermes 的处理方式是把任务分成两个阶段。接收端只做非常轻量的解析动作验签、判断事件类型、把repo pr_number head_sha存进队列然后立刻给 GitHub 返回 204。后端的 worker 从队列里取任务再去拉取 diff、分析、评论。队列可以用 Redis也可以用消息队列甚至直接用数据库表当队列都行。关键是要保证两点任务至少被消费一次每条评论写入要做幂等控制。只要把握住这两个底线后续怎么折腾都不会出大事故。2.3 一次评审的完整流水diff 拉取、上下文构建、模型推理、评论回写一次完整的评审我拆成下面几个阶段拉取元数据从 GitHub API 拿 PR 的标题、描述、变更文件列表、提交记录。拉取 diff调用/repos/{owner}/{repo}/pulls/{pr}/files接口拿到每个文件的 patch。构建上下文对 diff 做预处理提取相关函数、被调用的符号、对应语言语法树目标是让模型不用来回翻文件。分批推理把 diff 按文件或按函数切块送到 LLM 推理同时给模型的指令里带上项目自定义规则和全局约束。整理结果合并多批次的分析结果去重、按严重程度排序。回写评论通过 GitHub API 以 App 身份创建 review带上逐行评论或 suggestion。听起来不复杂但每个环节都有各种边界条件。比如第三步“构建上下文”如果直接用原始 diff很多语言模型会因为文件太长而截断或者因为缺少函数定义而看不懂改动到底在做什么。这一层做得好不好直接决定评审结果是不是真的能看所以我单独用第三章来讲。2.4 为什么坚持模型无关设计推理环节我坚持做成模型无关的接口。内部定义了一个统一的分析调用格式输入是评审任务包含文件、diff、上下文、规则输出是结构化的评审意见JSON。底层可以接任何大模型 API也可以接本地部署的开源模型。这么做的好处非常实际。第一成本可控。平时用便宜的模型处理琐碎检查遇到复杂核心逻辑再走贵一点的模型。第二不会被某一家模型限制住。不同模型在代码理解上的强弱差异很大你的真实需求也会变化。第三方便做 A/B 对比。同一段 diff 丢给两个模型看哪家给出的结论更有用保留效果好的这本身就是运维 Hermes 时经常要做的事。3. Diff 预处理与上下文构建评审质量的隐藏关卡3.1 直接拿原始 diff 喂给模型的三宗罪我最早的原型机就是直接把 GitHub 返回的 patch 文本拼进 prompt跑出来的结果惨不忍睹。总结下来原始 diff 有三个问题第一大量噪音。依赖锁文件、自动生成文件、格式化工具改过的文件会把 diff 撑得巨大严重挤占上下文空间模型可能看完了也没抓到真正重要的改动。第二截断问题。GitHub API 对超大文件的 patch 返回有大小限制直接拉出来本身就不完整。第三缺少语义上下文。模型看到的只是 hunk没有函数头、没有被调的接口、没有 import它很难判断这次改动会不会破坏其它调用。3.2 语义切片按“变更单元”而不是按行分析解决思路是把一个巨大的 diff 切成若干语义独立的小单元。我建议不要按 hunk 去切而要按“变更单元”去切。所谓变更单元在函数式语言里可以是一个函数在类里可以是一个方法在配置文件里可以是一个完整的配置块。判断到底在哪一段依靠的是语言解析器而不是字符串匹配。以 JavaScript/TypeScript 为例我先把文件用 Babel 解析成 AST定位变更行再找到变更行所在的函数或方法节点把整个函数体、函数签名、注释都保留下来形成一个最小分析单元。这样喂给模型的内容是一个“完整的函数改动”而不是几根支离破碎的 diff 行。这个切片动作同时解决了上下文和 token 预算问题。这里贴一段核心逻辑我用 Python 写处理脚本解析 diff 并定位变更范围def extract_changed_functions(file_path, patch_text, parser): changed_lines parse_patch_ranges(patch_text) tree parser.parse_file(file_path) units [] for node in find_all_function_nodes(tree): node_range set(range(node.start_line, node.end_line 1)) if node_range changed_lines: units.append({ function_name: node.name, start: node.start_line, end: node.end_line, source: node.source, }) return units这个函数本身不复杂但实际项目中要处理的情况远比这多一个函数有 500 行怎么办公共函数同时被多个 PR 改动怎么办我的建议是给分析单元设一个行数上限超过上限的函数再按 hunk 或者按语法块切到更细粒度同时保证每次分析时把“变更行所在的最小函数/方法”的完整签名给到模型其他不相关的大段实现可以不进上下文。3.3 上下文召回把“它调用了谁、谁调用了它”补进来切片之后模型仍然只知道这个函数本身还不知道它依赖的东西。真实 code review 里你看到一行await sendEmail(user)你得知道sendEmail大概在干什么才能评估这次改动是否合理。Hermes 的做法是定期扫描仓库建立一份符号索引每个函数名称、定义在哪个文件、接收什么参数、调用方大致有什么特征。评审时如果 diff 里出现了调用某个符号就把这个符号的简要定义或者调用处上下文一并塞给模型。这块不用做到非常重一条简单的文本索引就能解决大部分问题。重点是控制召回粒度把符号定义控制在一二百字以内调用点最多放两三个否则上下文又要爆。上下文构建是成本和质量最尖锐的矛盾点你必须不停调直到找到一个平衡。3.4 token 预算每个 PR 到底该花多少token 成本是你审时间长了以后一定会面对的。做一个大概估算假设一个 PR 改 10 个文件每个文件切片成 2 到 4 个分析单元每个单元带上函数体、符号定义、提示词一次推理大约消耗 2500 到 4000 个 token。如果每个 PR 再来一次全局总结分析可能又要 8000 token。对于每天 30 个 PR 的团队一天下来几十万 token乘以模型单价是不可忽略的开销。我从一开始就把“评价单元的粒度”和“是否做全局总结”设置成可配置项。轻量模式只评审高影响区业务源码、核心模块重量模式才去分析测试文件、配置文件和文档。这里有一个很容易被忽略的妙招如果模型对某种类型文件比如测试代码误报率特别高你可以直接把这些文件排除在评审范围之外省下的 token 远比你花在调试误报上的时间值钱——这个我后面还会再提。4. 提示词设计把“资深 Review 视角”教给模型4.1 先定义问题等级什么值得打断别人提示词设计的前提是先想清楚整套规则要识别什么、不识别什么。我把 Hermes 的评审结果分成四级阻断级Blocker——会导致线上故障、安全漏洞、严重性能恶化的问题应该改Should——明显逻辑缺陷但未必出大事建议Suggest——可读性、边界情况、潜在优化点风格Nit——命名不统一、格式问题等。分级的意义是给模型一个清晰的注意力引导让它不要把所有问题都按同一个强度提。如果一份评论满屏都是“Nit”开发者的处理体验会非常差。Hermes 的默认设置是Blocker 必须在 review 结论里置顶Should 应当出现Suggest 酌情Nit 默认不输出。这直接决定了评论会不会被团队当成噪音。4.2 提示词模板角色、任务、规则、示例四段式我最终的提示词基本固定为四段式结构第一段定义角色第二段写本次任务和输入格式第三段写项目自定义规则第四段是少样本示例。一个简化后的模板长这样你是资深 code reviewer请基于以下 diff 做评审。 任务 1. 只根据提供的 diff 和上下文作答不要臆测未出现的内容 2. 输出 JSON格式为 {comments: [{ file: ..., line: ..., severity: blocker|should|suggest, message: ... }]} 3. 如果没有任何值得提的问题输出空数组。 项目规则 - 不允许在日志中打印 token、密钥、密码 - 所有新增接口必须处理异常并记录错误 - 数据库查询不得在循环中执行。 变更文件 {file} 上下文 {context} Diff {diff}我实际用的模板比这个长得多还会根据语言加入不同规则。关键点在于“如果没有任何值得提的问题输出空数组”这句话加上这句之后空评论大幅减少模型更倾向给出克制结果。同时在任务里明确“不要臆测未出现的内容”可以避免模型拿通用知识补齐接口定义时编出貌似合理但实际不存在的调用。4.3 少样本示例教模型做“减法”而不是“加法”少样本里不要放“模型应该发现什么”的正向案例反而要放“什么情况不要评论”的反向案例。比如加一段diff 中一处方法改动了日志输出顺序与逻辑无关不应提为 should再比如一个临时调试代码片段出现在 dev 分支规则里允许存在则应标记为“建议删除”而非“阻断”。这些反向示例的作用和训练新人的思路是一样的人会被“最像问题的东西”吸引模型也是。如果你只教它发现 bug它会到处找 bug如果你教它区分“问题”和“需求上下文”它才会收敛。我给 Hermes 调提示词时最高频的操作不是加规则而是删规则加反例。很多团队在接入 AI 审查时体验不好根源就在这里他们疯狂往 prompt 里堆“应当”却忘了告诉它“什么时候不应该”。4.4 让模型“说人话”一份评论只能有一个核心问题生成的评论文本常常会有一种生硬的“AI 味”。我的办法是在提示词里加一条“message 用一句话说明问题和理由给出可操作建议不要输出‘建议优化代码’这类空话”。并且要求它把建议具体到行和函数名比如“这里user.id可能为空调用getProfile前建议判空处理”而不是“建议增强代码健壮性”。这样即使模型偶尔误判开发者也更容易判断这个评论是否值得处理。这里必须给一个重要提示模型会把行号搞错。它基于 diff 推断出的行号经常因为 hunk 起始行偏移而错位。如果直接用line字段去创建 inline review commentGitHub 会报“line must be part of the diff”之类的错误。我在第五章讲评论回写时会给出一个实际用过的校正方法。5. 评论回写与多轮交互从“报告”到“对话”5.1 三种回写方式的选择GitHub 上回写评论有三种主要方式PR 全局评论review 正文、逐行评论pull request review comments、以及代码建议suggestion。三者使用场景完全不同。全局评论适合放评审总结和统计指标比如“本 PR 共发现 2 个 blocker、5 个建议”。逐行评论适合针对具体某一行指出问题也是团队认为最不打扰人的方式。代码建议可以给出修复后的代码块开发者点一下就能应用适合明确的修改场景比如“变量名应改为 camelCase”。Hermes 默认把 Blocker 和 Should 发成逐行评论把 Suggest 合并进 review 总结只有触发“严格模式”的时候Suggest 级别的建议才变成可一键应用的 suggestion 评论。这样评论数量能压到 5 条以内开发者不至于被刷屏。5.2 行号校正用 Git diff 的 hunk 信息对齐评论位置模型输出里给的行号写的是分析单元内部的相对位置。实际运行时我写过一段校正逻辑拿到 diff 文件里的 hunk header它的格式是 -start,count start,count 其中start表示新文件中该 hunk 的起始行号。按顺序累加 hunk 的偏移量把模型给出的相对行号换算成 PR 中的绝对行号。这里用一个简化例子def map_line(hunk_start_new, model_relative_line): return hunk_start_new model_relative_line - 1真正的实现要考虑多个 hunk、删除行引起的偏移、空行位置等因素。基本逻辑是在做语义切片那一步把每个切片对应的新文件起始行号记录下来等推理完回写评论时直接查表映射。这是成本最低、最不容易错的方案千万别等模型输出后再试图去猜行号。5.3 去重与噪音控制让每个人愿意继续看评论评论风暴是最让团队反感的行为。Hermes 早期版本跑出来的 review经常是同一个问题在不同的文件切片里出现好几遍。后来我在合并阶段做了一层语义去重用规范化后的问题类型加文件名再加关键函数名组合成去重键。比如同一类空指针问题在不同位置出现只保留最前置的一条。另一个噪音来源是“建议了太多无关紧要的小事”。我后来给评论系统加了一个简单的评分公式每条评论的最终输出概率是严重级权重加上可执行性评分是否包含具体修改建议低于某个阈值直接过滤掉。目标不是说每条都必须对而是要保证即使错的那些评论也不能让团队因为太吵而取关这个机器人。5.4 从“单次报告”到“按需对话”在评论里 Hermes 追问做到这一步Hermes 已经能自动给出第一轮评审意见了。但 PR 是一个动态过程开发者改了一版之后机器人应该能跟进而不是只对最初版本说话。我给它加了事件监听pull_request_review_comment当有人创建新评论并 Hermes 时它会读取当前最新代码状态结合之前的评审上下文重新跑一轮分析并追加评论。这样整个流程从“一次性报告”变成了一个半交互式 Agent。它不是一个无人值守的裁判而是可以被追问的助手。开发者在评论里可以写“这个建议在当前分支已经处理了为什么还提”“你建议改成这样会不会影响某处的调用”Hermes 就会把相关的上下文拉回来再回答。这部分功能上线后团队对它的容忍度明显提高了因为评论区终于像一个正常讨论而不是机器人在单方面发号施令。6. 部署形态与稳定性GitHub Actions 和独立服务怎么选6.1 两种部署方式的本质区别Hermes 的部署方式我建议根据团队规模来决定。如果你的仓库不多、PR 量不大GitHub Actions 是更快的选择。在.github/workflows/hermes.yml里定义 workflow监听pull_request事件跑一个 Python 脚本完成拉取 diff、调用模型、回写评论整个链路在一个工作流里就闭环了。优势是零服务器成本、配置简单、用 GitHub 托管的运行环境。如果 PR 量上来了或者需要复杂的队列、多模型、自定义事件逻辑建议部署独立服务。独立服务可以用容器编排平台托管配有持久化队列和任务重试机制。Webhook 接收端和 worker 分离遇到模型 API 抖动时可自动重试同时在评论前落库避免因为中途失败而丢失评审任务。这两种形态甚至可以并存团队内部跑独立服务给核心仓库用边缘仓库只挂 Actions 轻量版本。我自己在落地时也是先用 Actions 验证效果等跑通后再迁到独立服务。6.2 用 GitHub Actions 快速起步的配置要点如果你想先试效果我建议保持入门配置尽量简单。Workflow 的核心就三件事触发事件、安装依赖、运行评审脚本。有个容易忽视的点在 Actions 里需要配一个 GitHub Token权限要设置为能写 PR 评论。如果使用 GitHub App则还需要额外引入获取临时 token 的动作如果用 PATPersonal Access Token必须小心不要把它放到公开仓库里。一个最小起步的 YAML 大致长这样name: hermes-review on: pull_request: types: [opened, synchronize] jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 with: fetch-depth: 0 - uses: actions/setup-pythonv5 with: python-version: 3.12 - run: pip install hermes-cli - run: hermes review env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} MODEL_API_KEY: ${{ secrets.MODEL_API_KEY }}这里fetch-depth: 0的作用是把完整 git 历史拉下来不要只拉最新一次 commit因为 diff 的比对需要在正确的 base commit 上进行。如果你用 event 里传的默认GITHUB_TOKEN它默认权限极小需要你在仓库设置里调高 job 的写权限否则评论会写不进去。6.3 独立服务的稳定性持久化、重试、幂等独立服务稳定性的核心其实是前面 2.2 节提到的队列表和幂等。我在生产环境用了一个表来记录已处理评论的外键repo pr_number head_sha result_hash写评论前先查这个外键重复消费时不二次写入。这样即使某个 webhook 因网络问题被重复投递也不会出现重复评论。模型 API 偶尔会超时或者返回 5xx所以 worker 里必须做退避重试。我的经验是第一次重试等 5 秒第二次 15 秒第三次 60 秒超过三次就把任务标记为失败并记录到日志里同时发一个降级通知给管理员而不是一直无限重试把队列堵塞。因为模型 API 的不稳定不只是网络还可能是你上下文太大导致的响应超时无限重试只会放大成本。6.4 认证和权限管理的几个关键细节如果你用 GitHub App私钥文件绝对不能提交进仓库。App 安装后的私钥应该放到密钥管理系统里运行时注入环境变量。另外创建评论时要给 App 设置足够的权限Pull requests 的读写权限、Contents 的只读权限等。权限给得越小越能避免 App 被滥用。还有一点很容易被忽略不要把模型服务的 API Key 放进业务日志里。模型推理出现异常时通常会把请求内容打出来方便排查如果你不脱敏key、token、甚至代码内容都可能流到日志聚合系统里。我在生产环境强制开启请求和响应的脱敏凡是符合 key 特征的字段统一替换成***。这个习惯救过我一次强烈建议一开始就加上。7. 上线之后的踩坑复盘5 个让我印象最深的问题7.1 同一个 PR 被重复评论根因是事件重放上线第一周团队成员反馈同一个 PR 总能收到两三条一模一样的评论。排查过程其实不复杂先看 Hermes 的日志发现同一个head_sha被消费了两次。再查队列发现消息队列在消费后确认动作由于网络抖动没执行成功导致消息重新进入队列。于是加了“按 head_sha 结果哈希去重”的一层保障重复消费不再产生新评论。这个问题最麻烦的点不在技术上而在于它会迅速消耗团队对机器人的信任。所以哪怕牺牲一点实时性也要把幂等做扎实。7.2 模型输出非法 JSON消费端直接崩掉如果你让模型输出 JSON它十次里总会有一次给你带个 Markdown 代码块包裹、或者多一个逗号、或者在 message 里出现换行符。直接在解析那一步抛异常任务就会反复重试。我的做法是解析之前先做一次轻量清洗去掉首尾的 标记、去掉多余空白再用json.loads解析解析失败则进行一次模型自动修复尝试即把原始输出和报错信息拼回给模型要求它只返回合法 JSON。经过两轮修复后成功率能到 99% 以上。剩下的失败任务进入人工处理队列不阻塞其它评审任务。7.3 测试文件的“戏精”时刻误把测试改动当成业务改动有一次 Hermes 在一个纯测试文件 PR 里提了一堆“业务逻辑 bug”比如“data可能为 undefined访问data.length前建议判空”这样的评论。乍一看没错但它没意识到那是it.each里的测试数据根本不需要也不能判空。问题的根源是语义切片时我把所有文件都当成业务代码处理没有给模型区分文件角色的信号。后来我加了一条规则分析每个文件前先判断它的类型源码、测试、配置、文档在传给模型时明确标出“这是测试文件”并且把测试专用规则和业务规则分开维护。那次之后类似误报基本消失。7.4 评论风暴引发的“全员屏蔽”我没有预料到的一点是当 Hermes 把 50 多条 Suggest 评论一次性贴到 PR 上开发者第一反应不是去改而是直接在通知设置里把它屏蔽了。这也让我下定决心执行“默认严格过滤只保留高置信度、高价值评论”的策略。我给每类问题定义了一个置信度阈值与可行动性做加权。比如“空指针”这种明确问题置信度可以高“代码风格”这种主观问题必须低低置信度的问题只有出现在核心文件中才会输出。调整后单条 PR 的平均评论量从 12 条降到了 4 条以内开发者返回与机器人互动的意愿反而大幅提升。7.5 差点把密钥直接打在公屏上加一道最终拦截最让我后怕的一次是模型在一个 PR 的 diff 里发现某行测试配置包含一个很像密钥的字符串于是它很认真地建议“这里可能有硬编码密钥”并把这段字符串原样写进了评论。我是在发布前检查时发现的。如果评论被推送到 GitHub敏感信息就会长期留在仓库的评论记录里。从那以后我在评论回写之前加了一道脱敏过滤凡是符合密钥格式、或者与仓库已配置的 secrets 相似的值一律替换成[REDACTED]。这已经不只是功能问题而是底线问题强烈建议每个做 AI 评审的都把这一步当成强制要求。8. 实际效果与我对自动化评审的边界判断Hermes 上线两个月后我拉过一次数据。每天 30 个 PR 的人工平均首次响应时间从 3 小时以上降到了 40 分钟以内PR 从提交到拿到至少一轮结构化意见的时间基本是 5 分钟。更重要的是它的评论里可以确认的真实有效比例稳定在 60% 以上剔除误报之后这个比例在“辅助性评审”这个定位下已经非常够用。但我必须说清楚我的边界判断代码审查的核心结论应该由人来下。Hermes 能让人省去通读 diff、找琐碎毛病的时间但它不能理解这次上线背后的商业意图。它不知道你为了赶版本在某个边界场景故意牺牲了部分稳定性它也不知道某个看似很丑的写法是因为上下游接口尚未统一。所以我在团队里的定位是“第一轮 Reviewer”而不是“最终审批人”。它还做不了大规模跨文件跨服务的影响面判断那是架构师的工作也是人独有的综合判断力所在。如果你也想做类似的东西我给三个建议第一开始就先分清主次把 diff 处理、工具链跑通、能稳定输出“不讨厌”的评论再考虑更复杂的功能第二模型能力提升很快但提示词和切片才是真正的护城河——同样的模型不同的切片和提示词结果差别可能很大第三想清楚什么时候不接入也比较重要如果你的仓库几乎没有人认真看 PR机器人只会输出一堆没有人修的问题并不会让团队工程文化自动变好。最后说一个小实操技巧在本地调试 Hermes 评论回写时我通常直接构造一个假的pull_request事件 payload发到一个测试仓库而不是在线上仓库里一边开发一边被真实 PR 触发。你可以用一个本地脚本模拟 GitHub 的 API 调用把评论写到测试仓库里整个过程迭代速度会快很多。这个习惯帮我省下了大量调试时间也希望能帮你少走一些弯路。