最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Agent 上下文空间告急:长对话任务该如何处理?
时间:2026-09-15 11:48:01 编辑:袖梨 来源:一聚教程网
随着开发任务持续推进,智能体需要记住的需求、代码和工具结果会不断累积。当上下文窗口接近上限时,早期关键信息容易被噪声覆盖,模型也可能出现判断失准和仓促收尾。要改善这种现象,重点并非立即训练新模型,而是重新设计信息如何进入、保留、压缩与取回。
当你在跟Agent不停地探讨开发你的项目时,刚开始可能觉得它真是太懂我了,你说出一个需求,它三两下就完美地帮你做出来。但是当对话持续地进行下去后,可能到50轮对话后,你让它修一个bug,结果它不停地改不停地错,甚至做出一些莫名其妙的行为,这时候你就要知道——它的上下文空间不够了!LLM在得知上下文空间不足时,会感到非常焦虑,这时它会一直想赶紧仓促对任务进行结尾,这会导致它的误判行为。那么你又觉得,这个Agent怎么这么蠢,我要你何用!
为了延长这次对话寿命,那就绕不开Agent的一大核心:Context Engineering——上下文工程。本文我们就来聊聊上下文工程的实现。
一、先避开两个坑
做 Agent 遇到效果不好,很多人的第一反应是这两条路:
- "Agent 不够聪明,我训一个自己的模型" —— 走 Fine-tuning 或 post-training
- "等产品稳定了,我用 RL 优化 Agent 的行为"
这两个坑的共同点是:都在试图改模型。但绝大多数场景下,你该改的是上下文。
二、上下文工程的五个维度
Context Engineering 的手段可以归成五类,每一类对应一个不同的问题:
- Offload(卸载) —— 上下文太挤 → 把信息搬到上下文之外(文件、数据库)
- Reduce(压缩) —— 上下文太长 → 压缩成更短的形式(摘要、向量化)
- Retrieve(检索) —— 需要的信息不在上下文里 → 从外部源检索(RAG、文件读取)
- Isolate(隔离) —— 一个上下文装不下所有的事 → 拆成多个独立上下文(Multi-Agent)
- Cache(缓存) —— 重复计算 → 复用已有的计算结果(KV Cache、Prompt Cache)
遇到问题先判断属于哪一类,再挑手段,比一上来就调 prompt 有效得多。
遇到多个问题同时存在时,它们之间还有优先级:
Offload > Cache > Reduce(先紧凑化,实在不行再摘要化)> Isolate > Retrieve
下面按「先卸载、再瘦身、最后按需取回」的思路逐个说。
三、Offload:上下文窗口是昂贵的
卸载的核心思路一句话:
上下文窗口是昂贵的,但是文件系统是廉价的。
能搬到文件里、数据库里的,就别堆在上下文里。这引出了两种截然不同的加载策略:
- 全量预填充:不管三七二十一,把 Agent 循环过程中拿到的所有信息全塞进上下文
- JIT(Just-In-Time)按需加载:不提前塞,等 Agent 真正需要某段信息时再填充
JIT 有三种落地方式:RAG、Agentic Search(运行时用工具探索)、Context Offloading(主动卸载 + 按需恢复)。
举个例子:让你排查"登录后每次都跳首页"这个 bug。
一上来就把整个项目读一遍,是最贵的做法。更聪明的做法是按成本递增排序工具调用——先用最便宜的工具,再用稍贵的,最后用最贵的拿细节:
- Glob:按文件名模式搜索,只返回路径,不读内容
- Grep:按内容模式搜索,返回命中的行
- Read:读最终定位到的那几个文件
先用便宜的工具把范围缩小,再用贵的工具拿细节。这就是 Agentic Search(运行时工具探索)——"按需加载"在实践中的样子。
记忆系统本质上也是一种卸载——把跨会话的信息搬到文件或数据库里,用的时候再捞回来。这也是为什么 Agent 需要记忆:上下文窗口就像网吧的电脑,你一下机,系统就重置了,第二天再打开,什么都没了。
四、Reduce:三层压缩,先轻后重
不管你的 prompt 管理做得多好,Agent 跑完 50 轮,prompt 长度大概率会爆。
Claude Code 的思路是:先试轻手段,不行再试重手段。
- Microcompact(紧凑化):不删消息、不破坏对话结构,只是把老旧的工具结果缩小。第 3 轮读了个文件拿到 3000 token,到第 30 轮模型早就不需要它了,就替换成一句
[Old tool result content cleared] - Snip(裁切):直接砍掉老消息,从历史记录头部开始删,被删的就永久丢失
- Auto-compact(摘要化):用 LLM 生成摘要。信息缺失最多,但 token 回收也最多
触发阈值是 effectiveContextWindow - 13k。
Auto-compact 的摘要不是随便写的,它是一套严格的 9 段结构:用户意图、技术概念、文件改动、错误修复、问题解决、用户消息、待办任务、当前工作、下一步。
压缩完还有关键一步:把最近读过的 5 个文件内容附回去。否则模型知道"要去改 auth.ts",却不知道 auth.ts 长什么样。
五、Cache:三个层次,一条分界线
缓存分三层,可控程度不同:
- KV Cache:模型推理层,不受我们管控
- Prompt Cache:API 层,开发者可控。在 system prompt 上打个缓存断点,几千 token 的规则就不用每轮重算
- Context Collapse(上下文折叠):与其把老消息删掉,不如折叠起来——老消息存进外部存储,上下文里只留一个折叠标记
Prompt Cache 有个很实用的设计推论:system prompt 在静态和动态之间有一条分界线。
const systemPrompt = [
// ---- 静态部分:全局可缓存,所有用户共享 ----
identitySection(), // "你是 XX,负责 YY"
systemRulesSection(), // 环境约束
taskGuidelines(), // 做事方式
riskGuidelines(), // 行动准则
toolUsageGuide(tools), // 工具指南
outputStyle(), // 输出风格
// ======== 分界线 ========
// ---- 动态部分:每会话不同 ----
envInfo(cwd, gitStatus), // 工作目录、Git 状态
userConfig(claudeMd), // 用户自定义规则
memoryContext(memories), // Memory 内容
]
分界线以上的内容所有用户共享,能命中全局缓存;以下每会话都变。把 prompt 按这条线切开、拆成独立模块,缓存友好度和可维护性都会好很多——改输出风格时,不会碰到身份和规则。
还有个细节:高频变化的信息别写进 system prompt,注入到对话消息里。比如当前打开的文件、今天的日期,这些每轮都变,写进 system prompt 就等于每轮都把缓存打穿。
六、Isolate:多 Agent 的两种隔离
一个上下文装不下所有事的时候,就拆成多个。
- By communication(消息传递):主 Agent 给子 Agent 发消息,子 Agent 处理完返回结果。对主 Agent 来说,上下文里只多了「发出去的消息 + 收回来的结果」,它不需要知道子 Agent 的内部状态和处理细节
- By sharing context(上下文共享):子 Agent 直接复制主 Agent 当前的上下文,在此基础上继续处理。对主 Agent 来说只多了一个结果,但子 Agent 的 token 消耗会大得多,因为它要复制一份完整的上下文
七、Retrieve:RAG 的上限在数据,不在模型
最后说检索。RAG 的管线是六步:
文档加载 → 数据分块 → Embedding → 向量储存 → 检索 → 注入上下文
流程不复杂,但每一步都会翻车:
- 文档加载:Markdown 最友好;PDF 最头疼,纯文本提取会丢掉表格和标题;代码不能按字符硬切——把一个函数从中间切开,两个 chunk 都会变得没意义
- 数据分块:固定大小硬切最糙;递归分块(先段落、再句子、最后 token)准确率最高
- 检索:语义相似不等于任务相关。所以要用混合检索(向量 + 关键词)兜底
还有个常见现象:搜出来 6 条,5 条都在说同一件事。这时候要上 MMR 去重。
记住这句话:
开卷考试,翻书也可能找不到答案。数据质量决定了 RAG 的效果,而不是模型聪不聪明。
八、总结
用一条线串起来:
- 别急着训模型 → 效果不好先看看是不是上下文没喂对
- 五个维度 → 卸载、压缩、检索、隔离、缓存,对应五类问题
- 优先级 → Offload > Cache > Reduce > Isolate > Retrieve
- 加载策略 → 全量预填充 vs JIT 按需加载,按成本递增调工具
- 压缩 → Microcompact → Snip → Auto-compact,先轻后重
- 缓存 → 把 prompt 按静态/动态切开,让静态部分稳定命中缓存
Agent Loop 是心跳,Tool System 是手脚,而 Context Engineering 是它的记忆和注意力——决定了它能跑多远,也决定了它跑到最后还记不记得自己要去哪。