LLM上下文的有效管理
LLM上下文的有效管理
使用说明:文中涉及的窗口占比阈值、预留比例、top_k、单次输出token数等,均为工程经验起点,不是跨模型、跨业务通用的标准答案。上线前应使用实际模型的tokenizer、真实对话分布和成本约束进行校准。
一、先分类:上下文超限的三大场景
大语言模型绝大多数上下文溢出问题,都可以先归入以下三类,再选择对应方案:
-
输入侧太长:历史对话轮次越来越多,旧对话持续占用token。典型场景:长对话聊天、多轮Agent。
-
输出侧太长:模型需要生成的答案体量很大,单次输出放不下。典型场景:长报告、代码库分析、万字文档改写。
-
长期记忆需求:跨会话、跨天、跨任务,需要记住远超单次窗口容量的信息。典型场景:个人助手、知识库、项目档案。
落地建议:上线前先建立基础监控,实时统计当前prompt总token,并为窗口上限预留安全余量。建议以约10%–15%作为初始安全余量起点,用于吸收不同分词器、消息格式和估算方式带来的偏差;对于极长prompt或对token极敏感的场景,应进一步校准。
二、场景1:输入历史过多,旧对话挤占上下文
方案1:固定窗口截断(滑动窗口)【最简单,优先基线方案】
原理:始终保留系统提示词(System Prompt)和最近N轮对话,更早的对话直接丢弃。例如窗口为8k时,可先设置保留最近6轮问答,更早对话删除。
适用:客服、简单聊天机器人、不需要回溯很早历史的业务。
优点:实现最简单、无额外LLM调用、开销低、延迟稳定。
缺点:早期重要信息会直接丢失;用户回头询问很早之前的内容时,模型容易“失忆”。
伪代码逻辑:
safe_margin = 0.15
max_token = model_context_window * (1 - safe_margin)
history = []
while count_token(system_prompt + history) > max_token:
history.pop(0) # 从最古老的一轮开始删除
实操注意:不要粗暴按“轮数”一刀切;优先按token数量动态截断,而不是固定保留N轮,避免单轮对话超长直接打满窗口。预留比例和保留轮数都应结合真实tokenizer校准。
方案2:滚动摘要Compaction(Rolling Summarization)【常用长对话方案】
原理:当历史接近超限时,把较古老的多轮对话合并成一段摘要放入上下文。上下文结构变为:
System Prompt + 【历史摘要】 + 最近若干轮原始对话 + 用户当前提问
适用:需要记住早期关键结论,但不需要逐字原文的场景,如项目讨论助手、代码评审多轮对话、顾问对话。
优点:保留关键信息,相比纯截断大幅缓解失忆问题;通常比全量RAG成本更低。
缺点:摘要可能产生幻觉、丢细节、扭曲信息;摘要本身也会持续变长,累积到一定程度仍需二次压缩。
可操作流程:
-
每次对话结束计算总token;例如可将“占用窗口约70%”作为触发摘要的起点,具体阈值需按业务校准。
-
单独调用一次LLM做摘要,可用更小更快的模型节省成本。摘要Prompt模板可参考:
下面是一段多轮对话,请精简摘要,只保留关键结论、用户明确要求、重要约束、数据,不要冗余描述;
禁止编造原文不存在的信息;摘要尽量简短。
对话内容:
{old_conversation}
输出格式:
【历史摘要】:xxx
-
替换:删除被摘要掉的原始对话,把生成的摘要插入对话头部。
-
兜底:为摘要设置最大长度;摘要过长时,对摘要再做一轮浓缩。
生产注意事项:摘要模型和主模型最好做校验;关键业务不要只依赖摘要。重要数字、需求最好单独抽取为键值对或结构化字段存储。
方案3:对话历史存入向量库,按需RAG检索【适合随时回溯久远细节】
原理:不把全部历史塞进上下文。每轮对话结束后,将本轮问答切片、向量化并存入向量数据库;用户新提问时,用query检索相似历史片段,只把少量相关片段放入prompt。
适用:长期项目对话、知识库问答、需要回溯数小时或数天前对话细节的场景。
优点:理论上支持海量历史;不占用常驻上下文。
缺点:检索不准会导致信息缺失;召回无关内容会造成上下文污染;增加向量库维护和嵌入模型调用成本。
可操作配置:
-
分片策略:以单轮问答为最小单元,如
{user: xxx, assistant: xxx}作为一条chunk;不要将几十轮揉成一大块。若单轮本身很长,可再按语义边界切分。 -
召回参数:top_k=3~5可作为常见起点,同时设置相似度阈值,低于阈值直接丢弃,防止垃圾召回。窗口越紧,越应减小k并提高阈值。
-
Prompt拼接模板:
{system_prompt}
【相关历史信息(来自检索)】
{retrieved_history_chunks}
【最近对话】
{recent_raw_chat}
用户当前问题:{user_query}
选型提醒:简单业务可用轻量向量库(Chroma、FAISS本地);线上高并发可用Milvus、Qdrant。
方案4:StreamingLLM / Attention Sink KV-Cache驱逐优化【推理层底层优化】
原理:不修改发给模型的文本,而是在推理侧管理KV缓存:固定保留最开头少量token(attention sink锚点)和最新生成token,中间的KV缓存直接丢弃,从而实现超长流式持续输出。
适用:一次性超长流式任务,例如一次性读取几十页文档、超长转录文本摘要。
优点:上层业务几乎不用改对话逻辑;不需要额外调用LLM做摘要。
缺点:它不会让模型记住中间全部内容,中间内容的认知会衰减;属于推理优化,不会扩大模型原生上下文窗口能力;需要模型推理后端支持(如vLLM、Transformers配套实现),并非所有API服务商开放。
落地边界:适合离线批量超长文本处理;不适合多轮对话长期记忆,用户回头询问中间细节容易答错。商用API绝大多数不开放该能力,一般需自建推理集群。
三、场景2:输出太长,单次生成放不下
很多人只关注输入超限,却忽略输出token也占额度:任务本身需要生成超长内容时,单次可能出不完。
方案1:分段续写(Prompt Chaining)
原理:控制单次生成长度,模型生成到上限停止;程序拿到上一轮结尾文本,构造续写prompt,接力继续生成,直到完成。
注意:continue_final_message: true不是OpenAI标准参数,属于部分国内大模型厂商或推理框架的扩展字段,不可跨厂商通用,不要强依赖。
通用续写模板:
你上一轮输出在这里中断了,请接着上文继续完成,不要重复前面已经输出过的内容,保持文风、格式、逻辑一致。
上文:{{previous_generated_text}}
继续:
落地控制:设置单次最大输出token,例如限制单次输出1500 token作为示例起点;循环续写;最后程序拼接所有片段。具体数值应按模型输出上限和任务类型调整。
风险:分段处逻辑断裂、编号错乱、上下文漂移;长续写时,越往后模型越容易遗忘最开始的要求。
方案2:规划-执行框架(Plan & Solve / ReAct,先拆分任务)
原理:不让模型一次性输出全文。第一步让模型输出任务大纲和子任务清单;第二步逐个执行子任务,每个子任务单独调用模型并返回结果;最后汇总。
适用:万字报告、文档重构、代码库分析、复杂方案撰写。
规划阶段Prompt模板:
你需要完成任务:{{task}}
受上下文长度限制,不能一次性完成。请先输出结构化大纲,拆分成独立子任务,子任务之间尽量解耦;每个子任务描述清晰,不要输出正文内容。
输出格式:
1. 子任务1:xxx
2. 子任务2:xxx
然后循环遍历每个子任务,单独调用LLM并收集结果;最后汇总整合。进阶做法:汇总阶段再加一轮LLM润色合并,统一格式。
方案3:流式输出 + 边生成边清理非必要KV缓存
配合vLLM等推理引擎的流式能力,生成后的中间KV缓存及时释放,控制显存占用。这更多是推理侧显存优化;业务层解决长输出问题,优先使用上面的任务拆分与分段续写方案。
四、场景3:长期外部记忆(跨会话记忆,MemGPT/Letta思路)
原理:把模型有限上下文看作高速工作内存,把向量库、数据库看作持久化硬盘。模型拥有读写记忆的工具函数:发现重要信息时主动调用工具写入长期记忆;需要时主动检索读取。这是MemGPT、Letta的核心思路。
适用:个性化Agent、私人助理、长期项目助手。
缺点:复杂度很高,属于Agent体系,不是简单对话应用;记忆读写本身也会出错,可能存储失败或检索不到;不存在真正“无限上下文”,只是把信息移出窗口。
极简可落地的最小记忆设计(不必上完整MemGPT)
-
定义工具
save_memory(content, tag):存入向量库并打标签。 -
定义工具
search_memory(query):检索历史记忆。 -
在system prompt中告诉模型:遇到用户重要偏好、长期需求、关键数据,主动调用
save_memory;需要历史信息时调用search_memory。 -
记忆单独做老化策略:低频记忆可归档,避免记忆库无限膨胀。
五、推荐工业组合流水线(可直接作为架构参考)
推荐组合:
System Prompt + 【可选:历史摘要】 + 最近N轮原始对话 + RAG检索召回的相关历史片段 + Token预算监控 + 兜底截断
执行顺序:
-
每次提问进来,先组装候选prompt并估算token。
-
未到约70%阈值:直接放行。
-
约70%–85%:优先尝试摘要压缩古老对话。
-
约85%:摘要已压不动,启动强制截断,优先删除最早内容。
-
如果是长期记忆场景,叠加RAG检索历史。
-
如果任务输出体量巨大,走规划拆分+分段续写。
-
自建推理集群的超长文本批量场景,可叠加StreamingLLM优化KV缓存。
上述70%/85%为策略框架示例,实际阈值应结合摘要质量、调用成本和业务对“失忆”的容忍度校准。
六、必须重视的坑清单
-
Lost-in-the-Middle中间遗忘问题:即使文本塞得进窗口,模型对上下文中部信息的识别能力也可能显著下降;重要信息尽量放在头部或末尾,不要埋在一大段中间。
-
Token计算器有误差:不同库、服务商的分词器不完全一致,预留安全余量必不可少。
-
RAG召回污染:无关片段进入prompt会误导模型;一定要加相似度过滤。
-
摘要幻觉风险:涉及生产业务、财务、需求文档时,摘要不能作为唯一可信来源;关键信息建议结构化存储(如JSON键值对)。
-
不要混用方案导致复杂度爆炸:普通聊天优先滑动窗口;顾问多轮对话优先滚动摘要;长期知识库才上RAG。
-
不同模型窗口规则差异:部分模型对System Prompt权重特殊,或对超长单块文本容忍度差。
七、选型速查表
| 方案 | 开发成本 | 额外开销 | 适合场景 | 核心短板 |
|---|---|---|---|---|
| 滑动窗口截断 | 低 | 无 | 简单客服、闲聊 | 久远历史直接丢失 |
| 滚动摘要Compaction | 中 | 额外LLM调用 | 中等长度多轮对话 | 摘要幻觉、细节丢失 |
| 对话RAG检索 | 中高 | 向量库+嵌入模型 | 需要回溯历史细节 | 召回不准、污染prompt |
| StreamingLLM KV驱逐 | 高(自建推理) | 显存优化 | 一次性超长流式文档 | 中间信息认知衰减,API很难用上 |
| Plan任务拆分续写 | 中 | 多轮LLM调用 | 超长输出(报告、文档) | 分段衔接容易断裂 |
| MemGPT式长期记忆 | 高 | 工具+向量库 | 个性化长期助手 | 体系复杂,记忆读写不可靠 |
更多推荐


所有评论(0)