上下文工程:长文档、长对话与记忆管理
同一个模型,为什么别人用起来像懂业务的同事,你用起来像刚入职的陌生人?差别往往在上下文:你每次给它的信息是否足够、是否有序、是否干净。上下文窗口(模型一次能读入的文本总量)是这章的核心概念,但它不是「越大越好」——塞得满、放得乱,效果反而更差。本章给长文档、长对话、指令摆放三套可操作的做法。
先建立对上下文窗口的直觉
把上下文窗口想成一张工作台:你给的资料、之前聊过的话、模型自己的回答,全都摊在同一张台子上。台子有限,而且有个反直觉的规律——台子越满,中间的东西越容易被忽略。
| 现象 | 原因 | 对策 |
|---|---|---|
| 材料前 10% 和后 10% 记得最清 | 注意力更集中在开头与结尾 | 把最重要的要求放在首尾各说一次 |
| 资料塞满后回答变浅 | 有效信息被无关内容稀释 | 只给相关段落,不给整本书 |
| 对话越长越跑偏 | 早期错误结论被反复引用,成了「既定事实」 | 定期总结并开新对话 |
| 同样问题两次结果差很多 | 上下文不同,或采样有随机性 | 固定提示词与材料顺序,重要结果复跑 |
结论是:上下文工程的目标不是「喂得多」,而是「喂得准、放得对」。
长文档处理三招
第一招:分段处理,先分后合
一份 3 万字的文档,直接一次丢进去通常只能得到泛泛概述。正确做法是分块并保留统一结构,最后再合并。
我要处理的文档共 8 段,我接下来会分段发给你,每次发一段。
请你对每一段做同样三件事,输出固定格式:
1. 这段在讲什么(一句话,30 字内)
2. 关键结论或数据(不超过 5 条,原样保留数字与专有名词)
3. 与上一段的衔接或矛盾点(没有就写「无」)
收到请回复「已就绪」,不要提前总结。全部发完后我会让你做整体合并。
全部分段处理完,再补一条合并指令:
下面是我们分段处理完的 8 段结果。请合并成一份完整摘要:
- 保留所有数字与原样专有名词,不要改写
- 标出前后矛盾或含糊的地方,单列「待核实」一节
- 按「总述 → 分块要点 → 待核实」三节输出,不要重复各段原文
第二招:先提纲后细节
面对陌生长文,先要结构再要内容,能大幅减少「读了半天抓不住重点」:
请只做一件事:通读下面的材料,输出它的结构提纲(一级标题 + 每节一句话说明),
不要总结内容,不要评论。我会根据提纲挑出需要的章节,再让你精读。
拿到提纲后,只挑真正需要的两三节让它精读,比整篇灌进去便宜也准确。
第三招:关键词检索,只给相关片段
文档远超窗口、或你只关心某个问题时,不要整篇给,先定位再喂。
下面是关于「退款流程」的 40 页制度文档。请只提取与「跨境订单退款」相关的全部段落,
逐段原样引用(不要改写),并标出每段所在的章节标题。如果文档中确实没有相关内容,
直接回答「文档未涉及」,不要用常识补充。
这就是 RAG(检索增强生成)的一句话原理:先从你的资料库里按相关性检索出若干片段,把这些片段拼进提示词再让模型回答。RAG 的价值在于让模型「基于你的材料说话」,代价是检索没找全时它会理直气壮地漏答。
| 长文档情形 | 推荐做法 | 不推荐 |
|---|---|---|
| 几千字,问整体结论 | 一次给全文 + 指定输出格式 | 分成八段来回粘贴 |
| 几万字,问某个细节 | 关键词检索出相关片段 | 整篇灌入再问细节 |
| 几十万字/多文件 | 建立片段索引(RAG)+ 逐问检索 | 试图靠长窗口硬扛 |
| 需要逐条核对 | 分段结构化处理 + 保留原文引用 | 让它一次输出全局总结 |
长对话管理:定期「存档」,而不是一直聊
长对话跑偏,通常不是模型笨,而是上下文里堆了太多过期结论。三条动作按节奏做:
- 每隔一段让它总结现状:把「已经确认的事、还没定的事、下一步该做什么」压缩成一小段,作为新的起点。
- 把结论落成文档:凡是要反复用的结论,立刻复制到自己的文档或知识库里,别指望对话窗口替你记。
- 在关键节点开新对话:把总结 + 必要材料贴进新对话,历史上下文清空,噪音归零。
请把我们到目前为止的讨论压缩成一份「交接备忘」,供我开启新对话时使用。
输出四节,总计不超过 400 字:
1. 已确认的决定(含关键数字与口径)
2. 已知的约束与前提
3. 未解决的问题
4. 下一步计划
不要复述讨论过程,不要写客套话,只要结论。
指令摆放:稳定的放前面,问题放最后
| 位置 | 该放什么 | 原因 |
|---|---|---|
| 最前面 | 角色、长期规则、术语口径、输出格式 | 稳定不变,作为全局设定被反复参考 |
| 中间 | 背景材料、参考资料 | 便于用分隔符夹住,避免与指令混淆 |
| 最后 | 本次的具体问题与最新数据 | 离生成最近,最不会被忽略 |
如果发现模型老忘掉某条要求,最省事的修法不是加长说明,而是把这条要求挪到末尾再说一遍。
什么时候该开新对话
| 信号 | 说明 | 动作 |
|---|---|---|
| 话题换了 | 上一话题的上下文对新话题是噪音 | 直接开新对话,或至少贴一份交接备忘 |
| 它开始引用早期错误结论 | 错误已变成「前提」 | 开新对话,把正确结论明确写进去 |
| 回复明显变慢、变浅 | 台子太满,注意力被稀释 | 总结后开新对话 |
| 需要复现上次的好结果 | 上下文已变,无法重现 | 把当时的提示词与材料存档,新对话里原样复用 |
| 任务进入新阶段(起草 → 审核) | 两个阶段的角色与要求不同 | 开新对话,用新的角色提示词 |
常见坑
| 坑 | 后果 | 改法 |
|---|---|---|
| 认为窗口大就不用管上下文 | 答得又浅又飘,还更贵 | 只给相关段落,结构化裁剪 |
| 材料与指令混在一起 | 材料里的句子被当命令执行 | 用 <资料> 标签或代码块夹住材料 |
| 一次粘贴 20 份文件 | 关键信息被稀释,答案泛化 | 先检索、再喂相关片段 |
| 长对话一直聊到几百轮 | 越聊越偏,还无法复现 | 定期总结存档,关键节点开新对话 |
| 结论只留在对话里 | 关掉窗口就丢了 | 结论当天落到自己的文档里 |
小结:把上下文窗口当有限的工作台——长文档分段处理、先提纲后精读、关键词检索只喂相关片段;长对话定期总结成交接备忘并落成文档;稳定指令放前面、当前问题放最后,跑偏的信号一出现就开新对话。