在Spring AI Agent实际开发中,绝大多数模型问答错乱、RAG检索失效、上下文超限报错、越聊越胡言乱语的问题,根源都不是模型能力不足,而是上下文Token管理失控。本文深度拆解LLM上下文Token四级优先级机制,结合Spring AI工程实战,手把手实现一套「优先级动态裁剪策略」,彻底解决上下文腐烂、中间信息遗忘、窗口溢出三大经典问题,适配生产级Agent开发场景。
关键词:Spring AI、Agent、Token裁剪、上下文管理、RAG优化、LLM工程化
一、前言:为什么你的Agent越用越崩?
很多开发者在使用Spring AI开发智能Agent、RAG问答系统时,都会遇到这几个共性难题:
- 对话轮次变多后,模型忘记初始任务规则,输出偏离需求;
- RAG检索到了有效资料,但模型完全不引用、回答凭空捏造;
- 上下文过长触发 context window 超限报错;
- 对话累积越多,模型回答质量越低、噪声越来越多。
大部分人会误以为是模型参数、Prompt写法的问题,实则核心原因是:LLM上下文窗口容量有限,但我们无脑堆积所有对话、RAG文档、工具信息,没有做优先级分层和动态裁剪。
LLM的上下文窗口如同固定大小的桌面,堆满无效信息就会覆盖关键信息,最终导致任务失效。本文将从原理到实战,落地一套生产可用的Token优先级管理方案。
二、核心原理:LLM上下文四级Token优先级机制
LLM对上下文不同位置、不同类型的内容,关注度和留存优先级完全不同。我们将所有上下文内容分为四个优先级梯队,窗口Token不足时,从低优先级到高优先级依次裁剪,核心规则永不丢失。
2.1 高优先级(绝对保护区)
包含内容:系统提示词(SystemPrompt)、核心任务目标、安全约束、基础任务规则
处理策略:永久保留、不压缩、不裁剪、不删除
核心意义:这是Agent的“底层行事准则”。一旦丢失或被压缩,模型会直接脱离任务逻辑,出现乱回答、违规输出等问题,是整个上下文的核心基石。
2.2 中优先级(可精简优化区)
包含内容:RAG检索文档、工具调用返回结果(Observation)
处理策略:禁止全量堆积,二次筛选、切片精简、保留核心有效片段
核心意义:这是模型本次回答的核心参考素材,不能直接丢弃,但原始检索内容存在大量冗余,全量塞入会浪费Token、干扰模型判断。
2.3 低优先级(可折叠丢弃区)
包含内容:早期历史对话、无效重复聊天记录、过期交互信息
处理策略:超阈值自动摘要压缩,Token紧张时优先丢弃
核心意义:久远对话对当前任务参考价值极低,是上下文噪声的主要来源,也是Token裁剪的首要对象。
2.4 阶段性优先级(动态装卸区)
包含内容:工具定义(ToolDefinition)、Schema规则、任务示例
处理策略:按需加载、用完即卸,非当前任务工具全部移除
核心意义:工具Schema是Token消耗大户,全部常驻上下文会占用大量窗口资源,严重压缩有效内容存储空间。
三、LLM上下文两大经典致命坑
理解优先级后,必须规避LLM天然的两个缺陷,这是绝大多数Agent优化忽略的关键点。
3.1 Context Rot(上下文腐烂)
随着对话轮次增加,大量无效、过期、重复的历史信息持续堆积,上下文噪声泛滥。模型无法精准识别关键有效信息,导致回答越来越冗余、偏离主题,最终完全失效。
解决方案:禁止无限追加历史消息,设置Token阈值,自动折叠、清理老旧对话。
3.2 Lost in the Middle(中间信息遗忘)
LLM存在天然注意力缺陷:对上下文头部、尾部内容记忆清晰,对中间位置内容极易忽略。
很多开发者将RAG文档、工具返回结果直接塞在消息列表中间,导致明明传入了参考资料,模型却完全不使用,出现“检索失效”的假象。
解决方案:核心参考素材尽量靠近消息尾部,增加专属标记强化注意力,控制单批次参考文档数量。
四、Spring AI 工程化落地:Token动态裁剪策略
基于上述优先级规则,我们落地一套生产可用的上下文管理流程:Token预检测 → 低优裁剪 → 中优精简 → 高优保护 → 动态装卸工具。
4.1 核心执行流程
- Token数量预统计:通过Token计算器统计当前上下文总Token数,预留安全冗余,不塞满窗口;
- 逐级裁剪降级:优先压缩老旧历史对话,仍超限则精简RAG素材,最后卸载无效工具定义;
- 永久保护高优内容:SystemPrompt全程固定,不做任何修改裁剪;
- 动态刷新上下文:每次Agent调用前执行裁剪,保证上下文轻量化、高纯度。
4.2 核心代码实现
/**
* Spring AI 上下文Token优先级裁剪工具类
* 裁剪顺序:历史对话 > RAG素材 > 工具定义,保护系统提示词
*/
public class ContextTokenTrimHandler {
// 模型上下文窗口上限,根据所用模型配置
private static final int MAX_WINDOW_TOKEN = 128000;
// 安全预留余量,避免窗口塞满报错
private static final int SAFETY_GAP = 8000;
// 最大允许Token数
private static final int MAX_ALLOW_TOKEN = MAX_WINDOW_TOKEN - SAFETY_GAP;
private final TokenCountCalculator tokenCalculator;
public ContextTokenTrimHandler(TokenCountCalculator tokenCalculator) {
this.tokenCalculator = tokenCalculator;
}
/**
* 上下文消息预处理&裁剪
*/
public List<Message> trimContext(List<Message> messages, List<Document> ragDocs, boolean needTool) {
// 1. 保护高优先级:固定系统提示词,不做任何处理
List<Message> systemMessages = filterSystemMessage(messages);
List<Message> businessMessages = filterBusinessMessage(messages);
// 2. 阶段性优先级:按需加载/卸载工具定义
if (!needTool) {
removeToolDefinitionMessage(businessMessages);
}
// 3. 中优先级:二次精简RAG检索文档,去除冗余内容
List<Document> slimRagDocs = trimRagDocument(ragDocs);
businessMessages.add(buildRagDocMessage(slimRagDocs));
// 4. 低优先级:循环裁剪,直到Token达标
int currentToken = tokenCalculator.countTokens(businessMessages);
while (currentToken > MAX_ALLOW_TOKEN) {
// 优先压缩/删除最早的历史对话
compressOldHistoryMessage(businessMessages);
// 仍超限则进一步精简RAG内容
if (tokenCalculator.countTokens(businessMessages) > MAX_ALLOW_TOKEN) {
trimRagContentMax(businessMessages);
}
currentToken = tokenCalculator.countTokens(businessMessages);
}
// 拼接最终上下文:高优系统词 + 裁剪后业务消息
List<Message> finalMessages = new ArrayList<>();
finalMessages.addAll(systemMessages);
finalMessages.addAll(businessMessages);
return finalMessages;
}
// 精简RAG文档:重排、去冗余、截取核心片段
private List<Document> trimRagDocument(List<Document> ragDocs) {
// 自定义RAG二次精简逻辑:rerank过滤低分文档、切片去冗余
return ragDocs;
}
// 压缩老旧历史对话:多轮旧消息摘要合并
private void compressOldHistoryMessage(List<Message> businessMessages) {
// 自定义历史消息压缩逻辑
}
// 过滤系统提示词
private List<Message> filterSystemMessage(List<Message> messages) {
return messages.stream().filter(msg -> msg instanceof SystemPrompt).toList();
}
}4.3 关键优化细节
- 规避Lost in the Middle:精简后的RAG核心素材、最新用户提问统一放在消息列表尾部,最大化模型注意力;
- 强化内容标识:为RAG参考资料添加【参考资料开始/结束】专属标记,辅助模型识别有效信息;
- 工具动态卸载:非当前任务场景,主动清除所有工具Schema,节省大量Token;
- 前置预裁剪:不等超限报错再处理,预留安全Token余量,保证服务稳定。
五、高阶优化:上下文缓存
在高并发生产场景下,重复加载固定的System提示词、工具定义会造成大量无效Token消耗和延迟。主流大模型均支持上下文前缀缓存,我们可以针对性优化:
缓存对象:高优先级固定内容(SystemPrompt、常驻工具Schema、通用任务规则)
核心收益:
- 大幅降低输入Token计费成本;
- 减少首字响应延迟(TTFT),提升接口响应速度;
- 降低模型解析固定内容的算力消耗。
注意事项:系统规则、工具定义变更后需手动刷新缓存,避免缓存过期导致逻辑异常,同时需结合业务压测验证缓存命中率。
六、生产踩坑总结
结合实际落地经验,整理3个高频错误方案与最优实践:
- ❌ 错误:无脑堆积所有历史对话、全量RAG文档、所有工具定义,等待超限报错;
✅ 正确:设置Token安全阈值,按优先级主动裁剪,轻量化上下文; - ❌ 错误:依赖模型自动处理上下文,无人工干预管理;
✅ 正确:Agent自主管理消息生命周期,区分内容优先级; - ❌ 错误:所有工具Schema常驻上下文,浪费大量Token;
✅ 正确:工具按需加载,用完即卸,最大化利用窗口空间。
七、总结
LLM Agent的工程化核心,不在于复杂的Prompt技巧,而在于精细化的上下文Token管理。通过四级优先级裁剪机制,我们可以彻底解决上下文溢出、模型失忆、RAG失效、上下文腐烂等生产问题,让Agent长期运行稳定、输出精准。