长上下文提示技巧:在百万 token 里用好模型
过去一年,主流大模型的上下文窗口从几万 token 一路膨胀到百万级别。Anthropic 的 Claude 3 家族默认提供 200K 上下文窗口,并宣称可接收超过 100 万 token 的输入;OpenAI 的 GPT-5.6 系列上下文窗口为 1.05M;Google 的 Gemini 2.0 Flash 也具备 1M token 的上下文窗口。这意味着你可以把一整本书、一个中型代码库或数百份文档一次性塞进提示里。
但「装得下」不等于「用得好」。本文讲解向长上下文模型投喂长材料时的组织技巧,帮助你把百万 token 的真正价值榨出来。
长上下文能做什么与不能做什么
先把预期摆正。长上下文窗口解决了「材料放不进去」的问题,但并没有自动解决「模型会不会认真读、会不会读对」的问题。
长上下文擅长:
- 跨多份文档做综合与对比,例如把十几份竞品报告汇总成一张对比表。
- 在单个代码库范围内做全局理解,例如「这个仓库里所有与鉴权相关的函数有哪些」。
- 保留长篇对话或多轮任务的完整背景,避免来回复述。
- 一次性核对一份长合同、长论文里的前后一致性。
长上下文不擅长,或者说不能假设它擅长:
- 自动记住中间段落里的每一个细节。相关结论放在中部时,模型容易遗漏。
- 替你做信息筛选。材料越多,噪声越多,模型越容易被无关内容带偏。
- 保证长输出里每一处引用都精确对应原文。
- 把超长材料里的因果关系完整推理清楚,尤其是需要跨越很远距离的信息时。
一句话:长上下文是「容量」的升级,不是「注意力」的免费升级。下面几个技巧,本质都是在帮模型把注意力放在对的地方。
lost-in-the-middle 现象
2023 年,Liu 等人发表了一篇影响很大的论文《Lost in the Middle: How Language Models Use Long Contexts》(arXiv:2307.03172,发表于 TACL 2023)。他们在两项需要「从输入中找出相关信息」的任务上测试模型:多文档问答和键值检索。
核心发现是:当关键信息在上下文中的位置发生变化时,模型表现会显著波动。性能通常在两种位置最高——相关信息出现在输入的开头,或者出现在输入的结尾;而当相关信息被放在长上下文的中间位置时,即使模型本身号称支持长上下文,表现也会明显下滑。
这个现象对提示工程的直接含义是:
- 不要默认模型会「公平地」读完所有内容。
- 关键指令、关键事实、关键约束,尽量放在提示的开头或结尾。
- 长材料的中间部分适合放「背景」和「次要支撑」,不适合放你最在意的那一条信息。
需要强调,这篇论文测试的是当时的一批模型,后续模型在长上下文利用上已有改进,但「位置偏好」仍然是实践中反复被观察到的真实问题,应当作为默认防范措施。
材料组织:分块、摘要与重排
当你要投喂的素材本身很长,第一步往往不是「全部粘贴」,而是先做一次组织。
分块
把超长材料切成有语义边界的块,例如按章节、按函数、按段落。分块的好处是每块都短而完整,便于你控制顺序,也便于后续做检索或重排。
摘要
对特别长的单份材料,先用模型生成一段结构化摘要,再把摘要放进主提示,原始长文作为可回溯的附件。这样主提示保持精简,模型先看到骨架,需要细节时再去翻原文。
重排
根据任务把材料重新排顺序,而不是机械地按文件名或时间顺序排列。常用策略:
- 与当前问题最相关的材料排到最前。
- 互相矛盾的材料相邻放置,方便模型对比而不是把它们隔开。
- 把「任务指令」与「输出格式要求」固定在提示头部和尾部,不穿插在材料中间。
下面是一段把多份检索结果重排后再拼进提示的示例:
def reorder_for_prompt(query, docs, top_k=5):
# docs: 已按相关性初排的 [(score, text)]
# 策略:最相关放最前,同时保留一份放到结尾做强调
ranked = sorted(docs, key=lambda x: x[0], reverse=True)[:top_k]
head = ranked[0] # 最重要,置顶
middle = ranked[1:-1] # 中间材料
tail = ranked[-1] # 次重要,置底收尾
ordered = [head] + middle + [tail]
return "\n\n".join(text for _, text in ordered)
prompt = "请基于以下材料回答问题,相关材料已按重要性排序:\n\n" + reorder_for_prompt(q, docs)
把关键内容放在头尾
这是 lost-in-the-middle 最直接的应对手段,也是成本最低的技巧。
- 系统指令写头部:角色、目标、硬性约束、输出格式,全部放在提示最前面。
- 最终要求写尾部:例如「请只依据上面材料作答,不得编造,并标注每条结论对应的材料编号」,放在材料之后、请求收尾处。
- 真正决定答案的那一条事实,如果只有一条,优先放头部;如果有两条,一条头一条尾,避免挤在中部。
- 长列表、长表格、长代码,尽量让「待回答的问题」紧贴在它们之后,减少模型需要回跳的距离。
一个常见的反面教材是:先贴 80 页文档,最后一句才说「请回答第 12 页提到的那个参数」。更好的写法是开头就声明任务,文档紧随其后,结尾再次复述问题。
长上下文与 RAG 的取舍
长上下文崛起后,一个常见疑问是:是不是有了百万 token,就不需要 RAG(检索增强生成)了?现实里两者不是替代关系,而是互补关系。
| 维度 | 长上下文 | RAG |
|---|---|---|
| 适合的材料规模 | 数十到数百份文档、一个中型代码库 | 海量知识库、持续更新的文档集 |
| 成本 | 输入越长,费用与延迟越高 | 只检索相关片段,成本更可控 |
| 新鲜度 | 取决于你投喂的内容,需自行更新 | 可接实时索引,天然适配变化 |
| 抗噪声 | 材料越多噪声越多,容易被带偏 | 只取相关片段,信噪比更高 |
| 跨库全局理解 | 强,适合综合对比 | 弱,受检索召回限制 |
实践中的组合方式:
- 先用 RAG 从大知识库里召回最相关的若干片段,缩小范围。
- 再把召回片段连同明确任务一起放进长上下文模型,做深度综合与推理。
- 对超长单文档(如一份长合同),可整份投喂长上下文模型,省去切分检索的工程成本。
简言之:材料会持续增长、需要实时性,用 RAG 做第一道筛选;材料规模可控、需要整体理解,直接用长上下文更高效。
代码库与文档场景示例
场景一:让模型理解一个代码库
不要直接把整个仓库压缩成一个文件丢进去。更稳的做法是分三层:
- 目录结构与模块说明放在最前,先给模型一张地图。
- 与问题相关的核心文件全文放在中部,按相关性排序。
- 函数签名清单、接口约定这类「契约」放在结尾,作为模型作答时的硬约束。
【系统指令】你是资深工程师,仅依据下面仓库材料回答,指出改动会影响哪些模块。
【仓库地图】
src/auth/ 鉴权相关
src/api/ 接口层
src/db/ 数据访问
【相关文件:auth.py】
(全文)
【相关文件:api.py】
(全文)
【接口契约】
login() 返回 token;refresh() 接受 token。任何改动不得改变这两个函数签名。
【任务】若在 auth.py 增加双因子校验,哪些模块需要同步修改?请说明原因。
场景二:长文档核对
把整份文档投喂后,把「你要核对的清单」放在头部和尾部各出现一次,让模型在长文首尾都能看到目标,降低遗漏概率。
场景三:多文档对比
多份竞品报告对比时,先为每份生成一句话定位摘要置于顶部,再附全文,结尾用固定表格模板要求输出,确保格式稳定。
小结
长上下文窗口让「一次投喂大量材料」成为现实,但模型对信息的利用并不均匀。关键要点:
- 长上下文解决容量问题,不自动解决注意力问题。
- lost-in-the-middle 意味着中部信息最易被忽略,关键内容放头尾。
- 投喂前先做分块、摘要、重排,控制材料的顺序与信噪比。
- 系统指令置顶、最终要求置底,问题紧贴材料。
- 长上下文与 RAG 互补:RAG 做筛选与实时性,长上下文做整体理解与综合。
- 代码库与文档场景里,先给地图、再给相关全文、结尾给契约,是最稳的组织方式。
参考与延伸阅读
- Liu, N. F., Lin, K., Hewitt, J., Paranjape, A., Bevilacqua, M., Petroni, F., Liang, P. 《Lost in the Middle: How Language Models Use Long Contexts》. arXiv:2307.03172,TACL 2023。核心结论:模型在长上下文中间位置利用信息的能力显著下降。
- Anthropic.《Introducing the Claude 3 family》. 官方说明 Claude 3 默认 200K 上下文窗口,并具备接收超过 100 万 token 输入的能力。
- OpenAI.《Models》文档(platform.openai.com/docs/models)。GPT-5.6 系列上下文窗口为 1.05M token。
- Google.《Gemini API Models》文档(ai.google.dev/gemini-api/docs/models)。Gemini 2.0 Flash 上下文窗口为 1M token。
- 本教程站内文章《RAG 提示技巧》(tutorials/prompt-engineering/rag-prompting.md),进一步讲解检索增强与长上下文的配合方式。