想象你明天要出发去旅行,但行李箱只有二十寸。护照和充电器必须带上,这是你到了目的地活下去的底线;这几天要穿的衣服最常用,得放得顺手;以前的旧衣服,扔了可惜,只能塞进真空压缩袋;如果拉链还是合不上,就不得不把最旧的那件 T 恤永远留在家。航空公司还会按超重行李收费——每多装一公斤,就多付一份钱。大模型的上下文窗口,正是这样一只行李箱:模型每轮回答能“看见”的信息总量是固定的,多塞一单位信息就多花一分钱。窗口怎么分配、装不下时怎么取舍、旧回忆怎么压缩、什么东西放最上层、超重费怎么省,就是 Context Engineering 每天要解决的问题。本文用这只行李箱贯穿始终,把六件事一次讲透。
上下文窗口管理是 AI 应用从“能跑通”走向“产品化”的分水岭:它决定长对话场景下的体验上限与单位成本,是 AI 应用工程师的核心基本功。
可视化演示
动态演示大模型上下文窗口管理策略的核心机制,通过入门/进阶/实战/优化四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
大模型上下文窗口管理策略:上下文窗 上下文窗口Token预算分配策 超长对话截断与滚动摘要技术 核心机制可视化 大模型上下文窗口管理策略整体架构与关键组件
窗口分配策略
出发前,老练的旅行者会先把箱子分成几个固定区域:证件和充电器永远放在最上面,这个位置谁也不能抢;衣服占大头;还要留出一点空间给回程时买的纪念品,最后再留一条缝保证拉链能合上。行李箱的空间规划,决定了后面所有打包动作是否从容。
上下文窗口也一样,总容量 C 是一块固定预算,必须提前分配给四类内容:系统提示词(证件)、对话历史(衣服)、模型输出(纪念品)、安全余量(合箱子的缝)。系统提示词负责设定角色、规则和任务边界,相当于“你是一个……你必须……”这些铁律,每一轮都要在,不能省也不能丢。
常见的工程经验是:系统提示词控制在窗口的 10%~20%;对话历史 60%~70%;输出预留 10%~20%;再留 5%~10% 作为安全余量。例如 8K 窗口(K 是千,即 8000 个 token;token 是模型处理文本的最小计数单位,可粗略理解成一个字或一个词)可以切成:系统 1024 token,输出预留 1024,历史约 6144,余量由代码动态把控。分配不是一次定死,很多框架会在每次请求前重新计算预算,回收被浪费的空间。
1. 总容量 C:上下文窗口的 token 上限,是行李箱的总容积,由模型决定。
2. 系统提示词预算:恒定占用的一块,设定角色与全局规则,永远最先保证。
3. 历史与输出两块:对话历史是最大弹性块,输出预留则保证模型有空间生成答案。
4. 安全余量:防止排满后因 token 计算误差溢出报错,相当于合箱子的那一条缝。
规划好了区域,后面截断和压缩才有依据:哪些是证件不能扔,哪些是衣服可以压——空间分配的本质,是在出发前就想清楚“谁最重要”。
截断策略
箱子塞不下了,最简单粗暴的做法是把最底下的旧衣服掏出来。但如果你慌乱中把护照也掏了出去,到了机场就傻眼了。截断的难点从来不是“删”,而是“删什么、留什么”。
截断就是在窗口超限时,从对话历史中丢弃一些轮次或片段。最朴素的方法是头部截断:把最早的对话直接删掉。但它有致命伤——最早几轮里往往藏着系统指令、用户最初的诉求和尚未完成的任务,删了它们等于扔掉护照。
更聪明的做法是“中央保真”:研究发现模型对开头和结尾的信息关注更强、中间部分容易被忽略(业内称为 lost in the middle,即“中间迷失”),所以保留开头(系统+目标)和结尾(最新对话)的原文,把中间的旧对话压缩或删除。工程上还会设一份“关键信息保护名单”:用户最新诉求、未完成任务、指令约束等条目永不截断,只截断闲聊和重复内容。
1. 每轮长度 t_i:第 i 轮对话(用户+助手)消耗的 token 数,是截断的基本单位。
2. 起始轮 k:截断后保留的第一轮,k 越大丢掉的旧对话越多,太大则会丢掉系统与目标。
3. 历史可用预算:右侧是总容量减去系统提示词和输出预留后的可用空间,历史总量必须被它罩住。
取舍的智慧在于:旧衣服可以扔,但证件和这次旅行的车票不能扔。截断不是“删最早的”,而是“删最不重要的”——这也是后面优先级策略的伏笔。
滚动摘要
有些旧衣服扔了可惜,因为路上可能还要穿。聪明的旅行者会拿出真空压缩袋:一袋羽绒服“嗖”地变成豆腐块大小。滚动摘要就是上下文的真空压缩袋。
滚动摘要的思路是:当历史接近预算阈值(比如用掉可用空间的 80%)时,把最老的一批对话交给模型提炼成一小段摘要,放进下一次请求。摘要的位置放在历史之前、系统提示之后,相当于把压缩袋塞进箱子角落。
摘要质量与压缩比 r 是关键。好的摘要保留“用户诉求、结论、未完成任务、关键实体”,丢掉寒暄与重复;压缩比通常做到 0.1~0.3,即 1000 token 的对话缩成 100~300 token 的要点。面对超长对话,还有分层摘要树:摘要超过阈值后,再对摘要做摘要,形成多级金字塔,从而支持任意长度的会话记忆。
1. 摘要生成函数:通常直接调用大模型把长文本提炼成要点,也可以用规则抽取。
2. 拼接操作:旧摘要和新被淘汰的对话拼接在一起作为压缩输入,保证信息连续。
3. 压缩比:新摘要长度除以压缩前总长度,远小于 1 意味着腾出了大量空间。
压缩袋不是把衣服揉成一团,而是抽掉空气、保留材质——摘要也是如此:丢掉废话、保留信息。它让“回忆”不占地方,还随时能打开接着用。
多轮优先级
箱子装好后,总有几样东西要放最上层:今晚要穿的睡衣、明早的牙刷,一伸手就摸到;底下的东西反正要弯腰翻。多轮对话里,信息也要分个尊卑。
不是所有历史轮次生而平等。刚说完的话(时效性)、与用户当前目标相关的话(相关性)、用户下达的指令(指令权重),都应该比闲聊权重更高。工程做法是给每条历史打一个优先级分 p,按分数排序分配窗口空间,低分的先丢进摘要或截断。
用户最新诉求和未完成任务通常设为最高优先级,称为“目标锚点”——就像箱子上层永远放着车票和行程单。当摘要本身也过长时,采用递归压缩:对摘要再做摘要,形成摘要树。这相当于把整个压缩袋再压缩一层,代价是信息多损失一档,但能对抗无限长的对话。
1. 时效性 f_i:信息越新越重要,因为对话延续性依赖最近上下文。
2. 目标相关性 g_i:与当前未完成任务的相关程度,越相关越该保留原文。
3. 指令权重 d_i:包含用户明确指令或约束的信息权重最高,类似“必须遵循的规则”。
4. 加权系数:α、β、γ 是超参数,工程上既可用人工规则,也可用数据学习得到。
优先级的本质,是把“最可能被用到的信息”放在最顺手的位置。箱子空间有限,但我们总能保证:当你需要车票时,它一定在最上层。
成本平衡
航空公司对超重行李按公斤收费,而且旺季每公斤更贵。模型厂商也一样:按 token 收费,输入一个价、输出一个价,长上下文模型的单价还更高。行李箱用多大、装多满,直接写在账单上。
成本公式很直白:每轮请求的输入 token 数乘以输入单价,加上输出 token 数乘以输出单价。注意输出单价通常是输入的两到三倍,但输入才是成本大头——因为每轮请求都要把整个上下文(系统+摘要+历史)重发一遍,十轮对话,历史信息就发了十遍。
所以削减输入 token 是省钱的第一杠杆:截断和滚动摘要正是为此而生。第二个杠杆是混合模型路由:把简单任务(如天气查询)路由到便宜短窗口模型,复杂任务(如长文档分析)才用贵的长窗口模型,相当于短途打车、长途坐高铁。第三个杠杆是请求级提示词缓存,让重复的前缀不再重复计费。
1. 输入单价 p_in:每千 token 的输入价格,通常比输出便宜。
2. 输入量 n_in:每轮请求携带的全部输入,包括系统、摘要、历史,是成本大头。
3. 输出成本:输出单价更高但数量小,两者之和才是单请求成本。
4. 降本杠杆:压缩 n_in 是最直接的控费手段。
省钱不是目的,把钱花在刀刃上才是。就像旅行者不会为省钱把箱子换小,而是会算清楚:哪些行李值得付超重费,哪些可以留在家里——上下文也一样,该精的地方精,该留的地方留。
最佳实践
老背包客的箱子永远整洁:他们从不临时慌乱打包,而是有一套固定流程——分层、防漏、清单、回程复盘。上下文窗口管理做到第五层,拼的就是这套工程习惯。
几条经过验证的实践:一是结构化提示词,系统提示写成固定模板,把关键指令放在开头和结尾(避开“中间迷失”区),方便后续裁剪复用;二是上下文分页管理,长文档按块拆分,按需把相关块注入窗口,而不是一次性全塞进来;三是记忆持久化,滚动摘要不只存在于请求里,还把摘要写入数据库跨会话复用,新会话可以直接加载“上次说到哪了”。
四是监控与调优:记录每轮 token 利用率、摘要长度、截断比例、回答质量打分,形成看板。目标是把利用率 u 保持在 0.8 左右——太低浪费容量,太高挤压输出导致截断报错。调优时依次检查:系统提示是否过大?历史是否冗余?摘要是否保真?用数据回答,而不是拍脑袋。
1. 实际用量:本次请求真正注入窗口的总 token 数。
2. 窗口上限 C:模型支持的上下文总容量。
3. 目标区间:u 过低浪费预算,过高则有溢出风险,经验上 0.7~0.85 为佳。
旅行者最后都会形成自己的打包清单。上下文管理的最佳实践,就是把“什么重要、什么可舍、怎么压缩、怎么复盘”沉淀成一套可复用的系统——箱子是有限的,但装东西的智慧可以不断升级。
AI 应用场景
智能客服的长会话记忆
阶段:Context Engineering(对话上下文管理)
解决的问题:传统客服机器人只保留最近 3-5 轮,用户前面提到的订单号、诉求、承诺事项在后半程全部“失忆”,用户不得不反复复述;每轮全量发送原始历史又让 token 账单飞涨。用滚动摘要 + 截断 + 优先级,让机器人像人类客服一样“记笔记”。
具体案例:某电商售后机器人平均会话 25 轮。改造前每轮把全部历史原文塞进窗口,单会话输入 token 约 15 万;接入滚动摘要后,历史被压缩成一段约 300 token 的“诉求纪要”,目标锚点(订单号、纠纷点)单独保真,单会话输入降到约 4 万 token,成本下降约 70%,用户诉求遗漏率从 18% 降到 4%。
长文档问答中的分页裁剪
阶段:RAG / 检索增强生成(上下文分配)
解决的问题:从知识库检索出的片段拼接后经常超窗,传统做法从尾部硬截断,可能恰好丢掉答案所在的段落。用优先级打分 + 分页注入:检索片段先按相关度打分排序,预算内保留高分段,用户当前问题相关的“锚点段落”永不截断。
具体案例:法律文书阅读助手,每份合同近 5 万字,检索出 30 个候选片段共约 9K token,窗口 8K。按相关度打分后保留 top 段 + 问题锚点段,答案定位准确率提升 25%,单次问答成本下降 30%。
多智能体任务编排中的共享记忆
阶段:Agent 编排(多轮工具调用上下文管理)
解决的问题:Agent 在执行“查航班→比价→预订→确认”时,中间步骤的结果(候选列表、价格快照)与用户目标争夺窗口。全保留则窗口爆掉,精简则丢失中间状态导致预订错误。用分级记忆:目标锚点与当前步骤关键结果保留原文,已完成步骤的结果滚动摘要化。
具体案例:一个订票 Agent 把每步中间结果压缩成结构化摘要(航班号、价格、座位状态),窗口占用降到原来的 40%,任务成功率从 71% 提到 89%,还能向下游步骤传递关键约束。
Python 演示
# -*- coding: utf-8 -*-# 上下文窗口管理器演示: 滑动截断 + 滚动摘要 + 成本估算 def estimate_tokens(text): """粗略估算 token 数: 中文约 2 字 1 token.""" return max(1, len(text) // 2) class WindowManager: def __init__(self, system_prompt, max_tokens=512, reserve=128): self.max_tokens = max_tokens self.reserve = reserve self.system_prompt = system_prompt self.history = [] self.summary = "" self.summarize_count = 0 def _tokens(self): sys_tokens = estimate_tokens(self.system_prompt) sum_tokens = estimate_tokens(self.summary) hist_tokens = sum( estimate_tokens(u) + estimate_tokens(a) for u, a in self.history ) return sys_tokens + sum_tokens + hist_tokens def _compact(self): budget = self.max_tokens - self.reserve while self._tokens() > budget and len(self.history) > 1: user, assistant = self.history.pop(0) gist = "用户问{0}, 助手答{1}.".format(user[:8], assistant[:8]) self.summary = (self.summary + gist)[-400:] self.summarize_count += 1 def add_turn(self, user, assistant): self.history.append((user, assistant)) self._compact() def build_prompt(self): parts = [self.system_prompt] if self.summary: parts.append("[滚动摘要] " + self.summary) for user, assistant in self.history: parts.append("用户: " + user) parts.append("助手: " + assistant) return "\n".join(parts) def report(self): total = self._tokens() sys_tokens = estimate_tokens(self.system_prompt) sum_tokens = estimate_tokens(self.summary) return [ total, sys_tokens, sum_tokens, total - sys_tokens - sum_tokens, self.max_tokens, self.summarize_count, ] def estimate_cost(input_tokens, output_tokens, in_price, out_price): return input_tokens / 1000 * in_price + output_tokens / 1000 * out_price def main(): manager = WindowManager( "你是一位耐心的客服助手, 请用简洁中文回答用户问题.", max_tokens=512, reserve=128, ) questions = [ "我的订单还没到, 能帮我查一下吗?", "下单当天是用的优惠券吗?", "那请问退款大概多久到账?", "如果到账时间超过7天怎么办?", "这个商品还有黑色款吗?", ] * 6 input_tokens = 0 output_tokens = 0 for i, question in enumerate(questions): answer = "好的, 我理解您的问题:{0} 已为您记录并同步处理, 请放心.".format(question) manager.add_turn(question, answer) if i in (0, 4, 9, 14, 19, 24, 29): total, sys_t, sum_t, hist_t, limit, comp_count = manager.report() print("第{0:2d}轮 | 总{1:4d}/{2} 系统{3:3d} 摘要{4:3d} 历史{5:3d} 压缩{6}次".format( i + 1, total, limit, sys_t, sum_t, hist_t, comp_count)) if i % 3 == 0: prompt = manager.build_prompt() input_tokens += estimate_tokens(prompt) output_tokens += 80 cost = estimate_cost(input_tokens, output_tokens, 0.002, 0.006) print("累计输入token: {0}, 累计输出token: {1}, 估算成本: ${2:.4f}".format( input_tokens, output_tokens, cost)) print(manager.build_prompt()[:180]) print("...") if __name__ == "__main__": main()
budget = self.max_tokens - self.reserve先扣掉输出预留,剩下的才允许历史和摘要占用,相当于给“回程纪念品”留位置。while self._tokens() > budget and len(self.history) > 1:只要超预算且还有旧对话可淘汰,就持续压缩。user, assistant = self.history.pop(0)弹出最早的一轮,这是最简单的“头部截断”。self.summary = (self.summary + gist)[-400:]把被淘汰轮浓缩成一句话并入摘要,并限制摘要总长不超过 400 字。parts.append("[滚动摘要] " + self.summary)构建请求时摘要紧跟系统提示,历史排在其后,让模型先看到“纪要”。manager.add_turn(question, answer)每来一轮对话就写入历史并触发可能的压缩,管理发生在请求之前。estimate_cost(input_tokens, output_tokens, 0.002, 0.006)按输入 $0.002/千token、输出 $0.006/千token 估算总成本。
常见误区
误区上下文窗口越做越大,直接把所有历史原文全塞进去不就行了?反正窗口装得下,效果肯定最好。
正解窗口大不等于效果好:研究发现模型对超长上下文的中间部分关注明显减弱(中间迷失),历史越长噪音越多,还可能稀释掉系统指令的影响力。就像行李箱再大,东西塞满后找护照也要翻半天,还容易压坏证件。正确做法是让关键信息靠头靠尾,中间旧内容用摘要压缩。
为何常见:厂商宣传长窗口参数(128K/1M),容易让人觉得“全保留=最佳”,小规模试用时差异又不明显。
误区窗口超限了,把最早的对话删掉就行,省事又不会影响结尾的回答。
正解最早的对话里常常藏着系统指令、用户最初的诉求和未完成任务。直接头部截断等于把护照扔了:模型后半程忘记用户要什么,回答跑偏。正确姿势是给关键信息设保护名单,并对被淘汰内容先做滚动摘要,再删原文。
为何常见:“最早的=过时的”符合直觉;初学时看不到早期指令对后续回答的隐性影响。
误区滚动摘要就是把旧对话简单拼接起来放前面,反正模型能看懂。
正解摘要的核心是“抽取信息”而非“搬运文字”:要提炼用户诉求、结论、未完成任务和关键实体。如果只是拼接原文,摘要比原文还长还带噪音,压缩比和保真度双输,就像压缩袋没抽气,体积没小还受潮。
为何常见:“摘要”听起来像“删减”,很多教程只讲流程不讲质量,导致低质量摘要的做法流传开来。
误区上下文窗口管理只是省钱的小优化,效果差点没关系,先上线再说。
正解窗口管理直接决定回答的一致性:忘记用户诉求、丢失指令、角色漂移,这些都是功能性错误,不只是消费账单的问题。就像行李箱没整理好,到了机场发现护照没带——不是多花点钱能补救的。
为何常见:成本超支是显性的,效果劣化是隐性的、滞后的,短期难以量化归因。
面试题
Q1. 系统提示词在上下文窗口中通常扮演什么角色?
- A.只记录用户的历史输入
- B.每次回答后自动更新
- C.恒定占用并约束全对话← 正确答案
- D.仅用于界面展示显示
答案:C。系统提示词就像行李箱里永远要带的护照和充电器——它负责设定角色、规则和任务边界,必须恒定占用窗口顶部,不能像历史对话那样被截断。A 错在历史才负责记录输入;B 错在系统提示通常保持不变;D 完全偏离了它的用途。
Q2. 滚动摘要最合理的触发时机是什么?
- A.每隔固定时间自动触发
- B.历史 token 逼近预算时← 正确答案
- C.用户每轮提问都触发
- D.模型输出结束后触发
答案:B。滚动摘要的触发要看“预算水位”:历史 token 逼近可用预算(比如 80%)才压缩,就像衣服多到快盖不上箱子时才动用压缩袋。固定时间触发太机械,每轮都触发会浪费成本,输出结束后触发与窗口占用无关。
Q3. 超长多轮对话中,哪些信息应当优先保留?
- A.用户尚未完成的核心诉求← 正确答案
- B.早期所有对话的完整原文
- C.仍未结束的任务目标信息← 正确答案
- D.与主题无关的闲聊内容
答案:AC。优先保留“未完成的诉求和任务目标”,因为它们是用户与模型之间的目标锚点,相当于行李箱必带的证件;完整旧原文和无关闲聊在空间紧张时应优先淘汰或压缩。B 和 D 会挤占宝贵的窗口空间。
Q4. "Lost in the middle" 现象指的是什么?
- A.窗口中间信息的关注度更弱← 正确答案
- B.中间信息的 token 单价更高
- C.中间内容总被自动截断掉
- D.头部信息一定会被忽略掉
答案:A。研究发现模型对超长上下文中开头和结尾的信息关注更强,中间部分容易被忽略,这与位置编码和注意力机制有关,就像箱子中间的衣服最难找。B、C、D 都不是该现象的本意。
Q5. 截断中的“中央保真”策略是指什么?
- A.只保留对话开头部分内容
- B.保留头尾并压缩中间内容← 正确答案
- C.删除中间的全部历史内容
- D.只保留每轮的最近一句话
答案:B。中央保真是利用“头尾关注更强”的规律:把开头(系统+目标)和结尾(最新对话)保留原文,中间的旧对话压缩成摘要,而不是简单从某侧删除。A 是只留头部,C 是粗暴删中间,D 是只留尾句。
Q6. 上下文按 token 计费时,成本的主要决定因素是什么?
- A.输入输出 token 的数量← 正确答案
- B.模型参数量与显存大小
- C.用户会话的持续时间
- D.提示词中文字的字数大小
答案:A。API 按 token 数乘以单价计费,且输入输出分开计价,所以关键因子是输入输出 token 数量与对应单价。参数量、会话时长、提示词字数(不是 token 数)都不直接参与计费。
Q7. 下列哪些做法属于窗口管理最佳实践?
- A.保持系统提示词结构化← 正确答案
- B.定期把旧对话变摘要← 正确答案
- C.无条件保留全部历史
- D.监控利用率并做调优← 正确答案
答案:ABD。结构化提示词便于裁剪复用,滚动压缩是核心省钱手段,监控利用率才能持续调优;无条件保留全部历史恰恰是反面做法——它只会白白烧掉 token 还稀释注意力,就像把所有旧衣服都塞进手提行李一样不明智。
Q8. 递归压缩机制的核心思想是什么?
- A.摘要之上再生成更高层摘要← 正确答案
- B.每轮对话都重新改写摘要
- C.用更大的窗口替代摘要
- D.把摘要永久保存在本地
答案:A。递归压缩是“摘要树上再长摘要”:当摘要本身超过预算时就对摘要做摘要,支持任意长对话,如同压缩袋外面再套压缩袋。B 是重复压缩而非分层递归,C 用大窗口本来就没压缩,D 只是存储行为。
Q9. 多轮优先级打分一般不包含哪项因素?
- A.信息的时效新鲜程度
- B.与当前目标的相关性
- C.指令遵从的重要程度
- D.消息来源的 IP 地址← 正确答案
答案:D。优先级打分通常由时效性、目标相关性、指令权重组成;IP 地址与内容价值无关,不参与打分,就像分拣行李看的是“常用+重要”而不是行李牌颜色。A、B、C 都是打分公式的常见因子。
Q10. 控制上下文成本的有效手段有哪些?
- A.缩减系统提示词长度← 正确答案
- B.定期滚动压缩历史← 正确答案
- C.采用混合模型路由← 正确答案
- D.无限扩大上下文窗口
答案:ABC。缩减系统提示、滚动压缩、混合路由(简单问题走便宜短窗口模型,复杂问题才用贵长窗口)都能降本;无限扩大窗口只会把成本抬上去,违背窗口管理的初衷,就像为了多带一件旧衣服去换更大的托运箱,结果付了更多超重费。