1. 当提示词开始失效:我在长对话里撞上的"失忆"问题
先说一个真实场景。几个月前我在做一个行业调研分析项目,为了让大模型帮我梳理一整条产业链,我在单次会话里陆续贴了几十份报告片段、访谈纪要、政策文件和历史对话结论。前二十轮还好,模型基本能接住我的提问,引用的数据也还算靠谱。但大概从第五十轮开始,它开始频繁犯一些低级错误——我前一天明确让它记住的某个关键数字,第二天再问它竟然一本正经地给出一个完全不同的答案,还煞有介事地标注了"根据此前对话内容"。
我最初以为是对话太长导致模型"变笨了",于是不断优化我的提问措辞,把问题写得更详细、更精确。结果发现帮助有限,该错的还是错。后来我才意识到,问题的根源根本不在"提示词"写得好不好,而在于我完全没有对对话上下文这个"环境"做任何管理——各种废旧信息堆在上下文窗口里,关键信息被淹没,模型面对一堆混乱材料,怎么可能稳定输出。
这个教训让我开始认真思考一个正在被越来越多从业者讨论的概念:上下文工程。
它和提示词工程是什么关系?简单说,提示词工程关注的是"你向模型说了什么话",而上下文工程关注的是"模型在回答时,它的工作台上到底摆着什么材料"。同一个模型、同一个提示词,工作台上是干净整齐的核心资料还是一团乱麻的历史记录,输出质量天差地别。这篇文章我就把自己这段时间在上下文工程上的踩坑、拆解和沉淀下来的方法论完整梳理一遍,尤其是长对话、复杂任务场景下的上下文管理,希望能帮你少走弯路。
2. 先把上下文窗口的"内部构造"拆清楚:模型到底在看什么
要谈上下文工程,首先要理解上下文窗口里到底发生了什么。很多朋友对上下文窗口的理解就是"一个能装文字的箱子,装得下就行",如果停留在这个层面,后面所有优化策略都没法落地。
2.1 从文本到Token:信息在模型内部不是以"字"为单位的
大模型处理文本的第一步是把文字切分成Token。Token不是按字或者按词切的,它更像是一种子词单元。举个例子,在绝大多数主流分词器里面,一个常见的中文词汇可能只占一个Token,而一个生僻的技术术语可能被拆成好几个Token。Token数量决定上下文窗口的占用,而不是字数。所以上下文工程首先就要培养一种"Token意识"——一段材料占多少Token,往往和你直观感受的字数差别很大。
我做项目时习惯在每条上下文材料后面标注Token估算值。这里有个很实用的经验公式:中文场景下,大概1.5到1.8个中文字符对应一个Token,英文大约是4个字符对应一个Token。混合文本要进行简单加总。别小看这个估算习惯,它直接影响你后面做上下文预算的准确性。一次我在设计多轮决策流程时,计划让模型读三份行业报告,每份感觉只有两三页纸,结果Token全部加起来远超预算,直接把系统提示词的核心指令挤出了有效注意力范围。
2.2 注意力机制和"Lost in the Middle"现象:模型并不是均匀读材料的
上下文窗口不等于有效上下文。这是上下文工程里最关键也最容易被忽视的一点。Transformer架构的核心是注意力机制,但注意力权重在整个上下文长度上并不是平均分配的。
学术界有一个非常著名的现象叫Lost in the Middle(迷失在中间):当需要从上下文中提取某个信息时,模型对上下文开头和结尾位置的内容利用得最好,而对中间位置内容的关注度显著下降。这不是玄学,是注意力分布的特性。多项研究反复验证了这一点,我自己实测也是一样的——把关键指令放在对话历史第50轮中间位置,和放在最新消息前面,模型执行出来的稳定性完全不是一个量级。
这个现象带来的直接结论是:信息位置本身就是一种工程变量。系统提示词里的指令、历史对话里的重要结论、检索回来的资料片段,它们在上下文窗口里的排布顺序,直接影响模型会不会"看见"它们。很多团队调试模型效果不好,反复改指令文本却毫无起色,最后发现是上下文里信息排布顺序出了问题。
2.3 KV Cache:上下文管理的隐性成本
再讲一个工程上特别现实的问题——KV Cache。模型每生成一个Token,都要重新读取整个上下文去计算注意力。为了加速计算,推理框架会把历史上文计算得到的Key和Value缓存起来,这就是KV Cache。它的大小基本和上下文长度、模型层数、注意力头数量成正比。也就是说,上下文塞得越满,不仅模型的注意力质量会下降,GPU显存压力、推理延迟和推理成本都会同步上升。
实测中一个长会话跑到几万Token以后,显存占用会明显涨一大截,响应速度也会变慢。这引出了上下文工程的另一个核心原则:**上下文不是免费的,它有质量成本,也有真金白银的算力成本。**很多团队做RAG时不管三七二十一,把检索到的所有相关文档全塞进去,结果模型输出变慢、费用变高,效果反而更差。上下文管理,本质上是在质量、成本和速度之间做一个动态平衡。
3. 上下文膨胀的三条死路:为什么长对话的模型会"越用越蠢"
理解了上下文窗口的机制,再回头看长对话里模型"变笨"的问题,就清晰多了。我排查了自己那个调研项目,发现当时踩了三个典型陷阱,基本覆盖了上下文工程最常见的失败模式。
3.1 上下文物化:垃圾信息沉淀,关键信息被稀释
这是最普遍的问题。对话进行到中期以后,上下文里已经积累了大量的寒暄语句、错误尝试、无意义的中间产物和重复表达。比如我在调研项目里早期问过几个后来被证明方向错误的子问题,这些内容全部留存在上下文里。模型每读一次上下文,就要浪费注意力在一堆没价值的信息上,关键信息的相对占比越来越低,自然越来越容易"看不见"它们。
这就像一张办公桌,刚开始很干净,资料摆得清清楚楚。干了五十轮之后,桌上堆满了草稿纸、零食袋和旧报纸,真正要用的合同被压在最底下。老板问你要合同内容,你还得翻半天才能找到,而且经常翻错地方。上下文物化问题处理不当,模型的表现和这个场景几乎一模一样。
3.2 事实漂移:早期结论被后续信息覆盖
第二个问题更隐蔽。LLM在推理时有一个倾向:越靠近上下文的末尾,信息对生成结果的影响越大。也就是说,当对话里出现了事实冲突,后进入上下文的信息往往占据上风。
在长对话里,这种问题的表现就是——我前期确认过的一个关键数字,后来在对话里因为临时讨论出现过一次错误的引用,模型之后就会越来越倾向于输出那个错误数字,哪怕早期的正确数据明明还在上下文里。它并不是"删除"了早期信息,而是在生成时更看重最新出现的内容。这就是所谓的事实漂移。如果你不在上下文管理层面做处理,长会话里的事实一致性会随时间推移加速恶化。
3.3 有效上下文缩水:标称窗口距离实际可用窗口的距离
第三个陷阱是关于"虚标"的。很多模型宣称支持128K甚至200K的上下文窗口,但实测下来,超长上下文的实际信息利用能力远低于短上下文。斯坦福等机构做过专门测试,很多模型的"有效上下文长度"只有标称长度的一半甚至四分之一。这个差距不是模型"不诚实",而是训练数据和注意力机制在超长输入下的固有限制。
我自己的实操体验是:在超过一定长度后,即使信息就在上下文里,模型也开始"假装看不见"。有一次我为了让模型结合某条早期信息做推断,特意在后续对话里再次提及"根据第20轮的数据",结果它明确说"您的对话历史中没有这个信息"。查了一下原文确实还在,但它已经无法有效调用了。
这三条死路叠加起来,结论非常明确:上下文工程的核心不是"塞更多信息",而是"让有限的有效上下文空间发挥最大价值"。
4. 对话框之外的事都有哪些管理空间
4.1 信息分层:让上下文作为结构体
我在复盘之后,把以前那套"无限往回填"的做法彻底废弃,改成对上下文信息按属性进行分层管理。这种思路有点像写代码的人做模块划分,系统提示词里只放绝不会变的基础设定与核心约束;可持续整理的关键结论与数据,则以结构化摘要方式固定到一个"只收窄、不改写"的区域;其余的原始材料、过程性内容作为可追溯的附件,再按需回调。
具体到操作上,我形成了一套通用的模板:系统提示词描述角色能力定位与输出规则;任务说明承载当前回合的用户目标;结论区存放必须遵循、不得超过的硬性事实;背景材料区存放支撑性内容,这个区要随时收缩与裁剪。这样模型每次推理时,高优先级的结论区永远处于上下文前后端的高注意力位置,不容易被中间段落淹没。
4.2 摘要与压缩,让上下文"长会话不存原始,只存状态"
对话过程里逐轮保留原始记录,是上下文物化的最大来源。我的做法是:阶段性生成"会话状态摘要",把当前进展、关键假设、已完成的任务、待办事项全部压缩成结构化文本,并把之前的原始内容从上下文里淘汰掉。这样的"状态快照"让模型永远是在跟一份实时更新的工作文档协作,而不是翻聊天记录。
这里有一个操作细节值得说清楚:摘要不能只是简单啰嗦的缩写,必须做成"可执行的上下文"。我要求自己每次压缩时至少分四个维度:"已验证的事实"、"未解决的问题"、"当前的决策"、"下一步行动"。这四类信息后续被模型引用的频率远超普通叙述性摘要。
4.3 相关性问题:让模型先判断"该不该看"
严格来说,上下文管理不能只靠"塞进去之后让模型自己找"。我的习惯是:把可能需要的背景资料先放到一个检索层,每一轮先用轻量级模型去筛选出与当前问题相关的片段,只把这些片段注入上下文。如果资料本身与问题不相关,再长也不注入;如果相关度低,适当削减。这种做法本质上在上下文之外先做了一次筛选,有效控制了Token膨胀。
我一度认为这种筛选会损失信息,后来发现并不是。多数情况下,任务需要的核心材料很少,真正拖累模型的是无关信息量太大。筛选层像一个助理,先帮模型把"今天的工作目录"准备好,而不是把所有抽屉都端上来。
4.4 位置策略:关键的,放在最前和最后
前面提到注意力分布的问题,这可以直接用来设计上下文排布。系统核心指令放在最开头,因为开头位置是注意力最高的区域之一。当前轮次用户的问题放在上下文最末尾,也就是紧贴模型生成的位置。中间放辅助资料,且要求它们具备紧凑的格式。整体上遵循"头尾放关键、中间放支撑"的排布原则。
不过要注意一个反向场景:如果模型是用于代码生成或工具调用,那么"最末尾"可能不应该是用户回复,而是工具的返回结果。这种情况下要把任务指令放在前部,最新工具输出放在后部。不同任务类型,位置策略要做微调,但底层逻辑是一样的——让最需要被模型注意的信息占据高注意力区域。
4.5 工具与记忆的回退机制:别让一次性对话承载一切
最后一个实用的思路是:把"该不该让这张对话承载这件事"这个问题前置。长期项目不应该只活在单条会话里,应该单独维护一个项目知识库,以向量检索或结构化文档方式存储。会话里只保留当前这一阶段的上下文,需要长期记忆时通过检索把必要的片段拉回来。这样单条对话的上下文永远不会无限膨胀。
我现在的习惯是,每个项目从第一天就建立一个"项目仓库",包含需求文档、结论记录、图谱和资料索引。模型每天的产出持续同步回仓库。这样即便换了新会话,只要把仓库里的核心摘要注入系统提示词,模型可以很快进入状态。这样反而解决了跟踪多轮对话、消息丢失的关键问题。
5. 用数据说话:我是怎么评估上下文管理方案好坏的
任何工程技术,如果没有评估手段,就谈不上优化。上下文工程也是如此。我之前很长一段时间处于"感觉效果好一点了"的模糊状态,直到建立起一套可量化的评估方式,才真正开始迭代出稳定的方案。
5.1 三个核心评估维度
第一是信息召回率。我在测试集里放入若干条关键事实,让模型在对话进行到第N轮时回答与中间某个事实相关的问题,看它能否正确引用。这个指标最直接地反映上下文排布和压缩策略是否有效。
第二是一致性保持率。我设计了多个相互依赖的问题链,让模型在前面回答中确立某个参数,后续再出需要用该参数的题。如果它能够先后一致,记为通过。这个指标反映事实漂移情况。
第三是上下文Token成本。我会统计完成相同任务所消耗的平均Token数,再比对任务完成质量。这个维度很多人忽略,但Token成本在长周期项目中会变成经济账。
5.2 我的一次完整评估实验
在重构上下文管理方案后,我专门做了一个对照测试。用同一个模型、同一套测试题,分别测试三种状态:不管理上下文的原始长对话、仅做摘要压缩的中间方案、做了信息分层加检索筛选的完整方案。
结果很有意思。不管理的方案在对话到第四十轮左右,信息召回率掉到了47%,一致性保持率更惨,只有32%。仅摘要压缩方案召回率能回到68%,但仍然有比较明显的漂移。完整方案在同样轮次下,召回率达到86%,一致性保持率88%。而Token成本这块,完整方案反而比不管理的方案低了近40%,因为淘汰了大量无关内容。
这个数据让我坚定了一个想法:上下文工程不是"看起来更高级"的提示词技巧,它是一项直接影响模型可用性的工程能力。很多团队把模型效果不佳的原因归结为模型不行,实际上有相当比例的问题出在上下文管理制度上。
5.3 建立你自己的上下文评估集
这里给一个比较落地的建议:不要等到项目出问题才想起来评估,一开始就建立一套针对你业务特点的上下文测试集。测试集不需要很大,十来个围绕核心业务的问答场景就够了。里面刻意加入需要跨轮次引用的信息、带冲突干扰的信息、长材料检索任务等。每次调整上下文策略后,跑一遍同样的测试集,你就能快速判断改动是正向还是负向。
另外一个实用的辅助手段是"过程日志"。我会记录每一轮的上下文结构快照——系统提示词是什么、摘要区更新了哪些信息、检索层放入了哪些片段。这样一旦出现输出质量下降,可以回溯定位是哪个上下文环节出了问题,而不是对着模型输出的结果瞎猜。
6. 尚待开路的地方:当应用与上下文工程须相互配合
说起最后,其实上下文工程刚走到"危及一个独立方向"的门口。它涉及的范围,远远不只是即时聊天里裁剪清理。模型在后端靠工具与外部知识完成大部分工作时,模型为何在上下文窗口内保持轻量,而将重资产交给外部仓库存储与计算。这部分是我在设计和实践之后比较大的体会。
展望不套空话,单纯从经验出发。整体上我认为上下文工程不是取代提示词工程,而是在提示词工程的基础上多了一层"环境的经营":真正有效的模型应用,既要会"说话"(提示词),也要会"收拾桌子"(上下文工程)。凡是做Agent、做长期项目、做复杂任务系统的同行,我建议从今天起,把上下文当做一个需要显式管理的资源,而不是一个无限装东西的箱子。建立分层习惯,做好摘要快照,量化评估效果,哪怕从最简单的这些动作开始,模型的稳定性和可用性都会有非常明显的变化——这是我在踩了无数个坑之后,最想分享给你的一条经验。