跳转至

上下文压缩与 Spill 外溢

生产级 Agent 的生命线:如何优雅处理超长上下文与巨型工具输出。

在真实编程场景中,Agent 经常会遇到几万行的日志、超大 JSON 响应或多达几十轮的深度对话。如果缺乏严谨的上下文控制,大模型不仅会触发上下文超限报错(Context Window Exceeded),还会产生高昂的 Token 账单。

DSH 打造了 Compaction(智能压缩)Spill(文件外溢) 双重防线。


核心文件速查

路径 职责 重要度
packages/compaction/compaction/src/index.ts 上下文压缩服务定义与策略 ⭐⭐⭐
packages/compaction/compaction-basic/ 基于 LLM 的滑动窗口摘要压缩器 ⭐⭐⭐
packages/spill/spill/src/index.ts Spill 巨型输出截流外溢服务 ⭐⭐⭐
packages/spill/spill-local/ 本地 Spill 文件落盘与读取引用 ⭐⭐

1. Spill 机制:巨型工具输出外溢截流

当 Agent 调用 bash 运行 npm test 或读取一个大文件时,输出可能高达数万行(例如 1MB)。

如果直接将这 1MB 原始文本喂给大模型: 1. 立即吃掉大部分上下文窗口; 2. 模型无法有效聚焦关键错误信息。

Tool Output (e.g. 500 KB raw text)
             │
             ▼
   [Is length > threshold?]
             │
      ┌──────┴──────┐
      │ YES         │ NO
      ▼             ▼
┌──────────────┐ ┌──────────────┐
│ Spill Engine │ │ Pass-through │
└──────┬───────┘ └──────────────┘
       │
       ├──► 1. 将完整 500 KB 写入 .dsh/spills/spill-xxx.txt
       │
       └──► 2. 生成紧凑的截流文本与头部/尾部预览:
            "Showing lines 1-100 of 2500 lines.
             Full output saved to .dsh/spills/spill-xxx.txt
             [Use offset=101 to continue]"

大模型收到这段紧凑输出后,既能看到关键的头部/尾部信息,又明确知道完整文件在何处,可以在需要时精准按行读取(read(offset, limit)),而不是盲目接收整个巨无霸 payload。


2. Compaction 机制:滑动窗口与智能摘要

当会话事件累积达到 Token 安全阈值(例如占用窗口 80%)时,ctx.compaction 会被触发: 1. 保留核心锚点:系统提示词、用户初始目标、最近几轮对话与关键未完结的工具上下文; 2. 生成结构化摘要:调用轻量模型将中间经过的几十轮繁琐探索压缩为一份精简的 Markdown 摘要; 3. 记录 session/compacted 会话事件; 4. 之后的 deriveMessages() 投影函数会自动将压缩事件之前的内容折叠,使上下文占用量瞬间下降 70%~90%。


本章思考与自测

  1. 思考题:为什么工具输出外溢(Spill)必须在 tools/post-execute 阶段由框架统一处理,而不是让每个工具自己去实现截流?
  2. 自测题:在发生 Compaction(上下文压缩)后,用户如果刷新前端 Web 界面,前端会丢失压缩前的那些历史气泡吗?为什么?