让编程智能体发现跨服务改动隐患
文章以字段重命名通过本地检查却破坏其他服务为例,说明智能体可靠性还依赖系统上下文、工具、架构约束和反馈机制。围绕这些外围设计逐层讨论修复方法及验证方式。
AI 深度解读
代码编译通过,测试全绿,AI 宣布完成,依赖同一个字段的另外两个服务却坏了。原文用这个例子解释 Harness Engineering:围绕模型搭建指令、上下文、工具、检查和权限,让 Agent 有机会发现并修复自己的错误。
它最有价值的结论是:可靠性交付不能只靠模型,也不能靠不断加规则。每项配置都要证明自己有用。对已经用 AI 改业务代码的程序员,这比再收藏一份超长提示词更值得花几分钟。
为什么代码全绿,改动仍然可能出错
原文给出一个公式:Agent = Model + Harness。模型负责推理,Harness 是包在模型外面的工作环境。其中一部分由工具提供,例如系统提示和文件搜索;另一部分需要团队围绕自己的代码库建设。
作者借用的分类很实用:行动前有引导(Guides),行动后有传感器(Sensors)。指令、技能和示例负责告诉 Agent 怎么做;测试、lint、类型检查和审查负责确认它做得对不对。
字段改名同时暴露了两边的缺口:Agent 没被告知字段属于跨服务契约,检查也没覆盖消费方。局部代码正确,不等于整个系统安全。
修复前,先看失败那次运行究竟读到了什么。如果其他服务从未进入上下文,继续强调「仔细检查」帮助有限。真正缺的可能是搜索指令、另一个仓库的访问权限,或者能捕获遗漏的检查。
Context Engineering 关注模型看到了什么;按本文采用的划分,Harness Engineering 还包括阻止、检查和修复。不过术语边界没有统一:HumanLayer 将后者视为前者的子集。实践中,先找信息和反馈缺在哪里,比争定义更有用。
规则会增加成本,检查也可能根本没生效
原文没有把 AGENTS.md 当成万能药。ETH Zurich 在 Python 仓库上的研究发现,指令文件总体没有可靠提高任务成功率,推理成本增加超过 20%,缩短文件也未改善结果。开发者编写的文件平均提升 2.4 个百分点,但不具统计显著性;研究认为,它更适合记录非标准编码惯例。
另一项覆盖 124 个 PR 的研究发现,AGENTS.md 让运行时间中位数下降 28.6%,输出 token 减少 16.6%,完成情况基本不变。两项研究的成本口径不同,不能直接比较效率结论。
因此,规则应该写团队特有、Agent 难以自行发现的事实。例如:orders/schema 的字段属于公开契约,改名前必须搜索其他服务并列出读取方。
OpenAI 的文件约 100 行,主要作为 docs/ 的目录;HumanLayer 控制在 60 行以内。这些是实践选择,不是最佳行数。原文还注明:Claude Code 优先读取 CLAUDE.md,从 v2.1.277 起,项目没有该文件时回退读取 AGENTS.md;大型仓库可以用嵌套 AGENTS.md 放置局部规则。
真正兜底的是独立契约检查。下面这段 TypeScript 使用 Vitest 和 Zod,检查消费方依赖的顶层字段是否仍然存在:
// contract.test.ts: runs in CI.
// This file, contracts/ and the CI job sit outside the agent's write access.
import { test, expect } from "vitest";
import { OrderSchema } from "../orders/schema";
import consumers from "../contracts/consumers.json";
// { "billing": ["customer_id", "total"], "shipping": ["customer_id", "address"] }
test("every field a consumer reads still exists", () => {
const fields = Object.keys(OrderSchema.shape);
const broken = Object.entries(consumers).flatMap(([service, needed]) =>
needed.filter((f) => !fields.includes(f)).map((f) => `${service} reads ${f}`));
expect(broken, `${broken.join("; ")}: keep the old name or update the consumer`).toEqual([]);
});
要看的是 Object.entries(consumers):预期来自消费方清单。若只遍历修改后的 schema,就可能连被删掉的字段也一起忘掉。原文用 Vitest 5 验证了失败与恢复,但这个示例只检查顶层字段存在性,生产环境还要比较类型、必填约束和真实接口。
决定任务是否完成的检查,必须处于被检查 Agent 的写权限之外。
测试、消费方清单和执行它们的 CI 步骤都需要保护。Agent 可以编写业务测试,却不能顺手修改验收标准让自己过关。
检查还必须把失败送回 Agent。作者记录过退出码为 1 却没传回消息的 hook、无法匹配 Edit 的 edit|write,以及脚本路径拼错后返回的退出码 2。看起来配置好了,不代表链路真的通了。
反馈要成功时安静,失败时说明原因和修法。HumanLayer 曾让每次修改后的完整测试输出塞入上下文,4,000 行通过日志反而干扰任务。
怎样验证这套配置值得保留
作者提供的工具包先运行 python3 kit/selftest.py,说明见 kit/README.md。它在临时副本上比较有无 hooks 的结果,也检查受保护文件是否改变。
11 月 3 日,Claude Code 2.1.292 下,Sonnet 5.5 的 8 次破坏性改动测试全部守住检查,其中演示仓库和作者仓库各 4 次;无 hooks 的 4 次对照全部留下破坏。Opus 5.5 收到了反馈,但在作者仓库的两次运行里坚持保留用户要求的改名,测试仍失败。所有运行都未改动受保护文件。后来换成 2.1.316,Sonnet 两次运行中又有一次在被 stop rule 退回后仍留下破坏。
这说明「阻止结束」和「成功修复」是两件事,也说明版本必须进入实验记录。
更系统的验证分四组:A 保持原配置,B 只加指令,C 只加检查,D 两者都加。收集十个左右真实失败任务,保留部分任务不参与设计;四组用同一套 Agent 看不到的验收测试评分,每项重复运行。
记录通过数、可信检查确认完成数、人工纠正次数,以及 token、时间和成本。新增检查不能兼任唯一评分器,否则 C 组天然占优。这种几十次运行的试点适合发现大效果,无法证明微小提升。
上下文管理也要接受同样检验。先清理旧工具输出,再考虑压缩对话或外部笔记;摘要应保留失败方案及原因。工具定义按需加载,在 Anthropic 示例里减少约 85% 的相关 token。子 Agent 可消耗数万 token,把结果压到 1,000–2,000 token,但检索错误也可能被压成自信结论。
记忆同样不是越多越好。Databricks 内部基准中,无记忆、可搜索原始记录、提炼经验、两者结合分别得到 22.3%、35.8%、66.1%、68.4%。这是其内部系统的结果;可借鉴的是整理经验并设置复查日期。
跨会话任务则需要完成清单、进度文件和可回滚提交。Anthropic 的实验用 JSON 保存功能清单,初始全部标为失败,每轮先读进度、检查基础功能,再继续工作。
我的判断
我认同「每条规则都要挣到自己的位置」。对前端和全栈团队,公开字段、共享类型、跨服务接口,比通用的「遵守最佳实践」更值得进入规则与检查。
但这篇没有证明某套 Harness 普遍最优。指令研究未发现稳定的成功率收益;作者的 hooks 实验样本少,模型和版本变化后结果也发生了变化。100 行、60 行这样的文件长度属于经验,不能当阈值。
权限层次的区分也成立:指令提出要求,hook 执行脚本,deny rule 阻止匹配工具调用,sandbox 限制实际可访问资源。它们的保证不同。原文提醒 hooks 以完整用户权限执行 shell 命令;deny rule 也可能被其他工具路径绕开。公开 API、迁移和跨仓库变更,仍需要匹配风险的人工确认。
成本更不能省略。Anthropic 研究系统里的 Agent 约消耗聊天模式 4 倍 token,多 Agent 约 15 倍,并非所有项目的固定倍率。连接器、第三方 skill 还可能带入恶意指令,读过一次只能降低风险。
原文的时间标注也有疑点:文末称链接和引文于 2026 年 10 月 22 日核验,正文却记录了 11 月 3 日实验及后续版本结果,没有解释更新过程。版本结论应按具体运行记录理解。
能拿来做什么
- 从最近一次 AI 改坏代码的任务入手,先确认它是否读到关键依赖,再选择补充一条项目规则或一项独立检查。
- 对 Node 服务的共享 schema,维护消费方契约并接入 CI;失败消息写清哪个服务依赖哪个字段,以及允许的修复方向。
- 花 10 分钟清理 AGENTS.md:移走长篇说明,只保留难以自行发现的命令、约束和文档入口,再加入最近一次遗漏的规则。
- 给长期任务保存明确的完成清单和进度记录;更换模型或版本后,重跑固定任务集,只保留确实改善结果的配置。