管理 LLM 上下文窗口:'智能区' vs. '愚蠢区'

大语言模型 (LLM) 的上下文窗口通常被宣传为拥有海量容量——达到 200k、1M 甚至 2M token——但这些数字往往无法代表一个可用的工作集。在实践中,随着窗口填满,性能通常会下降,从而在高性能的“智能区”和性能退化的“愚蠢区”之间产生分歧,在“愚蠢区”中,模型的注意力会下降且连贯性会丧失。

上下文腐烂的现实

有效的上下文通常只是广告宣传的限制的一小部分。诸如 RULER 基准测试和 Chroma 关于“上下文腐烂”的报告等研究表明,随着上下文窗口被填满,模型性能会逐渐下降。这对于编程代理 (coding agents) 尤为成问题,因为它们通过文件读取、调试会话和测试运行快速消耗 token,通常在任务完成之前就将模型推入“愚蠢区”(据某些人估计约为 100k token)。

虽然一些用户报告在大窗口下取得了成功——特别提到 Claude Opus 的 1M token 窗口在高达 800k token 时仍保持稳定——但其他人认为,注意力的“质量”被摊得太薄,导致全局平均出现“混乱”而非精确检索。

维持高信号上下文的策略

为了避免与大上下文窗口相关的性能衰减,开发者正在采用几种技术策略,以使模型保持在其“智能区”内。

1. 通过 Artifacts 外部化状态

与其依赖模型的内部会话记忆,不如通过将信息移入书面 artifacts 来实现高信号的交接。这包括:

  • 手动规范交接 (Manual Spec Handoffs): 打开一个新会话并提供一份自写的规范,以确保在没有长对话噪音的情况下保留最关键的信息。
  • 结构化工作流 (Structured Workflows): 使用像 obra/superpowersmattpocock/skills 这样的框架来围绕命名的 artifacts(如 PRDs、计划和子代理交接)组织代理工作流。
  • 文档即记忆 (Documentation as Memory): 将检入仓库的简洁 Markdown 文件(清单、索引页和计划)视为模型的主要“记忆”,这也同时作为人类可读的审计追踪。

2. 递归调用与根线程隔离

控制 token 使用的一种高级方法是防止在顶层对话线程中进行工具调用。通过使用递归调用——即代理下降到子进程中执行工具调用并仅向调用者返回结果——根对话线程可以保持精简。这允许用户在庞大的代码库上进行高层级对话,而不会在主线程中触及 100k token 的限制,即使在递归调用中消耗了数百万个 token。

3. 手动与自动压缩

许多现代代理,例如 Claude Code,实现了自动压缩 (auto-compaction),即对会话进行总结并重置。然而,批评者认为,如果总结是由一个已经处于“愚蠢区”的模型生成的,那么总结本身的质量可能会下降。手动压缩——例如使用 /last 命令来清除会话但仅保留最后一次输出——允许用户更精确地引导压缩过程。

反方观点与多变性能

并非所有用户都会经历普遍的“愚蠢区”。上下文大小的影响通常取决于任务:

  • 任务复杂度: 简单的管道任务可能在较长的上下文中保持稳定,而复杂的推理任务退化得更快。
  • 信号与噪声比: 有人认为性能退化不是由 token 数量引起的,而是由“碎片”或令人困惑的信号(例如重复的失败尝试)淹没了重要指令。
  • 模型架构: 不同的模型具有不同的注意力架构;因此,一个模型的行为不能推断到所有前沿模型。

"上下文窗口中事物的频率会赋予权重,即使它们是错误的东西。我有很多技巧,比如不给 LLM 很多工具,而是给它一个可以用来搜索工具的工具等等。"

结论:上下文即预算

将上下文窗口视为预算而非容量,是确保 LLM 可靠性的最可靠方法。通过刻意地将信息移出实时会话并进入结构化 artifacts,开发者可以最大限度地减少注意力机制必须应对的噪音,从而确保模型保持敏锐和专注。

Sources