跳到主要内容

dsh-cwl

已验证

dsh-cwl · v0.2.1 · MIT

CWL — Context Window Lifecycle for DeepSeek Harness: structured context eviction (arXiv:2606.11213). Graduated, deterministic, zero-LLM eviction of exploration/action episodes when context pressure exceeds budget — no summarization lossiness, no hallucina

安装

dsh plugin add dsh-cwl

用 dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南。

源码

标签

作者

说明文档

dsh-cwl

CWL — Context Window Lifecycle(上下文窗口生命周期) for DeepSeek Harness: 面向长时任务智能体的结构化上下文驱逐(eviction)。

范式论文:Beyond Compaction: Structured Context Eviction for Long-Horizon Agents(arXiv:2606.11213)

English | 简体中文

为什么不用摘要压缩(compaction)?

Compaction(上下文压力的常规应对手段)是用 LLM 把历史总结成摘要。根据 CWL 论文,它有四个结构性问题:

  • 损失不可预测 —— 摘要器决定什么重要,而不是任务本身。
  • 破坏结构 —— 因果链(工具调用 → 输出 → 决策 → 动作)被压平成散文。
  • 阻塞性开销 —— 任务进行中、token 紧张时还要触发一次完整 LLM 调用。
  • 压缩诱发幻觉 —— 在长度压力下做摘要,是已知的失败模式。

CWL 把对话记录当作结构化的工作记录,做确定性驱逐:智能体的轨迹被自动推导成类型化 episode 图(探索 expl / 动作 act,带依赖边);当上下文压力超过预算时,一个零 LLM、确定性的策略按分级逐步剥除内容——先驱逐探索段(纯上下文,最安全),再驱逐效果已落盘的动作段。用户消息永不驱逐。

工作原理

  1. Episode 推导(自动,无需智能体标注):连续的同类工具批次合并为语义段(expl 表示纯读/搜索类,含只读 bash(如 grep/cat);act 表示有副作用类:edit/write/写型 bash);每条用户消息关闭当前段(轮次边界),且每段有批次上限——单请求的连续自主长跑(几十次工具调用)也会分成多个有界、可驱逐的段,而不是塌缩成单个巨型段;某个 act 触碰的文件如果之前被某个 expl 读过,则建立依赖边。
  2. 压力计量:真实上下文压力 = input + cacheRead + output + reasoning tokens(从 assistant/message usage 事件累计——tokenMeter.measure().totalTokens 不含 cacheRead,而 cacheRead 在长会话中占大头)。
  3. 分级驱逐(挂在 agent/pre-step 瀑布上,每次 LLM 调用前,由细到粗):
    • 内容裁剪(细):expl 段内的大工具结果先改写为短标记([cwl-stub: …])——保留结构、削减 token、工具配对不受影响
    • 整段驱逐(粗):先 expl 段(纯上下文,保留一行"已探索: …"标记),再最旧的已完成 act 段;一律按 surface 位置块执行(位置是 replace 后唯一可靠的不变量——驱逐永不切开 tool-call/result 对造成孤儿消息)
    • 永不触碰最新尾巴(preserve-recent)和用户消息
    • 被驱逐区间用轻量标记替换(官方 surface-replace 接口;原始事件保留在日志中,cwl_recall 可恢复文件路径)

安装

dsh plugin --profile <name> add dsh-cwl                 # 从 npm 安装
dsh plugin --profile <name> add github:kalifun/dsh-cwl  # 或从 GitHub 安装

或者把目录放进你的 composition:

- id: dsh-cwl
  name: ./dsh-cwl/index.js

使用

无需配置。上下文在预算内(默认模型上下文窗口的 80%)时插件完全不干预,压力超过预算才开始驱逐。

# 可选:覆盖预算(tokens)——用于测试压力行为
DSH_CWL_BUDGET=30000 dsh web

驱逐策略(确定性重放验证:驱逐价值 −24% cacheRead、策略无关;batch 均值最优 −24.7%、7 会话方向一致 → 默认如下,可用环境变量覆盖):

环境变量 默认 取值 作用
DSH_CWL_EVICT_ORDER tail tail / oldest oldest 优先驱逐最老段
DSH_CWL_EVICT_BATCH 开 0 / false / off 关闭 合并相邻 episode 为一次 surface replace(减少缓存打断)
DSH_CWL_EVICT_TAIL_WINDOW 0 N 只驱逐 end 落在最近 N 个 surface 节点内的段
DSH_CWL_STRIP 开 0 关闭 细粒度级:整段驱逐前先裁剪 expl 段内的大工具结果内容(保留结构)
DSH_CWL_STRIP_THRESHOLD 1500 字符 结果文本超过该长度才裁剪
# 回退到保守配置(oldest + 逐段 replace)
DSH_CWL_EVICT_ORDER=oldest DSH_CWL_EVICT_BATCH=0 dsh web

会话分析(逐轮 token 明细 + "驱逐后下一轮 cacheRead" 指标):

node tools/analyze-session.mjs <session.jsonl>

面向智能体的工具:

工具 用途
cwl_recall 列出被驱逐 episode 涉及的文件路径,按需重新读取

观测端点:

端点 用途
GET /api/cwl/evictions 驱逐日志(会话 → 被驱逐的 episode)
POST /api/cwl/force 调试:对某个会话强制驱逐一次

验证

node check.js          # 纯函数单元检查(episode 推断/驱逐策略/裁剪/配对)

能力基准(live,helmsman 平台):BENCHMARKS.md —— 固定测试方案 (场景 A:12 轮长会话;场景 B:单请求自主长任务 ×3)配逐版本数据行,每次行为变更后刷新。

离线回归工具(用你自己的本地会话运行,数据不出机器): tools/cache-replay.mjs(确定性 cacheRead)、tools/replay-real.mjs --apply(真实 surface fold + 工具配对断言的引擎 apply 层回归)、tools/eval-episodes.mjs。

License

MIT