经典面试题:Agent上下文长度瓶颈
题目
在Agent开发中,上下文长度超了怎么办?
解答
在Agent开发中遇到上下文长度超限(Context Overflow)是一个非常常见的问题,尤其是当你构建需要多轮对话、长文档处理或多工具调用的复杂Agent时。
以下是几种系统性的解决方案,从简单到复杂排序,可以根据你的具体场景选择:
1. 换用更大上下文的模型(最简单)
这是最直接的方法。现在的模型上下文窗口越来越大(如Gemini 1.5 Pro的2M,Claude的200K,GPT-4 Turbo的128K等)。
-
做法: 如果用的是旧模型(如GPT-3.5的4K),直接切换到支持1M token的模型。
-
缺点: 成本会变高,且推理延迟可能会增加。如果真的超出限制(比如处理整本书),依然会失败。
2. 文本压缩与摘要
这是最常用的策略。既然存不下所有历史,就把历史“变薄”。
-
关键点摘要:
-
每当对话进行到一定轮次或接近Token上限时,触发一个“总结Agent”或调用LLM。
-
让模型把当前的对话历史浓缩成一段摘要(例如:“用户询问了天气,然后订了餐厅,现在在问路线”)。
-
清空历史缓冲区,只保留这个摘要 + 最近几轮完整的对话。
-
-
增量式摘要: 每次总结时,不是从头总结,而是将旧的摘要 + 新的对话合并,生成新的摘要。
-
优点: 保留了核心信息。
-
缺点: 会丢失细节(例如用户之前具体说过不喜欢吃什么)。
3. 检索增强生成应用于历史
将Agent的长期记忆视为一个向量数据库。
-
做法:
-
不再把所有的历史对话都塞进Prompt。
-
将过去的对话按轮次或时间切片,向量化存入数据库。
-
当用户发送新消息时,先用用户的query去检索最相关的几条历史记录。
-
只将检索到的相关历史 + 最近的对话放入上下文。
-
-
适用场景: 历史对话很长,但每次推理只需要参考其中几个关键片段的情况。
4. 基于窗口的滑动
维持一个固定大小的“最近对话”窗口。
-
做法:
-
设定一个最大消息对数量(例如保留最近的10轮对话)。
-
当第11轮到来时,丢弃最早的那一轮。
-
变种: 可以确保系统提示词、工具定义等关键信息永远不被丢弃,只丢弃对话历史。
-
-
优点: 实现简单,确保上下文不会爆,且模型专注于最新的意图。
-
缺点: 如果后续推理需要用到很早之前约定的信息,模型会遗忘。
5. 工具调用的优化
在Agent开发中,Tools/Function Calling的定义通常很占Token,尤其是参数描述复杂的时候。
-
精简Schema: 确保工具描述简洁明了,移除不必要的字段描述。
-
动态选择工具: 如果定义了上百个工具,可以引入一个“路由器”或“意图识别”步骤。先根据用户输入,选出可能用到的3-5个工具,只把这几个工具的Schema传给主模型,而不是把所有工具定义都塞进去。
-
用代码代替描述: 有些框架允许将工具逻辑写成代码,模型只需要知道“有这么一个函数”即可。
6. 阶段性状态转移
这是Agent架构层面的优化,适合复杂的任务型Agent。
-
做法:
-
将长流程拆分成多个阶段。
-
每个阶段结束时,生成一个“阶段总结”或“状态对象”。
-
下一阶段的Agent只需要读取这个总结,而不需要读取前一阶段的所有对话细节。
-
例子: 第一个Agent负责收集信息,输出一个结构化的表单;第二个Agent拿着这个表单去执行操作。
-
7. 外挂记忆存储
让Agent学会使用“便签”或“记事本”。
-
做法:
-
给Agent提供一个
write_note和read_note的工具。 -
当Agent发现信息重要但当前用不上时(比如用户的自述背景故事),它主动调用工具把它存到外部。
-
后续需要时,再调用工具读回来。
-
这模拟了人类的记忆机制:不把所有东西都放在脑子里(短期记忆),而是写在笔记本上(长期记忆)。
-
8. 关键信息提取
如果你知道对话中只有特定类型的信息是重要的(比如用户的偏好设置、账号信息),可以专门写一个解析器。
-
做法:
-
在对话过程中,实时解析最新消息,更新一个全局的“用户上下文对象”。
-
下次请求时,只把这个结构化的对象(如
UserPref = {city: "北京", diet: "素食"})放入Prompt,丢弃原始对话历史。 -
这种方法在聊天机器人或客服Agent中非常常见。
-
总结建议
在实际开发中,通常会组合使用这些方法:
-
保近丢远: 保留最近的N轮对话(滑动窗口)。
-
摘要旧话: 将超出窗口的旧对话进行向量检索或摘要。
-
精简工具: 只传递当前必要的工具定义。
更多推荐



所有评论(0)