DeepSeek Harness(简称 DSH) 是 DeepSeek AI 于 2026 年开源的智能体运行框架(Agent Harness)。在长周期的多轮工程任务中,会话的上下文预算主要由三层机制协同控制:Spill 负责将单次超大的工具输出落盘,Compaction 负责将较早的历史对话压缩为摘要,而 统计视图(ui-stats) 则用于实时观测上下文体积、KV Cache 命中率与各阶段耗时。

本文基于 0.2.2-rc.1(2026-11-04 发布)官方规范,系统拆解底层模型 API 的接入配置、三大上下文机制的触发阈值与缓存影响,并提供一套遵循 “先量化、再落盘(Spill)、最后压缩(Compact)” 的标准化排查流程。


一、 核心结论:长会话治理不是简单的“一键压缩”

在 0.2.2-rc.1 版本的默认基础配置中,dsh 已经默认挂载了 compaction-basic、command-compact、spill-local 和 spill-policy 四个核心组件。唯一的例外是 统计视图(ui-stats),它作为实验性开发者工具,默认处于未挂载状态。

因此,绝大多数生产或本地部署无需额外寻找第三方“上下文管理插件”,核心工作在于理清内置的 三种主机制、一个前置修剪器与一个只读观测视图 的分工边界:

机制组件 触发条件 核心执行动作 是否调用大模型 对 KV Cache 的影响
Spill(落盘) 单条工具返回结果超过 maxInlineTokens 仅在上下文内保留首尾片段,完整输出写入本地磁盘并返回可检索路径 否 友好(追加式写入,不破坏前缀缓存)
Pruner(修剪器) 达到压缩阈值后,单条文本超过 8,192 字符 保留头部 4,096 字符与尾部 1,024 字符,中间部分直接截断 否 局部失效(修改历史消息内容)
Compaction(压缩) 触发上下文压力阈值、窗口溢出或手动执行 /compact 将较早的完整对话轮次替换为一条结构化摘要消息 是(发起一次独立摘要请求) 部分失效(从首个被替换 Token 起缓存失效)
统计视图(ui-stats) 在 Web 界面开启“统计”页签或显式挂载插件 按轮次与步骤只读展示 Token 消耗、缓存命中率与延迟分布 否 无影响(纯客户端观测,不改变模型输入)

核心原则: Spill 解决“单次工具输出过大”,Pruner 解决“压缩前的粗粒度瘦身”,Compaction 解决“多轮历史累积过长”,统计视图 解决“动手调参前的瓶颈定位”。


二、 前置基础:DeepSeek Harness 大模型 API 接入配置

上下文预算的计算公式(如窗口上限 $W$、输出预留 $O$)以及 Compaction 摘要请求的响应速度,直接取决于底层接入的大模型服务。在调整预算参数前,需先在配置文件中完成模型端点的挂载。目前主流的接入方式分为 官方订阅直连 与 国内托管中转网关接入 两种路径。

1. 官方 API 订阅直连

如果运行环境具备稳定的国际或专线网络,且工作流仅依赖单一厂商模型,可直接配置官方 API 端点:

models:
  - id: primary-agent-model
    provider: openai-compatible
    config:
      baseURL: https://api.deepseek.com/v1
      apiKey: ${DEEPSEEK_API_KEY}
      model: deepseek-chat
      contextWindow: 1000000
      maxOutputTokens: 65536

2. 国内托管中转网关接入(以 4SAPI 为例)

在实际工程落地中,Agent 往往需要高频发起工具调用与长文本摘要请求。若团队处于国内网络环境,或希望在主任务模型与低成本摘要模型之间灵活切换,可将 baseURL 替换为支持标准 OpenAI 协议的国内托管中转站(例如 4SAPI):

models:
  - id: primary-agent-model
    provider: openai-compatible
    config:
      baseURL: https://4sapi.com/v1
      apiKey: ${FOUR_S_API_KEY}
      model: deepseek-v4
      contextWindow: 1000000
      maxOutputTokens: 65536

在 DeepSeek Harness 中采用此类托管网关的核心工程优势主要体现在三点:


三、 Compaction 机制:用摘要置换早期历史(非无损操作)

Compaction 的核心逻辑是:将会话中最旧的一段平衡对话范围(Balanced Range)合并替换成一条摘要消息,同时逐字保留近期的对话轮次,使智能体基于“摘要 + 近期原文”继续推进任务。

需要注意的是,Compaction 不会缩减系统提示词(System Prompt)、工具定义(Tool Schema)或固定会话前缀,也无法拆分单条不可分割的超大工具调用。

触发阈值与默认参数计算

Compaction 的默认自动触发阈值遵循以下公式:

$$\text{Trigger Threshold} = \lfloor \min(W \times \text{thresholdRatio}, W - O - \text{headroomTokens}) \rfloor$$

其中:

计算示例: 假设接入模型的上下文窗口 $W = 1,000,000$,单次输出预留 $O = 256,000$,默认触发阈值约为 678,464 Token;而近期逐字保留预算(按 $(W - O) \times 16%$ 计算)约为 119,040 Token。

对于常规代码开发或日常排障任务,等到 67 万 Token 再压缩通常偏晚,不仅单次推理成本高,且响应延迟明显。建议根据实际业务场景主动收紧配置:

- id: compaction-basic
  config:
    thresholdRatio: 0.7
    headroomTokens: 4096
    maxTokens: 4096
    retainTokens: 2048

配置注意事项:

  1. retainRatio 与 retainTokens 属于互斥参数,不可同时声明。
  2. 保留预算(Retain Budget)必须严格小于触发阈值,否则插件在初始化加载时会直接拒绝启动。
  3. 若设置 auto: false,系统将关闭自动压缩,仅保留 /compact 手动触发入口。
  4. 上述 YAML 会整条覆盖同 id 的默认配置;若当前 Profile 中已存在 compaction-basic,请直接合并字段,切勿重复声明两个同名块。

Compaction 的三个工程边界


四、 Spill 与 Pruner:优先拦截单条超大输出

1. Spill:大结果落盘与按需检索

当智能体执行 bash、grep 或网页抓取工具,一次性返回数万行构建日志、整页 HTML 或巨型 JSON 时,直接内联进上下文会瞬间击穿预算。Spill 正是为此类场景设计的无损卸载机制。

在默认基础配置中,spill-policy 的 maxInlineTokens 阈值为 12,500。一旦单次工具输出超标,模型在上下文中看到的将是:按原顺序保留的首尾片段、中间省略提示,以及完整结果在本地磁盘的存储路径。随后,模型可通过 read 工具(配合 offset / limit 参数)或 grep 工具对该文件进行按需精读。

Spill 的四大核心特性:

  1. 零模型调用: 纯本地 I/O 截断与路径注入,不消耗任何模型 Token 与推理时间。
  2. 数据完整无损: 全量文本写入本地磁盘,可读可搜;图像等二进制内容则按附件路径记录。
  3. 优雅降级(Best-Effort): 若磁盘满载或写入权限异常,系统会自动退回保留原始内联结果,绝不会将一次成功的工具调用转换为报错。
  4. KV Cache 极其友好: 采用追加式替换策略,新生成的文件路径位于已有可复用前缀之后,不会破坏历史 KV Cache。

自定义存储路径与清理策略: 默认情况下,本地后端会将文件写入私有临时目录,并按 sha256(sessionId) 生成子目录进行会话隔离,文件权限锁定为 0600。在生产服务器或云主机(如挂载了独立数据盘的云实例)上运行时,建议通过以下配置将 root 指向独立数据盘,防止 Spill 文件撑爆系统盘:

- id: spill-local
  config:
    root: /var/lib/dsh/spill
    cleanupPeriodDays: 30
- id: spill-policy
  config:
    maxInlineTokens: 12500

提示: root 强烈建议使用绝对路径(相对路径会基于进程当前工作目录解析)。cleanupPeriodDays 默认为 30 天,但过期清理仅在进程启动时扫描一次;对于长期不重启的守护进程,需配合外部定时任务(如 Cron)定期巡检磁盘空间。

2. Pruner:压缩触发后的前置修剪闸门

dsh-compaction-tool-result-pruner 经常被误认为是与 Spill 并列的日常截断工具,但实际上它是 Compaction 的前置步骤。


五、 统计视图(ui-stats):先量化观测,再动手调参

在盲目修改 maxInlineTokens 或频繁敲击 /compact 之前,最高效的做法是先打开统计视图看清预算账单。该视图按每一轮对话(Turn)和每一个执行步骤(Step),直观呈现上下文体积、输出 Token 数、KV Cache 命中率、首 Token 延迟(TTFT)、模型与工具耗时占比以及生成速率。

启用方式

  1. Web 界面启用: 进入“插件”管理页面,在“实验性插件”旁点击“更多”,勾选启用 “开发者工具”。
  2. 配置文件显式挂载:
- id: ui-stats
  name: '@deepseek-ai/dsh-experimental-client-ui-stats'

安全与性能提醒: 统计视图属于实验性功能。启用“开发者工具”会同步拉起本地调试后端,并开启未脱敏的 Host fetch 请求采集。因此,不建议在多人共享或生产环境的 Profile 中长期开启,仅在排查性能与预算瓶颈时按需挂载。

核心指标判读指南

(注:统计页签中的“总用时”为模型耗时与工具耗时的算术累加,并非实际墙钟时间 Wall-clock Time;当存在并行工具调用时,累加耗时条会显得偏长,因此该指标适合做纵向趋势对比,不宜作为严格的 SLA 计时依据。)


六、 场景决策矩阵与标准化排查流程

面对不同表现的会话膨胀或卡顿,可直接参照下表选择干预手段:

观测到的现场症状 优先处理动作 工程原因解析
单次工具返回数万行日志,上下文瞬间跳高 依赖 Spill;若仍偏大则调低 maxInlineTokens 零模型调用开销,既保护上下文窗口,又保留完整文件供模型检索
对话轮次极多,上下文平缓逼近上限,但当前任务未完结 自动 Compaction 或手动执行 /compact 将早期探索过程浓缩为摘要,腾出空间保障近期上下文的逐字精度
当前功能开发或排障已彻底结束,准备切换新课题 直接开启新会话(New Session) 成本最低、最彻底的预算清零方式,避免旧任务摘要污染新任务推理
上下文占用率很低,但每次回复等待时间极长 打开 统计视图 拆解模型与工具耗时 瓶颈通常在于工具死锁或上游 API 网络延迟,压缩上下文无法提速
压缩后发现关键细节丢失,需要核对早期原始输出 查阅底层 会话日志(Session Logs) 或轨迹文件 Compaction 仅在上下文内保留摘要,但完整的历史事件仍持久保存在日志中

六步标准化排查流程

  1. 基准测量: 挂载并打开统计视图,记录当前轮次的上下文大小、缓存命中率与工具耗时分布,拒绝凭直觉盲目压缩。
  2. 定位突变点: 若发现某一步上下文突然暴增,立即定位该步对应的工具调用类型。
  3. 收紧落盘策略: 若确认为单条大输出所致,检查 Spill 是否正常触发;若默认 12,500 Token 仍显宽裕,可将其下调至 6000~8000 让大文本更早落盘。
  4. 受控手动压缩: 若属于长线任务自然累积,在轮次空闲时输入 /compact 执行一次手动压缩,并在统计视图中核对压缩合成行的负增量。
  5. 验证摘要质量与缓存: 压缩后继续对话 2~3 轮,观察 KV Cache 命中率是否回升,并确认智能体是否遗忘核心约束(如有遗漏,及时在提示词中补充)。
  6. 避免连续重复压缩: 每次压缩后重新评估趋势,切忌对同一段已摘要的历史连续多次执行 /compact,以免造成信息严重失真与无意义的缓存击穿。

七、 常见技术问答(FAQ)

Q1:Compaction 和 Spill 最本质的区别是什么?

Q2:为什么在对话框输入 /compact 时提示命令不可用? 当前智能体正处于活跃的推理/工具执行轮次中,或者后台已有一个压缩任务正在运行。/compact 命令本身不会进入队列等待,也不会强行打断当前正在执行的轮次;而在压缩运行期间发送的普通用户提示词会自动排队,待压缩完成后依次执行。

Q3:为什么在插件列表里找不到“统计页签”? 统计页签不属于默认启用的常规插件。需要依次进入 Web 界面的 “插件 → 实验性插件 → 更多” 并开启 “开发者工具”,或在配置文件中显式挂载 @deepseek-ai/dsh-experimental-client-ui-stats。

Q4:Spill 落盘的文件存放在哪里?长期运行会导致磁盘爆满吗? 默认存储在系统私有临时目录下的 session-[hash] 子目录中,也可通过 spill-local 的 root 参数固定到指定磁盘路径。虽然 cleanupPeriodDays 默认配置了 30 天过期清理,但清理扫描仅在 DSH 进程启动时触发一次。因此对于常驻后台的服务,建议固定 root 目录并配合操作系统的定时清理策略。

Q5:执行压缩后,下一轮的 KV Cache 命中率大幅下跌,这属于异常吗? 属于正常现象。因为早期历史 Token 被替换为新的摘要文本,从第一个发生改变的 Token 位置起,后续的缓存前缀签名随之改变(仅替换点之前的系统提示词等前缀仍可复用)。请继续观察后续 2~3 轮对话,随着新对话在摘要之后不断追加,缓存命中率会逐步恢复正常;若持续低迷,再排查是否有动态变化的系统提示词或工具耗时异常。