上下文工程 Context Engineering

Context Engineering (Context Assembly Engineering)

上下文工程(Context Engineering)是在每次模型调用前系统性地组装、筛选、压缩与排序进入上下文窗口全部信息的工程方法,它关注信息架构与上下文预算的分配,比提示词工程更侧重「喂什么信息、喂多少、以什么顺序喂」,是智能体稳定性与长任务可靠性的关键。

详细解释

上下文工程(Context Engineering) 指的是在每一次模型调用之前,系统性地决定「这一轮到底要把哪些信息拼进 上下文窗口」,并对这些信息做筛选、压缩、排序与预算分配的一整套工程方法。它和 提示词工程 处于不同层次:提示词工程管的是「话怎么说」——怎么把指令写清楚、怎么给示例、怎么约束输出格式;上下文工程管的是「喂什么信息、喂多少、以什么顺序喂」——系统提示占多少 Token、检索回来几段资料、历史对话保留哪几轮、长期记忆要不要注入。两者不是替代关系而是叠加关系:措辞写得再好,如果关键资料没被放进去,模型也答不对;反过来资料齐全但指令含糊,输出同样不可用。

从来源看,进入上下文的信息可以归为四大类:一是系统提示与工具定义,决定模型是谁、能做什么;二是检索片段,来自 RAG 召回的外部知识;三是对话历史,即当前会话此前的轮次;四是长期记忆,跨会话沉淀下来的用户偏好与事实。这四类信息共享一个固定的窗口容量,因此核心工作就是做预算分配:哪一类多给一些,哪一类超预算时先砍。工程上有两类典型失效模式必须防住:其一是信息位置问题,被放在上下文正中间的关键约束容易被模型忽略,这种现象被称为 Lost in the Middle(关于长上下文位置敏感性的系统研究见 https://arxiv.org/abs/2307.03172 );其二是信息总量问题,也就是所谓上下文腐化(context rot)——当上下文里塞入大量与当前任务无关的历史或噪声后,模型表现会不升反降,历史越长反而越差。这两类失效的共同根源在于模型的注意力是一种有限的资源,它并不会平等地对待窗口里的每一段文字:位置靠中间或语义较弱的片段容易被忽略,而存在矛盾或已经过时的内容又会被不加区分地采纳。因此上下文工程的核心动作其实是做减法——不是把找得到的信息都塞进去,而是反复判断「哪一段信息对这一步推理真正有用」,把有限预算花在刀刃上。

落地方案上,团队通常会把这套逻辑收敛到 Agent 网关里统一实现。唯元智创 在网关侧做上下文组装与压缩:先按任务类型套用预算模板,再对 检索片段 做去重、重排与分级 上下文压缩,对对话历史按相关性裁剪并做摘要,对跨会话的 智能体记忆 只注入与当前任务相关的条目,最后按前缀缓存的友好顺序把稳定内容排在前面、动态内容排在后面。整个过程都会记录每一轮实际拼进去的成分与 Token 预算 占用,做到可回放、可定位,避免出了问题只能靠猜。对于检索密集的问答场景,还会额外记录召回条数、去重前后的片段数、压缩比以及最终真正注入的 Token 数,把不同上下文策略的收益做成可比指标。

提示词工程与上下文工程对比表

对比维度提示词工程上下文工程关注层次主要产出物典型失败模式优化手段
核心目标把单条指令写清楚、写准确让进入窗口的全部信息恰到好处措辞与指令对比信息架构Prompt 模板与 System Prompt指令含糊、模型不听话迭代措辞、补充示例
处理对象一段提示的文本表述系统提示、工具定义、检索片段、历史与记忆单点表达对比全局装配动态上下文组装流水线信息缺失或信息过载召回、去重、压缩、重排
时间尺度开发期打磨,上线后相对稳定每次请求动态组装,随会话状态变化静态对比动态每轮的上下文计划长会话后期质量衰减预算分配、动态裁剪
失败模式模型理解偏差、格式不合规关键信息被忽略、上下文腐化局部对比系统可观测的上下文日志Lost in the Middle 与噪声干扰双端强化、去噪精选
成本视角提示词变长会直接推高输入 Token通过压缩与缓存控制总预算表达成本对比预算成本上下文预算分配表成本失控、撞上窗口上限前缀缓存、分级压缩
团队分工产品与业务同学即可独立迭代需要工程、检索、平台多方协同单人对比协作可复用的上下文中间件各自为战、过程不可观测统一网关与全程埋点

上下文预算分配参考表

上下文成分建议预算占比超预算时的处理顺序可压缩性是否可缓存复用典型失效后果
系统提示与工具定义15% 至 25%最后才裁剪低,多为固定文本可,稳定前缀能命中前缀缓存裁剪过度会导致指令遵循下降
检索片段20% 至 35%先去重重排再截断高,可做摘要与压缩部分可缓存噪声过多会显著拉低准确率
对话历史15% 至 30%优先按相关性裁剪高,可摘要可丢弃前缀部分可缓存无关历史越长表现越差
长期记忆5% 至 15%优先裁剪低相关条目高,可摘要与合并可,稳定记忆块可缓存记忆过时会导致错误沿用
用户当前输入5% 至 15%不可裁剪极低否裁剪会直接丢失任务约束
预留输出空间15% 至 25%绝不占用不适用不适用占满会导致长回答被截断
唯元智创 上下文网关按任务动态分配,默认落在上表推荐区间自动按优先级逐级裁剪内置分级压缩支持前缀缓存友好排序配置不当会压缩过度

实战经验与避坑

  1. 不要把上下文窗口塞满到接近上限,必须留出足够的输出空间:很多团队为了「让模型知道得更多」,把检索到的资料、全部历史、全部工具定义一股脑塞进去,把窗口用到九成以上,结果模型刚要生成较长的回答就被迫截断,输出到一半戛然而止。正确做法是把窗口明确切成输入区与输出区,输出区至少预留 15% 至 25%,长回答场景还要更多;当输入超预算时,按「先砍低相关历史、再砍低分检索片段、最后才动系统提示」的顺序逐级裁剪。宁可少喂一点噪声,也不要让回答被腰斩。

  2. 关键约束不能只放在上下文开头或正中间,要做双端强化:Lost in the Middle 现象表明,模型对上下文两端的信息记得最牢,对中间位置的召回最弱。因此像输出格式、禁止事项、必须遵守的业务规则这类硬约束,绝不能只写在长长的上下文开头就完事。稳妥的做法是双端强化:在系统提示的开头说一遍,在用户输入前再简明强调一遍,让同一个约束同时出现在两端;对于工具定义与检索片段,也要把最重要的那条排在第一段或最后一段,而不是随手埋在中间。更细的做法是给约束编号,在上下文两端引用同一个编号,这样即使中间塞了很长的资料,模型也能明确知道两端说的是同一条规则。

  3. 历史对话要按相关性而不是时间顺序筛选,只保留与当前任务相关的轮次:直接保留最近 N 轮看似简单,但长会话里用户往往中途换过话题,「最近」未必「最相关」。更糟的是无关历史会占用预算并引入干扰,让模型把旧话题的条件误套到新任务上。正确的做法是按相关性筛选:先用向量或关键词把历史轮次与当前问题做匹配,只保留强相关的若干轮,其余丢弃或压成一句摘要;对已经解决的子任务明确标记为已完成并移除细节,只留结论。

  4. 检索片段必须先做去重与重排,塞入 20 段往往不如精选 3 段:检索召回的原始片段里重复、近似、低质的内容很多,如果不加处理直接拼进上下文,等于把噪声喂给模型。工程上的标准动作是:先用相似度去重合并近似片段,再用重排模型按与问题的相关性重新排序,最后只取分数最高的 3 至 5 段。实测的经验区间是,把片段数从 20 段精简到 3 至 5 段后,答案准确率通常不降反升,因为模型不再被自相矛盾或离题的内容牵制。

  5. 上下文组装过程必须可观测,要记录每次请求实际拼进去的成分与 Token 数:上下文工程最大的坑是「出了问题是黑盒」。如果无法知道这一轮到底注入了哪些检索片段、保留了哪几轮历史、各类成分各占多少 Token,就只能靠猜来调参。因此必须在组装环节埋点,记录每一类成分的条数、Token 占用与被裁剪的部分,保留最近一段时间可供回放。有了这份日志,才能快速判断某次答错究竟是召回错了、历史污染了、还是预算把关键信息挤掉了。条件允许时,把这份记录与最终答案、用户反馈对齐,就能反推出什么样的上下文组合更容易得到正确答案。

  6. 稳定前缀要放在前面以便命中前缀缓存,动态内容放后面:上下文里有一部分内容是跨请求稳定的,比如系统提示、固定的工具定义、不变的规则说明;另一部分每次都变,比如用户当前输入、最新检索结果。由于提示词缓存(前缀缓存)依赖请求前缀的完全一致,把稳定内容排在前面、动态内容排在后面,就能让每次请求复用同一段缓存前缀,命中部分的输入成本可降至零头,延迟也明显下降。业界实测的典型收益是,长系统提示加长工具定义的场景下,缓存命中可让输入成本下降三成到六成,是性价比极高的一条优化。要拿到这个收益,前提是稳定部分的文本逐字节完全一致,任何一处标点或空格的变动都会让缓存整体失效,因此模板里的动态变量必须严格放在稳定前缀之后。

常见问题

上下文工程和提示词工程到底有什么区别,是不是换了个说法?
不是换个说法,两者关注的层次不同,提示词工程管「话怎么说」,上下文工程管「喂什么信息、喂多少、以什么顺序喂」。可以把上下文窗口想成一张有限的桌子:提示词工程是研究怎么把这张桌子上那张写着指令的纸条写得又清楚又准确;上下文工程则是研究整张桌子上应该摆哪些资料、每份资料占多大地方、先摆哪份后摆哪份,让模型一眼就抓到重点。它们在复杂度上差一个量级:单轮问答里,几个小技巧就能把提示词调好;但在需要检索、多轮记忆、调用工具的智能体场景里,一次请求可能要拼进系统提示、十几条工具定义、若干段检索结果、多轮历史与跨会话记忆,如何分配有限的 Token、如何避免噪声干扰、如何让关键约束不被忽略,就变成了一个系统性工程问题。所以更准确的关系是:提示词工程是上下文工程的一个子集,前者解决表达,后者解决信息架构与预算,二者叠加使用而不是相互取代。
什么是上下文腐化,为什么历史越长模型反而越差?
上下文腐化指的是当上下文里堆入大量无关或冗余信息后,模型的表现不升反降,历史越长、噪声越多,退化越明显。直觉上「信息越多应该越好」,但模型并不是在数据库里查,而是在一段有限的注意力里做推理:无关的历史会稀释与当前任务真正相关的信号,过时或被推翻的结论会被模型当成仍然成立,多轮之间相互矛盾的说法也会让模型无所适从。它的典型表现是:短会话里回答准确、长会话到十几轮后开始答非所问,或者把很早之前聊过的旧条件错误地套到当前问题上。此外还有一个相关的现象是位置敏感性,也就是关键信息落在上下文正中间时更容易被忽略。应对手段有三条:一是按相关性而非时间裁剪历史,只留与当前任务强相关的轮次;二是对必须保留的长历史做摘要压缩,把多轮浓缩成要点;三是控制检索片段数量并做去重重排,宁可精不要多。把上下文当成一份需要编辑的简报,而不是一份需要堆满的仓库。
上下文预算到底怎么分,有没有可以参考的经验值?
预算没有唯一正确答案,但有一套可参考的起点:系统提示与工具定义占 15% 至 25%,检索片段占 20% 至 35%,对话历史占 15% 至 30%,长期记忆占 5% 至 15%,用户当前输入占 5% 至 15%,并预留 15% 至 25% 的输出空间。这套比例的思路是:把占比最大的两块留给「最可能决定答案对错」的信息,也就是检索片段与对话历史;把系统提示与工具定义这类基本固定的内容控制在四分之一以内;给长期记忆留一小块,够用即可。分配的关键在于超预算时先砍谁,推荐的顺序是:先砍低相关的对话历史,再砍低分检索片段,然后精简长期记忆,最后才动系统提示与工具定义;用户当前输入与预留输出空间属于硬底线,任何情况下都不应被占用。还要注意两点:一是不同任务的最优比例差别很大,代码修复类任务往往要给历史和工具定义更多空间,知识问答类任务则要给检索片段更多空间;二是别把窗口用满,留出余量既是为了输出,也是为了应对突发更长的输入。把上面这套比例当起点,再用自己业务的真实流量跑 A/B 校准,才是稳妥做法。