上下文说明
这篇文章解决什么问题
很多人在用大模型时,嘴上会说“上下文不够了”“模型忘了前面说过的话”“这个模型支持 128K”,但真正落到工程里,常常还是混着几件不同的事:
- 什么叫上下文
- 为什么模型非得依赖上下文
- 为什么长度一定有限
- 128K、200K、1M 到底分别代表什么
- 这个长度是模型天生的,还是我自己能调的
- 同样一个窗口,怎样组织内容才不浪费
这篇文章就是把这些问题拆开说清楚。
先说结论
- 上下文就是模型在“这一轮请求里”能看到的全部输入,以及它接下来要生成的输出预算。
- 模型不是天然有长期记忆,它每次回答都只基于当前这次请求里带进去的内容。
- 上下文长度有限,不只是因为“厂商没放开”,更主要是算力、显存、延迟、训练分布和位置编码都在限制它。
- 真正可用的输入空间,不等于标称窗口长度,因为你还要给输出留位置。
- 提高上下文有两条路:一条是换更长的模型或推理配置,另一条是把同样的窗口用得更有效。
- 对大多数真实项目来说,决定效果的往往不是“128K 还是 200K”,而是你有没有把信息组织对。
什么是上下文
最直接的理解是:
上下文 = 这次请求里,模型在生成答案前能看到的全部 token
它通常包含这些部分:
- system / developer 指令
- tool 定义或 schema
- 检索回来的资料
- 历史对话
- 当前用户问题
- 预留给模型输出的 token 空间
很多官方文档都把它定义成“模型当前工作时能回看的范围”。
如果用一句更通俗的话说:
上下文就是模型这次答题时,桌上摊开的全部材料。
桌面再大,也不是无限大。
为什么要有上下文
因为模型不是凭空回答问题的。
它虽然在预训练阶段学过大量通用知识,但到了实际调用时,仍然需要知道这次任务的现场信息:
- 你现在到底要它做什么
- 你们前面已经说到了哪里
- 当前要遵守什么格式
- 当前允许使用哪些工具
- 当前有哪些外部资料
如果没有上下文,模型每次都只能把你的最后一句话当作孤立输入。
比如同一句:
text
继续没有上下文时,这句话几乎没有意义。
有上下文时,它可能表示:
- 继续翻译上一段
- 继续输出刚才被截断的 JSON
- 继续刚才的总结
- 继续写那篇文章的下一节
所以,上下文的作用不是“让模型更聪明”,而是让模型知道:
- 当前任务是什么
- 当前边界是什么
- 当前历史发生过什么
上下文不是训练知识,也不是长期记忆
这三个概念很容易混在一起。
| 概念 | 它是什么 | 它不是什么 |
|---|---|---|
| 训练知识 | 模型在训练阶段学到的统计规律和知识 | 不是你这次临时塞进去的文档 |
| 上下文 | 本次请求里实际送进去的内容 | 不是永久记忆 |
| 长期记忆 | 应用层自己存的用户资料、摘要、偏好、历史索引 | 不是模型天生自带的稳定记忆 |
所以当人们说“模型记住了”,很多时候真实发生的是:
- 应用把之前的信息存了下来
- 下一轮又把相关内容重新放回上下文
- 模型因此看起来像“记得”
模型自己并不会跨请求永久保留你刚才说的话。
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.4 | 1,050,000 | 128,000 | 当前旗舰推理模型 |
OpenAI gpt-4.1 | 1,047,576 | 32,768 | 1M 级长上下文 |
OpenAI gpt-4o | 128,000 | 16,384 | 通用型多模态主力 |
Anthropic Claude Sonnet 4.6 | 1M | 64K | Claude 当前主力速度 / 智能平衡型模型 |
Google Gemini 2.5 Pro | 1,048,576 | 65,536 | 1M 级长上下文 |
常见开源 / 开放权重模型
| 模型 | 官方标称上下文 | 官方标称最大输出 | 备注 |
|---|---|---|---|
Qwen2.5-7B-Instruct | 131,072 | 8,192 | 官方模型卡给出 full 131,072 |
Meta-Llama-3.1-8B-Instruct | 128K | 模型卡重点写上下文,输出上限通常看具体推理实现 | 常见开源长上下文基线 |
这里有两个很重要的提醒:
不同厂商写法不一样
有的直接写“context window”,有的分成 input / output token limit。标称长度不等于有效质量
一个模型支持 1M,不代表它在 1M 的每个位置都同样稳。
这些长度到底哪里能配
要分四层看。
第一层:模型能力上限
这是最硬的一层。
比如:
gpt-4o的窗口不是你自己改成 200K 就能生效Claude Sonnet 4.6的上限由官方模型能力决定Gemini 2.5 Pro的上限由模型能力决定
也就是说:
- 你能选模型
- 你不能凭空把闭源模型的硬上限改大
第二层:请求级参数
这一层通常能配的是“这次最多生成多少”和“超长时怎么处理”。
OpenAI
Responses API 文档里有这些直接相关参数:
max_output_tokenstruncation
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 servevLLM
vLLM 官方文档里可以通过 --max-model-len 设置,或者让它自动按显存选择。
示意:
bash
vllm serve Qwen/Qwen2.5-7B-Instruct --max-model-len 32768这里要注意:
- 你只是给服务设了可分配上限
- 不代表模型训练上真的在这个长度里稳
第四层:模型配置层
在开源模型和 Transformers 库 体系里,你还会看到这些字段:
max_position_embeddingsrope_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-4o的128K换到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 会话 | 摘要丢细节、语气和边界 |
| 检索裁剪 | 外部资料 / 文档块 | 只保留和当前问题最相关的 chunks | RAG、知识库问答 | 召回不准会把关键证据丢掉 |
| 抽取式压缩 | 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 裁剪
这是知识库场景里最主流的一类,不是严格意义上的“文本压缩”,但在工程上常被当作最有效的上下文压缩。
原理是:
- 先从大知识库里召回一批候选 chunks
- 再用 reranker 或排序策略挑出最相关的 top-K
- 只把最值得看的少量证据送进模型
它解决的不是“把一段文本压短”,而是:
- 不要把 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 项目页直接写到,它已经被集成进 LangChain 和 LlamaIndex。
这至少说明它不是很边缘的实验性路线。
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
它们不是没价值,而是:
- 更偏模型侧
- 更需要训练或定制推理栈
- 不太像应用团队的第一步
该怎么选
如果你现在遇到的是“上下文过长”,推荐按这个顺序判断:
先看是不是根本不该全塞
能检索就别全量塞,能 top-K 就别把 top-100 都送进去。再看是不是旧历史太多
聊天场景优先做摘要和状态提取。如果必须保留原始证据
优先考虑抽取式压缩,而不是摘要式改写。如果是检索后材料仍然过长
优先考虑 query-aware 压缩、rerank、CompAct、LongLLMLingua 这类路线。只有在重复大前缀、系统级优化场景里
再考虑 gist tokens、KV compression 这类更底层的方案。
一个更实用的判断标准
不要先问“压缩率最高的是谁”,而要先问:
- 我需不需要保留原词
- 我压的是历史,还是证据材料
- 我能不能接受改写
- 我有没有当前 query 可用
- 我愿不愿意引入额外模型或训练步骤
很多时候,真正最优的不是“最先进论文”,而是:
- 对话历史用摘要
- 知识库用检索和 rerank
- 检索结果再做抽取式压缩
这三步叠起来,往往比单押一种方案更稳。
怎么把上下文组织给模型
这部分比“用多长模型”更决定结果。
一个普遍更稳的顺序是:
固定规则
system / developer 指令、角色定义、禁止项工具和输出约束
tool schema、JSON schema、输出格式要求稳定背景
项目背景、用户长期偏好、固定事实外部资料
检索片段、文档摘录、数据库结果历史摘要
更早对话的压缩版结论最近几轮原文
保留临近上下文,避免摘要丢掉语气和细节当前问题
最后把这轮真正要回答的问题放清楚最终输出要求
例如“先结论,再步骤,最后风险”
一个推荐写法
text
[系统规则]
你是...
回答必须...
[工具说明]
你可以使用...
[稳定背景]
项目是...
用户偏好是...
[检索资料]
资料1...
资料2...
[历史摘要]
到目前为止,已经确认...
[最近对话]
user: ...
assistant: ...
user: ...
[当前任务]
请回答...
[输出格式]
按以下结构输出...这个顺序的核心思路很简单:
- 前面放稳定规则
- 中间放证据材料
- 后面放最新问题
为什么建议“静态前、动态后”
这是因为多数缓存和前缀复用都更喜欢稳定前缀。
OpenAI 的 prompt caching 文档明确建议把静态内容放前面,把变化内容放后面。
Anthropic 的 prompt caching 文档也强调,工具定义、system 指令、上下文和示例应该优先放在前部,并在静态部分结束处设缓存断点。
除了缓存,这样排还有一个现实好处:
当你调试时,更容易看出问题到底出在哪一层:
- 是规则写歪了
- 是检索片段不对
- 还是当前问题表述不清
常见错误组织方式
1. 整段原始历史无脑全塞
结果通常是:
- 窗口浪费
- 旧噪音太多
- 新问题反而被淹没
2. 先放大段资料,最后才写规则
这样模型往往先被资料“带跑”,后面的格式要求约束力变弱。
3. 检索片段太多,但没有排序
不是片段越多越好。
低相关材料多了,反而会稀释真正有用的内容。
4. 不做 token 预算
很多上下文问题不是模型不够长,而是你根本没算:
- system 占了多少
- tool schema 占了多少
- 文档占了多少
- 输出还剩多少
5. 把“记忆”全寄托在聊天历史
更稳的做法通常是把长期信息结构化存储,再按需回填,不要全靠对话原文。
怎么判断你现在的问题是不是“上下文问题”
常见信号有这些:
- 模型忘了刚刚确定过的要求
- 前面能遵守的格式,后面开始飘
- 文档明明给了,模型却漏掉中段信息
- 多轮对话越长,回答越空泛
- 一加 RAG 资料,回答反而更乱
- 同样问题,在短上下文时更稳定
如果这些现象同时出现,优先检查:
- token 预算
- 历史裁剪策略
- 检索内容是否过多或过杂
- 输出预算是否不足
- 消息组织顺序是否合理
我的判断
上下文不是一个“模型参数小知识”,而是大模型产品能不能稳定工作的核心约束之一。
很多人把问题归结成“模型不够聪明”,但实际更常见的原因是:
- 喂进去的材料太乱
- 顺序不对
- 噪音太多
- 输出预算没留
- 硬上限和有效容量没分开看
如果把模型当成一个一次性阅读当前材料再作答的系统,那么上下文管理本质上就是:
- 控制这次让它看到什么
- 控制这些信息按什么顺序出现
- 控制哪些历史该保留,哪些该压缩
窗口当然重要。
但更重要的是,你有没有把窗口用在刀刃上。
TODO:围绕上下文继续补的关联问题
- [ ] prompt caching 和 KV cache 到底是什么关系
- [ ] 为什么长文档问答常见“中间丢失”现象
- [ ] RAG 和长上下文应该怎么配合,而不是互相替代
- [ ] 多轮对话里,摘要回填应该怎么设计
- [ ] 摘要式压缩和抽取式压缩,什么时候该选哪一个
- [ ] LLMLingua、LongLLMLingua、LLMLingua-2 的适用边界怎么分
- [ ] 工具调用时,tool schema 太长该怎么裁
- [ ] 本地推理里,显存和上下文长度怎么估算
- [ ] RoPE scaling、YaRN、LongRoPE 这些方法分别在解决什么
参考链接
- OpenAI: GPT-5.4
- OpenAI: GPT-4.1
- OpenAI: GPT-4o
- OpenAI: Responses API
- OpenAI: Counting tokens
- OpenAI: Prompt caching
- Anthropic: Context windows
- Anthropic: Models overview
- Anthropic: Messages API
- Anthropic: Token counting
- Anthropic: Prompt caching
- Google Gemini: Models
- Google Gemini: Long context
- Google Gemini: Count tokens
- Google Gemini: Generate content
- Qwen2.5-7B-Instruct 模型卡
- Meta Llama 3.1 8B Instruct 模型卡
- Ollama: Context length
- vLLM: serve / max-model-len
- Hugging Face Transformers: RoPE utilities
- Anthropic: Contextual Retrieval
- Selective Context
- LLMLingua
- LongLLMLingua
- LLMLingua-2
- Gist Tokens
- CompAct
- Characterizing Prompt Compression Methods for Long Context Inference