跳到主要内容

你的 Agent 发布说明只是在列出文件,但集成商需要的是行为差异(Behavior Diffs)。

· 阅读需 14 分钟
Tian Pan
Software Engineer

一个平台团队在周三下午发布了他们的每周智能体 (agent) 版本。内部更新日志写得很尽职:三次系统提示词 (system-prompt) 提交,模型别名从 -0815 快照升级到 -1019,四处工具描述修改,新的评估准则 (eval-rubric) 权重,以及更新后的检索器索引。到了周五,支持队列里出现了 18 个工单,平台团队中没人能把这些工单与变更对应起来。工单 2 和 7 说 “机器人突然拒绝总结私有仓库”。工单 11 说 “输出中的每个代码块现在都带有语言标签,我们的下游解析器因此崩溃了”。工单 15 说 “在长输入下工具 X 的调用频率翻了一番,我们触及了速率限制”。

这些工单没有一个提到更新日志中的任何一行。平台团队的发布说明是一份文件移动清单。集成方的工单是一份行为变更清单。这两份文档互不交集,而信任就在这个鸿沟中流失。

这是智能体发布问题的一个缩影。一个 “智能体” —— 指的是提示词、模型、工具、检索器和评估准则的编排系统,作为一个单一产品交付 —— 向其使用者暴露了一个行为表象 (behavioral surface)。工程更新日志追踪的是产生该表象的代码。而集成方则是针对表象本身进行编码。当更新日志与表象不同步时 —— 每次发布都会发生这种情况,因为没有人负责翻译 —— 捆绑发布的版本就会变成一场波及所有依赖团队的协调性生产事故。

发布是捆绑包,而非部署

将智能体发布视为普通的部署是第一类错误。普通部署发布的是一个代码单元并继承了一份契约:相同的 API、相同的响应格式,且没有消费者未同意的行为变更。而一个智能体发布同时交付了至少五种不同的产物,每一种都会以任何单一 Git diff 都无法显示的方式扰动行为表象:

  • 系统提示词编辑 (System-prompt edits)。增加一行以减少模棱两可的回答,会改变对边缘问题的拒绝率。增加一行以强制 JSON 输出,会改变空格、转义以及模型添加前导词的频率。仅凭 diff 无法测试出这些影响。
  • 模型别名升级 (Model-alias bumps)。即使在同一个供应商系列中,从一个快照升级到下一个快照也可能改变语气、冗长度、指令遵循度以及工具调用频率。供应商自己的更新日志(如果存在的话)使用的是内部评估的语言;而集成方需要的是投射到你产品行为表象上的变化,这是另一份文档。
  • 工具描述微调 (Tool description tweaks)Anthropic 的工具编写指南明确指出,描述字段不是文档 —— 它是提示词的一部分,引导模型何时调用工具。收紧或放宽描述的措辞足以让某一类输入的调用频率翻倍或减半。
  • 评估准则调优 (Eval-rubric tunings)。调整准则权重会改变哪些提示词被视为通过,这意味着发布期间的准入门槛决定发生了变化,这意味着之前未通过门槛的行为现在通过并发布了 —— 而面向模型的代码行根本没有变化。
  • 检索器索引重建 (Retriever index rebuilds)。使用新的分块方案、更新的嵌入模型或更新的语料库重新编制索引,会改变智能体最终用于回答问题的参考文档。上周返回相同答案的两个查询现在由于检索顺序的变动而产生了分歧。

这些都是正当的工程变更。但它们共同构成了一个发布捆绑包,集成方无法通过阅读文件 diff 来预测其行为。“捆绑包” 是消费单位,但 “diff” 是编写单位 —— 而单位错误的更新日志对读者来说在操作上是毫无用处的。

文件 Diff 是错误的衡量货币

工程更新日志对库文件有效,是因为文件 diff 和行为差异是紧密耦合的:函数重命名是可见的,参数更改是经过类型检查的,返回格式的变化会破坏编译。更新日志可以列出文件编辑,并相信消费者会推断出行为变化 —— 有时通过阅读 diff,更多时候是依靠类型系统在集成时捕捉破坏性变更。

智能体没有这种耦合。系统提示词没有经过类型检查。工具描述没有在集成方的 CI 中进行单元测试。检索器索引没有在索引偏移时报错的模式 (schema)。评估准则是内部的。这些扰动都不会出现在集成方的编译步骤中。它们直接出现在用户的屏幕上。

因此,更新日志必须完成类型系统本该完成的工作。它必须将文件编辑转化为集成方实际会观察到的行为变更 —— 并且必须使用集成方能够与其自身产品表象进行匹配的词汇表。

这种翻译不是通过撰写散文摘要来实现的。写下 “改进了格式一致性” 或 “收紧了工具使用指南” 与供应商模型发布说明属于同一种营销文案,且具有同样的缺陷:它告诉集成方某些东西朝着平台团队认可的方向移动了,却隐瞒了预测集成方下游系统是否会崩溃所需的信息。一份有用的行为更新日志不是将工程更新日志重新起草为友好的语言。它是一份不同的文档,源自不同的源头。

集成商真正需要的四个维度

行为变更日志(behavior changelog)应围绕集成商编写代码时所依赖的可观测行为维度进行组织。大致有四个维度:

Prompt-output 形状。响应的结构属性——JSON 与散文的对比、长度分布、代码块格式、前导词或后置词的有无、引用格式、Markdown 中的标题层级。集成商需要对此进行解析。中位数长度增加 14% 意味着在运行 200 token 限制的客户中,响应会被截断。从三反引号到带语言标识的代码块切换,意味着基于正则的解析器会在每一个代码响应上崩溃。这就是隐性的格式一致性退化(silent format-adherence regressions)存在的地方。

工具调用频率与形状。Agent 调用每个工具的频率、针对哪些输入、以及参数形状。工具调用可观测性指南 建议将总工具调用次数和单个工具调用率作为一级指标进行跟踪,正是因为它们会随着 prompt 和描述的变化而变化。如果对工具描述的微调使得 Agent 在长输入上调用该工具的频率增加了一倍,那么运行单个工具预算上限的集成商会非常在意这一点。

拒绝模式。哪些类别的输入现在遭到了拒绝,而以前没有,反之亦然。VentureBeat 关于监测 LLM 行为漂移的指南 将拒绝率飙升视为安全过滤器过度校准或 prompt 漂移的早期预警。面向客户的集成商会关注这一点,因为从用户的角度来看,以前成功的回答现在变成了拒绝,这就是一种退化——即使平台团队的初衷是将新的拒绝作为一项功能。

延迟与成本分布。中值和尾部延迟、prompt-token 和 output-token 分布、单次调用成本分布、重试率。即使准确率数字没有变化,如果一个检索器重构悄无声息地使平均上下文大小翻倍,对于按 token 付费的集成商来说,这就是 2 倍的成本退化。

这四个维度并非详尽无遗,但它们是最小可行分类法:每一个值得告知集成商的行为变化都会映射到其中至少一个维度。围绕这些维度组织变更日志——而不是围绕移动了哪些文件——能为集成商提供一份他们真正可以扫描并采取行动的文档。

从评估差异生成变更日志

大多数平台团队不发布行为变更日志的原因是,手动编写一份日志是极其困难的。没有人想通过检查来枚举系统 prompt 编辑与模型别名升级以及检索器重构之间产生的所有交互方式。影响范围(blast radius)无法先验地(a priori)获知;它是通过在评估套件上运行新捆绑包并测量变化,后验地(a posteriori)观察到的。

这种观察正是生成变更日志的来源。每次发布运行都会产生一份评估差异(eval-delta)报告——按类别划分的通过率变化、在预留探测集上的退化和改进、长度分布偏移、工具调用频率以及拒绝率。解密 AI Agent 评估 介绍了将运行这些评估作为发布门禁的规范。大多数团队已经有了这份报告。需要建立的规范是:将评估差异报告视为面向集成商的变更日志的权威来源,并针对它生成文本,而不是针对工程日志。

生成的变更日志形状是机械式的:对于上述每个维度,列出超出噪声阈值的指标,提供前后对比数值,并用一行文字描述是哪些输入类别驱动了这一变化。集成商阅读它的方式与后端工程师阅读 API 发布说明的方式相同:扫描你依赖的维度,检查差异是否超出了你的承受范围,决定是否需要采取行动。

变更日志中“哪些没变”的一半与“哪些变了”的一半同样重要。如果基于模式约束(schema-constrained)的 prompt 的 JSON 一致性没有变化,请明确说明。如果医疗问题集群的拒绝率保持不变,也要说明。集成商在面对平台团队无意扰动的隐性变化时承担着风险;明确的不变量(invariants)与明确的差异警告同样具有安抚作用。

面向集成商的语义化版本,而非面向文件编辑的语义化版本

一旦行为差异成为沟通的单元,版本号也应该对行为进行编码。大多数平台团队对 Agent 进行版本控制的方式与对代码库进行版本控制的方式相同——补丁(patch)对应小文件差异,次要版本(minor)对应新功能,主要版本(major)对应已知破坏性变更——结果是集成商无法从版本号判断新版本是否可以安全升级。

解决方法是根据可观测的行为进行版本升级,而不是根据编辑量。如果一次发布将跟踪指标移动到了发布的容差范围之外,无论移动的文件多么少,这都是一次主要版本升级。一次触及了 40 个文件但在每个维度上都保持在容差范围内的发布则是一个补丁。 Semver 是为行为契约设计的;将其用于代码形状契约的团队是在向消费者泄露错误的信息。

发布的容差是大多数团队跳过的部分,也是最核心的环节。如果没有明确的容差——“JSON 一致性保持在 99.5% 以上,标准套件上的工具调用频率保持在 ±10% 以内,拒绝率保持在 ±2 个百分点以内”——升级规则就是一个主观判定,而主观判定会发生偏移。有了它,规则就是机械的:评估差异报告告诉你如何升级,集成商知道每个级别的升级意味着什么,而需要人类审议的情况则是规则与直觉不符的情况。

弃用节奏:行为即契约

契约的另一半是弃用(deprecation)。一旦集成方开始依赖某种特定的行为——例如解析代码块格式、围绕工具调用率制定预算、或对某一类别的拒绝姿态有所预期——这种行为就构成了契约界面,即使平台团队从未将其正式声明为契约。Sentry SDK 破坏性变更手册Dapr 弃用策略 将任何消费者可感知的变更都视为破坏性变更,并提供公示的提前通知期和迁移路径。Agent 的发布也需要同样的纪律。

难点在于枚举哪些行为属于契约范畴。务实的回答是:集成方针对其编写过代码的任何内容,都会在生产环境的遥测数据中表现为解析器、预算上限或客户可见的工作流,而通过这些环节的任何行为在隐式上都是“承重”的。被追踪的指标、客户反馈的预期,以及集成方代码中的解析器和规则,构成了初始清单。随时间演进的变更日志(changelog)则是正式清单——一旦某种行为作为“承重”项出现在变更日志中,将其移除时就必须给集成方留出弃用窗口期。

窗口期本身的形式与任何 API 弃用一致:发布公告、双重发布(新旧行为并存,通过配置标志或固定版本访问)、收集迁移信号、按计划停止支持。新颖之处在于,弃用的单位不是函数或参数,而是行为属性——“我们正在从三反引号代码块转向带语言标识的围栏格式;这是保留旧行为的标志位,这是移除该标志位的时间表。”集成方获得了与普通 API 变更相同的迁移体验,因为行为一直就是 API;平台团队之前只是在假装它不是。

文档背后的架构转型

行为变更日志只是表层的产物。它在底层强制推动的转型才是真正的变革:Agent 的行为就是消费者编写代码所依据的契约。一旦团队接受了这一点,问题的组织方式就会重构。发布不再是“移动了哪些文件”,而是“改变了哪些可感知的行为”。测试不再是“代码是否编译通过”,而是“评估差异报告(eval-delta report)是否保持在容差范围内”。版本管理不再取决于代码编辑量,而取决于集成方可见的变更。弃用不再关乎删除的代码,而关乎退役的行为。

从理论上讲,这些都不新鲜。API 已经以这种方式运作了数十年,围绕它们的纪律已经非常成熟。新鲜之处在于,Agent 是第一类契约界面并非 API 形态而是行为分布的系统,而大多数团队在撰写发布说明时,仍表现得好像两者是一回事。它们并不是。当消费者需要行为变更说明,而团队却只发布文件变更时,就是在两者之间的静默地带交付破坏——而在每一次发布中,这种静默最终都会在周五下午的支撑队列中爆发,而平台团队中没人能识别出其中的模式。行为变更日志是打破这种静默的文档。而发布包则是它必须存在的原因。

References:Let's stay in touch and Follow me for more thoughts and updates