dsh-memory-ladder:DSH 的分層壓縮後端

前言

在 DSH(DeepSeek Harness)裏跑長任務,遲早會遇到上下文被撐滿的問題。默認的壓縮策略是”快到窗口上限時,把最老的一段壓成摘要”,這在長任務裏有兩個實際麻煩:觸發太晚,等到窗口用了八成才動手,壓縮本身要重放整段歷史,請求已經貼着上限;壓完之後新舊內容混成一個摘要,模型分不清哪些是剛纔發生的事、哪些是十輪前的背景。

下面介紹的插件 btyg123/dsh-memory-ladder 換了一種組織方式:讓上下文按新舊分層,每層有各自的預算,最新一輪永遠有最大的空間,越遠越薄。它由 BTYG123 維護,MIT 許可,分類是記憶。

這是什麼

一句話定位:一個 DSH 的 bundle 插件,作爲壓縮後端替換默認策略。它繼承 @deepseek-ai/dsh-compaction-basic 的 BasicCompactionEngine,只替換觸發策略和 summarize(),壓縮事務(括號鎖、收縮校驗、表面替換)仍來自上游。

它不是備份工具,也不是無損壓縮。README 明確寫的是”它省的是容量,不是信息本身”,二級細節會隨層級下移被丟棄。

分層預算怎麼算

設路由模型的上下文窗口爲 T,各層預算如下:

層級 內容 預算
最新一輪 上次檢查點之後的全部原始消息 T/3
上一輪 上一輪壓縮出的摘要 T/6
上上輪 再往前的摘要 T/12
… 每深一層減半 T/(3·2^d)

最新一輪與上一輪的比例因此穩定在 2:1。v0.2 還受 maxSummaryTokens 約束:當層級總預算超過摘要輸出空間時,摘要各層按幾何比例縮小,並保留檢查點框架空間。

v0.2 起多了原文歸檔

新版保留原有分層睡眠事務,並在壓縮前把用戶、助手及工具消息的文本寫入當前會話獨立的歸檔。之後根據用戶問題檢索已經離開上下文的原文,經 Harness 的動態上下文接口提供給模型;不會直接改寫凍結的模型請求。

關鍵行爲:

  1. 默認歸檔位置是會話工作目錄下 .dsh-memory-ladder/,文件名使用會話 ID 的 SHA-256。
  2. 原文保留消息 ID、角色和順序。重複壓縮不會重複歸檔同一消息。
  3. 系統指令、舊檢查點和運行時上下文不歸檔。
  4. 歸檔是本地明文狀態,不會自動上傳到其他服務;被選中的摘錄會隨下一次模型請求發送給當前模型服務商。
  5. archiveRecall: false 同時停用歸檔寫入和檢索。恢復同一會話 ID 可繼續讀取歸檔;fork 到新會話 ID 不會自動複製父會話歸檔。

一次睡眠發生什麼

按 README 的鏈路,一次睡眠有四步:

  1. 最新一輪的 token 數達到 T/3(或模型報告上下文溢出)。
  2. 一次模型調用把”舊階梯 + 本輪原始記錄”重寫成新階梯:舊 Tier 0 變成新 Tier 1,逐層下移,最深一層落進歸檔鏈接。
  3. 事務把被遮蔽的整段歷史替換成一條用戶消息(surfaceOp: replace),原始事件仍留在會話日誌裏,可回放。
  4. 本輪從新階梯繼續。

/compact 手動命令複用同一條路徑,只是跳過閾值判斷。

安裝

前置條件是 dsh 的插件命令依賴 pnpm。README 給出的官方命令是:

npm i -g pnpm

# 方式一:插件管理器(推薦,已實測)
dsh plugin --profile <你的 profile> add git+https://github.com/BTYG123/dsh-memory-ladder.git

裝完會自動把 dsh-memory-ladder 加進該 profile 的 dsh.profile.bundles。

方式二是手動放進 profile 的 node_modules,並在 patch 裏停用官方壓縮後端、插入本插件:

- id: compaction-basic
  disabled: true
- insert:
    - id: memory-ladder
      name: 'dsh-memory-ladder'

這一步不能省。ctx.compaction 只接受一個實現,兩個後端同時掛載會在啓動時報 service "compaction" has been registered。bundle 的 patch 已包含停用步驟,手動安裝時要自己加。

配置

配置項按 README 的配置表列出,均爲原文給出的字段與默認值:

# 睡眠觸發線:最新一輪佔窗口的比例
newestFraction: 1/3
# 階梯最多描述多少層
tierCount: 6
# 更深層級低於此預算就並進歸檔鏈接
minTierTokens: 200
# 睡眠請求的輸出上限
maxSummaryTokens: 8192
# 可壓縮跨度小於此值直接跳過,避免白花一次模型調用
minCompactionTokens: 512
# 留空則沿用最近一次路由的 provider/model
summarizationProvider: ""
summarizationModel: ""
# false 只保留手動壓縮
auto: true
# 壓縮前歸檔原文,下一步按問題檢索
archiveRecall: true
# 歸檔目錄,相對會話工作目錄,也可設絕對路徑
archiveDirectory: .dsh-memory-ladder
# 每次檢索上下文的 UTF-8 字節上限,含來源信息和框架
recallMaxBytes: 4096

兼容性

README 寫的驗證環境是 @deepseek-ai/dsh@0.2.1-rc.5 + Node 22/24,peerDependencies 已 pin 到 0.2.1-rc.5。需要注意兩點:

  1. 本倉庫的安裝根通過 overrides.zod = 4.6.6 修復已知的集合校驗內存耗盡漏洞;npm 不會把依賴包內的 overrides 自動應用到宿主工程,作爲 bundle 安裝時仍需由 Harness 宿主統一管理 Zod 版本。
  2. compactRegion() 是公開契約,相對穩定;構造函數與基類字段屬於實現細節,上游重構可能導致本包失效。

已知限制

這些是 README 明確列出的限制,落地前值得先看清楚:

  1. 單條超大消息壓不動。一條 5 萬 token 的 assistant 輸出是不可分割單元,表面壓縮無法修復,屬於壓縮接縫的固有限制。
  2. 歸檔寫滿後該會話不能再壓縮。archiveMaxBytes(默認 32 MiB)是硬上限,寫滿時拋 ARCHIVE_CAPACITY,壓縮事務拒絕替換原始消息。代價是該會話此後每次睡眠都失敗、上下文一路增長,需要調大上限、輪轉歸檔或關掉 archiveRecall。長期運行的會話建議提前調到 64–128 MiB。
  3. 睡眠本身要花一次調用。若摘要比原文還長,事務拒絕提交併記錄失敗;密集睡眠會推高輸入成本。
  4. 不是無損的。要無損就調大 newestFraction,或者不用本插件。
  5. 摘要質量取決於模型。本地無法校驗事實是否被忠實保留。

實測數據

README 在一次 20 分鐘的 CrowdStrike 事件調研上對比同一策略的兩種窗口:

默認 T/3(1M 窗口) 32k 等效窗口
觸發線 349,525 token 10,905 token
峯值上下文 185,359 token 32,636 token
sleep 次數 0 10
會話表面節點 266 142
產出 41 KB / 23 個來源 16 KB / 10 個來源

在 12 個合成留出案例(每模型 96 題)中,Flash 從原版 76/96 提升到 90/96,Pro 從 84/96 提升到 91/96;費用相對原版增加約 32%/31%,相對完整歷史降低約 28%/34%,完整歷史仍爲 96/96。這是特定壓縮壓力下的質量/費用取捨,不是所有長任務都更優的證明。README 同時保留了消融組的一次失敗和逐題錯誤記錄。

適用場景與注意

適合的場景:長任務中需要保留”最近發生了什麼”的優先級,同時接受遠端細節衰減,並且願意爲摘要調用付一筆額外模型費用。期望無損或期望壓縮完全不出錯的場景不適合。

另外,插件以當前 dsh 進程權限運行。它是 bundle,自帶 cordis.patch.yml,會在啓動時停用 compaction-basic 並插入自己的實現——安裝前應該先讀一遍源碼和 patch,確認這符合你的 profile 預期。許可證是 MIT,歸屬聲明見倉庫 LICENSE。目錄頁是第三方社區站點,與 DeepSeek / 幻方無官方從屬關係。

結尾

它的價值在於把”什麼時候壓、壓多細”改成由分層預算決定,而不是等到窗口快滿才一次性清空。代價是每次睡眠的模型調用、歸檔容量上限和遠端細節衰減,三者都需要在配置裏做取捨。

目錄頁:https://www.skillhub.cn/plugins/BTYG123/dsh-memory-ladder
倉庫:https://github.com/BTYG123/dsh-memory-ladder

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜