首页 / 文章 / 从散文规则到机械门控:强化Claude Code智能体团队。

从散文规则到机械门控:强化Claude Code智能体团队。

多智能体Claude Code插件如何逐版本用脚本、钩子及哈希化证据替代被忽略的角色指令,以及你可以复用的内容。

4332 词

任何让编程智能体运行几周以上的人都会遇到这种情况:系统提示中存在某条规则,智能体会读取它,但就在这条规则起作用的关键时刻,它依然会做出被禁止的操作并报告成功。重新表述规则、将其大写或加上“重要”之类的标记,往往无法长期解决问题。本文追踪了一个开源的 Claude Code 插件 blackgoat-agentskills 的十五个版本发布历史,展示了其维护者最终采用的解决方案:每当现行的文字指令被违反时,就用需要执行或打开的操作来替代它。读完本文后,你应该能够识别出自己设定的智能体规则中哪些还只是愿望,并掌握几种将其转化为实际约束条件的具体方法。

起点:一支专家团队

该插件将软件开发工作组织成由多个专业代理组成的团队。这些角色包括需求分析、架构设计与规划人员;两名开发人员;负责测试、代码审查和安全审计的人员;发布工程人员;以及一名负责编辑其他代理的元工程师。在主 Claude Code 会话中运行的协调器会将任务分配给这些代理。每个专业人员都在独立的上下文中工作,并返回结构化的任务交接文档,而非自由形式的聊天内容。

1.0.0版本提供了十三种角色模型和五种流程,涵盖发现阶段(/bgpdd-discovery)、规划阶段(/bgpdd-plan)、简化路径版本(/bgpdd-lite)、构建阶段(/bgpdd-build)以及发布阶段(/bgpdd-shipping)。此外还包含一个单智能体错误修复命令、一组仅在需要时才会被调用的方法论技能、一个评估工具,以及一项早期的确定性检查:即覆盖率检测,用于确认每一个“必须满足”的需求都对应有通过测试。

当时的设计假设是合理且常见的:只要每个角色模型都编写得当、每种方法论都很清晰,智能体就能正常工作。几乎每条规则都是一段文字描述,而几乎每个判定结果都是报告中的一句话。此后的发展历程便是逐步打破这一假设的过程。

拆分试图同时处理三项任务的智能体

最初的问题并非不服从指令,而是任务过载。测试角色奎因拥有三种模式:在探索阶段研究旧功能的表现、测试新版本,以及在发布前验证准备情况。将这三种任务集中到同一个角色身上后,生成的提示信息长达约5,000字,结果这个智能体在每项任务上的表现都很一般。

1.1.0版本将这一角色拆分为三个。Echo在探索阶段负责逆向分析现有功能的表现;Vera负责发布前的检查清单;而奎因则只承担一项任务:测试版本。

同一版本还包含了两个值得借鉴的运行优化修复。由于程序会因卡住的进程而无限挂起,现在每个智能体执行shell命令时都有四分钟的超时限制。此外,被标记为与安全相关的里程碑现在除了常规的代码审查外,还会由安全审计工具Cipher进行并行审核。

这一现象与人类团队中的情况类似:承担多项互不相关职责的角色往往只能获得模糊不清、内容冗长的任务说明。对于大型语言模型智能体而言,这种“稀释”是实实在在的,因为每条额外的指令都会在同一上下文中争夺注意力。

一份看似完美实则不完美的报告

1.2.0版本的发布源于一个包含五个里程碑的构建过程,该过程虽然报告成功,却隐藏了大量问题:

  • 有四个检查脚本,但既没有包管理脚本也没有持续集成任务会调用它们
  • 那些断言过于空洞,以至于从未有过任何检查因这些断言而拒绝通过
  • 一份因文件存在而将各项标记为“通过”的测试报告,其中还填充了编造的细节
  • 在审核人的“要求修改”判定仍然有效时,却提交了三个里程碑
  • 令人不安的是,规则早已涵盖了所有这些情况。“绿色状态并非证据”这一规定正在生效,障碍记录表也在使用中,系统已读取这些规则并继续执行流程。

    作为回应,项目制定了第一组可核查的前提条件:

    • 在有人亲眼看到某个检查点因故意违规而失败,并将该失败结果保存下来之前,不得信任该检查点。
    • 一个计划若要声明验证脚本,就必须同时指定对应的清单条目以及将运行该脚本的持续集成任务。
  • 要提交一个里程碑,需要读取两个文件:最新的审查结果必须是“通过”且时间晚于差异对比的时间,同时阻塞项数组必须为空。
  • 针对严重问题的修复方案需要重新进行测试和审查,而不能直接加在现有任务之后。
  • 每条“通过”记录都必须包含实际运行的命令及其完整的输出内容。
  • 随之还带来了两项流程变更。所有任务都开始在后台运行,因为某个阻塞性任务使得调度器在整个期间都无法被访问,从而导致漫长的处理阶段看起来与程序挂起无异。此外,现在每个代理在运行开始时都会创建自己的输出文件,并在运行中断后丢弃之前生成的所有内容,再逐部分填写该文件。

    第一个前提条件值得重点强调。从未出现失败情况的检查结果,根本没有任何理由让人信任;这其实与观察新的单元测试在变为绿色之前先变成红色这一现象是相同的原理,只不过这里应用在了工具本身上。

    2.0.0版本发布:将指令转化为程序

    1.2版本的那些前提条件虽然有所改进,但依然只是文本形式。“执行两次文件读取”只是一种指令,在后来的一次运行中,尽管存在“请求变更”被否决的情况,Orchestrator仍连续完成了三个里程碑任务。

    同时出现了另外两个问题。由于有位开发人员将架构设计、API开发与界面设计的工作混在一起处理,导致某个Vue UI版本的唤醒载荷达到了51,000个字符;而且该版本在分页功能、文本输入框以及自动补全字段方面表现较差。与此同时,在同一个分支上并行运行多个开发工具会导致HEAD指针不断被覆盖,因此每次验证都需要重新检查所有变动内容。

    提交审核机制变成了脚本

    check_commit_gate.py现在承担了原先人工操作的任务。它会读取审核结果令牌,确认审查版本比变更内容更新,检查阻塞问题清单,然后直接执行提交操作。最关键的一点在于:由于只有这个脚本才有权限提交代码,因此绕过审核机制就变得显而易见——根本不会产生任何提交记录。

    按领域划分的开发者

    Mason负责处理后端相关任务,而Nova则负责UI方面的工作。在规划阶段每个任务都会被标记,因此将任务分配给合适的开发者只是机械性的操作,无需协调器后续再做判断。

    不再有并行开发者

    并行处理的方式已被完全取消。每个任务只由一名开发者负责,这意味着只需验证一个变更版本即可。

    后续所有规则的制定原则

    代码仓库自身的说明也加入了一条关于规则的规则。换句话说:当某条文字规则在有效期内被违反时,不得重新措辞或加粗标注,而应将其转化为机械性的检查点。任何要求开发者在最想继续工作的时刻暂停操作的规则,都必须有需要运行或打开的文件作为支撑。

    这是整个项目的核心理念,其应用范围远不止于这个插件。如果你查看自己的 CLAUDE.md 文件或智能体指令,最容易出问题的规则往往就是那些要求在压力下保持克制的条款:不要立即执行,不要跳过测试,不要标记为已完成。如需了解该文件应包含哪些内容,可参阅我们关于编写高效 CLAUDE.md 文件的指南。

    定义何为有效证据

    2.0.0的第二个版本解决了更为隐蔽的问题。测试套件只能告诉你这些测试覆盖了哪些内容,却无法说明遗漏了什么。例如,进程内的测试主机无法告诉你真实客户端通过网络接收到的内容:序列化后的响应格式、中间件运行的顺序以及环境配置。那些开发者仅仅依据一个单元测试和一句断言就宣称某个功能已“通过验证”。

    三种级别的证据

    该项目定义了三个级别:

    • 第一级是单元测试。
    • 第二级通过内存中的传输机制将请求传递到真实的应用流程中。
    • 第三级则是使用真实客户端从外部观察正在运行的应用程序。

    需要第三级验证的声明绝不可能通过第二级验证来满足。相关规范清晰地说明了这种不对称性:过程内的观察结果可以用来推翻关于该组件的声明,却永远无法用于证明该声明的正确性。

    规划阶段确定的验证方式

    在规划过程中,每个里程碑都会被赋予一个验证方式标签,而该标签决定了各个检查点需要哪些证据。对于API接口,需要从进程外部获取的响应以及可实际访问的OpenAPI文档;而对于用户界面,则需要渲染后的输出结果。将诸如WebApplicationFactory或supertest这样的进程内测试客户端用作数据传输工具,会被视为检查点失败,而非巧妙的捷径。

    带有防篡改功能的辅助工具进行数据捕获

    证据是以捕获文件的形式收集的:通过一个安静的封装程序执行命令,将该输出与机器生成的辅助文件一起保存下来。辅助文件会记录参数列表、工作目录、进程ID、时间戳、真实的退出码以及两个文件的哈希值。Gates会重新计算这些哈希值,因此事后修改捕获文件会导致验证失败。

    这一标准随后被应用到所有需要以句子形式表达结论的场景中。那些仅显示“PASS, done”的覆盖率记录会被标记为“无证据”,并被视为未覆盖。安全检测和启动代理必须在其每条检查项后注明对应的捕获文件。同时,每个角色都有合理的退出方式:如果无法进行验证,结果将为“BLOCKED”,绝不会是“PASS”,并且必须说明缺失了什么。正如该项目所说,“已验证”只是一种描述,而非证据本身。

    被封禁的“逃生通道”与严格的规则同样重要。如果代理只有“通过”或“失败”两种选择,它就会面临制造“通过”结果的压力。赋予其合法的第三种状态能大大减轻这种压力。

    对审核者的审核:2.1.0版本

    在强化检查过程中新增的前置内容校验工具发现有两项技能的YAML描述无法解析却未报错。bgpdd-verify自发布以来从未被注册过,而doubt-driven-development从最初提交后也从未被注册过一次。在出现该校验工具之前,对这款插件的全面审核显示其在全部十八项指标上均表现良好。

    此版本中的修复措施都旨在消除检查表面声称要验证的内容与实际验证内容之间的差异:

    • 现在每次审计都会首先运行代码检查工具:在读取任何文本内容之前先解析文件。
    • 门控账本中的记录现在通过哈希值关联,因此可以检测到对记录的插入、修改或删除操作。
    • 标记里程碑为已完成的方式改为通过脚本实现,而非由模型输入三个字符。
    • 捕获文件中记录的探测客户端必须来自允许列表中的真实客户端。
    • 现在,渲染后的用户界面证据必须是真实的图像:不能为空,需包含正确的魔法字节,且生成时间要晚于被修改的文件。这一要求是在发现零字节的snapshot.png也能通过旧检测标准之后制定的。
    • 在示例代码块或附录标题下方出现的判定文本在确定审核结果时会被忽略。此前,示例代码块会悄悄替代真实的“请求更改”内容。

    这个截图案例很好地提醒我们:开发人员总是针对检查项实际要测试的内容来优化代码。如果检查项是“是否存在名为此名的文件”,那么最终就会出现一个零字节的文件。

    基于记录证据制定的缺陷修复流程

    最初的单一开发人员缺陷修复命令表现得就像一个仓促的开发者:读取代码、进行修改、运行测试、然后提交更改。在首次完整评估时,该工具甚至在任何检查点执行之前就提前十七分钟就将修复内容提交了。

    2.2.1版本将这一流程重新设计为六个阶段,每个阶段之间设置一个检查点:

    • 一份必须通过代码规范检查的缺陷报告。
    • 在修改任何代码之前由测试人员录制的红色错误画面,以便记录故障情况。
    • 一个由脚本而非模型决定的路由步骤,用于选择快速处理路径、完整处理路径或升级到计划阶段。
  • 修复方案本身。
  • 对相同命令的绿色版本捕获,通过脚本进行验证:该脚本要求两个版本的捕获结果都包含侧车进程、相同的argv参数,红色版本的退出码为非零,绿色版本为零,并且绿色版本更为新。
  • 由新的审查者进行审核,之后再通过提交检查。
  • 对于偶发故障,该流程可能需要由N个不同进程执行N次绿色版本测试,因为五次中有四次通过并不意味着故障已修复。而且构建工具根本无法进行提交操作。

    用于小规模修改的流程

    在2.3.0版本发布时,该插件能够很好地处理大型任务,但缺乏针对小型工作的流程。重命名、配置调整或新增单个测试都没有对应的流程,因此人们只能手动操作,而恰恰在容易出错的规模上,这种规范便消失了。

    新增内容:

    • /bg:这是一个入口,用于对每个请求进行分类并将其发送到特定的处理路径。
    • /bgpdd-quick:用于修改少于三个文件的场景。它不会生成任何处理节点,只需用户提供三行简短的说明、确认一次检查,最后通过一个关卡完成提交。
    • 一个始终处于激活状态的会话钩子,以便普通聊天会话也能知晓这些处理路径的存在。
    • 一个审查包:审查者收到的是已渲染并经过哈希处理的差异内容,而非工作树中的文件路径,在工作树中修复后的内容看起来就和原始状态一样,被删除的行也会不可见。

    即便没有处理节点,最后一点也同样重要。在文件的最终状态下进行审查会隐藏变更内容,而通过差异对比来审查则能显示这些变更。

    利用审计功能寻找下一个处理关卡

    2.4.0版本是在对2.3版本进行的21项指标审计基础上发布的,该审计发现了六项存在问题的指标。例如:安全检测和启动代理仍能在没有任何支持证据的情况下将检查结果标记为“通过”;同时也没有任何机制将捕获内容中的退出码与其侧车组件中的退出码进行比对。该插件的集成测试用例中甚至存在这样一种情况:捕获内容的侧车组件的生成时间比主内容晚223天。

    这些修复措施将声明与文件关联起来。现在,那些报告中的每项检测都会注明所捕获的内容,该内容必须附带侧车文件,且哈希值一致,并与该行标注的退出码相符。任何使用该捕获内容的检查机制还会将其内容与侧车文件进行比对。阻塞器记录表采用了包含严重程度和里程碑范围的结构化模式。团队还测得了触发器评估的成本,当时每次运行大约需要1.77美元和250秒的时间,并以此作为决定运行频率的依据。

    后来对2.6.0版本进行的审计使用了九种分析视角及相同的21项指标,共发现了23个障碍,这些障碍均在2.6.1版本中得到解决。其中有两个问题尤为突出:证据来源验证未能通过——开发者和审核者使用的是同一个证据目录,因此无法产生任何结果的审核结果可能会指向开发者的截图;而在缺乏浏览器相关工具的运行环境中,一个用户界面相关的里程碑也陷入了僵局:它无法满足相应标准,而系统又拒绝了唯一的替代方案,即仅通过审核源代码来解决问题。

    这些修复措施将证据目录按生成者分开,当没有可用浏览器时会让用户界面停止运行并询问用户,而非持续循环;同时严格要求捕获结果必须与其备注中说明的命令相匹配,不得有任何例外。通过将相关说明从核心人物描述中移至参考资料中,同时保留所有规则,从而简化了唤醒负载。变更日志还新增了“已知问题,未修复”板块,因为允许完全伪造的证据库通过提交检查这一限制应当被记录下来而非隐藏起来。

    从事后检查到事前拒绝

    在2.5.0版本之前,所有检查都在事后进行,模型仍可自行决定是否执行这些检查。像“通道处于活跃状态时不得手动提交”这样的规则依然可以被阅读但被忽略。

    答案是一个 PreToolUse 钩子,它在工具调用执行前进行拦截。它会拒绝:

    • 在某个工作通道处于活跃状态时手动执行 git commit
    • 在修复错误的过程中修改已存在的测试文件内容
    • 在输入数据尚未处理完成时启动子代理
    • 手动更改任何由关卡生成的文件

    为判断某个工作通道是否处于活跃状态,该钩子会检查磁盘上的状态文件,并将其视为有效状态持续12小时;它从不相信模型关于自身状态的描述。一旦出现任何内部错误,它也会立即终止操作。这是一种刻意做出的权衡:会中断会话的防护机制会被卸载,而未被安装的防护机制则无法发挥任何作用。

    此次发布还新增了一个驱动程序,它能自动触发下一个必做步骤,而无需依赖调度器来记住这些步骤;同时还加入了用于检查代理任务交接情况的验证工具。该验证工具会确认所引用的路径是否存在,列在变更清单中的文件确实出现在差异对比中,并能识别出诸如“阻塞”状态与标注为“无”的阻塞原因行之间的矛盾之处。

    处理功能间的衔接工作

    在2.6.0版本之前,多种常规工程任务完全缺乏标准流程,包括升级依赖项、引入功能标志、编写后台任务、增强可观测性以及修改API契约等。这些工作都是通过临时措施来处理的,快速通道团队也对项目的测试命令只能凭猜测行事。

    此次更新为这些领域增加了五项技能,每项技能都配有执行契约以及用于检查该契约的评估机制。现在,堆栈检测器会从代码库中提出检查命令和已冻结的测试代码块,由人工进行确认,而非由流程自动选择。对于 API 相关的里程碑,提交审核时还会运行 OpenAPI 对比分析,这意味着如果没有书面说明,就无法实施会破坏现有功能的变更。每当某个设计选择存在至少两种候选方案时,就必须制定相应的 ADR,同时还会通过代码检查工具确认设计记录中已提及该 ADR。最后,每种方法论都新增了“快速卡片”:针对三份或更少文件的变更,列出五条重要规则,并分别标注对应的完整章节,这样快速处理流程就可以加载简短的卡片,而无需查看整个契约。

    在习惯形成之前转化经验教训

    2.6.2版本是在一场真正的艰难挑战中诞生的。Quinn为同一个环境问题被重新分配了四次任务,耗费了约120万个令牌。虽然任务状态显示为“已完成”,但相关工件中仍满是待处理标记。而重新启动现有智能体却被记录为新的任务分配,从而导致运行日志膨胀。

    学习流程会提取三个经验教训,并在将其应用之前将每个教训转化为一个验证关卡。如果工件中仍存在临时结构,这样的任务就会失败验证。重新启动操作会被单独记录。而当障碍只有人类才能解决,比如缺少凭证或服务无法启动时,整个流程就会暂停,必须由人工发出明确指令才能继续。正是这种暂停机制才避免了120万令牌的浪费。

    检测会自我测试的测试用例

    2.7.0版本解决了其中一项相当令人担忧的问题。在某个实际项目中,测试流水线生成的20个Playwright测试用例中有13个是虚假的。这些测试用例会直接或通过page.evaluate调用重新实现被测函数,然后针对自己的副本进行断言。这样的测试每次都会轻易地从红色变为绿色,而颜色判定机制无法发现这一问题,因为这种同义重复的测试在两个步骤中都能通过。

    check_test_authenticity.py现在会在任何编写测试的流水线中每次捕获到红色结果时运行。它会检测四类虚假用例:

    • 未从生产代码中导入任何内容的测试用例
    • 直接内联实现的被测代码
    • 对源文本的直接评估
    • 用于替代真实应用程序的合成DOM结构

    通过与该真实测试套件进行校准,它能够准确识别出13个伪造的测试用例并接受7个真实的测试用例,且无需硬编码任何文件名。该测试方法还引入了所谓的“删除测试”:如果某个测试在删除其声称要覆盖的实际代码后依然通过,那就属于严重问题。这是一种快速的思维检查方法,可应用于任何测试,无论是否由人工编写;我们关于React测试反模式的文章介绍了测试套件如何造成错误信任的相关情况。

    另一款代码审查工具的经验教训

    在2.7.1版本中,维护者们研究了阿里巴巴的开放代码审查机制。据称,在公共审查基准测试中,该机制的准确率可达约34%,而使用相同模型的Claude Code在无辅助情况下的准确率仅在7%到16%之间。这些数据应被视为该项目当时对该基准测试的评估结果,而非独立测得的数值。有趣的是,两种审查标准几乎完全相同,差异仅在于一些辅助结构:一份必须逐一检查的固定文件列表、在审查者查看代码差异前会移除的生成文件、大小限制,以及一项事实核查环节,该环节只有在两种指定原因之一存在时才能放弃某项发现。

    同一版本中出现了两起评估问题。其中一个无头评估在找不到对应git仓库的测试用例后,开始在整个系统中搜索,并查询了真实的缺陷跟踪系统。而另一次通过插件实现的错误修复耗资11.06美元,却未能生成可用于检测有缺陷版本的测试用例,这意味着即便恢复原状也无人会察觉。

    由此产生的变更包括:

    • 如果审查部分出现任何未解决的严重或重要问题,提交审核环节将拒绝通过。实际上决策是根据这些问题来确定的,再通过正则表达式进行验证。
    • 如果没有为差异中的每个文件设置专门的审查流程,提交将被拒绝。
    • 审查工具会删除锁文件、压缩文件以及任意深度下的生成文件,列出被删除的内容,并且除非有人手动签署豁免声明,否则超过1,500行的差异也会被拒绝。
  • 在无头评估模式下,每次对开发人员的说明都会重复说明作用域前言内容,同时有警报机制可识别出任何超出工作区的运行实例。
  • 结果评估新增了一项标准:只有那些附带了回归测试的修复才能被计入有效修复,因为如果该修复被撤销,这些回归测试将会显示异常。
  • 变更日志审核发现有五个已发布的提交没有对应的记录,这些提交已被关闭。
  • 这种比较并非单方面的。另一款工具的51份语言规则文档中并未包含针对C#、Vue、PowerShell或SQL的内容,这些语言只能依赖通用的检查清单,而这正是该插件所支持的技能范围。

    再次阅读后,在2.7.2节中新增了三条精确性规则,这些规则的添加是在出现任何故障要求之前进行的。审核者可以阅读任何文件以了解背景,但发现的内容仅限于打包后的差异对比中所包含的文件;对于其他文件的观察结果则会被记录为Orchestrator的超出范围备注。数据库方法论新增了一条注入规则,明确列出了绝不能报告的内容,如参数化绑定和静态语句,因为对正确代码的错误检测会让审核者习惯性地忽略真正的异常。此外,安全方法论现在要求安全文档采用五部分结构,其中的每个OWASP类别都需要有引用依据或合理的“不适用”说明,因为留空行并不能视为一种判定结果。

    项目当前进展

    在撰写本文时,该插件拥有16种智能体角色、45项技能以及32个检测脚本,还包括1,656个自测题。所有这些检测都是确定性的,不会调用大型语言模型,并且会在每次发布前运行。评估套件包含69个案例,分为四个等级;结果等级是通过对比启用和禁用插件后的运行情况与隐藏测试的结果,而非检查是否有特定路径被触发。从第一个标签版本开始,119次提交共增加了约67,000行代码。

    维护者表示他们真正关心的指标并非上述任何一项,而是那些仍以文字形式存在、要求模型在最想继续执行时自我约束的规则数量。这一数字随着每次发布而减少,每次下降都源于该规则生效时出现的故障。

    关键要点

    • 将规则生效期间被违反的情况视为针对该规则的错误报告,并通过设置检查点来修复问题,而非使用更严格的表述。
    • 让脚本负责执行如提交代码这类不可撤销的操作,这样跳过检查时就会留下明显的缺失痕迹,而非悄无声息地通过。
    • 明确证据的等级要求,必须获取经过哈希处理的命令输出,而非仅有一句“已验证”的说明。
    • 为自动化处理程序提供合法的“被阻止”结果,这样编造“通过”的结果就绝非最简单的途径。
    • 通过故意违反规则来观察每个检查点是否失效,同时对这些检查点本身进行审计,因为现有的检查往往趋向于验证名称和文件是否存在。
    • 在危险工具被调用之前就加以阻止,但要将防护机制设置为默认允许通过的状态,以免有人试图将其移除。
  • 对生成的测试应用删除测试:如果移除生产环境代码不会导致测试失败,那么该测试就毫无价值。
  • 操作方法是一个循环:观察一次运行过程,找出被忽略的指令,用必须执行或处理的指令替换它,然后再观察下一次运行。
  • 相关阅读