跳转到主要内容

Agent 系统中的技术债累积在提示词里

Agent 代码库的腐坏方式不同:债务集中在提示词、工具 schema 和无人校验的隐式约定中。

一张电路板的微距照片,显示走线、焊点和表面贴装元件,景深较浅

债务不在 linter 检查的地方

传统软件把债务累积在编译器最终会抱怨的地方:重复的逻辑、过时的接口、没有文档的不变量。Agent 系统把债务累积在没有任何东西会抱怨的地方。提示词是一个字符串。工具 schema 是一份 JSON 文档。关于哪个 agent 拥有哪项决策权的约定,存在于一份第二个 sprint 之后就没人再读的设计文档里。

这不是风格问题,而是结构问题。当决定系统行为的产物是无类型、无版本的散文时,每一次改动都是静默的改动。没有任何东西构建失败。系统继续运行。它只是运行得不一样了,而这个差异要在几周之后才会被发现——当下游某个 agent 开始产出看起来合理、却以某种具体且可复现的方式出错的输出时。

在多个 agent 之间重复、且已静默分叉的提示词片段

一种常见模式:诸如「始终引用源文档」这样的共享指令被复制进四个 agent 的提示词。六周后,其中三个被改过。一个现在写的是「在可用时引用源文档」。另一个写的是「如果检索成功则引用源文档」。第四个没动。没有任何测试失败。有条件引用的 agent 和无条件引用的 agent 产生不同的审计轨迹,而这个差异只有在有人试图跨流水线对账输出时才会浮现。

债务不是重复本身。重复很廉价。债务是缺少一个能检测分叉的机制。一个在构建时导入的共享提示词片段会让分叉变成一次 diff。一个复制粘贴的片段让它变得不可见。

不再匹配其所封装服务的工具 schema

工具 schema 是一份契约。当底层服务发生变化——某个字段被重命名、某个可空字段变成必填、某个错误以 200 加一个 status 字段的形式返回——schema 不会自我更新。agent 继续用旧的形状调用这个工具。服务要么拒绝这次调用,此时 agent 会重试并烧掉 token;要么接受它并返回一些 agent 会误读的东西。

第二种情况更糟。一个大声失败的工具是一个会被修好的工具。一个安静失败的工具会产出自信而错误的输出。这是 agent 系统里等价于「返回 null 而不是抛异常」的那种函数。

关于哪个 agent 拥有哪项决策权的无文档约定

多 agent 系统会发展出隐式的归属关系。一个 agent 决定何时升级。另一个决定何时重试。第三个决定何时总结。这些决策很少被写在一个地方。它们从提示词、编排代码以及 agent 被加入的顺序中涌现出来。

当引入一个新 agent 时,它不继承其中任何一项。它做出自己的决策,有时与既有 agent 冲突。这个冲突不是任何一个 agent 的 bug,而是一份缺失的规格说明。系统现在对同一项决策有了两个所有者,而如何解决取决于执行顺序。

Code on screen dark

这是最难看见的一类债务,因为它不在任何单一产物里。它在产物之间的缝隙里。

让它可见

补救办法不是写出更好的提示词,而是让提示词、schema 和约定接受与代码同等的纪律约束。

把提示词当作有所有者和变更日志的版本化产物

提示词应该住在仓库里,而不是住在通过管理面板编辑的某个数据库行里。它应该有一个所有者——一个团队或一个角色,而不是某个人——以及一份记录了什么被改动、为什么改动的变更日志。变更日志比版本号更重要。一次没有理由说明的提示词 diff,是一次会被下一个看不懂它的人回滚掉的 diff。

版本化还使回滚成为可能。当一次提示词改动降低了输出质量时,能否回退到一个已知良好的版本,就是十五分钟的修复和数天的排查之间的差别。

用真实端点检验工具 schema 的契约测试

工具 schema 应该像测试一个 API 客户端那样被测试:调用真实端点,并断言响应符合 schema。这不是一个带 mock 的单元测试。mock 把 schema 编码成写 mock 时它所被理解的样子,而这恰恰就是那个需要被证伪的假设。

针对工具 schema 的契约测试断言三件事:端点接受 schema 所声明的输入形状;响应包含 schema 所承诺的字段;错误条件以 agent 能够据以行动的方式暴露出来。第三条断言是最常被跳过的,也是最重要的,因为一个无法区分瞬时错误和永久错误的 agent,会一直重试一个永久错误,直到耗尽预算。

一份把每个 agent 映射到其工具、记忆作用域和升级路径的注册表

注册表是归属关系的唯一事实来源。对每个 agent,它记录:它可以调用哪些工具、它可以读写哪些记忆作用域、以及在什么条件下它会升级。注册表不是文档,而是编排层读取的配置,因此一个 agent 无法调用它并不拥有的工具,也无法写入它并不持有的记忆作用域。

这把一项隐式约定转化为一项被强制执行的约定。取舍是真实的:注册表增加了一层间接性和一份维护负担。每新增一个工具都需要一条注册表条目,而每一条注册表条目都是一个潜在的故障点——如果它与代码发生漂移的话。另一种做法——让归属关系保持隐式——在第一次冲突决策出现之前都更便宜,而一旦出现,诊断的成本就会以很大的幅度超过注册表的成本。

Fiber optic cables dark

重构规则

如果某个行为很重要,它就属于代码或 schema,而不属于提示词里的散文。

这就是全部规则。它说起来容易,做起来难,因为提示词是阻力最小的路径。往提示词里加一句话,比往 schema 里加一个字段更快。那句话立刻生效。而 schema 需要一次迁移、一个测试和一次评审。

这条规则不是对散文的禁止。提示词需要散文来处理语气、框定,以及那种抗拒形式化的引导。这条规则是一条边界:散文用于那些可以变化而不会破坏系统的东西。schema 和代码用于那些不能变化的东西。

一个有用的检验:如果这个行为是你愿意为它写测试的东西,它就不属于提示词。如果你不会为它写测试,它可能属于提示词。测试就是那条分界线。

这要付出什么代价

诚实的取舍是:这套纪律会拖慢第一个版本。一个有所有者、有变更日志的版本化提示词,比一个在仪表盘里编辑的字符串上线更慢。一个契约测试比一个 mock 写起来更慢。一个注册表比一项约定搭建起来更慢。

回报不在第一个版本,而在第五个版本。改动成本低的 agent 系统,是改动清晰可读的系统。清晰可读来自那些可以被 diff、被测试、被拥有的产物。住在仪表盘里的提示词写起来便宜、改起来昂贵。住在仓库里的提示词写起来昂贵、改起来便宜。选择在于付哪一笔成本,以及什么时候付。

对于在生产环境中运行 agent 系统的团队来说,相关的问题不是债务是否存在。它存在。问题是它是否可见。一个已经静默分叉的提示词片段是不可见的债务。一个有版本、有所有者、有变更日志的提示词片段是可见的债务,而这是唯一一种能够被偿还的债务。

总结

Agent 代码库的腐坏方式不同。编译器不检查提示词、工具 schema 或归属约定,所以债务在没有任何信号的情况下累积。让它可见,需要把提示词当作版本化产物、用真实端点测试工具 schema,并维护一份 agent 能力与升级路径的注册表。重构规则很简单:如果某个行为很重要,它就属于代码或 schema,而不属于提示词里的散文。成本先付;回报在之后的每一次改动中兑现。

封面照片:Arturo A / Pexels。

分享XLinkedIn永久链接7 分钟阅读

这能回答的问题

Why does technical debt in agent systems concentrate in prompts?

Because prompts are untyped, unversioned prose. Nothing compiles them, nothing tests them, and nothing detects when two copies of a fragment diverge. The debt accumulates silently until a downstream output is wrong in a reproducible way.

What is a contract test for a tool schema?

A test that calls the live endpoint the tool wraps and asserts three things: the endpoint accepts the declared input shape, the response contains the promised fields, and error conditions are surfaced in a way the agent can act on. It replaces mocks that encode stale assumptions.

What should an agent registry contain?

For each agent: the tools it may call, the memory scopes it may read and write, and its escalation path. The registry is read by the orchestration layer, so ownership is enforced rather than documented.

When should behaviour live in a prompt rather than a schema?

If you would write a test for the behaviour, it belongs in code or a schema. If you would not, it may belong in a prompt. Prose is for tone and framing; schemas are for anything that must not vary.