跳到主要内容

流式回滚问题:你无法收回已发送的 Token

· 阅读需 11 分钟
Tian Pan
Software Engineer

观察某人第一次使用聊天产品时,你会发现他们在模型完成输出之前就开始阅读了。这种“边出边读”的行为正是流式传输(streaming)存在的全部意义:它将数秒的等待转变为一种对话般的感觉。然而,这也是你的输出防护栏(guardrails)悄然失效的原因。

这是一个令人尴尬的过程。模型生成了第 1 个 Token、第 2 个 Token、直到第 150 个。每一个 Token 在到达时都会立即渲染。到第 200 个 Token 时,模型产生了一个虚假的用药剂量、泄露了一个电子邮件地址,或者生成了一句违反内容政策的话。你的输出侧防护栏正确且立即触发了。但“立即”已经太晚了——用户已经阅读了前 200 个 Token。你无法撤销渲染。防护栏履行了职责,但违规内容仍然传达给了人类。

这就是流式回滚难题(streaming rollback problem),它不是某个具体防护栏的 Bug,而是现代 AI 产品同时追求的两大目标之间的结构性冲突:一是像生成一样快的实时输出,二是让输出在呈现给人类之前经过检查。你可以利落地拥有其中之一,但无法两者兼得。大多数团队先上线流式传输,再补上防护栏,却从未意识到第二个功能在第一个功能面前早已悄然失效。

流式传输与内容审核的直接冲突

输出防护栏——如 PII(个人隐私信息)检测、政策分类、幻觉评分、越狱响应检测——需要上下文才能做出准确判断。针对单个 Token 的 PII 检查看到的是 john;它无法预知接下来的四个 Token 会组成一个完整的电子邮件地址。对半句话进行的幻觉检查无法评估一个尚未完成的陈述。有效的检查需要一段文本窗口,通常是一个完整的句子或段落。

流式传输的需求则恰恰相反。它的核心价值在于 Token 产生的一瞬间就将其发出。发送速度越快,体验就越好——首个 Token 的响应时间(TTFT)是用户能真实感知到的指标,如果产品在此处停顿,在答案质量被评判之前就会失去用户的注意力。

因此,这两项需求产生了明显的分歧。防护栏希望在评判前累积文本,而流式传输希望在评判前释放文本。当你释放一个 Token 的那一刻,你就做出了一个不可逆的承诺,因为渲染是人类屏幕上的一个副作用,而人类的屏幕没有回滚日志。对于一个人已经读过的内容,没有 git revert 可用。

这就是为什么“为我们的流式接口添加防护栏”并不是一个小任务。你不是在给水管加过滤器。你是在为每个产品决定,你愿意牺牲多少延迟优势,来换取遵守安全检查的能力——而这个决定并没有一个放之四海而皆准的默认正确答案。

两个糟糕的默认选项

面对冲突,大多数实现方式会陷入以下两种姿态之一,两者都因某种原因而不尽如人意。

先流式传输,后后悔(Stream-then-regret)。 Token 在生成时即传送到屏幕上;防护栏在后台并发运行。当触发检查时,你取消流式传输。这是常见的默认做法——它保留了快速的体验——供应商也很诚实地记录了其代价。OpenAI 的防护栏指南坦率地描述了流式模式:速度更快,但“在触发防护栏之前,违规内容可能会简短地出现”。这里的“简短”一词承担了很重的分量。简短的时间仍足以让人读到一个泄露的电话号码,截图一句诽谤性的言论,或根据错误的医疗建议采取行动。你构建了一个安全控制机制,其保证却是“先显示坏东西,然后再撤回”。

先缓冲,后展示(Buffer-then-reveal)。 拦截所有 Token,直到每一项输出检查都通过,然后释放验证过的文本。这是真正的安全——不安全的内容永远不会暴露——这也是对合规性要求极高的应用应该采用的方式。但它抹杀了你添加流式传输的初衷。用户又回到了盯着加载动画的状态,只不过现在的动画除了生成延迟外,还加上了防护栏的延迟。你拥有一个流式 API,却提供着非流式的体验。

陷阱在于将此视为配置文件中的二进制开关(streaming: truefalse),而它实际上是一个光谱,有趣的工程实践往往存在于中间地带。

折中的缓解策略

你无法消除冲突,但可以缩小暴露窗口并使剩余风险显性化。这里有三种技术,大致按成本排序。

滑动窗口检查点缓冲(Sliding-window checkpoint buffering)。 不要按 Token 释放,而是积累一个小缓冲区(Chunk),并在释放该 Chunk 之前对近期上下文窗口运行防护栏。NVIDIA 的 NeMo Guardrails 将此作为其流式模型:一个可配置的 chunk_size(默认 200 Token)用于检查前的批处理大小,以及一个 context_size(默认 50 Token)的滑动窗口,用于处理前文,以便捕捉跨越 Chunk 边界的违规行为。这个旋钮是一个直接的延迟与安全性的调节器。Chunk 越小,暴露风险越低,首个 Chunk 的延迟也越低,但对于幻觉检测等需要完整陈述才能评估的检查来说,上下文较差。Chunk 越大,检查越准确,但暴露的风险也越高。没有一个设置能全赢;只有最匹配你风险等级的设置。

带有可见撤回的投机性流式传输(Speculative streaming with a visible retract)。 乐观地进行流式传输,但在 UI 设计上预设撤回的可能性。如果触发了防护栏,你不要静默切断连接,而是移除违规片段并显示该操作。这用完美的体验换取了诚实的体验,至关重要的是,它将回滚从“不可能”变为了“可见”,这本身就是一种真正的改进,尽管它并非完美的修复。

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