多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Hermes实战:Agent化PR审查如何提升代码评审效率

Hermes实战:Agent化PR审查如何提升代码评审效率 作为一名在研发效能领域折腾过不少工具的人我这两年对“代码评审自动化”这件事的态度经历了一个很大的转变。早些年看到这类工具总觉多是花架子跑个demo还行真正放进生产仓库里就容易变成噪音制造机。直到上个月把Hermes接入团队的GitHub主仓库让它实打实跟完了几十个PR我才意识到这一代PR审查工具已经不是我记忆里的那个只会做静态检查的小插件了。这篇东西不打算写成一份软文式的介绍而是把我在接入、配置、调优到处理各种意外情况的全过程连同我对这类Agent化工具边界的思考一起拆开揉碎讲清楚。1. 为什么人工PR评审总在“最后一道关”翻车先说个挺扎心的事实绝大多数代码仓库的最后一道质量防线其实是最薄弱的一环。CI跑的测试、Lint规则、类型检查这些都只能拦住规则明确的问题但PR评审恰恰处理的是规则之外的东西比如设计合理性、边界条件考虑是否周全、异常路径是否干净、改动是否真的和PR描述一致。这些活儿天然依赖“人”的领域知识和上下文理解能力所以长久以来它只能靠人来扛。但人的问题是评审质量极度依赖评审者当时的状态、对这块代码的熟悉程度、甚至是当天的会议多不多。我统计过自己团队过去三个月的数据一个常规PR从发起到被完整review完毕平均耗时26个小时其中真正盯着代码看的时间往往不超过20分钟剩下的时间全花在“谁有空”“谁熟悉这块”“谁记得之前那次讨论的结论”这些流程损耗上。更要命的是reviewer越忙给出的评论就越趋于“安全”最后变成一句“LGTM”或者“改一下命名就行”。这种情况下漏掉的多是那种需要跨文件追踪才能发现的逻辑漏洞。比如A文件里改了接口签名B文件里还在用旧参数编译器或类型检查器如果配置不全这个问题就会直接漏到合并后的主分支里。我之前就撞上一次前端改了一个API的query参数名后端对应的SDK封装文件也跟着改了但中间隔着一个深层调用的中间层没动结果线上偶发报错查了整整两天最后定位到是一次PR里三处文件没有同步修改导致的。这种问题单一工具、单一检查项都很难发现因为它需要理解“调用链”而不只是“单文件语法”。正是在这种背景下我开始关注具备Agent能力的自动化评审工具。它们和传统静态检查最大的不同在于它会尝试“读”整个PR的上下文理解改动的意图再结合代码库的历史和结构给出类似人类reviewer才会提的建议而不是机械地报“这行超过80字符了”。Hermes就是这类工具里我实际用下来觉得最接近“可用”状态的一个。2. Hermes的技术底座它到底在用什么方式“读代码”想评估一个自动化评审工具靠不靠谱第一件事是搞清楚它内部是怎么处理代码的。如果它还停留在正则匹配、关键词扫描的水平那基本可以直接放弃。Hermes之所以能在处理复杂仓库时给出靠谱意见核心在于它的三层代码理解机制。第一层是语法感知。它不是把PR当成一堆纯文本diff来看而是会先对改动涉及的代码文件做完整的语法解析生成抽象语法树。这意味着它能准确理解一个函数是从哪一行开始、到哪一行结束新增的分支是不是真的被包裹在正确的逻辑块里有没有出现悬空的else或漏掉的return。这一层解决的是“机器知不知道自己在看什么”的问题。第二层是语义关联。只懂语法不足以发现跨文件问题所以Hermes会对整个仓库建立索引追踪变量、函数、类在多个文件之间的引用关系。当PR中修改了一个函数的签名它能追踪到这个函数在哪些地方被调用并检查这些调用点是否仍然兼容。这个能力相当关键因为很多团队根本没有完整的集成测试覆盖跨模块破坏是PR阶段最高频的漏网之鱼。第三层是变更意图推断。这一层是最“Agent”的地方。Hermes会把PR的标题、描述、commit信息、关联的issue连同diff内容放在一起做综合推断形成对“这次改动到底想干什么”的理解。然后基于这个理解逐一检查diff中的代码改动是否和意图一致有没有“顺手改”却和主题无关的行有没有明明声明了修复某个bug但实际代码逻辑根本对不上的情况。这套三层体系在实际效果上体现在哪我拿之前我们仓库里一个真实PR来举例。那位同事提交的PR标题是“优化用户列表页的查询性能”他在修改的Mapper文件里把原本的循环单查改成了批量查询这个改动本身是没问题的。但Hermes在审查时发现他同时顺手改了另一个不相关的工具类里一个公共方法的访问修饰符从public改成了private而这个工具类恰好被另一个微服务模块引用。这个改动如果合进去下游模块编译必然失败。人工reviewer大概率只会把注意力放在“查询性能优化”的主线上谁会逐行盯到无关工具类的一行修饰符改动但Hermes因为是语义级扫描跨文件追踪到了引用关系直接以高优先级评论的形式把这个问题拎了出来。这就是纯静态检查和语义级审查的本质区别。3. 把Hermes接进仓库从创建应用到首个自动评论Hermes的接入方式走的是GitHub App路线这意味着不需要在CI的YAML里写一堆自定义脚本也不用给机器人单独搞个token。GitHub App的权限模型比传统token安全得多最小权限原则下可以精确控制它能看哪些仓库、能读哪些内容、能写什么类型的评论。整个接入过程如果文件都准备齐全的话十分钟左右就能搞定。第一步是创建GitHub App。打开GitHub Settings进入Developer settings点New GitHub App。这里有几个关键的配置项需要填GitHub App name建议和项目关联比如我起的是hermes-review-prod方便之后在多个环境间区分。Homepage URL随便填个仓库地址就行Webhook部分才是重点。如果只是个人仓库存量项目Webhook URL可以暂时随便填个占位符因为后续如果用流程控制模式而非被动触发模式的话Webhook不是必须的。真正要勾选的是Repository permissions里的Contents权限需要给Read级别因为Hermes要读取代码内容Pull requests权限给Read这是它能看PR细节的基础。还有一个容易被忽略的权限是Checks建议给Read或Write这关系到它能否以Check Run的形式在PR页面上展示结果而不是单纯靠评论区飘红。第二步是生成私钥。App创建成功后在General页面最下面找到Private keys区域Generate a private key会生成一个.pem文件。这个pem文件加上GitHub App的App ID就是Hermes后续向GitHub API发起请求时的身份凭证务必存放到安全的文件位置我习惯放在专门的secrets目录里用环境变量指向该路径。第三步是安装App到目标仓库。这一步直接使用创建好的App的Install页面勾选需要接入的仓库即可。注意GitHub App的安装是按账户或组织维度的可以一次安装选定多个仓库也可以只选特定仓库。独立仓库建议只勾选真正要管的目标仓库。第四步是启动Hermes服务本身。我这里用的是Docker方案compose文件大概长这样services: hermes: image: hermesagent/hermes:latest ports: - 3000:3000 environment: HERMES_GITHUB_APP_ID: 123456 HERMES_GITHUB_APP_PRIVATE_KEY_PATH: /secrets/hermes.private-key.pem HERMES_GITHUB_INSTALLATION_ID: 987654321 HERMES_TARGET_REPOS: yourorg/yourrepo,yourorg/another-repo HERMES_LLM_PROVIDER: openai HERMES_LLM_API_KEY: ${LLM_API_KEY} volumes: - ./secrets:/secrets启动之后Hermes会通过GitHub API拉取历史PR数据做初始化索引。这一步耗时取决于仓库规模我们那个中等规模的Java仓库大概有两千多个文件初始化索引跑了差不多三分钟。索引完成之后它就算正式待命了。验证接入是否成功最直接的方式就是提交一个小PR。我会在测试仓库里改一行代码刻意在逻辑里埋一个明显的错误比如数组越界风险或者空指针隐患然后提交观察Hermes是否给评论。如果配置没问题一般会在PR提交后的半分钟到一分钟内看到机器人的审查评论。这里有个容易踩的坑如果你发现评论始终不来先查服务的日志有没有报GitHub API的权限错误。我之前就卡在Installation ID填错这个问题上填成了App ID导致认证一直失败日志里会反复弹出401。把三层身份信息搞清楚就好办了身份要素从哪拿作用App IDGitHub App General页顶部标识应用本身Installation IDGitHub App Advanced页面标识“安装到某个仓库”的这个关系Private Key应用创建时生成下载的.pem文件应用身份证明用于生成JWT4. 规则调优不是配参数是“教工具分轻重”很多人在接入这类工具后第一反应是去系统里关掉所有噪音型规则也就是把“代码风格”“命名规范”类的检查全部禁用只保留逻辑错误和潜在bug类。这种思路方向是对的但落到Hermes这个工具上它有个更细粒度的东西值得琢磨基于PR的“影响范围”动态决定审查深度。什么意思我的经验是一个改动20行工具类方法的PR和一个改动500行核心交易流程的PR它们的风险等级完全不在一个量级上审查的严格程度自然应该不同。Hermes的配置里支持按文件路径、变更规模、涉及模块来设定不同的审查策略。我第一次调的时候走了弯路给它设定的是统一审查深度结果小PR也被精细审查评论质量虽然不低但感觉有点杀鸡用牛刀大PR反而觉得深度欠点火候。后来我改成了分级策略思路也不复杂改动行数在50行以内且不涉及核心模块和生产配置的PR属于“轻量审查”。这一层级我只让它查真正的bug风险也就是空指针、资源未释放、明显的逻辑写反这类硬问题绝对不会对命名和代码风格指指点点。改动行数超过50行或者触碰了支付、订单、用户鉴权这几个核心模块的升级为“深度审查”。这时除了bug风险还会开启“变更一致性”审查也就是检查跨文件的调用链是否同步更新以及是否有“挂着羊头卖狗肉”的无关改动混进来。还有一个“仅记录”模式用在新人PR或者架构预研型PR上。这种模式下Hermes不做拦截但会生成一份审查报告留在PR页面上供后续人工review参考。这套分级玩法的核心配置文件里主要是opinion配置段。大致骨架如下review: levels: light: max_lines: 50 excludes: - *.md - *.lock checks: - critical_bug deep: checks: - critical_bug - cross_file_consistency - intent_alignment - edge_case_review monitor: comment_mode: summary_only这些配置项都不是表面参数每一项对应着Hermes内部不同的审查流水线。比如intent_alignment这个开关需要调用大模型对PR描述和实际diff做语义比对计算量明显高于轻量检查所以要在配置里保留它作为模块开关而不是全局强开。此外还有一个我觉得特别实用的配置维度是自定义“禁区”规则。每个团队都有一些明文规定但写不进静态检查工具里的规则比如“数据库表结构变更必须附带迁移脚本”“禁止在事务内调用外部HTTP接口”“日志里不得打印用户手机号”。这些规则如果只靠人记总会有人在某个周五下午赶工的时候忘掉。Hermes支持用自然语言定义这类规则它会作为审查时的额外约束条件。实测下来效果很好尤其是“禁止在事务内调用外部接口”这种规则它能根据代码里的事务注解和HTTP客户端调用做到语义级别的判断比正则匹配可靠得多。配置调优这件事我交了很贵的学费才明白一个道理没有任何一个审查工具开箱即用是完美的一周内不调参它就会从“帮手”变成“噪音源”。最好的调优路径是先观察一周的真实评论把那些被你人工忽略的低价值评论收集起来下周集中关掉对应的检查项或调整检查深度而不是一上来就铺一大堆规则。5. 实测记录它抓出了哪些人工评审容易漏掉的问题理论说再多不如看实战。我摘几个这一个月里Hermes在真实PR中给出的、让我觉得“这东西真没白接”的评论。第一个是事务内调用外部接口的问题。团队里一位后端同事在重构订单取消流程时在标注了Transactional的方法体里加入了一个调用外部物流平台的HTTP请求。从编译器视角看代码完全合法类型检查也没问题。但Hermes直接给出了一条高优评论指出当前代码在持有数据库事务锁期间执行了外部网络调用线上高并发场景下可能拉长事务时间造成连接池耗尽。这个判断不是看出来的而是它同时理解了Spring事务注解的语义、HTTP调用代码的特征、以及“外部服务不可控响应时间”这个通用风险模型综合推断出来的。这类问题人工reviewer如果没有被事务和网络问题坑过很难一眼发现。第二个是跨文件的不一致修改。另一个前端同事在优化一个React组件时把props的结构改了从props.data.items改成了props.data.list组件内部的消费逻辑也都同步调整了但有一处调用该组件的入口文件没有同步传入新结构而那个入口是动态加载的老页面。编译层面由于涉及的是不严格的类型文件没有直接报错但运行时一定会出错。Hermes的评论准确指出了这个跨文件不一致给出了具体文件路径和行号直接避免了一次线上回归。第三个是PR描述与实际改动的偏离。我们有次发布一个“添加导出功能”的PRHermes重点检查了导出功能相关代码域但发现diff中夹带了几个配置文件里关于数据库连接池参数的修改而这些修改干脆没有在PR描述里被提及。这个“顺手改动”的问题人工review通常都默认作者在PR里描述的范围内很少会逐行怀疑无关文件但Hermes会把PR描述和diff做系统性比对把不匹配的地方单独拉出来提醒。这种情况不是工程能力问题更像注意力管理的问题但机器真的能做到“不凭信任跳过文件”。第四个是边界条件的遗漏。有次改动是给搜索接口增加分页参数人工review可能会往前走请求是如何构造的、返回结构怎么定义但Hermes提示了一个我们没注意到的边界条件pageSize参数如果传入0或者负数当前代码会直接抛异常没有做参数校验和兜底。这个提法也不算高深但恰好是人脑容易遗漏的角落。我把这四周的评论数据简单统计了一下共审查了42个PR给出有效评论87条其中被我们人工评审采纳或直接修改代码的有61条占比约七成。剩余三成里有一部分是Hermes对业务语义理解不足导致的误报比如它不熟悉“临时兼容逻辑”这种团队内部的约定。还有一小部分是它对历史代码的“考古”不够完整给出了已经过时的建议。整体来说它的误报率比预期低尤其是在排除了太重度的风格审查之后。6. 常见故障排查从“没反应”到“评论乱飞”接入这类工具最怕遇到的就是三种情况完全不工作、间歇性不工作、工作得太亢奋。我分别踩过坑挨个说下排查思路。完全不工作的情况排除掉服务没启动这类基础问题之后八成是身份认证或权限配置问题。GitHub App的身份认证流程是Hermes先用App ID和私钥生成一个JWT再用这个JWT去GitHub换取Installation Token最后用Installation Token调用PR相关的API。这个链条上任何一环配置错了都会导致静默失败。最常见的错误是我前面说的把Installation ID填成App ID这种配置错误日志里基本会稳定出现401。间歇性不工作的情况通常是GitHub API的限流问题。GitHub对每个App的每小时请求数有配额如果你同时给多个大仓库开启了审查而Hermes初始化索引的时间又集中在一起很容易甩到次限流阈值。排查方法也简单看服务的HTTP请求日志里是不是频繁出现403里面会带Rate limit exceeded字样。解决思路有两个一是调低Hermes的并发请求数二是在GitHub App的Permission里勾选Metadata的Read权限Metadata请求的配额是独立计算的把它单独放开通常能缓解压力。“评论乱飞”的情况也就是一天发了几百条评论把PR页给刷爆的那种通常不是故障而是规则配置出了问题。我之前把light级别的max_lines设成了500也就是改动500行以内的PR都只做轻量审查结果一个大功能改动被划到轻量级Hermes在轻量级模式下的规则里又开了“edge_case_review”面对一堆复杂逻辑代码疯狂挑边界条件噪音量瞬间爆表。这里的教训是每一档审查级别的checks列表要严格收敛轻量级就只留最高价值的检查项要开深度检查就老老实实把PR划到deep级别。还有一个常见问题是评论里出现乱码或英文。这是LLM Provider返回内容的语言问题Hermes的配置里其实有语言偏好设置默认跟随PR描述语言但如果不是标准的英文或中文设置偶尔也会飘。我自己为了方便统一输出直接强制设了中文评论省得团队成员还要脑内翻译。排查路径我整理成一张简表作为SOP放在团队文档里现象优先排查点处理方式没有收到任何评论App ID、Installation ID、私钥路径逐项核对三个身份配置查看服务启动日志偶尔没评论GitHub API限流查看日志是否有403限流调整请求并发或单独配置Metadata权限评论大量重复是否多个Hermes实例在跑同一个仓库检查服务进程数确保只有一个实例对同一仓库负责评论内容乱码LLM Provider返回异常排查上游模型API的响应内容确认语言配置是否生效特定文件始终不审查配置的excludes是否误伤检查excludes规则里的通配符确认是否覆盖了预期的目录7. Agent化评审的边界哪些场景我会主动关掉它任何工具都有边界Hermes也不例外。用了一个多月我对它“能干什么”和“不能干什么”的认知越来越清晰也学会了对某些情况主动关闭它。第一种情况是纯重构型PR也就是只调整代码结构、不改变外部行为的大规模重命名或模块拆分。这种PR里涉及大量重复的机械性改动Hermes的审查价值很低还容易因为对“重构前后行为等价”的判断不够充分给出误导性意见。我的做法是给这类PR打上特定标签Hermes的配置里支持按标签跳过审查直接不干预。第二种情况是架构设计类PR。比如引入一个新的缓存中间件、定义一套新的跨服务通信协议这类改动本质上是在做“用代码表达的架构决策”。这种决策的好坏取决于对业务未来演进的判断目前任何自动化工具都难有发言权。Hermes对架构级PR能给出的意见通常停留在“连接是否安全”“事务边界是否合理”这类细粒度问题上但架构方向上的整体判断必须靠人来兜底。第三种情况是涉及对外承诺或合规约束的改动。比如要修改安全策略、隐私相关文案这些不是简单的代码质量问题而是法律和产品上的约束过度依赖机器审查反而会弱化相关角色的责任意识。还有一点我的体会是工具越强人的惰性就越容易滋生。有Hermes盯着代码里的基本问题后团队里一些新人开始出现“机器人看过了应该就没问题”的心态这就很危险。我在接入后的第二周就特意给Hermes加重了一个原则——它的评论里必须有明确的“解释”而不是结论。光说“这里有风险”毫无价值必须说明风险场景、触发条件和建议方案。这一步的目的不是让工具变强而是倒逼工具使用者保持审慎。我现在的定位是Hermes是一个“第一道关卡”的守门员它负责把所有低级、机械、确定性的问题过滤掉让人工reviewer的精力被释放出来集中在这个规格级别的讨论、代码风格的偏执、以及业务逻辑的合理性上。这种分工对我个人来说是效率提升最明显的部分。8. 个人经验选型前先想清楚这五个问题最后按我自己的习惯在工具选型或接入之前把最关键的问题抛出来。如果你也在评估是不是要有一套自动化PR评审工具先别急着看功能列表先把下面这五个问题和团队对齐能省下后面大量的调适成本。第一你们团队当前的评审瓶颈到底是什么如果瓶颈是“没人愿意review”那换任何工具都救不了问题出在流程文化上。如果瓶颈是“review耗时太长”才值得认真考虑自动化辅助。第二代码仓库的语言生态是否足够主流Hermes对主流语言及框架的分析深度远高于边缘语言冷门技术栈下它的判断精度会明显退化。第三你们能不能接受一定比例的误报任何基于语义理解的自动化审查工具都有误报率如果团队对误报零容忍那基本上就告别Agent化评审了。与其追求零误报不如训练团队快速辨别和删除无意义评论。第四谁来负责维护工具本身这类工具不是装上就能永久运行的规则会过时、模型会更新、仓库结构会变化必须有人持续关注它是否还在产出有效评论否则三个月后它就会变成环境噪音。第五你们是否具备“让评论有闭环”的机制Hermes提了一个问题后面解决没有、怎么解决的需要有记录和追踪。如果只是评论生成后就翻篇那工具的价值起码打了对折。我的整体感受是以Hermes为代表的Agent化PR评审工具正在把代码评审这件事从“人的注意力游戏”改成“机器前置过滤加上人做终审”的协同模式。这件事的价值不是让机器取代人而是把人的注意力从低水平重复劳动里腾出来放到真正精密的部分。前提是你要愿意花时间去调它、喂它、甚至忍受它前期的各种小毛病。我自己的实践路径是先在一个中等活跃度的边缘仓库试跑两周观察评论质量和团队的接受度然后再扩展到核心仓库。等再跑一段时间我可能会尝试把它的审查结果关联到团队的代码质量看板里看看能不能从数据层面验证这套协作方式对缺陷密度的真实影响这是下一步想做的事。
返回列表