跳到主要内容

上下文的隐性成本:管理生产级 LLM 系统中的 Token 预算

· 阅读需 11 分钟
Tian Pan
Software Engineer

大多数初次发布 LLM 应用的团队都会犯同一个错误:他们将上下文窗口视为免费存储。模型支持 128K tokens?太好了,塞满它。模型支持 1M tokens?更棒了——把所有东西都扔进去。接踵而至的是在产品真正跑通前三周就提前到达的账单冲击。

上下文不是免费的。它甚至一点也不便宜。除了成本之外,盲目填充上下文窗口实际上会让你的模型变得更糟。一个精简的 300 token 上下文通常优于一个松散的 113,000 token 上下文。这不是极端情况——而是一个有明确名称的文档化失效模式:“中间迷失”(lost in the middle)。管理好上下文是你对 LLM 产品做出的最高杠杆的工程决策之一。

为什么上下文长度成本呈非线性爆炸

根本原因在于注意力机制本身。自注意力计算随序列长度呈 O(n²) 比例增长——上下文增加一倍,计算量就会增加四倍。在实践中,这意味着发送一个 8,000 token 的代码文件,其处理成本是 1,000 token 问题的 64 倍,而不是 8 倍。

目前旗舰模型的定价让这一点变得非常具体。输入 token 的价格约为每百万 2.50 到 3.00 美元,而输出 token 的价格要贵 4 到 5 倍。这些数字看起来很小,直到你计算生产环境的流量。一个每月处理 100 万次对话、每次包含 500 个输入和 200 个输出 token 的客服 Agent,使用中端模型每月大约花费 3,250 美元。如果在上下文中塞入对话历史、工具 Schema 和检索到的文档,你可能会在不更改任何一行产品逻辑的情况下,让账单翻三到四倍。

延迟是另一个维度。预填充延迟(Prefill latency)——即在生成第一个输出 token 之前处理输入 token 的时间——在当前硬件上处理最大上下文时会超过两分钟。这使得交互式应用在高上下文长度下变得不切实际。1M token 上下文所需的 KV 缓存(KV cache)每个用户大约需要 15GB。对于 128K token 的 70B 参数模型,每个用户的 KV 缓存约为 42GB——超过了单个 GPU 的容量。长上下文模型是令人印象深刻的工程成就。但在真实的生产流量中大规模运行它们是另一回事。

“中间迷失”问题

即使撇开成本和延迟不谈,更多的上下文也并不稳健地意味着更好的结果。针对 18 个模型的研究表明,随着上下文长度的增加,性能会出现一致的下降。其机制已被充分理解:旋转位置编码(RoPE)衰减导致序列开头和结尾的 token 比较中间的 token 获得更多的注意力权重。如果你的模型所需的信息埋在长上下文的中间,它将被部分忽略——而且模型不会告诉你。

让这一现象显现出来的基准测试是“大海捞针”(needle in a haystack)测试:将一个特定的事实埋在长文档的某个地方,并要求模型检索它。当事实位于中间位置时,模型失败的频率明显更高。与相同信息出现在输入开头或结尾时相比,准确率下降了 30% 以上。

实际意义是:更多的上下文不能替代更好的检索。用相关性较弱的文档淹没上下文不仅没有帮助,通常反而有害。有效的上下文应该是高密度且相关的,而不是全面且模糊的。

生产环境上下文管理的四种策略

大规模运行 LLM 系统的团队会采用分层方法,而不是单一技术。正确的选择取决于你的应用的对话模式、成本敏感度和延迟要求。

滑动窗口截断(Sliding window truncation)是最简单的策略:只发送最后 N 条消息。它速度快,没有额外开销,并且在处理无状态任务或短对话时表现尚可。但一旦会话早期的重要上下文变得关键,它就会失效——一个忘记用户三轮前说的话的客服 Agent 会让人感到沮丧,有时甚至会给出错误的答案。

层级总结(Hierarchical summarization)保留最近 N 轮的逐字对话,然后在上下文缓冲区超过阈值(通常为窗口的 70–80%)时总结旧的对话。摘要会被添加在截断的历史记录之前。这保留了对话早期重要的事实,而不会背负全部 token 重量。权衡之处在于:它增加了一次总结 LLM 的调用,引入了延迟和直接成本。如果总结提示词(Prompt)写得不对,你就会丢失重要的信息。

检索代替包含(Retrieval instead of inclusion,即 RAG 模式的上下文管理)将你的上下文窗口视为检索目标,而不是垃圾堆。你不再包含所有的对话历史或所有相关文档,而是对它们进行嵌入(Embedding)和索引,然后每轮仅检索最相关的片段。无论对话多长,这都能保持上下文精简。失效模式在于检索质量:如果你的嵌入模型或分块策略遗漏了相关信息,模型就会在缺失信息的情况下作答,且不知道自己漏掉了什么。

多智能体上下文隔离(Multi-agent context isolation)将上下文划分到不同的专门智能体中,而不是将所有内容集中处理。规划智能体负责任务状态;检索智能体处理文档查询;执行智能体仅获取其执行特定子任务所需的内容。这种架构防止了任何单一上下文窗口堆积所有内容,并自然地限制了 token 膨胀。它增加了协调开销并使调试变得更难,但对于复杂的流程,这通常是唯一能保持在成本和延迟限制内的方案。

Prompt Caching:最常被低估的优化手段

Prompt Caching 是大多数团队尚未实施的投资回报率(ROI)最高的单项优化。其机制是:提供商会缓存你 Prompt 前缀中已处理的 KV 矩阵。在共享相同前缀的后续请求中,它们会跳过重复计算并从缓存中读取。缓存命中的成本比普通输入 Token 便宜 10 倍,且返回时间不足 5 毫秒,而全新的推理则需要 2–5 秒。

Anthropic 需要在 API 请求中显式添加缓存控制标记;OpenAI 则对超过 Token 阈值的 Prompt 自动执行缓存。无论哪种方式,结构性要求都是一致的:稳定的内容必须放在前面。系统指令、工具 Schema、检索到的文档——把所有这些都放在 Prompt 的开头。动态内容(用户当前的消息、特定会话的数据)放在最后。如果你在 Prompt 中穿插动态内容,就会破坏缓存效果。

现实中的缓存命中率根据工作负载的不同在 20%–67% 之间。输入 Token 67% 的命中率意味着该部分支出大约能降低 73%。在大规模应用中,这就是“可控的 LLM 账单”与“需要高管签字的账单”之间的区别。

与上下文管理的交互非常重要:当你的系统 Prompt 和工具 Schema 庞大且稳定时,Prompt Caching 的效果尤为显著。如果你在每个请求中都花费 3,000 个 Token 来定义工具,那么缓存这 3,000 个 Token 就能免费降低延迟和成本。请优化你的 Prompt 结构以最大化稳定前缀,然后仅对动态尾部进行截断或总结。

Prompt 压缩

对于无法通过检索或总结轻松缩减上下文的应用场景——如长文档、密集的工程规范、监管文本——Prompt 压缩值得评估。LLMLingua 及其变体可以移除输入中概率较低的 Token,同时保留模型准确回答所需的语义内容。

在基准测试中,2–3 倍的压缩仅会造成极小的准确度损失(在推理任务中低于 1.5%)。在 10 倍压缩下,权衡会更加明显,但在某些应用中仍然可行。实际的账单计算是:一个 2,000 Token 的 Prompt 在 3/1MToken的单价下,压缩10倍后单次调用成本从3/1M Token 的单价下,压缩 10 倍后单次调用成本从 0.006 降至 $0.0006——在大规模调用下意义重大。

LongLLMLingua 专门通过重新排序和优先处理压缩输出中的重要信息来解决“迷失在中间”(lost-in-the-middle)的问题。在 RAG 工作流中,它在仅使用原先四分之一 Token 的情况下,实现了 21.4% 的准确度提升。

建议先从保守方案开始:对 5% 的流量应用 2–3 倍的压缩,对照未压缩的基准验证输出质量,然后再扩大范围。丢失关键信息的压缩比不压缩更糟。在将其推向生产流量之前,请先建立好回滚路径。

针对重复查询的语义缓存

语义缓存(Semantic Caching)位于 LLM 层之上,旨在完全消除冗余的 API 调用。当一个查询到达时,你将其向量化(Embedding)并与之前缓存的“查询-响应对”进行比对。如果余弦相似度超过阈值,则直接返回缓存的响应,而不调用 LLM。

对真实聊天机器人流量的分析显示,18% 的查询是完全重复的,47% 的查询在语义上是相似的。结合精确匹配和语义缓存,在典型的客服或 FAQ 工作负载中,可以实现 30–40% 的命中率。AWS 对 63,796 个真实聊天机器人查询的研究发现,通过激进的语义缓存,成本降低了 86%,延迟提高了 88%。

阈值调优至关重要:FAQ 查询可以使用较高的相似度阈值(0.94+),因为答案是稳定的。产品搜索查询需要较低的阈值(0.88),因为意图的细微差别会产生不同的结果。交易型查询需要最高的阈值(0.97+),因为将缓存的答案返回给略有不同的交易意图会导致正确性错误。

基础设施层面的预算执行

成本控制属于基础设施,而不属于 Prompt。API 调用中的 Token 限制封顶了输出长度。在每个请求中加入归因元数据(用户 ID、功能名称、团队 ID)能让你知道是哪个功能或用户在消耗资金——如果没有这些,你只能看到总成本,而无法采取行动。

API 网关(如 Portkey)可以在组织、工作空间或功能层面执行 Token 预算,形式可以是警报或硬性限流。将你的上下文窗口视为明确的预算:分配 X% 给系统 Prompt,Y% 给工具 Schema,Z% 给检索到的上下文,其余的分配给对话历史。如果某个组件超过了其配额,它在请求发出之前(而不是在你看到账单之后)就应该被压缩或截断。

在监控标准应用指标的同时,也要监控缓存命中率、每个请求的平均上下文长度以及输出 Token 比例。上下文长度漂移(Context length creep)是 LLM 成本意外增长最常见的原因之一。在问题爆发之前,它是隐形的。

实践层级的优先顺序

如果你现在正在为生产系统构建 Token 预算管理,请按以下顺序进行:

  • 优化 Prompt 结构以最大化缓存前缀长度(稳定内容在前,动态内容在后)
  • 针对高重复性的查询模式实施语义缓存
  • 根据对话模式通过滑动窗口或总结来限制上下文
  • 为每个请求标记归因元数据并设置预算警报
  • 仅针对高流量、文档密集型工作流评估 Prompt 压缩

模型在利用长上下文方面变得越来越强。但运行它们的经济逻辑并未改变:注意力的计算复杂度是二次方的,输出 Token 是昂贵的,且“迷失在中间”的问题并不会随着窗口的增大而消失。在 LLM 基础设施上获胜的团队,是那些将上下文视为“受管资源”而非“自由变量”的团队。

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