做AI应用开发的朋友应该都有过这种体验同一个模型同一个问题只是前面塞进去的资料不同、排列顺序不同回答质量就天差地别。有人把这种不稳定归结为“模型玄学”其实背后是一个可以系统化研究的问题也就是上下文工程。这几年大模型的上下文窗口不断变大能塞进去的内容越来越多怎么选题、怎么排序、怎么保持信息新鲜正在成为比“话术”更关键的变量。如果你正在做大模型应用开发或者觉得自己的提示词方案时灵时不灵这篇文章就是为你准备的。我会先讲清楚上下文工程到底是什么、和提示词工程有什么区别再从模型内部原理解释它为什么有效最后给出一套我在实际项目中反复验证过的实操抓手和自检清单。整篇内容不依赖某个特定模型凡是用大模型做应用的人都能直接用上。1. 从同一条提示词的不同命运说起为什么上下文成了主角先说早期经验。大模型刚开始普及的时候大家发现同一道算术题直接写“9.11和9.9哪个大”和写“请用数学思维一步步比较9.11和9.9哪个大”答案可能完全不同。于是提示词工程火了大家一门心思研究“怎么说更有效”。那个阶段上下文窗口通常只有几千个token能放的内容非常有限操作空间不大把精力放在措辞上是合理的选择。窗口变大之后情况就变了。我做内部知识库问答时遇到过一个典型场景用户问“差旅报销需要哪些材料”。第一版方案图省事把整个报销制度文档约两万字直接塞进上下文让模型自己找答案。结果回复经常漏掉“必须附发票查验单”这类关键项甚至把制度里的例外情况当通用规则输出。后来改成先用检索把文档切成片段只挑最相关的两段送进模型回答反而又准又稳。资料更少效果更好这件事让我第一次意识到上下文工程的核心不在“多给”而在“给对”。再后来我发现顺序的影响同样明显。一次测试里我把关键结论放在上下文中部连续试了几次模型都没找到把同样一句话挪到上下文最末尾正确答案一下就出来了。提示词一个字都没改变的只是上下文里信息的摆放位置。那段时间我开始系统整理这些现象发现它们背后有一个共同变量上下文。所谓上下文简单说就是模型做一次推理时能读到的所有信息包括系统指令、用户输入、外部资料、历史对话和工具返回结果。以前这个变量几乎不需要专门管理因为空间太小现在窗口大了自由度大了反面就是要认真管理。打个比方小办公桌上只能放三样东西怎么摆差别不大换成大仓库怎么分拣、怎么上架、哪些定期下架就成了非常专业的问题。上下文工程就是这个时代背景下长出来的新课题。2. 上下文工程的准确内涵它到底管什么不管什么2.1 一个可操作的定义我给上下文工程下的定义是围绕一次或者一个会话的模型推理对送入模型的所有信息进行有目的的选择、整理、压缩、排序和动态更新让模型输出更符合预期的一整套方法与实践。这个定义里有两个层次需要分开。“一次推理”的上下文是一次性拼好的比如单轮问答时把相关资料和问题组装好送进去“一个会话”的上下文则是逐渐累积的对话到了第五轮、第十轮哪些历史信息该留、该压、该丢都要动态管理。大多数实际项目属于后者难度也高得多。只做单轮问答的系统相对简单把检索和拼装做好就够了做客服助手、Copilot、Agent这类多轮应用上下文工程的核心挑战才会完全暴露出来。2.2 它管什么不管什么上下文工程管辖的范围用五句话可以概括选什么进上下文——检索、过滤、去重、权限控制。以什么顺序呈现——关键指令放最前还是最后辅助资料放哪里。以什么结构呈现——用纯文本、列表、JSON、表格还是标记语言。放不下时怎么办——压缩、摘要、丢弃、归档。内容过时后怎么办——动态更新、版本替换、会话级遗忘。边界同样重要。上下文工程不负责修改模型权重不做微调也不改变解码参数。温度、top_p这些采样设置属于另一套优化手段和上下文工程是两回事。把这条边界想清楚能少走很多弯路很多人发现上下文效果不好第一反应是去调模型参数而不是审视输入本身。实际上绝大多数不稳定输出问题的根源都在输入链路而不在模型侧。2.3 和提示词工程、RAG到底是什么关系提示词工程关注“怎么说”上下文工程关注“让模型读什么、以什么结构读”。前者设计的系统指令、用户请求只是上下文的一部分。更准确地说提示词工程是上下文工程的子领域只不过它研究的是句子层面的措辞和指令设计。RAG检索增强生成也不是和上下文工程并列的概念而是上下文工程的一种成熟落地方案。RAG通过检索把外部知识临时拼进上下文解决了“选什么”的问题但顺序、结构、压缩、更新这些环节仍然要靠上下文工程来解决。这也是为什么很多团队把RAG链路搭好之后效果依然不稳定——他们只解决了信息来源没解决上下文的组织方式。把这三个概念放进一张表会更清楚概念关注层典型产出提示词工程句子措辞与指令设计更有效的提问模板和系统指令RAG外部知识的检索与注入参考片段列表、引用依据上下文工程完整输入链路的组织与更新可复用的上下文组装方案3. 模型内部视角上下文是怎么影响输出质量的3.1 注意力机制模型怎么读长文本大模型的底层是Transformer架构内部运作靠的是自注意力机制。通俗解释就是模型在处理某个字词时会把它和上下文里所有其他字词做一次相关性打分相关性高的信息获得的权重更大。所以模型并不是逐字逐句从头读到尾更像是在一大片信息里做加权筛选把注意力集中在它认为重要的地方。这个机制带来一个关键推论你放进去的内容能不能发挥作用取决于它能否在相关性打分中胜出。如果上下文里有大段和当前问题无关的文本模型对关键词的注意力权重就会被摊薄。这就是为什么“塞进去的资料越全”不一定越好的根本原因——模型不是数据库它不会先存储再提取而是把所有内容一次性读入并当场加权。3.2 迷失在中间位置有时比内容更敏感长上下文研究里有个非常经典的现象信息在长文本中的位置会影响模型利用它的效果开头和结尾的信息更容易被记住插在中间的内容容易被忽略。这个现象后来被人总结为“lost in the middle”。实操含义非常直接需要模型严格遵循的指令放在上下文最前面需要模型直接输出的关键结论放在最后面辅助性背景资料放中间。经典的三段式“指令—资料—请求”之所以在无数项目里都好用是有原理支撑的不是单纯的形式主义。我自己测试过把指令从中间挪到开头把关键答案从中间挪到结尾模型的正确率肉眼可见地提高。3.3 噪音稀释为什么资料更多不总是更好想象开一场会桌上堆了一摞无关宣传册主持人嗓门再大核心议程也容易被淹没。模型也是一样注意力总量有限放进去的无关信息越多关键信息分到的权重就越小。很多项目的失败案例都是“把所有资料一股脑塞进去”。表面看是充分利用上下文窗口实际是主动给模型制造噪音。上下文工程的基本功首先是做减法宁可上下文短而精不要长而杂。如果你发现回答总是泛泛而谈、引用不到重点先别怀疑模型能力回头看一眼上下文里有多少内容其实和当前问题毫无关系。4. 上下文工程在真实项目里的四个实操抓手4.1 检索与重排决定“该给模型看什么”知识库问答项目的起点通常是检索处理流程一般是把知识库切成若干文本片段并向量化。用户提问时做向量召回和关键词召回拿到候选片段。对候选片段做重排序用重排模型按“问题—片段”相关性二次打分。只把得分最高的TopK片段拼进上下文。为什么不直接用向量召回的TopK就开始做因为向量召回是初筛主要目的是“别漏掉”它的相关性排序不够精细经常混入“看起来相关但实际无关”的内容。重排则是精筛能在更小的候选集合里把真正有用的信息提到最前面。经验参数一般是召回Top50-100重排后再取Top3-5效果通常优于直接取Top10。这里有一条很关键的实操准则宁可给模型3段高相关性片段也不要给10段“好像相关”的片段。信息少但精准模型反而容易给出确定答案信息多而杂模型就有更大的概率被带偏。4.2 格式与结构决定“以什么结构看”同样是知识呈现方式不一样模型解析的难度完全不一样。纯散文段落里找答案模型需要自己定位关键句把内容整理成要点列表或表格模型可以直接引用对应行。举个例子一份报销制度文档有一万多字直接全量塞进去模型回答时很容易混入“例外情况”。但如果把内容抽成三张表——报销标准表、流程步骤表、材料清单表——模型引用准确率会上一个台阶。原因是表格天然把“对象”和“属性”绑定在一起模型不需要在长文本里做语义跨越。还可以用轻量标签给上下文划边界比如system你是客服助手只能根据资料回答/system context差旅报销标准高铁二等座以下可全额报销……/context user我需要报销高铁票要准备什么/user标签本身不是魔法它真正的作用是帮助模型分清不同信息的身份减少“资料内容被误当成指令”的风险。需要提醒的是标签不要过度嵌套结构越简单模型理解得越稳。4.3 压缩与摘要决定“放不下的时候怎么办”长对话是上下文工程的主战场。对话到三十轮之后把所有历史原文直接拼接上下文窗口再大也不够用。常见做法是先让模型对历史对话做任务导向摘要只保留下一步真正需要的信息用户目标、已确认事项、关键偏好、待办动作。寒暄和重复内容直接丢弃然后“摘要加最近若干轮原文”共同构成新的上下文。这样做既保留语义连续性又控制住token开销。这里要特别强调摘要必须是任务导向的而不是让模型写一段“聊天总结”。客服系统里“用户对价格敏感”这个摘要比“用户聊了很久关于费用的问题”有用得多Agent场景里“用户要求最终输出必须是JSON格式”就比“用户解释了格式需求”更有价值。摘要丢细节是必然的所以要定期验证摘要内是否覆盖了当前任务的关键约束。4.4 动态更新与遗忘决定“上下文如何随时间变化”单次问答里上下文拼好就结束了多轮会话里上下文是不断演化的。最典型的情况是用户中途改主意。比如用户先说“我想退货”聊了几轮后又改口“还是换货吧”。如果旧上下文中还留着大量“退货”相关内容模型很容易在两个方向之间摇摆。这需要在每次交互后更新意图槽位用新意图覆盖旧意图同时把旧相关描述降权。时效性数据也一样。价格、库存、活动规则这类信息变化频繁每次推理前都必须重新检索用最新版本替换旧版本。过期信息留在上下文里比没有信息更危险——它会让模型信心满满地给出一个已经失效的答案。所以“遗忘”不是副作用而是上下文工程里应该主动设计的功能。某问答系统第一版全量文档加全量聊天历史直接拼进上下文。第二版检索重排Top3加任务导向摘要再按轮次更新意图槽位。相同模型、相同提问第二版的引用准确率明显更高。这种差异我在多个知识库项目里都反复观察到了。5. 判断好上下文的五个朴素标准一份实践自检清单5.1 相关性每条信息都要用得到判断标准很简单一条上下文如果删掉之后答案没有变差那就是冗余。自查时问自己——模型当前要完成的任务需不需要依赖这段信息如果只是“顺便放进去”就应该删。尤其是背景介绍性质的开场白十有八九是噪音。上下文不是展示台每一条内容都要服务于这次推理的目标。5.2 信息密度用最少的token表达同样的信息“关于这个问题我们首先需要了解的是由于整个流程相对比较复杂……”这类句子放进上下文里纯属浪费。同样的意思“关键事项逐级审批”七个字更高效。自查时问自己能不能把三段话压成一张表格把形容词删掉之后意思有没有变化结构化信息优先于散文因为模型解析表格和要点的成本远低于从长句里提取语义。5.3 位置与排序把主角放在开头或结尾需要模型“一定使用”的信息不要放在上下文中段。自查时问自己模型要引用的标准排在第几段如果落在中间要么调整排序要么在它前面加一句前置总结。前面提到的注意力位置偏好是所有模型共通的弱点设计上下文结构时把它当成默认约束来处理。5.4 时效性过期信息比缺失信息更危险不少错误回答不是模型笨而是参考内容太旧。自查时问自己信息源有没有版本号当前时间窗口内有没有更新数据价格、库存这类动态字段有没有在每次推理前重新拉取制度类文档相对稳定可以靠缓存动态业务数据必须实时刷新宁可少给不能给旧。5.5 安全性警惕外部文本里的指令干扰用户输入、网页资料里可能藏着“忽略上面的指令”这类内容这在前两年已经被反复验证过属于提示注入的范畴。上下文工程在组装阶段就要做防护用户文本和检索文本分开封装不要混在一个区域内对高风险内容做注入检测必要时在系统指令里明确模型只能执行哪些动作。自查时问自己这段文本有没有可能改变模型行为如果有可能就不能直接信任地塞进上下文。过去我调试模型输出不稳定总是在问法上反复试越试越玄。后来养成了固定习惯先问“该让模型看到什么”再问“按什么顺序看”最后问“看到多少最合适”。把上下文管理清楚之后那些曾经让人挠头的“玄学问题”大部分都变成了可以排查、可以复现、可以通过调整输入链路解决的问题。如果你刚开始接触上下文工程我建议别急着学各种花哨技巧就从自己项目里最痛的那个环节入手——要么检索不准要么长对话失忆先做减法再谈优化。跑通一轮之后再回头看概念你会发现自己已经摸到门了。