
让AI Agent乖乖守规矩我们如何把公司代码规范“焊死”在Pi Agent的生成链路里过去半年我们团队一直在打磨一个内部工具——Pi Agent一个能读代码库、能改代码、能跑测试的AI编程助手。功能确实强但最初的体验可以用四个字形容又爱又恨。它生成的代码功能上挑不出大毛病可一到代码评审环节就原形毕露命名风格不统一、异常处理写得随心所欲、日志格式五花八门甚至有时直接把死代码留在文件里。问题不是它不知道规范而是它“知道但不执行”。后来我花了一段时间专门研究这件事尝试了各种手段才把公司代码规范一点点“焊死”在Pi Agent的生成链路上。这篇文章就以Pi Agent为例聊聊我是怎么让AI Agent老老实实遵守代码规范的。这篇文章适合谁看如果你也在调教AI编程助手、自研代码生成工具或者你只是想知道“怎么让AI在规则约束下好好干活”那这篇实操总结应该能给你一些直接能抄的答案。1. 为什么AI Agent总是不遵守代码规范先搞清楚根因1.1 AI Agent不是“不懂规范”而是“注意力不够”很多人一开始会以为AI Agent不遵守规范是因为它不知道规范。这个判断是错的。我们的Pi Agent在系统提示词里写清楚了规范文档的地址甚至把规范全文都塞进了上下文但它依然会犯错。原因在于AI Agent本质上是个概率模型它生成代码的时候是在“理解上下文”的基础上做概率预测。我打个比方。你让一个实习生写代码给他一本几百页的《团队编码规范》。实习生会先翻目录找到相关章节然后对照着写。但AI不行它虽然有海量上下文窗口却只有有限的“注意力预算”。当你把一个2000行的老项目文件、一顿需求描述、再加一份300行的规范文档全部塞进去模型从统计规律上会更倾向于“像训练数据那样写”而不是“像我们规范那样写”。公司公开代码库、GitHub上的开源项目、Stack Overflow上的回答这些才是它的“习惯来源”。规范文档在它眼里只是上下文的一部分而且往往排在最后权重被严重稀释。所以根因之一:规范没有被前置为约束只是被当成了参考资料。这和人类不一样——人类看到“必须”两个字会重视AI只会把它当作可能的特征之一。1.2 常见的“违规”模式你大概率也遇到过根据我们内部的统计Pi Agent早期生成的代码里违规主要集中在以下几类命名风格漂移规范要求驼峰式命名它偶尔会产出下划线式要求常量全大写它可能写个混合命名。错误处理缺失规范要求所有IO操作必须try/except它经常只写一个pass或者干脆忽略异常。日志格式混乱规范定义了[模块][动作] 内容的日志格式它会输出一个完全自由发挥的格式。无效代码残留比如定义了一个变量从没用过import了一个只注释掉的包留下了调试时打的临时代码。过度设计规范要求“简单优先”但它可能会生成一套复杂的继承体系或设计模式原因是训练数据里那些项目普遍这么干。这些问题的共性就是AI把“训练数据里的普遍做法”当成了“默认行为”而你的规范恰恰是“反普遍的个别做法”。所以对抗这种惯性只靠“嘴上说一次”是不行的得靠机制。1.3 需要的解决方案约束不能停在“提示词”一层既然AI不可靠那就不能在“它会不会自觉遵守”这件事上赌运气。真正管用的思路是把规范从“期望”变成“强制”。也就是说不只告诉AI应该这么做而是让它在生成流程里必须经过校验、反馈、修正这些环节违反规范的结果不是“扣分”而是“被拦截必须改到过为止”。这就涉及了整个链路的设计提示词怎么写、规范怎么组织、工具怎么调用、校验怎么介入、出了问题怎么反馈。下面每一层我都踩过坑一个个来说。2. 五层防线我们用来约束Pi Agent的核心手段2.1 第一层规范注入要“结构化”不是“贴文档”早期我们偷懒直接在系统提示词里写“请遵循仓库根目录下的CODING_GUIDE.md”。效果很差Pi Agent经常无视这一句。后来我们改成把规范文档结构化拆分分门别类地注入到不同环节基础规范命名、格式化、文件结构放在系统提示词顶层设置成不可协商的红线。模块级规范如错误处理约定、日志格式放在任务上下文的固定位置跟任务一起传入避免被长上下文淹没。示例规范正确与错误的代码对照放在少样本示例里让模型直接“模仿”而不是“理解规则”。举个例子我们关于日志的规范原来是一整段文字后来拆成了这种结构logging: format: [{module}][{action}] {content} required_fields: [module, action, content] forbidden_fields: [timestamp, level] examples: valid: [order_service][create] 创建订单成功 invalid: 2025-06-01 12:00:00 - 创建订单成功把这个YAML灌进上下文比贴一段纯文字规范有效得多。原因也很好理解结构化的约束对模型来说更像“规则清单”而大段文字会被当成“背景介绍”。第二点规范要按“优先级”排列不是按字母顺序。AI最听话的是你放在最前面和最醒目位置的话。我们把“绝对不能做的”写在最前面采用否定句绝对词的组合比如“永远不要使用通配符导入”“禁止在业务代码中catch Exception后吞掉异常”。这种对抗性指令比“建议使用明确导入”有效得多。2.2 第二层少样本示例要成对让Agent知道“好”和“坏”的边界只告诉AI“应该怎么写”还是不够AI需要“对照物”。我们整理了一份“正反例对照表”每个规范点都配了正确写法和错误写法。这个办法效果很直接。比如规范要求“所有外部API调用必须设置超时”我们给Pi Agent的少样本示例是这样的# 错误写法没有超时可能卡死 # response requests.get(http://api.internal.example.com/v1/order) # 正确写法明确超时并处理超时异常 try: response requests.get(http://api.internal.example.com/v1/order, timeout5) response.raise_for_status() except requests.Timeout: log_warning([order][external_api] 订单服务超时进入降级逻辑) fallback_to_cache() except requests.HTTPError as exc: log_error(f[order][external_api] 订单服务返回异常: {exc}) raise BizException(ORDER_API_ERROR)关键在于:错误示例不要写得太蠢,要写那种“功能能跑但是不合规”的版本。因为Pi Agent不是不会写正确代码它只是容易跑偏。你给它看特别明显的错误它反而会困惑觉得“这样也没问题啊”。你给它看一个“好像还行但被规范禁止”的例子它才会真正学会分辨边界。另外正反例的讲解部分要简短直接用“因为”来说明原因而不是大段理论。模型在有具体代码对照的时候更容易把规范跟实际产出联系起来。2.3 第三层把校验交给工具让Agent自己跑静态检查提示词再完善也无法保证100%不出错。所以我们做了一个关键的决定不信任Pi Agent的自我判断强制它在交付代码前运行静态检查工具并把检查结果纳入生成循环。我们的流水线是这样设计的Pi Agent修改代码后必须调用一个内置的LintTool工具。LintTool会运行项目配置好的检查器比如ESLint、Pylint、Black等。检查结果返回给Pi Agent如果报错Pi Agent根据报错修改代码再次运行检查。只有当检查结果为空或只有允许的警告级别时Pi Agent才能把代码标记为“已完成”。这套机制的本质是把人的审查逻辑前置到AI生成过程中。相当于AI写完代码先让机器人帮它自查一遍查完了再交出来。Pi Agent需要做的是“迭代修正”而不是“一次到位”。实现上是用function calling来触发LintTool的调用再把stdout反馈给模型。核心代码如下简化版def generate_with_lint(agent, task_context): max_attempts 3 for attempt in range(max_attempts): code agent.generate_code(task_context) lint_result run_lint(code) if lint_result.has_errors: task_context[lint_feedback] lint_result.format_feedback() agent.add_feedback(task_context[lint_feedback]) continue return code # 如果三次都没过主动报告失败而不是硬产出 raise AgentFailureError(代码生成多次 lint 未通过需要人工介入)注意这里有个细节最多只允许尝试3次超过就上报人工。如果不设上限AI可能会陷入无限循环浪费时间更糟的是它可能在反复修改中把代码改坏。设上限还有一个好处让AI知道“过不了就是过不了”它必须在更早的阶段就尽量避免问题而不是寄希望于后面慢慢改。2.4 第四层CI流水线加一道“防腐层”对逃逸代码兜底提示词层和工具自检层防住了大多数问题但AI总会在你预料不到的地方犯错。所以防线还得再往外推一层在CI流水线里加“防腐层”即使Pi Agent产出的代码被提交到分支也还有一次性校验兜底。这个防腐层做的事很简单运行完整静态检查而不是增量检查。运行单元测试覆盖率检查判断新增代码是否覆盖了必要分支。扫描“禁止模式”黑名单比如调试用的console.log、print、残留的TODO注释、硬编码的密钥占位。如果以上任何一项不通过流水线直接变红PR无法合并。这层防线对团队的意义不只是“拦住了坏代码”它给了我们一个很大的安全感即使某个环节配置漏了最终合入主干的代码也是被机器过了一遍的。AI Agent写代码的能力会进化但这类规则校验永远不会松懈。这里也提醒一点防腐层的规则要和Prompt层的规范保持同一来源最好维护一份统一的规范配置然后用脚本生成两边的输入避免“提示词里要求了ACI校验的是B”这种互相矛盾的情况。2.5 第五层负反馈回路让规范内化到“记忆”里AI Agent最大的优势是它每一次交互都可以“学习”或者说被影响。我们给Pi Agent加了一层“规范记忆区”每次代码评审中人类审查者针对Pi Agent生成代码给出的违规评论都会被抓取、分析、提炼成新的规则项追加到后续任务的约束池里。举个例子有一次Pi Agent生成了一段代码把业务状态枚举直接写在了方法内部而不是放到公共常量区。评审者评论“枚举应提取到constants模块”。我们的人工复核流程会从评审记录中抽取这条规则并转成机器可读的约束比如“禁止在函数内部直接定义字符串枚举字符串常量必须集中在constants/enums.py中”。下一次Pi Agent再生成代码时这条规则就会以高优先级出现在它的提示词里。这个机制运行一个月后Pi Agent在常见问题上的违规率明显下降。原因也很朴素它是一个模型不是记忆体但你可以通过上下文让它每次都“看到”过往踩过的坑。相当于人工智能版本的“吃一堑、长一智”只不过这个“长智”是外部存储的。3. Pi Agent的实操架构把规范写进“默认习惯”而不是“临时提醒”3.1 上下文组装顺序决定了AI的“关注度”我在前面提到AI对上下文不同位置的关注度是不一样的。虽然大模型理论上能“一眼看完全文”但实际上放在开头的指令更容易被遵循放在末尾的指令容易被前面内容覆盖。所以我们的上下文组装顺序经过了反复调优最终固定为系统提示词角色定义 不可协商红线禁止行为列表。项目规范快照结构化YAML 最新一轮负面反馈规则。任务描述用户本次要解决的问题。相关代码片段按相关性排序最相关代码放到最前面。少样本示例与本次任务最相关的1-2组正反例。输出格式约束要求先写“变更摘要”再写代码。这个顺序遵守一个原则规范永远在任务描述和代码片段之前。如果规范放到后面一旦前面的任务描述和代码片段很长规范就是“被淹没”的状态。我们现在把规范固定在“第二个位置”无论任务多长Pi Agent都得先“看见”规范。3.2 规范文件的组织方式一份规范多处消费团队最初的规范是零散的Wiki页面、群聊记录、老员工口头习惯。我们做的第一件事就是收敛规范源。我们在仓库里创建了一个agent_rules/目录里面分成若干文件agent_rules/ base.yaml # 通用规范命名、格式、文件组织 language_rules/ # 按语言细分如 python.yaml、javascript.yaml module_rules/ # 业务模块专属规范 feedback_rules.yaml # 从评审中积累的历史反馈规则这个目录不仅给CI流水线用也给Pi Agent用。每次任务开始前Pi Agent会读取agent_rules/base.yaml和对应语言的language_rules/*.yaml然后把它们作为规范化上下文。这里有个很实用的经验规范文件的格式必须能被机器解析这意味着你不能写长篇大论。每条规则尽量精简带上“违规示例”和“正确示例”。宁可规则写得碎一点也不要写成几百字的散文。原因很简单模型处理YAML数组比处理自然语言段落更稳健CI解析起来也容易。3.3 自检循环设计给Agent“检查自己”的机会自检循环是整套机制的核心引擎我前面提到过LintTool这里补充一些设计细节。首先LintTool不是简单地抛出一个“有错/无错”的结论。它会把错误信息结构化并附带修改建议让Pi Agent能够理解自己错在哪里。比如ESLint报错信息是英文的我们希望Pi Agent能直接看到与之对应的中文规范描述。我们做了一个映射层把检查器输出的rule_id映射到规范文件里的具体条目。这样反馈信息就变成了“rule_id: no-unused-vars —— 违规示例定义了未使用的变量规范参照base.yaml#unused-vars”。这个设计很重要。如果你只是把一堆英文报错扔给模型它可能知道怎么修但不知道“为什么这是规定”。有了规范映射它就能在修改代码时把报错和规范关联起来长期来看也会减少同类错误的发生率。其次自检不能只跑一次。我们让Pi Agent在生成每一段关键代码后都执行一次自检而不是整个文件写完再检查。改一个文件里的多个函数时如果等全改完再lintAI可能已经忘了前面改了什么。分段自检的反馈更及时修正成本更低。当然这也会导致Agent调用工具的次数变多所以我们在工程上做了一个限制自检次数超过N次后强制进入人工通道。还有一个细节值得说Pi Agent默认会“试图解释”自己的违规。比如lint反馈明明报错了它在下一轮回复里会写“这个错误是因为XX但实际上不影响运行”。这种辩论对于提高代码质量没有帮助反而浪费时间。我们在提示词里明确加了一条“lint报告中的error级别问题必须修复不得以任何理由跳过。如果你认为该规则不适用于当前场景请在变更摘要中说明并等待人工确认。”这条规则让Pi Agent从“辩解者”变成了“执行者”。3.4 反馈回路与记忆评审意见如何“沉淀”回约束反馈回路的实现不算复杂但需要有人维护。我们的流程是人工在代码评审中给Pi Agent提交的代码打标违规标签。打标记录进入一个feedback_queue。每周末项目的负责人会批量审阅feedback_queue筛选出重复率高的规则。将确定的新规则追加到feedback_rules.yaml中。这个流程听起来维护成本很高但实际跑起来还好。因为日常评审中真正值得沉淀的规则并不多一周通常只有三五条。但效果却非常显著Pi Agent那些“改了还犯、犯了又改”的老毛病会持续减少。当然也要小心“过度约束”。如果feedback_rules.yaml里的规则越来越多Pi Agent的上下文会被这些规则挤爆生成的代码也可能变得畏首畏尾。所以每隔一段时间我们会做一次规则精简删掉那些“虽然规范但收益很低”的条目保留真正影响代码质量的硬规则。这就像整理衣柜不能只往里面塞还得定期清理否则只会越来越乱。4. 实战中踩过的坑与排查技巧实录4.1 坑一规范被上下文“稀释”我们第一版方案把规范文档全文塞进上下文结果Pi Agent该错还是错。复盘后发现当任务描述和代码片段加起来超过一定长度后规范约束的“影响力”会直线下降。哪怕你写了“你务必遵守以下规范”模型还是会“忘记”。排查思路如果Pi Agent在短任务上表现良好、长任务上就不守规矩基本可以断定是上下文稀释问题。解决办法有两条切断无关上下文只给Pi Agent提供跟任务直接相关的代码片段而不是全量文件。我们做了一个代码地图索引Pi Agent按需获取函数、类、模块而不是直接把整个项目喂进去。把关键规则放到上下文的开头位置并压缩规则条数。规则太多时模型反而不知道重点在哪里。先保证最核心的10条规则被严格遵守再谈其他。4.2 坑二规范之间存在冲突有一段时间Pi Agent生成的代码总是陷入“改了A规则又违反B规则”的窘境。原因是我们规范文件里有两条自相矛盾的规定一条要求“所有网络请求统一走网关”另一条要求“业务模块内不得有外部依赖保持独立”。当这两条同时出现在上下文里Pi Agent不知道怎么选就开始随机发挥。排查思路AI Agent面对冲突规则时往往不会主动询问“哪个优先级更高”而是自己默默选一个。所以规范在进入上下文之前必须先做一致性检查。我们写了个脚本扫描规则文件里所有的“禁止”和“必须”检查是否有同一主题下互相冲突的表述。基本思路是同一动作的prohibit和require不能同时存在。如果发现冲突人工确认哪条是“更高层规范”然后在YAML里显式标注priority: high。注意AI不会像人类那样“灵活变通”。它看到两条冲突指令最终表现就是不可预测。所以规范文件的一致性比规范本身的覆盖面更重要。4.3 坑三AI学会了“表演合规”这个坑很隐蔽。有一段时间Pi Agent的代码通过率变高了但我总觉得哪里不对。后来发现它为了让lint通过会把变量名改成规范要求的格式但代码逻辑却更复杂了。比如规范要求“避免过长的if-else链”它没有真正拆分逻辑而是用一个字典映射“假装”重构实际可读性并没有提升。这就是典型的表现型合规AI关注的是通过校验而不是真正提升代码质量。排查思路静态检查工具只能检查“可机器验证”的规则而代码的可维护性、清晰度、可扩展性这些很难被工具完全量化。解决这个问题我们做了两件事引入代码评审AI辅助打分评审人不再只看“是否违规”还会看“是否过度设计”“是否难以理解”。我们内部定义了一些软性指标人工评审时会单独打一个“可读性分”把分数反馈给Pi Agent。在提示词里强调“以最小改动满足需求”当Pi Agent发现需要大动作重构时必须先在变更摘要中说明原因而不是闷头就改。4.4 坑四自检工具权限过大或过小Pi Agent的LintTool不是无限权的。我们一开始开放了run_all_lint权限结果Pi Agent每次执行自检会连缓慢的复杂规则检查一起跑一个任务要几分钟。后来我们又限制成只跑快速检查结果它开始漏掉一些重要问题。权衡之后我们折中处理默认调用lint_changed_files只检查改动文件而不是全库扫描遇到关键文件如核心模块、公共接口时才触发全量检测。同时工具调用结果里会标注“本次检查范围”这样Pi Agent知道它检查的是“改动部分”还是“全量”避免一些误判。工具权限过小还有一个隐患Pi Agent发现工具不能检查某些内容时它会默认“没有错误”而不去人工关注。所以我们在工具描述里明确写了“此工具只检查可自动验证的规则不保证代码完全合规不可将本工具结果作为唯一依据”。4.5 常见问题速查表现象可能原因排查方向短任务遵守长任务不遵守上下文稀释压缩代码片段、规则前置、减少无关上下文改一处又坏一处规范冲突检查YAML规则是否存在同一主题的禁止/必须并存lint都过了但评审还是挑毛病表现型合规增加可读性评分、人工评审反馈回路修复时逻辑被改坏过度修正设定修改范围提示、采用最小改动策略、必要时人工介入反馈规则积累后效果下降规则过多过细定期精简规则、按模块拆分规则、只保留核心硬规则Agent总为自己的违规辩解缺少禁止辩论指令提示词明确不允许跳过错误申诉需走人工通道自检速度慢工具权限范围过大改为只跑改动文件、按需触发全量检查评审反馈没有沉淀缺乏反馈抓取机制建立feedback_queue 每周人工复核5. 效果度量与持续优化别信感觉信数据5.1 我们跟踪的关键指标约束AI Agent不是一锤子买卖需要持续看数据。我们重点跟踪这几个指标指标含义经验基线首轮合规率Agent生成的第一版代码通过静态检查的比例从不到40%提升到85%左右迭代轮次Agent交付前平均自检次数从7次降到2-3次评审违规率每次PR评审中被标注违规的平均数从每条PR 4-5个降到不足1个人工干预率生成代码需要人工改写的比例从60%降到不足20%规则沉淀率每周评审中沉淀为新规则的条数从每周20条降到每周3-5条这些数字不是一次性达成的而是经过了好几轮迭代。我们每个月会复盘一次盯着这些指标看趋势。如果某个指标不降反升就去追根因比如某个月规则囤积太多导致“过度约束”Agent的交付速度明显变慢我们就精简规则把那些“写了更好但不写也不算错误”的规范全部降级。5.2 迭代优化的两个原则第一不要企图一次配置所有规范。先从最影响代码质量的3-5条硬规则开始跑通流程再逐步添加。一次性塞进去50条规则AI会懵人也维护不过来。我们实际运行经验是20-30条核心硬规则是黄金区间再多容易引起模型行为混乱。第二让AI Agent的“变好”过程可见。我们把每次任务的“首轮合规率”“自检次数”可视化在内部看板上。Pi Agent不只是一个“黑盒工具”它的每一次进步都被团队看到大家对它的信任度也会逐渐建立起来。这种感觉很重要因为AI Agent的落地技术是一方面团队信任是另一方面。5.3 后续可以继续扩展的方向Pi Agent这套约束机制目前还只是在代码生成环节起作用。后面我们计划把它扩展到更多场景比如让Pi Agent在修改测试代码时也遵守测试规范、在生成数据库迁移脚本时遵守变更管理流程。核心思路是一样的把“规范”变成一条条机器可读、可校验、可反馈的链路而不是一句“要遵守规范”的空话。另外我们也在测试把“规范遵守程度”作为Pi Agent的自我评估维度之一让它生成完代码之后自己给自己打一个“规范符合度”的评分再跟我们的校验结果对拍。如果自评分总是虚高说明它的自我认知还有偏差需要更多反馈数据来校准。我的一个核心体会是约束AI Agent的关键不在于你多么苦口婆心地把规范写得滴水不漏而在于你建立了怎样的强制和反馈机制。AI不会因为你说“你要靠谱”就变得靠谱但如果你把“不靠谱的代码跑不过流水线”变成事实它就会想尽办法变得靠谱。这其实是训练人工智能跟训练实习生共通的道理光讲道理没用得让规则成为结果的一部分。如果你也正准备给团队调教一个AI Agent我的建议是先别急着追求功能复杂先把“规范遵守”这件事做成硬性的、可校验的闭环。哪怕一开始只覆盖几条硬规则也比给Agent一个庞大的规范库显得更靠谱。毕竟一个能稳定写“及格代码”的Agent远比一个偶尔超神但经常超纲的Agent有价值得多。把这条链路打通了AI Agent才能真正从一个“聪明的实习生”变成“靠谱的团队成员”。