Skip to content

上下文说明

这篇文章解决什么问题

很多人在用大模型时,嘴上会说“上下文不够了”“模型忘了前面说过的话”“这个模型支持 128K”,但真正落到工程里,常常还是混着几件不同的事:

  • 什么叫上下文
  • 为什么模型非得依赖上下文
  • 为什么长度一定有限
  • 128K、200K、1M 到底分别代表什么
  • 这个长度是模型天生的,还是我自己能调的
  • 同样一个窗口,怎样组织内容才不浪费

这篇文章就是把这些问题拆开说清楚。

先说结论

  • 上下文就是模型在“这一轮请求里”能看到的全部输入,以及它接下来要生成的输出预算。
  • 模型不是天然有长期记忆,它每次回答都只基于当前这次请求里带进去的内容。
  • 上下文长度有限,不只是因为“厂商没放开”,更主要是算力、显存、延迟、训练分布和位置编码都在限制它。
  • 真正可用的输入空间,不等于标称窗口长度,因为你还要给输出留位置。
  • 提高上下文有两条路:一条是换更长的模型或推理配置,另一条是把同样的窗口用得更有效。
  • 对大多数真实项目来说,决定效果的往往不是“128K 还是 200K”,而是你有没有把信息组织对。

什么是上下文

最直接的理解是:

上下文 = 这次请求里,模型在生成答案前能看到的全部 token

它通常包含这些部分:

  • system / developer 指令
  • tool 定义或 schema
  • 检索回来的资料
  • 历史对话
  • 当前用户问题
  • 预留给模型输出的 token 空间

很多官方文档都把它定义成“模型当前工作时能回看的范围”。

如果用一句更通俗的话说:

上下文就是模型这次答题时,桌上摊开的全部材料。

桌面再大,也不是无限大。

为什么要有上下文

因为模型不是凭空回答问题的。

它虽然在预训练阶段学过大量通用知识,但到了实际调用时,仍然需要知道这次任务的现场信息:

  • 你现在到底要它做什么
  • 你们前面已经说到了哪里
  • 当前要遵守什么格式
  • 当前允许使用哪些工具
  • 当前有哪些外部资料

如果没有上下文,模型每次都只能把你的最后一句话当作孤立输入。

比如同一句:

text
继续

没有上下文时,这句话几乎没有意义。
有上下文时,它可能表示:

  • 继续翻译上一段
  • 继续输出刚才被截断的 JSON
  • 继续刚才的总结
  • 继续写那篇文章的下一节

所以,上下文的作用不是“让模型更聪明”,而是让模型知道:

  • 当前任务是什么
  • 当前边界是什么
  • 当前历史发生过什么

上下文不是训练知识,也不是长期记忆

这三个概念很容易混在一起。

概念它是什么它不是什么
训练知识模型在训练阶段学到的统计规律和知识不是你这次临时塞进去的文档
上下文本次请求里实际送进去的内容不是永久记忆
长期记忆应用层自己存的用户资料、摘要、偏好、历史索引不是模型天生自带的稳定记忆

所以当人们说“模型记住了”,很多时候真实发生的是:

  1. 应用把之前的信息存了下来
  2. 下一轮又把相关内容重新放回上下文
  3. 模型因此看起来像“记得”

模型自己并不会跨请求永久保留你刚才说的话。

Anthropic 的 Messages API 文档就明确把它描述成无状态接口:多轮对话时,需要你在每次请求里把相关历史继续带上。

为什么长度有限

这件事至少有四层原因。

1. 计算量会明显变大

经典 Transformer 在处理长序列时,注意力计算会随着序列长度快速膨胀。

直观地说:

  • token 越多,彼此之间要看的关系越多
  • 预填充越长,首 token 延迟通常越高
  • 长文档、多轮对话、大代码库都会让首轮处理更重

很多模型虽然“能吃下”很长上下文,但并不代表它“吃得轻松”。

2. KV Cache 会占显存和内存

模型生成时通常会把前面 token 的 Key / Value 缓存下来,后续解码继续用。
上下文越长,这部分缓存就越大。

所以长上下文带来的不只是:

  • 更高输入成本

还包括:

  • 更高显存压力
  • 更高服务成本
  • 更高并发压力

这也是为什么很多本地推理工具虽然支持调大 context,但一调大就更吃显存。

3. 模型训练时本来也只在某个范围里学过

上下文长度不是单靠推理时放开开关就能无限变长。

因为模型训练时,本来就只在某种长度分布里见过数据。
如果它主要在 8K、32K、128K 的范围里学习过,直接在推理时暴力拉到更长,往往会出现:

  • 注意力退化
  • 远距离引用变差
  • 中间内容被忽视
  • 回答表面上能跑,质量其实下降

所以“能设更长”和“设更长后仍然稳定”不是一回事。

4. 产品层面还要考虑延迟和成本

上下文越长,通常意味着:

  • 计费更高
  • 响应更慢
  • 更容易撞到配额
  • 更难稳定做交互产品

所以很多厂商就算有长上下文能力,也会按模型档位、接口、Beta header、配额等级来区分开放方式。

上下文长度不只看输入,还要给输出留空间

这是最容易踩坑的一点。

一个模型写着 128K context,不等于你能塞满 128K 输入然后还让它正常输出一大段结果。

更接近真实的理解是:

text
总窗口
= system + tools + 文档 + 历史消息 + 当前问题 + 输出预算

OpenAI 的 token 概念文档明确写到:对文本生成模型来说,提示词和生成出的输出加起来,不能超过最大上下文长度。

所以如果你拿一个 128K 模型:

  • 输入已经用了 124K
  • 又想让它再吐 8K

那就已经超了。

工程上更稳的做法是先预留输出空间。

比如:

  • 总窗口 128K
  • 预留输出 8K
  • 那你的可用输入预算就应该按 120K 左右算

常见模型上下文有多长

下面这张表只列常见、且我这里能直接查到官方资料的代表型号。
时间点是 2026-04-22,后面可能继续变化。

API / 商业模型

模型官方标称上下文官方标称最大输出备注
OpenAI gpt-5.41,050,000128,000当前旗舰推理模型
OpenAI gpt-4.11,047,57632,7681M 级长上下文
OpenAI gpt-4o128,00016,384通用型多模态主力
Anthropic Claude Sonnet 4.61M64KClaude 当前主力速度 / 智能平衡型模型
Google Gemini 2.5 Pro1,048,57665,5361M 级长上下文

常见开源 / 开放权重模型

模型官方标称上下文官方标称最大输出备注
Qwen2.5-7B-Instruct131,0728,192官方模型卡给出 full 131,072
Meta-Llama-3.1-8B-Instruct128K模型卡重点写上下文,输出上限通常看具体推理实现常见开源长上下文基线

这里有两个很重要的提醒:

  1. 不同厂商写法不一样
    有的直接写“context window”,有的分成 input / output token limit。

  2. 标称长度不等于有效质量
    一个模型支持 1M,不代表它在 1M 的每个位置都同样稳。

这些长度到底哪里能配

要分四层看。

第一层:模型能力上限

这是最硬的一层。

比如:

  • gpt-4o 的窗口不是你自己改成 200K 就能生效
  • Claude Sonnet 4.6 的上限由官方模型能力决定
  • Gemini 2.5 Pro 的上限由模型能力决定

也就是说:

  • 你能选模型
  • 你不能凭空把闭源模型的硬上限改大

第二层:请求级参数

这一层通常能配的是“这次最多生成多少”和“超长时怎么处理”。

OpenAI

Responses API 文档里有这些直接相关参数:

  • max_output_tokens
  • truncation

max_output_tokens 用来控制这次最多生成多少。
truncation 用来决定当输入超过窗口时,是自动裁掉前面的内容,还是直接报错。

示意:

json
{
  "model": "gpt-5.4",
  "input": "...",
  "max_output_tokens": 4000,
  "truncation": "auto"
}

Anthropic

Messages API 里最直接相关的是:

  • max_tokens
json
{
  "model": "claude-sonnet-4-6",
  "max_tokens": 2048,
  "messages": [
    { "role": "user", "content": "..." }
  ]
}

Gemini

Gemini API 里最直接的是:

  • 选模型
  • generationConfig.maxOutputTokens

示意:

json
{
  "model": "gemini-2.5-pro",
  "contents": "....",
  "generationConfig": {
    "maxOutputTokens": 4096
  }
}

这层的本质是:

  • 你能控制“用多少”
  • 不能突破“模型最多支持多少”

第三层:本地推理或自托管服务

如果你跑的是开源模型,本地推理框架通常允许你调分配给推理服务的上下文长度。

Ollama

Ollama 官方文档给了两种方式:

  • App 里用滑块调
  • 用环境变量 OLLAMA_CONTEXT_LENGTH

示意:

bash
OLLAMA_CONTEXT_LENGTH=64000 ollama serve

vLLM

vLLM 官方文档里可以通过 --max-model-len 设置,或者让它自动按显存选择。

示意:

bash
vllm serve Qwen/Qwen2.5-7B-Instruct --max-model-len 32768

这里要注意:

  • 你只是给服务设了可分配上限
  • 不代表模型训练上真的在这个长度里稳

第四层:模型配置层

在开源模型和 Transformers 库 体系里,你还会看到这些字段:

  • max_position_embeddings
  • rope_parameters
  • 各种 rope scaling

Hugging Face 文档明确写到,可以通过 rope_parameters 配不同类型的 RoPE scaling,用来扩展上下文。

示意:

python
config.rope_parameters = {
    "rope_type": "dynamic",
    "rope_theta": 1000000.0,
    "factor": 4.0,
    "original_max_position_embeddings": 8192,
}

但这件事一定要分清:

  • 这是“扩展或外推”能力
  • 不是“无损白送更长上下文”

如果模型本身没做过相应训练或适配,强拉长度通常会掉质量。

如何提高上下文能力

这里也要分成两类。

第一类:提高硬上限

这类办法是在真的把可容纳 token 上限变大。

1. 直接换更长窗口的模型

这是最稳的办法。

比如:

  • gpt-4o128K 换到 gpt-4.1 的 1M 级
  • Claude Sonnet 4.5 这类 200K 档位换到 Claude Sonnet 4.6 这类 1M 档位
  • 从 8K、32K 级旧模型换到新一代长上下文模型

2. 在本地推理框架里调高分配长度

比如:

  • Ollama 的 OLLAMA_CONTEXT_LENGTH
  • vLLM 的 --max-model-len

前提是:

  • 显存扛得住
  • 模型本身也别超出太多

3. 对开源模型做长上下文扩展

比如:

  • RoPE scaling
  • LongRoPE / YaRN 一类方法
  • 长上下文继续训练或微调

这是“研究和工程改造”路线,不是普通产品配置项。

第二类:提高有效上下文

这类办法不一定把硬上限变大,但能让同样的窗口装下更多有用信息。

这通常比单纯追大窗口更重要。

1. 做摘要,而不是硬堆完整历史

长对话最常见的问题不是窗口太小,而是历史里有大量重复、寒暄、无效确认。

更稳的做法是:

  • 旧历史压缩成摘要
  • 只保留最近几轮原文
  • 把关键偏好、约束、决策单独抽出来

2. 用 RAG,而不是把整个知识库一次塞进去

不要把全部文档原文都塞给模型。
先检索,再只放最相关的几段。

3. 去重和清洗

真实业务里很浪费窗口的东西通常是:

  • 重复段落
  • HTML 噪音
  • 样板页脚
  • 冗余日志
  • 无关字段

先清理,再送进去,效果常常比“多 32K”还明显。

4. 给静态内容做稳定前缀

OpenAI 和 Anthropic 的 prompt caching 文档都强调了一点:

  • 把稳定不变的内容放前面
  • 把动态内容放后面

这样做有两个好处:

  • 更容易命中缓存
  • 更容易保持 prompt 结构稳定

5. 预留输出预算

如果你每次都把输入塞到极限,模型一输出就会撞顶。
工程上应该提前给输出留空间。

6. 拆任务,不要迷信“一次塞完”

如果任务天然可以拆成:

  • 检索
  • 初筛
  • 汇总
  • 最终回答

那就分段做。
很多任务不是必须一口吞进一个超长上下文里。

如果上下文已经过长,常见压缩路线怎么选

这里最容易犯的错,是把“压缩”理解成一件事。

其实常见做法至少分成五类,而且它们压的对象并不一样:

路线压什么核心原理最适合什么场景主要风险
滚动摘要对话历史把旧历史改写成更短的状态摘要长聊天、Agent 会话摘要丢细节、语气和边界
检索裁剪外部资料 / 文档块只保留和当前问题最相关的 chunksRAG、知识库问答召回不准会把关键证据丢掉
抽取式压缩token / 句子 / 段落删除低信息密度内容,尽量保留原词长 prompt、few-shot、长文 QA删掉连接词或指代关系后可读性下降
改写式压缩文档或历史用更短文本重写原内容历史归档、阶段性总结容易引入改写偏差
学习型压缩表示prompt 表示本身把长 prompt 编成少量可复用“摘要 token”重复出现的大前缀、系统提示需要训练或专门模型,通用性较弱

先分清你压的是什么,再决定技术路线,不然很容易:

  • 该做检索的地方去做摘要
  • 该做抽取的地方去做重写
  • 该保留原词的地方硬压成一句话

压缩的基本原理

绝大多数压缩方法,底层都在做下面几件事里的某一种,或者几种组合。

1. 删除低信息密度内容

这是最直接的一类。

它假设原始文本里有很多内容虽然“通顺”,但对当前任务贡献并不大,比如:

  • 重复表述
  • 语气词
  • 样板话
  • 冗余解释
  • 和问题弱相关的背景

这类方法会尽量保留原文里的关键 token、句子或段落,只把低价值部分拿掉。

2. 做任务相关的保留

不是所有信息都要“普遍重要”,很多时候只要对当前问题重要就够了。

比如问:

text
2023 年 Q2 的收入增长是多少?

那真正该保留的,是:

  • 公司
  • 时间
  • 收入 / 增长
  • 和问题相关的上下文

而不是整份文档的全部叙述。

所以更强的压缩通常不是“全局删短”,而是“围绕当前 query 保留关键证据”。

3. 把原文改写成更短的状态

这种做法最常见于:

  • 对话历史摘要
  • 文档归纳
  • 多轮 Agent 记忆

它不是删除一部分原文,而是把整段内容重写成更短版本。

优点是压缩率高。
缺点是它已经不是原文了,所以会引入摘要偏差。

4. 把长内容编码成少量特殊表示

这类方法更偏研究和系统层。

思路不是保留人类可读文本,而是:

  • 让模型把长 prompt 压成少量可复用表示
  • 后续只传这组压缩后的表示

这就是为什么有些论文会讨论:

  • gist tokens
  • soft prompt compression
  • latent compression

它们压缩的是“表示”,不只是“文字”。

现在更实用的压缩技术是什么

如果从真实工程落地看,不同方案的优先级差异很大。

1. 滚动摘要 + 最近原文

这是对话系统里最实用、也最稳的一类。

做法通常是:

  • 很旧的历史压成摘要
  • 关键偏好、限制、决策单独提取
  • 最近几轮原文保留

它的原理很简单:

  • 旧历史里大部分信息不会再逐字引用
  • 真正重要的是状态,不是原文长度

适合:

  • 长聊天
  • 客服
  • 多轮助手
  • Agent 执行流

不适合:

  • 你需要保留原话措辞
  • 法律、合规、医学这类不能随便改写的内容

2. RAG 检索 + rerank + top-K 裁剪

这是知识库场景里最主流的一类,不是严格意义上的“文本压缩”,但在工程上常被当作最有效的上下文压缩。

原理是:

  1. 先从大知识库里召回一批候选 chunks
  2. 再用 reranker 或排序策略挑出最相关的 top-K
  3. 只把最值得看的少量证据送进模型

它解决的不是“把一段文本压短”,而是:

  • 不要把 100 份资料全塞进去
  • 只给模型看它现在最该看的 5 份、10 份或 20 份

Anthropic 在 Contextual Retrieval 里给出的结果很有代表性:

  • 只做 contextual embeddings + contextual BM25,top-20 retrieval failure rate 可下降 49%
  • 再加 reranking,可下降 67%

这类方法的本质是:

  • 先选对材料
  • 再谈要不要进一步压缩材料本身

3. 抽取式 prompt compression

这是近两年最值得单独区分的一类。

它和摘要式压缩最大的不同是:

  • 尽量不重写
  • 尽量保留原文中的关键 token、句子或短语
  • 通过删冗余来缩短输入

2024 年一篇专门比较不同 prompt compression 方法的论文给出的结论很直接:

  • extractive compression 往往优于摘要式改写和 token pruning
  • 在不少任务上能做到最高约 10x 压缩,同时准确率损失较小

这件事很重要,因为它说明在很多长上下文推理场景里:

  • “保留原词、删掉冗余”
  • 往往比“先总结成更短的话”

更稳。

原因并不复杂:

  • 原词还在,事实和措辞不容易漂
  • 删除冗余比生成新表述更不容易幻觉

4. Selective Context

Selective Context 是这类方法里很典型的代表。

它的思路是:

  • 识别上下文中冗余部分
  • 把低价值内容裁掉
  • 让输入更紧凑

论文结果里,一个很常被引用的数字是:

  • 上下文成本下降 50%
  • 推理内存下降 36%
  • 推理时间下降 32%

而下游质量只出现较小变化。

这类方法适合:

  • 长文档摘要
  • 长对话响应
  • 长上下文问答

它的优点是:

  • 不要求重训练主模型
  • 思路直接
  • 容易作为外部预处理接在前面

5. LLMLingua / LongLLMLingua / LLMLingua-2

这组方法现在讨论度很高,而且已经不只是论文里的概念。

Microsoft 的 LLMLingua 项目页直接写到,它已经被集成进 LangChainLlamaIndex
这至少说明它不是很边缘的实验性路线。

LLMLingua

它的核心原理是:

  • 用小模型的 perplexity 去估计 prompt 冗余
  • 做 coarse-to-fine 压缩
  • 在高压缩率下尽量保住语义

项目页给出的结果是:

  • 最多可做到 20x 压缩
  • 在 GSM8K 上 20x 压缩时,性能只下降约 1.5 个点

LongLLMLingua

LongLLMLingua 是把这个思路更明确地推到长上下文场景。

它强调两点:

  • 长上下文里,关键信息密度和位置信息都会影响效果
  • 压缩不仅能降成本,还可能改善模型对关键证据的感知

论文摘要里给出的代表结果是:

  • 在 NaturalQuestions 上,相比原始 prompt,最高可提升 17.1%
  • 同时输入 token 大约减少到原来的 1/4
  • 对约 10k tokens 的 prompt,在 2x-10x 压缩下可带来 1.4x-3.8x 端到端加速

这类方法适合:

  • few-shot prompt 很长
  • 多文档 QA
  • 长代码上下文
  • 检索结果很多,但还想继续压

LLMLingua-2

LLMLingua-2 继续往前走了一步。

ACL 2024 论文把它表述成:

  • 用 data distillation 学压缩目标
  • 把 prompt compression 变成 token classification
  • 用双向 Transformer encoder 抓全局上下文

它想解决的是早期基于 entropy / perplexity 的方法不够对齐压缩目标的问题。
论文里给出的结果是:

  • 比已有 prompt compression 方法快 3x-6x
  • 2x-5x 压缩比下,可带来 1.6x-2.9x 端到端加速

如果只看当前路线演化,我的判断是:

  • LLMLingua 更像早期实用代表
  • LongLLMLingua 更偏长上下文优化
  • LLMLingua-2 更像把压缩器单独训练成一个更稳定组件

6. Query-aware 文档压缩

还有一类很值得单独拎出来:

  • 它不是直接压整个 prompt
  • 而是围绕当前问题压缩检索到的长文档

这类方法特别适合:

  • 多跳问答
  • 大量检索结果拼接
  • 文档之间有交叉证据

CompAct 就是很典型的代表。
它强调的是“active strategy”,也就是压缩时持续围绕问题保留真正相关的证据,而不是一次性粗暴删减。
论文摘要里给出的数字很激进:

  • 在多跳 QA 上可达到 47x 压缩

这类方法的价值在于:

  • 不是把检索出来的材料直接摘要成一坨
  • 而是尽量保住对问题真正有用的证据链

7. Contextual Retrieval

严格说,Contextual Retrieval 不是“压缩技术”,而是“检索前增强 + 检索后裁剪”。

但它在解决“上下文过长”时很实用,因为它能减少:

  • 召回失败
  • 低相关 chunks 被送进模型
  • top-K 里无效内容太多

Anthropic 的做法是:

  • 先给每个 chunk 加上短的解释性上下文
  • 再做 embeddings 和 BM25
  • 最后再加 reranking

这个方案特别适合企业知识库,因为它压的不是 token 数本身,而是:

  • 无效上下文比例
  • 错误 chunk 进入最终 prompt 的概率

学习型压缩表示为什么现在还没成为默认方案

Gist Tokens 这类方法很有意思。

它的核心思路是:

  • 把长 prompt 压成少量可复用的 gist tokens
  • 后续反复使用这些压缩表示

论文里给出的结果是:

  • 可做到最高 26x 压缩
  • FLOPs 最多下降 40%

这类方法从研究上很漂亮,但它到现在还没有成为多数团队的默认选择,原因通常是:

  • 需要训练或特殊模型支持
  • 依赖特定架构和注意力掩码
  • 工程接入门槛高于“摘要 + 检索 + 抽取”

所以它更像:

  • 基础设施路线
  • 模型侧路线
  • 重复大前缀场景的高阶优化

而不是多数应用层团队的第一选择。

如果只看现在更热门的方案,我的判断

这部分不是官方排行榜,而是我根据官方工程博客、集成情况和近两年论文趋势做的工程判断。

还有一个容易被忽略的前提:

  • 不是所有场景都必须压缩

Anthropic 在 Contextual Retrieval 文章里明确提到,如果知识库还小到能直接放进模型窗口,比如低于约 200K tokens,直接整库放进 prompt 有时反而是更简单的办法。
这时候如果再配合 prompt caching,未必比先切块、再检索、再压缩更差。

第一梯队:最常见、最实用

  • 滚动摘要 + 最近原文
  • RAG top-K + rerank
  • 去重清洗 + token 预算

原因很简单:

  • 接入成本低
  • 和现有系统兼容
  • 对模型无侵入
  • 立即能解决大部分“上下文塞爆”问题

第二梯队:值得认真关注

  • Contextual Retrieval
  • Selective Context
  • LLMLingua / LongLLMLingua / LLMLingua-2

这类方案在“资料还是太长,但不想单纯摘要改写”时特别有价值。
尤其是当你需要:

  • 保留原词证据
  • 控制成本
  • 缩短长 prompt 延迟

第三梯队:更偏研究和基础设施

  • Gist Tokens
  • KV cache compression
  • 更激进的 token pruning / latent compression

它们不是没价值,而是:

  • 更偏模型侧
  • 更需要训练或定制推理栈
  • 不太像应用团队的第一步

该怎么选

如果你现在遇到的是“上下文过长”,推荐按这个顺序判断:

  1. 先看是不是根本不该全塞
    能检索就别全量塞,能 top-K 就别把 top-100 都送进去。

  2. 再看是不是旧历史太多
    聊天场景优先做摘要和状态提取。

  3. 如果必须保留原始证据
    优先考虑抽取式压缩,而不是摘要式改写。

  4. 如果是检索后材料仍然过长
    优先考虑 query-aware 压缩、rerank、CompAct、LongLLMLingua 这类路线。

  5. 只有在重复大前缀、系统级优化场景里
    再考虑 gist tokens、KV compression 这类更底层的方案。

一个更实用的判断标准

不要先问“压缩率最高的是谁”,而要先问:

  • 我需不需要保留原词
  • 我压的是历史,还是证据材料
  • 我能不能接受改写
  • 我有没有当前 query 可用
  • 我愿不愿意引入额外模型或训练步骤

很多时候,真正最优的不是“最先进论文”,而是:

  • 对话历史用摘要
  • 知识库用检索和 rerank
  • 检索结果再做抽取式压缩

这三步叠起来,往往比单押一种方案更稳。

怎么把上下文组织给模型

这部分比“用多长模型”更决定结果。

一个普遍更稳的顺序是:

  1. 固定规则
    system / developer 指令、角色定义、禁止项

  2. 工具和输出约束
    tool schema、JSON schema、输出格式要求

  3. 稳定背景
    项目背景、用户长期偏好、固定事实

  4. 外部资料
    检索片段、文档摘录、数据库结果

  5. 历史摘要
    更早对话的压缩版结论

  6. 最近几轮原文
    保留临近上下文,避免摘要丢掉语气和细节

  7. 当前问题
    最后把这轮真正要回答的问题放清楚

  8. 最终输出要求
    例如“先结论,再步骤,最后风险”

一个推荐写法

text
[系统规则]
你是...
回答必须...

[工具说明]
你可以使用...

[稳定背景]
项目是...
用户偏好是...

[检索资料]
资料1...
资料2...

[历史摘要]
到目前为止,已经确认...

[最近对话]
user: ...
assistant: ...
user: ...

[当前任务]
请回答...

[输出格式]
按以下结构输出...

这个顺序的核心思路很简单:

  • 前面放稳定规则
  • 中间放证据材料
  • 后面放最新问题

为什么建议“静态前、动态后”

这是因为多数缓存和前缀复用都更喜欢稳定前缀。

OpenAI 的 prompt caching 文档明确建议把静态内容放前面,把变化内容放后面。
Anthropic 的 prompt caching 文档也强调,工具定义、system 指令、上下文和示例应该优先放在前部,并在静态部分结束处设缓存断点。

除了缓存,这样排还有一个现实好处:

当你调试时,更容易看出问题到底出在哪一层:

  • 是规则写歪了
  • 是检索片段不对
  • 还是当前问题表述不清

常见错误组织方式

1. 整段原始历史无脑全塞

结果通常是:

  • 窗口浪费
  • 旧噪音太多
  • 新问题反而被淹没

2. 先放大段资料,最后才写规则

这样模型往往先被资料“带跑”,后面的格式要求约束力变弱。

3. 检索片段太多,但没有排序

不是片段越多越好。
低相关材料多了,反而会稀释真正有用的内容。

4. 不做 token 预算

很多上下文问题不是模型不够长,而是你根本没算:

  • system 占了多少
  • tool schema 占了多少
  • 文档占了多少
  • 输出还剩多少

5. 把“记忆”全寄托在聊天历史

更稳的做法通常是把长期信息结构化存储,再按需回填,不要全靠对话原文。

怎么判断你现在的问题是不是“上下文问题”

常见信号有这些:

  • 模型忘了刚刚确定过的要求
  • 前面能遵守的格式,后面开始飘
  • 文档明明给了,模型却漏掉中段信息
  • 多轮对话越长,回答越空泛
  • 一加 RAG 资料,回答反而更乱
  • 同样问题,在短上下文时更稳定

如果这些现象同时出现,优先检查:

  1. token 预算
  2. 历史裁剪策略
  3. 检索内容是否过多或过杂
  4. 输出预算是否不足
  5. 消息组织顺序是否合理

我的判断

上下文不是一个“模型参数小知识”,而是大模型产品能不能稳定工作的核心约束之一。

很多人把问题归结成“模型不够聪明”,但实际更常见的原因是:

  • 喂进去的材料太乱
  • 顺序不对
  • 噪音太多
  • 输出预算没留
  • 硬上限和有效容量没分开看

如果把模型当成一个一次性阅读当前材料再作答的系统,那么上下文管理本质上就是:

  • 控制这次让它看到什么
  • 控制这些信息按什么顺序出现
  • 控制哪些历史该保留,哪些该压缩

窗口当然重要。
但更重要的是,你有没有把窗口用在刀刃上。

TODO:围绕上下文继续补的关联问题

  • [ ] prompt caching 和 KV cache 到底是什么关系
  • [ ] 为什么长文档问答常见“中间丢失”现象
  • [ ] RAG 和长上下文应该怎么配合,而不是互相替代
  • [ ] 多轮对话里,摘要回填应该怎么设计
  • [ ] 摘要式压缩和抽取式压缩,什么时候该选哪一个
  • [ ] LLMLingua、LongLLMLingua、LLMLingua-2 的适用边界怎么分
  • [ ] 工具调用时,tool schema 太长该怎么裁
  • [ ] 本地推理里,显存和上下文长度怎么估算
  • [ ] RoPE scaling、YaRN、LongRoPE 这些方法分别在解决什么

参考链接

基于 VitePress 的个人知识库骨架