跳到主要内容

一次导致所有运行中 Agent 任务失效的 Prompt 热重载故障

· 阅读需 11 分钟
Tian Pan
Software Engineer

传呼机在晚上 11:47 响了。一名客户在退款对话中进行了十分钟,智能体突然停止调用它在整个会话中一直在推理的 process_refund 工具,幻觉出了一个确认码,并结束了聊天。当我们回溯原因时,事后看来显而易见:一位队友在 11:46 推送了更新后的系统 Prompt。推送很顺利,测试通过了,每个新会话都运行完美。但已经在进行中的几百个会话却出问题了。

我们构建的 Prompt 注册中心支持了 2026 年每家 Prompt 版本控制供应商都作为特性推销的功能:无需重新部署的热重载(hot-reload)。我们将这种能力视为 CDN 缓存刷新——一种在全球范围内立即生效的全量替换。但那天晚上我们学到,它实际上是破坏了契约。每个活跃的会话都是 LLM 与一组指令及工具定义之间正在进行的协商。当注册中心在这些对话进行中更换了 Prompt 时,协商好的一半上下文就过时了。

最终的解决办法是停止将 Prompt 版本视为部署时的全局变量,转而将其视为每个会话的契约。与其说这是一个巨大的架构变更,不如说是一个微小的思维转变。

为什么“热重载”看起来安全,直到它出问题

Prompt 注册中心被吹捧为一种将 Prompt 编辑与应用部署解耦的方法。这个卖点极具吸引力:你的 Prompt 工程师修正了一个措辞问题,点击发布,下一个请求就会采用它。无需 CI 运行,无需容器重启,无需回滚仪式。对于单次补全(one-shot completions)——分类、摘要、单轮问答——这个卖点基本上是成立的。请求从注册中心读取最新的 Prompt,调用模型,然后返回。唯一的风险窗口是在读取和模型响应之间,而这个窗口非常短。

智能体在两个方面打破了这种模型。首先,一个智能体的运行不是单次 LLM 调用;它是一个循环。系统 Prompt 和工具 Schema 在该循环的每一轮都会重新发送给模型,因为这是无状态聊天补全 API 的工作方式。其次,LLM 在会话中的推理是路径依赖的。它已经根据三轮前看到的工具、五轮前系统 Prompt 告诉它的角色以及开头确定的输出格式制定了计划。在循环中途更换其中任何一项,你不是在刷新上下文,而是在对模型进行“煤气灯”操纵(gaslighting)。

注册中心的抽象静默地假设 Prompt 是纯输入。在智能体循环中,Prompt 更接近于 Schema。在数据流写入时更改 Schema,正是分布式数据库花了二十年时间才弄清楚如何安全实现的事情。

具体失效模式

“退款中途停止”事件影响最大,但并非唯一。一旦我们开始排查,就发现了一系列指向同一根因的失效模式。

工具定义相对于系统 Prompt 过时。 我们的 Prompt 推送将 process_refund 重命名为 issue_refund,并相应更新了系统 Prompt 的示例。单独部署的工具注册中心仍然向运行中的会话暴露 process_refund。模型忠实地遵循新的 Prompt,调用了并不存在的 issue_refund——收到了工具未找到的错误——并自我合理化出一个幻觉的成功结果。

输出 Schema 在会话中途发生漂移。 另一次推送将 JSON 输出格式从“字符串列表”收紧为“带有 reason 字段的对象列表”。运行中的会话在前几轮中模型生成了旧格式且解析器接受了它。切换后,模型看到了新指令并生成了新格式,而下游消费者崩溃了,因为它在编写时假设会话的输出 Schema 是稳定的。

角色转变困惑了多轮推理。 销售聊天中途,措辞从“你是一个简洁的助手”变为“你是一个周全的助手”。对话的前半部分是简短的回答;后半部分则是多段话。用户注意到了。他们认为智能体出了故障。实际上,它只是在严格执行每个后续 Prompt 告诉它的内容。

护栏使先前的批准失效。 安全策略的更改将一类操作从“允许”移动到“需要确认”。在第三轮已预先批准该操作的对话,在第七轮尝试执行该操作时被拦截了。用户看到一个片刻前还能工作的工具突然被拒绝。从他们的角度看,智能体对自己的权限产生了失忆。

连接这四点的线索是:没有任何东西崩溃。LLM 太过宽容了。它吸收了矛盾,并产生了一个自信、看似合理但恰好错误的响应。智能体注册中心团队的热重载预案假设失效模式会是某个地方出现明确的错误。而实际的失效模式是无声的语义损坏(silent semantic corruption),这在输出全是“听起来很合理”的文本系统中,是最糟糕的一类 Bug。

心智模型:会话是契约,而非缓存

这里的 bug 不在注册中心的实现,而在于注册中心所暴露的抽象。将 prompt 视为可缓存的值,意味着过期读取的代价是有限的——最坏的情况不过是在几百毫秒内获取到了上周的 prompt。而将 prompt 视为契约,则意味着打破它的代价是无限的。因为消费者(LLM)已经构建了状态——思维链(chain-of-thought)、中间计划、工具调用历史——这些都依赖于契约在整个交互期间保持不变。

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates