14-Context 上下文管理:支撑长期任务的机制

系列第 14 篇 · 生产篇

上篇讲 Workspace 让 Agent "身份持久"。但有个隐含前提:上下文不能无限膨胀。

模型上下文窗口是有限的。一个跑几小时、累积几十轮工具调用的 Agent,迟早撞上 context_length_exceeded。大多数框架的做法是粗暴截断文本------结果 Agent "失忆",长任务崩掉。

2.0 提供了一套四层上下文工程策略,目标不是"塞下更多",而是"保住关键信息、丢掉噪声"。


一、四层策略总览

sql 复制代码
flowchart TD
    A[长会话] --> B{上下文太深?消息数/ token 堆积}
    B -->|是| C[① 结构化压缩CompactionMiddleware]
    C --> D{单条工具结果超大?}
    D -->|是| E[② 大结果卸载ToolResultEvictionMiddleware]
    E --> F{模型返回context_length_exceeded?}
    F -->|是| G[③ 溢出兜底recoverFromOverflow 强制压缩重试]
    G --> H[继续执行]
    A --> I[④ 参数截断TruncateArgsConfig压缩前的轻量预处理]
    I --> C

四者相互独立、可自由组合,且都默认关闭。下面逐个讲解。


二、1 结构化压缩(CompactionMiddleware)

触发条件:消息数或估计 token 数超阈值。一次 LLM 调用把对话前缀蒸馏成结构化摘要,保留最近 N 条原文,把 摘要 + 最近尾部 写回 AgentState。

java 复制代码
HarnessAgent agent = HarnessAgent.builder()
    .name("long-task-agent")
    .model("dashscope:qwen-max")
    .workspace(Path.of(".agentscope/workspace"))
    .compaction(CompactionConfig.builder()
        .triggerMessages(30)     // 消息数到 30 触发
        .keepMessages(10)        // 保留最近 10 条原文
        // .triggerTokens(8000)   // 也可按 token 触发
        // .keepTokens(2000)
        // .model("dashscope:qwen-plus")  // 压缩用独立小模型省成本,不填则用主模型
        .build())
    .build();

摘要默认按SESSION INTENT / SUMMARY / ARTIFACTS / NEXT STEPS四节组织------特别适合工程/编排类 Agent,保住"目标、状态、结论、下一步",丢掉闲聊与中间推理噪声。

与记忆协同:flushBeforeCompact(默认 true)会在压缩前,把对话前缀里的事实抽取进 MEMORY.md(由 MemoryFlushMiddleware 执行);offloadBeforeCompact(默认 true)会把原始消息写进未压缩的 *.log.jsonl。这样即使前缀被摘要掉,信息仍在------Agent 之后还能 memory_search 找回。


三、2 大工具结果卸载(ToolResultEvictionMiddleware)

和摘要压缩独立。某条工具结果文本超过阈值(默认80K 字符 ≈ 20K tokens),框架把全文写进 Workspace 目录,上下文里只留首尾各约 2K 字符 + 一个read_file路径指针,Agent 想看全文就自己 read_file。

java 复制代码
HarnessAgent agent = HarnessAgent.builder()
    .name("log-analyzer")
    .model("dashscope:qwen-max")
    .workspace(Path.of(".agentscope/workspace"))
    .toolResultEviction(ToolResultEvictionConfig.defaults())  // 一行开启
    .build();

默认排除 read_file/write_file/edit_file/grep_files/glob_files/list_files/memory_*/session_search------它们要么自带分页、要么返回值很小。shell执行默认不排除,因为命令输出可能极大。


四、3 溢出兜底(Overflow Safety Net)

如果模型真的返回 context_length_exceeded / maximum context / token limit 等错误,HarnessAgent.recoverFromOverflow() 会强制走一次 triggerMessages=1 的极端压缩,自动重试一次。

javascript 复制代码
// 前提:构造时就配了 .compaction(...)
// 溢出时框架自动 recoverFromOverflow() + 重试,无需你写代码
HarnessAgent.builder()
    .compaction(CompactionConfig.builder().triggerMessages(30).build())
    .build();
// 只要开了 compaction,溢出恢复自动生效;
// 没开 compaction,错误会原样抛出

这条兜底无需额外配置:只要 compaction 开了,溢出恢复就跟着开。但没开 compaction,错误就直接抛给你------所以长任务务必开 .compaction(...)。


五、4 参数截断(TruncateArgsConfig)

在 LLM 摘要之前,先做一次零成本的字符串截断,裁掉过大的工具调用参数(如 write_file/edit_file 的大段 body):

javascript 复制代码
CompactionConfig.builder()
    .triggerMessages(80)
    .truncateArgs(CompactionConfig.TruncateArgsConfig.builder()
        .maxArgLength(2000)                  // 参数超 2000 字符截断
        .truncationText("... [truncated] ...")
        .build())
    .build();

很多负载中,光这一步就能大幅推迟摘要触发,且成本近乎为零。


六、压缩"碰不到"的东西

ConversationCompactor 只操作 AgentState.contextMutable() 的对话消息列表。以下活在 AgentState 的其他字段,摘要不触碰:

  • Plan Mode 状态:是否激活、当前计划文件路径(计划文件本身在 workspace/plans/,由 Plan Mode 自己管理,呼应6)。

  • 子 Agent 后台任务:结果存在 workspace/agents//tasks/.json,通过 system-reminder 回推给父 Agent,不进对话流。

  • todo 任务清单(tasksContext):独立字段,随 AgentState 持久化但不走压缩。

如此就能保证压缩不会"误删"你的计划、后台任务或待办------设计上实现了隔离。


七、新手最常踩的 6 个坑

  1. 长任务没开 compaction:上下文迟早溢出,且因为没开,溢出兜底不生效,错误直接抛。

  2. 以为压缩会丢计划/任务:不会,它们在不同字段,摘要碰不到。

  3. keepMessages 设太小:保留的近期原文太少,压缩后 Agent 忘了"刚说了什么",对话连贯性下降。

  4. 大结果卸载后 Agent 不读全文:它只拿到首尾预览 + read_file 指针,需要 prompt 里引导它"必要时 read_file 看完整结果"。

  5. 用主模型做压缩烧钱:长会话频繁压缩,建议 .model(...) 指定一个小模型专门干摘要。

  6. 关掉 flushBeforeCompact 又指望记忆:关了就不会把事实写进 MEMORY.md,压缩后信息可能真丢了。


小结

  • 2.0 上下文工程四层:结构化压缩 / 大结果卸载 / 溢出兜底 / 参数截断,全部默认关闭、可组合。

  • 压缩保留 SESSION INTENT / SUMMARY / ARTIFACTS / NEXT STEPS,与记忆(MEMORY.md)协同不丢信息。

  • 大结果卸载:超 80K 字符写文件、上下文留首尾预览。

  • 溢出兜底的前提是开了 compaction------长任务必开。

  • 计划、后台任务、todo 不进压缩路径,安全。

上下文稳了,但 Agent 越自主,越需要"边界":它能删文件吗?能改订单吗?模型挂了怎么办?跑起来怎么观测?下一篇内容 权限 / 容错 / 可观测性将讲解权限三态决策、FallbackModel 主备切换、OpenTelemetry + 28 种类型化事件流,把 Agent "管得住、稳得住、看得清"。


如果这篇文章对你有帮助,欢迎关注公众号「栈知见」,我会持续输出有深度的技术实战笔记

相关推荐
Topskys1 小时前
DeepSeek 稀疏注意力
agent
小七-七牛开发者1 小时前
多 Agent 架构中的 Subagent 拆分与合并策略
agent·multiagent·subagent·agent架构·harness #工程实践
努力变大白1 小时前
ReAct Agent 创建:tools 协议与文本 ReAct 双路线实践
python·agent·react框架
jerrywus1 小时前
DeepSeek Harness 和 Pi Agent 怎么选?先想想你愿意折腾什么
前端·agent·deepseek
武子康1 小时前
HunyuanVideo-1.5 跑得更快,先减步数还是开缓存?
人工智能·后端·agent
货拉拉技术1 小时前
一句话叫车:货拉拉小程序 AI 叫车实战
前端·agent·ai编程
thusloop1 小时前
零门槛接入 GPT-6-astra 与 claude-opus-5-5,三大场景实战指南
python·gpt·算法·agent·claude·codex
不是株1 小时前
Agent 评测体系:三层分类与一条流程
agent
前端双越老师1 小时前
程序员 1v1 访谈系列第八期:大龄女程序员的困境
agent·ai编程·全栈