Agent开发中的上下文管理:压缩策略、工具返回处理与多Agent隔离实践

发布时间:2026/10/26 20:20:53

Agent开发中的上下文管理:压缩策略、工具返回处理与多Agent隔离实践 1. 上下文管理为什么成了Agent开发的分水岭做Agent开发的人迟早会撞上同一堵墙模型本身够聪明工具调用也跑通了但一旦任务链条拉长到十几步甚至几十步整个系统就开始失忆——前面确认过的约束被遗忘中间读过的文件内容被截断用户三轮前强调的偏好消失得无影无踪。这不是模型能力问题而是上下文管理没做好。我接触过不少Agent项目从简单的单轮问答到复杂的多工具协作系统真正拉开差距的从来不是提示词写得多花哨而是上下文怎么组织、怎么裁剪、怎么在有限的token预算里塞进最有价值的信息。热词里频繁出现的Agent、OpenCode、Codex、Claude Code这些工具本质上都在解决同一个问题让模型在长任务中保持记得住、想得清、不跑偏。这篇内容适合三类人看一是刚上手Agent开发、被上下文长度折磨过的新手二是已经在用Codex或Claude Code这类工具、想搞懂底层机制的中级开发者三是正在设计多Agent协作架构、需要系统性方案的人。我会从上下文的基本构成讲起拆解几种主流的压缩与检索策略再结合工具链的实际配置给出可复现的操作路径最后聊聊那些文档里不会写的坑。先说一个反直觉的结论上下文管理的核心不是塞更多而是丢得准。很多人第一反应是扩大窗口从8K到128K再到200K但实测下来窗口越大模型对中间段落的注意力反而越涣散这就是所谓的lost in the middle现象。真正有效的做法是动态决定每一轮该保留什么、丢弃什么、压缩什么。2. 上下文窗口里到底装了什么2.1 四层信息结构一个运行中的Agent它的上下文通常由四层信息叠加而成理解这四层是做好管理的前提。第一层是系统指令层包括角色设定、行为约束、输出格式要求。这部分通常固定不变占用token少但优先级最高任何裁剪都不能动它。第二层是对话历史层记录用户与Agent的往返消息这是最容易膨胀的部分也是压缩的主要对象。第三层是工具调用层包含工具定义、调用参数、返回结果其中返回结果往往是token杀手——一次文件读取或网页抓取就可能塞进几千token。第四层是外部检索层通过RAG或记忆库动态注入的相关片段按需加载。这四层的优先级顺序是系统指令 当前任务相关 近期对话 历史对话 外部检索。裁剪时必须从优先级低的开始动否则Agent会忘记自己是谁。2.2 token预算的分配逻辑假设你用的是128K窗口的模型实际可用预算要打个七折因为输出也要占额度而且留出安全边际能避免边界溢出。我通常按这个比例分配层级建议占比说明系统指令5%-10%固定不参与动态调整工具定义10%-15%工具多时可精简描述对话历史30%-40%核心压缩区工具返回20%-30%大结果需截断或摘要检索注入10%-20%按相关性动态调整输出预留10%硬性保留这个比例不是死的任务类型不同要调整。比如代码生成类任务工具返回占比会更高而纯对话类任务历史对话占比更大。关键是心里要有一本账知道当前上下文里哪部分在膨胀。2.3 为什么记得多反而更差这里要解释一个常见误解。很多人觉得上下文越长模型掌握的信息越多表现应该越好。但实测恰恰相反。原因有两个一是注意力稀释Transformer的注意力机制在长序列上会分散关键信息被淹没在噪声里二是冲突信息干扰历史对话里可能包含已经过时的约束比如用户先说用Python后来说改用Go如果两段都保留模型可能被旧信息误导。所以上下文管理的目标不是最大化信息量而是最大化信噪比。每一轮都要问自己这段信息对当前决策还有用吗如果没用果断丢。3. 三种主流压缩策略的取舍3.1 滑动窗口简单但会丢关键信息滑动窗口是最容易实现的策略只保留最近N轮对话超出的直接丢弃。代码大概长这样def sliding_window(messages, max_turns10): system [m for m in messages if m[role] system] dialogue [m for m in messages if m[role] ! system] return system dialogue[-max_turns:]优点是实现简单、token可控。缺点是硬截断会丢失早期关键约束。比如用户在第二轮说了数据库用PostgreSQL到第十五轮时这条信息早被冲掉了Agent可能就用了MySQL。我的改进做法是滑动窗口只作用于普通对话但关键约束单独抽取出来放进系统指令层。具体就是在每轮结束后用一次轻量模型调用判断这轮有没有产生新的持久约束有就追加到系统提示里。这样约束不会随窗口滑动而丢失。3.2 摘要压缩平衡信息与成本摘要压缩是把较早的对话用模型总结成一段简短描述替代原始消息。这样既保留了语义又大幅降低token。def summarize_history(messages, keep_recent5): if len(messages) keep_recent: return messages old messages[:-keep_recent] recent messages[-keep_recent:] summary llm_call( 把以下对话压缩成要点保留关键决策、约束和结论\n format(old) ) return [{role: system, content: f历史摘要{summary}}] recent这里有个坑摘要本身也会丢信息。如果摘要模型不够强或者提示词没写好可能把关键细节压没了。我的经验是摘要提示词里必须明确要求保留数字、名称、约束、未完成事项这四类信息其他可以模糊。另一个坑是摘要的递归问题。如果每轮都摘要摘要的摘要会越来越失真。解决办法是保留原始消息的索引摘要只作为快速索引需要细节时再回查原文。3.3 向量检索按需加载而非全量保留向量检索的思路是把历史消息存进向量库每轮根据当前问题检索最相关的几条注入上下文。这样上下文里只放当前用得上的信息。def retrieve_relevant(query, history_store, top_k3): query_vec embed(query) results history_store.search(query_vec, top_ktop_k) return [r[content] for r in results]这种策略适合长周期、多主题的任务比如一个持续几天的项目助手。但它对检索质量依赖极高检索不准就会注入无关信息反而干扰模型。实测中我发现纯向量检索在对话场景下召回率往往不够最好和关键词检索做混合。三种策略的对比策略token节省信息保留实现复杂度适用场景滑动窗口高低低短任务、约束少摘要压缩中中中通用对话向量检索高高依赖检索高长周期多主题实际项目中我通常三者组合使用近期对话用滑动窗口中期用摘要远期用向量检索按需召回。4. 工具返回结果的特殊处理4.1 工具返回才是真正的token黑洞很多人优化上下文时盯着对话历史却忽略了工具返回。一次read_file可能返回几千行代码一次网页抓取可能塞进上万token。这些内容如果不处理几轮下来窗口就爆了。我的处理原则是工具返回永远不直接进上下文先过一层过滤器。过滤器做三件事截断超长内容、提取关键字段、生成结构化摘要。def process_tool_result(result, max_tokens2000): if count_tokens(result) max_tokens: return result # 超长时提取结构 if is_code(result): return extract_signatures(result) # 只留函数签名和注释 if is_json(result): return extract_key_fields(result) # 只留关键字段 return result[:max_tokens] \n...[已截断]4.2 代码类返回的压缩技巧代码是最占token的内容之一。我的做法是只保留函数签名、类定义和关键注释函数体用省略号代替。Agent需要看具体实现时再用工具按行号读取。def extract_signatures(code): lines code.split(\n) result [] in_function False for line in lines: stripped line.strip() if stripped.startswith((def , class , async def )): result.append(line) in_function True elif in_function and stripped.startswith((, , #)): result.append(line) elif stripped and not line.startswith(( , \t)): in_function False return \n.join(result)这样一份5000行的代码文件压缩后可能只剩200行签名token直接降一个数量级。Agent先看签名了解结构需要细节再按需读取效率高很多。4.3 结构化数据的字段裁剪JSON返回也是重灾区。一个API返回可能包含几十个字段但Agent当前任务只关心其中三五个。我的做法是根据任务类型预设字段白名单只保留白名单内的字段。FIELD_WHITELIST { user_query: [id, name, status], order_query: [order_id, amount, created_at], } def trim_json(data, task_type): fields FIELD_WHITELIST.get(task_type, []) if not fields: return data return {k: v for k, v in data.items() if k in fields}这个白名单要随任务演进动态维护不能一劳永逸。5. 多Agent协作下的上下文隔离5.1 为什么多Agent不能共享上下文单Agent的上下文管理已经够复杂多Agent协作时问题会指数级放大。核心原则是每个Agent只应该看到自己任务相关的上下文而不是全局共享。原因很简单如果所有Agent共享一个大上下文一是token爆炸二是角色污染——负责写代码的Agent看到了测试Agent的报错日志可能被误导负责规划的Agent看到了执行细节可能陷入局部。我见过一个失败案例一个多Agent系统让所有Agent共享完整对话历史结果规划Agent在执行Agent还没跑完时就开始脑补结果整个流程乱套。后来改成每个Agent独立上下文只通过结构化消息传递必要信息才稳定下来。5.2 上下文传递的三种模式多Agent之间传递上下文我总结出三种模式模式一摘要传递。上游Agent把结果压缩成结构化摘要传给下游。适合信息量大的场景比如研究Agent把一堆资料压缩成要点传给写作Agent。模式二引用传递。上游只传一个引用ID下游需要时自己去取。适合大文件、大数据集场景避免重复传输。模式三全量传递。直接传原始上下文适合强依赖场景比如调试Agent需要看完整执行日志。但这种模式要严格控制使用频率。def handoff(from_agent, to_agent, modesummary): if mode summary: payload from_agent.summarize_output() elif mode reference: payload {ref_id: from_agent.store_output()} else: payload from_agent.full_context() to_agent.receive(payload)5.3 共享记忆库的设计多Agent系统通常需要一个共享记忆库但共享不等于全开放。我的设计是分层记忆全局层存项目级约束所有Agent可见角色层存各Agent的专属记忆仅自己可见临时层存当前任务状态任务结束即清。class SharedMemory: def __init__(self): self.global_mem {} self.role_mem {} self.temp_mem {} def get(self, agent_id, key): if key in self.temp_mem: return self.temp_mem[key] if key in self.role_mem.get(agent_id, {}): return self.role_mem[agent_id][key] return self.global_mem.get(key)这样既保证了信息共享又避免了上下文污染。6. 工具链实操从配置到验证6.1 环境准备中最容易忽略的细节不管用的是哪类Agent工具环境准备阶段有几个细节经常被忽略但会直接影响上下文管理的效果。第一是模型窗口参数要显式配置。很多工具默认用模型的最大窗口但实际可用窗口要减去输出预留。我通常把配置里的max_context设成模型标称值的80%留出安全边际。第二是token计数要用对分词器。不同模型的分词器不一样用错分词器会导致预算估算偏差20%以上。配置时要确认工具用的是目标模型对应的分词器。第三是日志要记录每轮的token分布。没有这个数据你根本不知道上下文是怎么膨胀的。我习惯在每轮结束后打印各层级的token占用方便定位问题。def log_context_usage(messages): usage { system: count_tokens([m for m in messages if m[role]system]), history: count_tokens([m for m in messages if m[role]!system]), total: count_tokens(messages), } print(f[上下文] 系统:{usage[system]} 历史:{usage[history]} 总计:{usage[total]})6.2 配置文件的关键字段解析Agent工具的配置文件里和上下文管理相关的字段通常有这几个max_tokens单次请求上限、context_window上下文窗口、compression_threshold触发压缩的阈值、keep_recent保留最近几轮。我的配置经验是compression_threshold设成窗口的70%keep_recent设成5到8轮。阈值太低会频繁压缩增加延迟太高则可能溢出。keep_recent太少会丢近期上下文太多则压缩效果不明显。{ context_window: 100000, max_tokens: 8000, compression_threshold: 70000, keep_recent: 6, tool_result_max: 2000 }6.3 跑通之后的验证方法配置好之后怎么验证上下文管理是否生效我通常做三个测试测试一长任务约束保持。让Agent执行一个20步以上的任务中途插入一个约束比如所有输出用中文看最后几步是否还遵守。如果遵守说明约束抽取机制有效。测试二token增长曲线。跑一个长对话记录每轮的token占用。健康的曲线应该是锯齿状——增长到阈值后被压缩降下来而不是单调递增直到溢出。测试三关键信息召回。在早期对话里埋一个关键信息几十轮后提问相关内容看Agent能否正确回忆。这测试的是检索和摘要机制。这三个测试跑下来基本能定位上下文管理的薄弱环节。7. 那些文档里不会写的坑7.1 摘要模型的幻觉压缩用模型做摘要时它可能会编造原文没有的内容。我遇到过摘要里出现用户要求使用Redis但原文根本没提Redis的情况。这种幻觉在压缩比高的时候尤其明显。对策是摘要提示词里加一句只压缩原文出现的信息不要推断或补充并且在摘要后附上原文的消息ID方便核查。关键决策类信息我宁可多留原文也不完全依赖摘要。7.2 工具返回的时序错乱多工具并行调用时返回顺序可能和调用顺序不一致。如果上下文里按返回顺序排列Agent可能把结果对应错。我的做法是给每次工具调用分配唯一ID返回结果里带上ID上下文里按ID排序而非按到达顺序。def merge_tool_results(calls, results): result_map {r[call_id]: r for r in results} return [result_map[c[id]] for c in calls if c[id] in result_map]7.3 压缩触发时机的选择压缩什么时候触发很讲究。在工具调用中间触发压缩可能把正在进行的任务状态压没了。我的经验是只在轮次边界触发压缩即一次完整的用户输入-模型响应-工具执行循环结束后再判断是否压缩。这样不会打断任务流。7.4 系统指令被意外覆盖有些实现里压缩逻辑会把系统指令也当成普通消息处理导致角色设定丢失。这是低级但常见的bug。防护措施是在压缩函数入口就把系统消息单独拎出来压缩只作用于非系统消息。def safe_compress(messages): system [m for m in messages if m[role] system] others [m for m in messages if m[role] ! system] compressed compress(others) return system compressed7.5 多语言混合的token估算偏差中英文混合时token估算容易偏。中文一个字可能占1到2个token英文一个词可能占1到3个。如果按字符数估算误差会很大。必须用实际分词器计数不能拍脑袋。我在实际项目里踩过最深的坑是早期用字符数除以4来估算token结果中文场景下严重低估导致频繁溢出。换成真实分词器后预算才准了。8. 从单轮到长周期上下文管理的演进思路刚开始做Agent时大家往往只关注单轮对话能不能答对。但随着任务变长上下文管理的重要性会逐渐超过提示词工程。我的体会是一个Agent系统的上限很大程度上由上下文管理决定。演进路径大致是这样起步阶段用滑动窗口就够了简单直接任务变长后引入摘要压缩平衡信息与成本再往后加向量检索支持跨会话记忆多Agent协作时做上下文隔离和分层记忆。每一步都是被实际需求推着走的不用一上来就上全套。有个容易被忽略的点上下文管理策略要可观测、可回滚。每次压缩前后都记录token数和关键信息出问题时能对比。我见过团队改了压缩策略后Agent表现下降但因为没留日志排查了两天才找到原因。最后分享一个实用技巧给上下文里的每条消息打上时间戳和来源标签压缩时优先保留近期和高优先级来源的消息。这个小改动能让压缩决策更合理实现成本却很低。上下文管理没有银弹核心是理解你的任务特征然后针对性设计。任务短就简单点任务长就精细点多Agent就隔离好。把token预算当成稀缺资源来经营Agent的稳定性会有肉眼可见的提升。
延伸阅读

更多相关文章

2026/10/26 20:20:53

PIVOTOPD:让多轮智能体学会从关键失误中自我恢复

最近在做多轮智能体相关的项目,说实话最头疼的不是模型笨,而是它一旦在中间某一步判断错了,后面所有轮次全跟着歪,用户重新纠正好几遍它也回不到正轨,整个对话直接报废。这种“犯错就废”的困境,相信每个做…

2026/10/26 20:20:53

GPU算力租赁指南:H100、A100、昇腾等选型与对接验证

1. 从"找卡"这件事说起:为什么租算力比买卡更考验判断力做AI这行的朋友大概都有过这种体验:模型代码写完了,数据集也清洗好了,结果卡在最后一步——没有卡跑。自己攒机器吧,一张高端卡的价格够养一个小团队半…

2026/10/26 20:20:53

单像素成像Matlab算法选型:CG、OMP、TV与FISTA对比避坑

简介:面向单像素成像与压缩感知重建学习者的Matlab算法对照包,聚焦在同一实验框架下比较不同SPI重建思路的表现,适合需要理解算法差异、复现实验或做课程与科研验证的本科生、研究生及工程人员。包内共10个文件,以9个.m函数脚本和…

2026/10/26 21:11:37

深入解析处理器体系结构与流水线优化技术

1. 为什么需要深入理解处理器体系结构在计算机科学领域,处理器体系结构就像是一栋建筑的地基和骨架。很多程序员在编写代码时,往往只关注高级语言的语法特性和算法实现,却对代码如何在硬件层面执行知之甚少。这就好比一个厨师只懂得菜谱&…

2026/10/26 21:11:37

AI漫剧:多模态模型如何重塑动态漫生产与变现逻辑

你刷短视频的时候,不知道有没有注意到一个现象:最近半年,那种画面精致、剧情紧凑、几秒一个反转的竖屏漫剧突然变多了。它们不是传统意义上的2D动画,也不是真人短剧,而是介于漫画和动画之间的一种新形态——人物动态自…

2026/10/26 21:11:37

VS2005环境下LZO压缩算法实战集成方案

简介:本资源是一份面向C/C初学者与嵌入式开发者的LZO轻量级压缩算法实践工程,聚焦于在Visual Studio 2005环境下完成压缩/解压缩功能的完整实现与调试验证。资源包含17个文件,涵盖核心源码(minilzo.c/h、testmini.c)、…

2026/10/26 21:11:37

NeuroNCAP闭环评测框架拆解:从场景生成到评分落地的工程实践

1. 拆解 NeuroNCAP:一个评测框架的骨架与野心第一次看到 NeuroNCAP 这个名字,我脑子里蹦出来的第一反应是:这大概率是个把“神经网络”和“碰撞测试评分”两件事捏在一起的评测框架。后来翻了一圈资料,确认了这个判断——它本质上…

2026/10/26 21:06:35

关系代数与SQL的转换及查询优化实践

1. 关系代数与SQL的桥梁作用 关系代数和SQL就像数据库领域的两种语言——前者是严谨的数学表达,后者是工程实践中的通用工具。我在实际数据库开发中经常遇到这样的场景:当需要优化一个复杂查询时,先用关系代数理清逻辑关系,再转化…

2026/10/26 0:20:20

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/26 1:53:47

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/26 0:20:17

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/26 0:00:48

Nested Learning:解决AI灾难性遗忘的分层记忆架构

1. 为什么AI需要"记忆"能力?在传统深度学习模型中,我们常遇到一个根本性问题:模型在处理新任务时,往往会完全遗忘之前学到的知识。这种现象被业界称为"灾难性遗忘"(Catastrophic Forgetting)。想象一下&#…

2026/10/26 0:00:48

企业级大模型应用:OCR预处理、Dify编排与DeepSeek落地实战

1. 这不是“用大模型”,而是重构工作流的起点“大模型的应用和工具”——这八个字现在被贴在无数技术分享、招聘JD、内部立项书的标题栏里,但绝大多数人点进去后看到的,是零散的API调用示例、几个开源UI截图、或者一句“接入LLM就能降本增效”…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑