跳到主要内容

记录概率性功能:模型行为与开发者引导之间缺失的一层

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的文档说 /summarize 端点会返回一个简明扼要的摘要。这没错。但它每次返回的摘要都不一样,有时会遗漏关键点,偶尔在你忘记在提示词(prompt)中指定格式时返回结构化的 JSON,并在你毫不知情的模型更新后发生无声的性能退化。而这些都没有出现在文档中。

传统的 API 文档记录的是契约:给定输入 X,预期输出 Y。而 AI 驱动的功能从根本上打破了这一模式。这里没有稳定的契约可供记录。同样的提示词、同样的模型、同样的参数 —— 却会产生不同的输出。然而,团队在发布这些功能时,使用的文档风格仍与编写数据库查询文档时如出一辙:一个函数签名、一个返回类型,或许还有一句关于错误代码的说明。

你的文档所描述的内容与功能的实际表现之间的鸿沟,正是开发者信任消亡的地方。

为什么传统文档对 AI 功能失效

问题不在于团队懒惰。而在于文档的思维模型从一开始就错了。

确定性 API 具有后置条件(postconditions):给定有效输入,函数返回特定形状的输出。你只需记录一次该形状,测试套件验证它,任务就完成了。而由大语言模型(LLM)驱动的功能没有后置条件 —— 它们拥有的是输出分布。记录它们的“正确”方式是描述这种分布,而不是其中的单个实例。

对 LLM API 使用模式的实证研究发现,即使你配置了确定性参数,非确定性依然存在 —— 在实践中,temperature=0 并不能消除输出差异,因为非确定性不仅存在于采样过程中,还根植于基础设施层。基于测试用例编写文档的开发者,实际上记录的是分布中的一个样本,而不是分布本身。

这导致了三个让团队倍感头疼的失败模式:

可复现性的谎言。 文档说“返回操作项的列表”。在生产环境中,12% 的调用返回的是散文段落。功能并没有损坏 —— 你只是把一种输出模式当成了唯一的模式记录了下来。

无声退化问题。 模型更新改变了功能处理边缘情况的方式。你的文档对于典型情况(modal case)依然准确,但那 8% 表现发生变化的输入却没有任何文档痕迹。

下游破坏。 另一个服务正在解析你功能的输出。你的文档说输出是 JSON。现在一次提示词更新使得它有时会在 JSON 周围返回 Markdown 代码块标识符。下游解析器崩溃了。没有任何操作违反了文档中的契约 —— 因为从未正式规定过输出结构。

AI 功能文档中应该包含什么

可以将 AI 功能文档视为三个不同的层级。大多数团队只编写了第一层。

第一层:行为包络(Behavioral envelope)。 调用者可以依赖的内容,以统计保证而非确定性承诺的形式表达。不要写“返回一个包含这些字段的 JSON 对象”,而是写类似这样的话:“在正常运行条件下,超过 95% 的调用会返回符合此 schema 的结构化输出。在涉及超过 8,000 个 token 的输入或具有显著格式伪影(artifacts)的输入的边缘情况下,可能会出现违反 schema 的输出。请参阅已知限制。”

行为包络格式应明确说明:

  • 输出 Schema 一致性率(而不仅仅是 Schema 本身)
  • 退化案例的频率(空输出、拒绝回答、格式错误)
  • 能力限制(输入长度、语言覆盖范围、主题领域)
  • 导致行为退化的条件

这就是研究人员所说的分布后置条件(distributional postcondition) —— 针对输出分布而非单个输出的后置条件。针对 LLM API 的正式契约框架已开始将其表达为 (p, δ, k) 满足度:最小合规概率 p、可接受的软约束偏差 δ、恢复窗口 k。即使你不编写正式契约,这些维度也会告诉你需要衡量和记录哪些内容。

第二层:版本化契约。 哪些变更构成破坏性变更(breaking changes),以及如何通知调用者。这是 AI 功能文档与传统 API 文档区别最明显的地方。

对于确定性 API,规则很简单:更改响应 schema 就是破坏性变更。对于 AI 功能,规则需要更丰富:

  • 输出 Schema 变更 是破坏性变更。如果你的功能返回结构化输出,而提示词更新更改了字段名称或增加了必填字段,下游消费者就会受到破坏。这是与 REST API 版本化最清晰的类比。
  • 能力移除 是破坏性变更。如果该功能之前支持 12 种语言,而更换模型后减少到 7 种,那么依赖那 4 种语言的调用者的集成就会失效 —— 即使响应格式完全一致。
  • 统计阈值偏移 根据你的 SLA 可能会构成破坏性变更。如果幻觉率从 2% 上升到 8%,这虽然不是 schema 变更,但可能违反了已文档化的可靠性保证。
  • 典型情况下的行为变化 通常不是破坏性变更,但应出现在变更日志(changelog)中,并附带前后对比示例。

实际上,这意味着你的变更日志需要两个部分:“破坏性变更”(schema/能力)和“行为变更”(常见情况下的分布偏移)。大多数团队只跟踪部署,而不跟踪提示词更新 —— 这意味着他们的变更日志永远是不完整的。

第三层:操作手册(Runbook)。 当功能行为退化时如何诊断和响应。这是大多数团队文档中完全缺失的一层。

核心挑战在于:LLM 故障看起来不像传统故障。延迟正常,错误率为零,但功能却在悄无声息地返回更糟糕的输出。传统的监控仪表盘保持绿色,而行为却在退化 —— 因为 LLM 漂移发生在语义空间,而不是发生在错误率或响应时间上。

AI 驱动功能的运行手册需要包括:

  • 评估指标基准和警报阈值(而不仅仅是延迟/错误率 SLO)
  • 语义监控步骤 —— 如何检测生产环境中的质量退化,而不仅仅是故障
  • 取证追踪协议:当行为异常时,应提取哪些日志、追踪信息和提示词版本
  • 针对不可复现事件的升级路径(在调查期间故障可能不会再次发生)
  • 独立于模型和提示词版本的回滚流程

运行手册的触发条件应该是评估指标降至阈值以下 —— 例如 groundedness(归因性)降至 0.85 以下,schema 一致性降至 0.92 以下 —— 而不仅仅是一个来自失效 HTTP 端点的 PagerDuty 警报。

行为变更日志

一个能产生不成比例红利的结构性变化是:在独立于代码变更的专用变更日志中跟踪行为变更。

典型的软件变更日志记录了代码的变化。对于 AI 功能,变更日志需要记录 行为 的变化。这是两回事。提示词更新可能只是单行代码的改动,但可能导致显著的行为变化。更换模型可能完全不涉及应用代码,却会改变每个功能的输出分布。

行为变更日志条目如下所示:

## 2026-03-15 — 提示词更新:改进了 Schema 符合度

**变更:** 系统提示词现在明确指示使用 JSON 输出模式。
**之前:** Schema 符合率:93%。在 <5% 的边缘案例输入中偶尔会出现散文泄漏。
**之后:** Schema 符合率:98.5%。在测试输入中消除了散文泄漏。
**测试基于:** 来自过去 30 天的 500 个生产样本。
**调用方无需采取行动:** 输出 Schema 未改变。

对比大多数团队实际写的日志:fix: update summarization prompt

这种差异对每一个下游消费者都很重要。行为变更日志也是你进行破坏性变更沟通的基础:如果行为变更日志条目影响了输出 Schema 或记录的能力边界,它就是一个破坏性变更,需要进行主版本号升级。

可扩展的版本控制规范

当你在生产环境中拥有的提示词超过几个时,版本控制问题就会变得复杂。对生产环境 LLM 部署的分析一致发现,拥有 10 个以上提示词的团队将版本控制列为首要的运维痛点——而这些团队中大多数根本没有系统的版本控制。

最小可行提示词版本化系统:

将提示词作为代码产物进行版本控制。 将提示词与你的应用程序代码一起存储在版本控制系统中。命名规范:{feature}-{purpose}-{env}-v{N}。像对待配置文件一样对待提示词:变更需要审核,历史记录予以保留。

将提示词版本与模型版本分开。 它们可以独立变化并产生独立的影响。你的变更日志和回滚流程需要反映这一点——你可能会回滚提示词更新但保留新模型,反之亦然。

阶段性晋升。 提示词像代码一样在环境间移动(开发 → 临时环境 → 生产)。任何提示词更新在未经过与生产环境输入分布相匹配的临时环境数据集评估前,都不得直接进入生产环境。

固定模型版本。 在所有环境中使用供应商特定的模型版本(例如,使用 claude-3-5-sonnet-20241022 而非 claude-3-5-sonnet)。自动升级到最新版本会破坏“昨天的文档仍然有效”这一假设。

针对高风险变更进行金丝雀发布。 将 1-5% 的流量引导至新的提示词/模型版本。在全量发布前评估行为指标。这是确定性服务的标准部署实践;没有理由在 AI 功能上跳过它。

模型卡和系统卡真正解决的问题

对于构建内部 AI 功能的团队来说,模型卡(Model cards)和系统卡(System cards)经常被视为只有 AI 实验室才需要制作的东西。这是错误的。

模型卡记录了模型在不同输入分布下的性能特征、已知的故障模式以及预期的使用场景。对于内部功能,这可以转化为:“这是该功能在不同用户群体输入下的表现,以及它处理得不好的输入类型。” 这正是下游团队在决定是否依赖你的功能时所需的信息。

系统卡更进一步:它们记录模型周边的系统,而不不仅仅是模型本身。对于面向客户的 AI 功能,系统卡将涵盖:使用的模型、提示词架构、现有的防护栏、模型不可用时的回滚行为,以及针对被标记输出的人工审核流程。

这些都不需要是 50 页的合规文件。一个一页纸的内部系统卡,以结构化格式记录行为包络、版本控制契约和运维手册,比没人读的 10 页文档更有用。

监管趋势使得现在就进行投资是值得的。欧盟 AI 法案(EU AI Act)和 NIST AI 风险管理框架(NIST AI Risk Management Framework)都包含与模型卡和系统卡格式紧密结合的文档要求。现在建立这种规范的团队,在合规变成强制要求时就不必手忙脚乱。

从文档到可观测性的转变

成熟 AI 工程团队最深刻的洞察是:概率性功能的最佳文档是实时可观测性仪表板,而不是静态文档。

静态文档说你的功能在 >95% 的情况下返回结构化输出。可观测性仪表板则显示你的功能目前返回结构化输出的比例为 89.3%,低于上周的 97.1%。这不仅仅是更好的文档——它是可操作的。

新兴的基础设施是 OpenTelemetry 针对 LLM 调用的语义规范,它标准化了每个 LLM 请求捕获的内容:模型、提示词、补全、Token 计数、结束原因。当你存储这些数据并在此基础上构建仪表板时,你就获得了功能随时间变化的行为记录——一个自动捕获行为漂移的活生生的变更日志。

对文档实践的启示:你的静态文档应该描述 预期 的行为包络,而你的可观测性基础设施应该持续验证实际行为是否匹配。当它们发生偏离时,这就是行为变更日志条目——或手册升级(runbook escalation)的信号。

做对这一点的团队并不是在写更好的静态文档。他们正在构建这样一种系统,其中文档和可观测性是同一个底层行为规范的两个视图。


概率性功能所需的文档并不比确定性功能的少。它们需要的是不同的文档——一种将输出分布视为一等产物、使版本控制规范明确化、并将静态文档与实时可观测性联系起来的文档。这种模式足够新,以至于还没有成熟的标准可以复制。但做得好的团队都有一个共同的见解:记录调用方可以依赖的内容,而不是功能在一切顺利时的表现。

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