尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

LLM - 大模型上下文窗口管理的那些事:从长度焦虑到上下文工程

LLM - 大模型上下文窗口管理的那些事:从长度焦虑到上下文工程 文章目录从「能塞多少」到「该塞什么」一、上下文窗口到底是什么1.1 一个直观的定义1.2 为什么会有这个上限二、长上下文的幻觉为什么「读得进」不等于「读得懂」2.1 「迷失在中间」Lost in the Middle2.2 上下文腐烂Context Rot2.3 注意力预算是有限的2.4 成本与延迟的现实约束三、把窗口做大扩展上下文的底层技术3.1 位置编码让模型理解「顺序」3.2 位置插值用微调「撑大」已有模型3.3 高效注意力击穿 O(n²) 的墙3.4 KV Cache推理阶段真正的显存大户四、上下文管理的四大核心策略4.1 截断与滑动窗口最朴素也最危险4.2 摘要压缩用信息密度换空间4.3 检索增强RAG把外部知识按需取用4.4 记忆系统短期与长期的分层五、Agent 时代的上下文工程5.1 从提示词工程到上下文工程5.2 一次 Agent 调用里上下文由什么组成5.3 工具结果是最大的「上下文杀手」5.4 让 Agent 拥有「外部草稿纸」5.5 多智能体用「分而治之」对抗上下文膨胀5.6 一个贯穿全流程的例子深度研究 Agent六、评估与调优让上下文管理可度量6.1 关注这几个核心指标6.2 用「大海捞针」测试评估长上下文能力6.3 几条经验法则七、未来的方向结语上下文窗口曾经是模型能力的天花板如今它更像是一门需要精心经营的资源管理艺术。当模型的注意力有了标价如何在有限的窗口里放对信息、放好信息成了决定 Agent 成败的关键。从「能塞多少」到「该塞什么」两年前大家谈论上下文窗口时讨论的焦点几乎只有一个数字4K、8K、32K、128K、200K、1M……仿佛这个数字越大模型就越聪明。彼时的技术竞赛本质上是一场「长度军备竞赛」。但真正把大模型用进生产环境的工程师很快发现事情没那么简单。窗口开到了 100 万 token模型却在第 30 万个 token 处「失忆」上下文塞得越满回答反而越含糊一次调用的账单肉眼可见地膨胀,延迟也随之攀升。人们逐渐意识到上下文窗口的大小决定了能力的上限而上下文的管理方式决定了能力的下限——而后者才是日常工程中真正稀缺的东西。于是一个新的工程学科在 2024 到 2026 年间悄然成型它有了一个专门的名字上下文工程Context Engineering。它不再关心「模型最多能读多少字」而是关心「在每一步推理时究竟该把哪些信息、以什么结构、按什么顺序放进那扇有限的窗口里」。这篇文章会从底层机制讲起一路走到 Agent 时代的上下文工程实践。无论你是在做 RAG、搭 Agent还是单纯想搞清楚为什么你的长文档问答效果时好时坏都能在这里找到一条清晰的脉络。一、上下文窗口到底是什么1.1 一个直观的定义上下文窗口Context Window指的是模型在一次前向推理中能够「同时看到」的 token 数量上限。它既包括你输入的提示词Prompt也包括模型自己生成的内容Completion二者共享同一个预算。这里的基本单位是token而不是字或词。对中文来说一个汉字通常占 1 到 2 个 token对英文来说一个常见单词大约是 1 个 token较长或较生僻的词会被切成多个子词subword。粗略估算时可以按「1 个中文汉字 ≈ 1.5 token1 个英文单词 ≈ 1.3 token」来心算。举个例子一个宣称支持 128K 上下文的模型理论上能一次性处理约 8~9 万个汉字相当于一本中篇小说。但请记住这个额度是输入和输出共用的——如果你把 12 万 token 全塞进了输入那留给模型回答的空间就只剩下几千 token 了。1.2 为什么会有这个上限上下文窗口不是产品经理拍脑袋定的数字它背后是实打实的计算与显存约束。理解这一点才能理解后续所有优化技术的动机。主流大模型基于 Transformer 架构其核心是自注意力机制Self-Attention。在计算注意力时序列中的每一个 token 都要和其他所有 token 计算相关性。这意味着当序列长度为 n 时注意力矩阵的规模是 n × n计算复杂度和显存占用都是O(n²)。这个平方关系是残酷的序列长度翻一倍注意力的计算量和中间显存就要翻四倍。从 8K 扩到 128K 是 16 倍的长度增长朴素实现下对应的却是约 256 倍的注意力开销。这就是为什么长上下文一度是一件极其昂贵的事。除了注意力矩阵本身还有一个常被忽视但在推理阶段更关键的显存消费者——KV Cache我们会在第三节专门展开。二、长上下文的幻觉为什么「读得进」不等于「读得懂」在深入技术之前必须先破除一个普遍的误解把窗口开大、把资料全塞进去模型就能用好这些信息。大量实验和线上事故都证明事实恰恰相反。2.1 「迷失在中间」Lost in the Middle这是长上下文领域最著名的现象之一。研究者把关键信息放在一段长上下文的不同位置进行测试结果发现了一条清晰的 U 形曲线模型对开头和结尾的信息记得最牢而放在中间的关键信息检索准确率会显著下降。这意味着如果你把一份 50 页的合同一股脑丢给模型然后问一个答案恰好埋在第 25 页的问题模型很可能视而不见——哪怕这段文字确确实实在它的上下文窗口里。实践启示很直接把最重要的指令和信息放在上下文的开头或结尾不要指望模型在漫长的中段保持同等的注意力。2.2 上下文腐烂Context Rot随着上下文变长模型整体性能会缓慢而持续地退化这种现象被称为「上下文腐烂」。它不是在某个长度突然崩溃而是像温水煮青蛙一样逐步劣化前面提到的约束条件被逐渐「遗忘」早期的错误结论被当作事实继续沿用形成累积误差对新指令的响应变得迟钝倾向于重复之前的模式。上下文腐烂对 Agent 尤其致命。一个需要几十步才能完成的任务Agent 会不断把工具调用的结果、中间思考、报错信息追加进上下文窗口迅速被「历史包袱」填满真正重要的当前目标反而被稀释。2.3 注意力预算是有限的可以用一个更本质的视角来理解上述现象模型的注意力是一种守恒的、有限的资源。上下文里的 token 越多分摊到每个 token 上的「注意力份额」就越薄。塞进十条无关信息不仅浪费了预算还会主动干扰模型对那一条关键信息的聚焦。所以上下文管理的第一性原理其实非常反直觉多往往是有害的。好的上下文不是尽可能全而是尽可能准——用最少的 token 承载解决当前问题所必需的、且仅必需的信息。2.4 成本与延迟的现实约束最后是最朴素的两条钱和时间。成本绝大多数模型 API 按 token 计费输入 token 通常也要收费。把 100K token 反复喂给模型做多轮对话账单会以惊人的速度累积。延迟输入越长首个 token 的返回时间TTFT越久因为模型需要先「读完」整段输入即 prefill 阶段。对交互式应用来说这直接伤害体验。这两条现实约束是「能塞满也不该塞满」的最后一块拼图。三、把窗口做大扩展上下文的底层技术理解了长上下文的代价我们再来看工程界是如何在「物理上」把窗口做大、做便宜的。这一节偏底层但它是理解现代长上下文模型为何能存在的钥匙。3.1 位置编码让模型理解「顺序」Transformer 的注意力机制本身是「无序」的——它并不天然知道哪个词在前、哪个词在后顺序信息完全依赖**位置编码Positional Encoding**注入。而位置编码的设计直接决定了模型能否泛化到训练时未见过的长度。早期的绝对位置编码如原始 Transformer 的正弦编码、可学习位置向量有一个硬伤训练时见过的最大位置是多少推理时就基本只能用到多少外推能力很差。RoPE旋转位置编码的出现改变了格局。它不再给每个位置分配一个固定向量而是通过「旋转」的方式把位置信息编码进 Query 和 Key 的向量角度中天然地表达了 token 之间的相对距离。RoPE 具备一定的外推潜力且几乎成了当下开源大模型的标配。ALiBi则走了另一条路它直接在注意力分数上按 Query 和 Key 的距离施加一个线性的惩罚偏置距离越远惩罚越大。这种方式简单、外推性好无需显式的位置向量。3.2 位置插值用微调「撑大」已有模型真正让「128K、200K 上下文」变得普及的是一系列基于 RoPE 的位置插值Position Interpolation技术。核心思路是与其从头训练一个长上下文模型成本极高不如把一个已经训好的短上下文模型的位置编码「压缩/拉伸」到更长的范围再用少量长文本微调。线性位置插值PI把超出范围的位置索引等比例缩放回训练范围内简单有效但对高频信息有损。NTK-aware 插值借鉴神经正切核的思想对不同频率的维度采用不同的缩放策略高频少缩、低频多缩缓解了 PI 的信息损失。YaRN进一步精细化了频率分段策略用极少的微调步数就能把上下文窗口扩展数倍是目前长上下文微调的常用方案之一。这些方法的意义在于扩展上下文不再需要天价的从头预训练中小团队也能在开源模型上「撑大」窗口。3.3 高效注意力击穿 O(n²) 的墙FlashAttention是工程上里程碑式的工作。它没有改变注意力的数学定义而是重写了计算方式通过分块tiling计算并巧妙利用 GPU 的高速缓存SRAM避免了把巨大的 n × n 注意力矩阵完整写入显存。结果是显存占用从 O(n²) 降到接近 O(n)速度还更快。FlashAttention 及其后续版本是今天所有长上下文推理的底层基石。此外还有一类稀疏注意力Sparse Attention与线性注意力Linear Attention的思路前者让每个 token 只关注一个子集如滑动窗口 少量全局 token代表如 Longformer、BigBird后者用核函数近似把复杂度降到 O(n)。它们在超长序列上有优势但通常要在效果上做一定妥协。3.4 KV Cache推理阶段真正的显存大户这是理解推理成本绕不开的一环。在自回归生成时模型每生成一个新 token都需要用到前面所有 token 的 Key 和 Value 向量。为了避免重复计算这些 K、V 会被缓存下来这就是KV Cache。KV Cache 的大小与「序列长度 × 层数 × 注意力头数 × 头维度」成正比随上下文线性增长。在长上下文场景下KV Cache 往往比模型权重本身还要吃显存。围绕它诞生了一系列关键优化MQA多查询注意力/ GQA分组查询注意力让多个注意力头共享同一组 K、V大幅压缩 KV Cache 体积。GQA 在效果和压缩比之间取得了很好的平衡已被广泛采用。PagedAttentionvLLM 的核心借鉴操作系统虚拟内存分页的思想把 KV Cache 切成小块非连续存储几乎消除了显存碎片让吞吐量成倍提升。KV Cache 量化与驱逐把缓存量化到低比特或按重要性淘汰旧的、不重要的缓存条目进一步节省空间。对上层应用开发者来说不必手写这些优化但理解它们能帮你想明白一件事为什么复用同一段前缀prefix的请求会更快更便宜——因为它们的 KV Cache 可以被缓存复用这正是「prompt 缓存」类功能的原理。四、上下文管理的四大核心策略技术上把窗口做大之后回到应用层我们手里的核心命题始终是在有限且有成本的窗口里如何动态地维护一份高质量的上下文。下面是四类经典且互补的策略。4.1 截断与滑动窗口最朴素也最危险最简单的做法是当对话或历史超长时直接砍掉最早的部分只保留最近的 N 个 token像一个滑动的窗口。它的优点是实现零成本、延迟可控。缺点也很明显被砍掉的可能恰好是关键信息——比如用户在对话最开始交代的核心需求。因此纯粹的截断很少单独使用通常会配合「锚定关键信息」的技巧把 System Prompt、用户的核心目标等固定在窗口顶部永不删除只对中间的对话历史做滑动。4.2 摘要压缩用信息密度换空间更聪明的做法是压缩Compaction当历史变长时用模型自己把早期的对话或工具结果总结成一段更短的摘要用摘要替换原文。这在长对话和长任务 Agent 中极为常见。典型实现是「滚动摘要」维护一段持续更新的摘要每当新的对话积累到一定量就把它和旧摘要一起压缩成新的摘要。压缩的艺术在于保留什么。一个好的压缩策略会刻意保留未完成的任务目标、已确认的关键事实与约束、重要的中间结论、以及待办事项而丢弃寒暄、冗余的思考过程、已经失效的临时信息。下面是一个滚动摘要的简化伪代码用来演示这个思路MAX_HISTORY_TOKENS4000SUMMARY_TRIGGER6000defmanage_history(history,running_summary,llm,count_tokens):totalcount_tokens(history)iftotalSUMMARY_TRIGGER:returnhistory,running_summary# 保留最近的对话压缩较早的部分recent,oldersplit_by_tokens(history,keep_tokensMAX_HISTORY_TOKENS)summary_promptf这是此前的对话摘要{running_summary}以下是新增的对话请更新摘要。务必保留 - 用户尚未完成的目标 - 已确认的关键事实与约束 - 重要的中间结论 舍弃寒暄与冗余推理。 新增对话{format(older)}running_summaryllm.complete(summary_prompt)returnrecent,running_summary这段逻辑的关键不在代码本身而在那段压缩提示词——它定义了「什么信息值得被记住」这才是压缩策略真正的护城河。4.3 检索增强RAG把外部知识按需取用面对海量、远超任何窗口的知识库企业文档、代码库、历史工单把全部内容塞进上下文既不现实也不明智。检索增强生成RAG的思路是把知识存在外部通常是向量数据库在每次回答前只检索出与当前问题最相关的几个片段注入上下文。RAG 的本质就是一种「按需加载」的上下文管理把上下文窗口当作 CPU 的高速缓存把向量库当作大容量硬盘用检索这个动作在两者间搬运数据。它的效果高度依赖三件事切分Chunking文档如何切块块太大浪费预算、太小丢失语境检索质量向量召回、关键词召回、二者混合以及重排序Rerank注入方式检索到的片段如何组织、如何标注来源、放在上下文的什么位置。结合第二节的「迷失在中间」一个实用技巧是把 Rerank 后最相关的片段放在离问题最近的位置通常是末尾而不是随意堆放。4.4 记忆系统短期与长期的分层更完整的方案是构建一套记忆系统Memory把人类记忆的分层思想借鉴过来短期记忆 / 工作记忆当前会话的上下文窗口本身容量小、访问快、随会话结束而清空。长期记忆持久化存储可以是向量库语义记忆、结构化数据库事实记忆甚至是一份不断更新的用户画像文档。跨会话存在用时检索。一个成熟的 Agent 通常会在这两层之间主动搬运信息从当前对话中提炼出值得长期记住的偏好或事实写入长期记忆在新会话开始时把相关的长期记忆检索回来放进上下文。这套机制是让 Agent 从「一次性工具」进化为「越用越懂你的助手」的关键。五、Agent 时代的上下文工程如果说前面四种策略是「术」那么这一节要谈的是「道」——为什么在 Agent 时代上下文管理会从一个可选的优化项升级为决定成败的核心工程学科。5.1 从提示词工程到上下文工程2023 年的主题词是「提示词工程Prompt Engineering」关注的是如何雕琢一句静态的指令。而到了 Agent 时代主题词变成了「上下文工程Context Engineering」关注的是如何在一个多步骤、动态演进的任务中持续地为模型的每一次调用构建最优的上下文。二者的差异是根本性的提示词工程面对的是一句话上下文工程面对的是一个随时间不断变化、可能膨胀到失控的信息流。可以给上下文工程下一个务实的定义在每一步推理时用尽可能少的 token为模型提供完成当前这一步所必需的全部信息——不多不少。5.2 一次 Agent 调用里上下文由什么组成拆解一个典型 Agent 单步调用的上下文通常包含这几个部分System Prompt角色、能力边界、行为准则。相对静态应放在最前面并保持稳定有利于 prompt 缓存。工具定义Tools可用工具的名称、描述、参数 schema。工具越多这部分越占空间。对话/任务历史用户指令、模型的历次思考与行动、工具返回结果。这是增长最快、最需要管理的部分。检索到的知识RAG 或记忆系统按需注入的外部信息。当前状态/草稿区任务的待办清单、已完成步骤、中间产物。上下文工程本质上就是对这五个部分做动态的编排、压缩与取舍。5.3 工具结果是最大的「上下文杀手」Agent 场景里最容易撑爆上下文的往往不是对话而是工具返回的原始结果。一次数据库查询可能返回上千行一次网页抓取可能带回几万字的 HTML一次文件读取可能是整个代码文件。把这些原始结果不加处理地追加进上下文是新手最常犯的错误。成熟的做法有几种结果精炼工具返回后先用规则或小模型提取出真正需要的字段只把精炼结果放进上下文。比如数据库查询只保留关键几列的前若干行加一个总数。引用而非内联Reference over Inline把大块结果存到外部文件系统、状态对象上下文里只放一个引用/句柄和简短摘要需要时再按需读取。这就是所谓的上下文卸载Context Offloading。及时清理一旦某个工具结果被消费完、不再需要就从上下文中移除它而不是让它一直占着预算。5.4 让 Agent 拥有「外部草稿纸」一个非常有效的模式是给 Agent 配一块持久化的外部工作区——最常见的形式就是文件系统或一份结构化的状态对象。Agent 可以把长期计划、待办清单、阶段性成果写到「草稿纸」上而不是全部囤在上下文里。需要时再读回相关部分。这样做的好处是双重的既释放了宝贵的上下文预算又让任务状态得以在上下文被压缩甚至重置后依然存续。很多优秀的编码类 Agent都会主动维护一份todo清单文件本质上就是把「工作记忆」外置到了一块不受窗口限制的空间。5.5 多智能体用「分而治之」对抗上下文膨胀当单个 Agent 的任务复杂到上下文注定会爆炸时一个有效的架构是多智能体Multi-Agent 上下文隔离。思路是由一个主 AgentOrchestrator负责拆解任务把每个子任务派发给独立的子 Agent。每个子 Agent 拥有自己干净、独立的上下文窗口只专注于自己那一小块工作完成后只把精炼后的结论返回给主 Agent。这样海量的中间探索过程被隔离在各个子 Agent 的上下文里「阅后即焚」主 Agent 的上下文始终保持清爽只汇集各路的最终成果。深度研究类、复杂编码类的 Agent 系统普遍采用这种分而治之的结构来突破单窗口的容量极限。5.6 一个贯穿全流程的例子深度研究 Agent把上面的策略串起来看一个「深度研究 Agent」如何管理上下文接到问题主 Agent 把研究问题拆成若干子课题写入一份计划文件外部草稿纸。并行探索为每个子课题派发子 Agent。子 Agent 各自搜索、抓取、阅读原始网页内容全部留在自己的独立上下文里绝不回传主 Agent。精炼回传每个子 Agent 只把「这个子课题的核心发现 关键来源链接」这几百字的摘要交还主 Agent。滚动压缩随着子课题增多主 Agent 定期把已完成课题的发现压缩进一份滚动摘要。按需回溯撰写最终报告时若需要某个细节再通过引用句柄去读取当初存下的原文而非一直把它放在上下文里。整个过程中任何一个窗口都没有被无意义地塞满而一个远超单窗口容量的研究任务却被顺利完成。这就是上下文工程的价值所在。六、评估与调优让上下文管理可度量上下文管理不能凭感觉需要建立可观测、可评估的闭环。6.1 关注这几个核心指标Token 用量分布统计每次调用中System Prompt、工具定义、历史、检索内容各占多少。你往往会惊讶地发现某个部分悄悄吃掉了大半预算。有效信息占比在注入的上下文中真正被模型用到的比例有多高。过低说明检索或压缩不精准。任务成功率 vs. 上下文长度画出这条曲线你能直观看到自己的系统在多长的上下文下开始「腐烂」。成本与延迟每次任务的平均 token 成本和 P95 延迟是所有优化最终要对齐的现实指标。6.2 用「大海捞针」测试评估长上下文能力评估一个模型或你的 RAG 系统在长上下文下的检索能力业界常用「大海捞针Needle in a Haystack」测试在一段很长的无关文本中藏入一句特定信息针然后在不同上下文长度、不同插入位置下提问观察模型能否准确找到。这套方法能有效暴露前面提到的「迷失在中间」问题帮你判断到底该在多长的窗口内工作。6.3 几条经验法则先精简再扩窗在把窗口开大之前先问自己现有的上下文里有多少是冗余的。多数时候问题出在信息质量而非窗口大小。锚定关键信息核心指令放开头最相关的检索内容放结尾别把要紧的东西埋在中间。让历史可压缩、让结果可引用从架构上就为压缩和卸载留好接口而不是等窗口爆了再打补丁。为缓存而设计把静态内容System Prompt、工具定义放在前缀且保持稳定最大化利用 prompt 缓存来省钱省时。七、未来的方向上下文管理仍在快速演进几个值得关注的趋势更长且更「实」的窗口百万级 token 窗口正在普及但真正的挑战从「能读多长」转向「在多长的窗口内还能保持稳定的推理质量」。评测正从长度比拼转向有效性比拼。架构层面的突破状态空间模型如 Mamba 一类、混合注意力架构试图在根本上摆脱 O(n²) 的桎梏让超长序列处理变得廉价。原生记忆能力把记忆的存取从「外挂工程」逐渐内化为模型或框架的原生能力让 Agent 天然具备跨会话的持久记忆。自适应上下文管理让 Agent 学会自己判断何时该压缩、何时该检索、何时该卸载把上下文工程本身也变成一种可学习、可自动化的能力。结语回到开头那个转变从「能塞多少」到「该塞什么」。上下文窗口的容量固然重要但它终究只是一个舞台的大小真正决定演出效果的是导演如何在这个舞台上安排每一个角色的出场与退场。对今天的开发者而言与其焦虑地追逐更大的窗口数字不如把功夫下在上下文的经营上让每一个进入窗口的 token 都物有所值让每一次调用都只带上此刻真正需要的东西。当你开始像管理一份稀缺预算那样管理上下文你会发现很多曾经归咎于「模型不够聪明」的问题其实只是上下文没有放对而已。这就是上下文窗口管理这件事的全部要义。
返回列表