DSH Hub / 插件 / dsh-compaction-instant KitDoesIt/dsh-compaction-instant ↗ ★ 5
dsh-compaction-instant VCC-style instant, near-lossless deterministic compaction engine for the DeepSeek Harness — a drop-in replacement for @deepseek-ai/dsh-compaction-basic
包名 dsh-compaction-instant
版本 0.1.4
许可证 MIT
最近更新 2026年8月14日 GitHub ↗ 文档 ↗ 安装 $ npx -p @deepseek-ai/dsh dsh plugin --profile web add github:KitDoesIt/dsh-compaction-instant复制
dsh-compaction-instant
为 DeepSeek Harness 打造的即时、近无损上下文压缩 引擎——装上就能直接替换官方引擎 @deepseek-ai/dsh-compaction-basic ,用 lllyasviel/VCC 的"对话编译"思路取代原来的 LLM 摘要。
对话太长了怎么办?普通方案是让模型把旧内容"总结"一遍(慢、花钱、还会丢细节)。本引擎不总结,而是把旧内容重新整理成一份紧凑的存档 (后面统称"检查点"):毫秒级完成、不调用模型、只使用原来的原文,不改写、不编造。被收进存档的内容随时可以原样找回来。
主要特性
免 LLM ——压缩过程完全不调用模型:没有摘要请求、没有推理等待、不花 token。它只是确定性的文本处理,哪怕一百万个 token 的历史也是毫秒级搞定。
近无损 ——存档里只有原文;每处被省略的内容都有标记并注明出处(seq 序号),之前的存档会原封不动地保留。
即时 ——把旧内容扫描一遍就完成;不联网、不调模型、不占 KV 缓存。
完全兼容的替换 ——对外接口、事件、计费和报错方式都和官方引擎一致;内置预设不用改任何东西就能用(见"别名安装")。
示例
一段包含用户提问、助手回答 + 工具调用及其结果的历史,压缩后长这样:
[user]
please fix the bug
[assistant]
on it
* read "a.js" (seq 2 -> result 3)
[user]
next question
每个工具调用只占一行 :白名单里的工具(toolArgTools)显示关键参数,其他工具只显示名字(* job_kill (seq 9 -> result 10)),hideTools 里列的工具完全不出现。工具结果不占位置——通过 -> result N 指针,用一次 recall(type:"result") 就能取回。较长的用户/助手文本按预算截断,并在末尾标注 ...(truncated from seq N);每处省略都写明了完整内容存在哪个事件里。
Recall:把丢掉的内容找回来
本包还配套了"找回"能力——同一会话内的回读 ,模型和人都能用。因为会话日志只增不改,编译器省略过的每一个字都还在,随时可取:
入口 模块 作用 recall 工具 (给模型用)dsh-compaction-instant/tool按类型恢复原文:type:"seq" 配合 (seq N)/(seqs A-B) 标记,type:"result" 配合 result N 指针,type:"checkpoint" 配合 [checkpoint N] 序号——把原始内容一字不差地恢复到当前工具结果里 search 工具 (给模型用,grep)dsh-compaction-instant/tool在整个持久日志里按关键词/正则搜索——包括被压缩掉的内容——返回带 (seq N) 指针的匹配事件,可直接交给 recall 取回 /recall 命令 (给人用,grep)dsh-compaction-instant/command/recall 追加一条持久的用户消息,内含匹配事件和 seq 指针,下一轮模型就能看到
dsh-compaction-instant · DSH Hub
dsh-compaction-instant/recall + dsh-compaction-instant/search
seq 解析(12、3-7、seq 12 / seqs 3-7)、日志展开、预算、字段筛选;正则编译与命中展示
Recall 能取回一切 :文本、推理过程、工具调用的完整参数、嵌套的工具结果;只在日志里出现过的事件会以带标签的原始数据展示;找不到的 seq 会明确报错。maxRecallTokens 预算(默认 16000 )超限时会截断并标注来源、统计跳过多少;搜索限制展示条数(maxSearchHits,默认 50 )。这两个插件是独立的一行,可以挂在任何 压缩引擎旁边——它们只读日志,不依赖本引擎。
每个检查点开头还附了一段简短的 RECALL 使用指南 ,告诉模型怎么用 recall / search 找回被省略的内容。如果更早的检查点因为空间不够被省略,它不会无声消失:会留下一行 [checkpoint N](N 是压缩序号,1 = 最早),用 recall(type:"checkpoint", id:"N") 就能完整恢复。
配置 键 默认 含义 thresholdRatio0.5上下文用到多大比例时自动触发压缩(0.5 = 用到一半) retainRatio0.05对话最新的一段(按窗口比例)一字不差地保留,不压缩 retainTokens— 直接指定保留多少 token;与 retainRatio 二选一 manualRetainRatio0.05手动 /compact 时保留当前对话的比例(保证正在聊的内容不会被收走) manualRetainTokens— 手动模式直接指定保留 token 数;与 manualRetainRatio 二选一 autotrue开启自动压缩:监听 agent/pre-step 压力事件和 agent/request-error 溢出恢复 maxTokens8192单个检查点总预算的下限(按内容密度估算的 token) checkpointScale0.1实际预算 = max(maxTokens, 被压缩掉的 token 数 × checkpointScale),再封顶于 checkpointCap——内容很多时不会把每条都压成一句话 checkpointCap65536检查点预算的封顶值 textTokens512每条助手文本的预算 userTextTokens1024每条用户文本的预算 toolCallTokens128每个工具调用单行的预算(这个永远不缩放——见下面的省略规则) toolResultExcerptTokens256仅为兼容官方配置而接受;不起作用 ——工具结果本来就不占位置 includeReasoningfalse是否在检查点里保留推理过程 stripNoiseXmltrue是否去掉用户文本里配置的噪音标签 noisePatterns见 compiler 噪音标签的正则来源,按 s 模式匹配 toolKeyFields内置 额外的"工具名 → 参数里的关键字段"映射,用于单行展示 toolArgTools见 compiler 白名单:这些工具的关键参数会显示在单行里(read/write/edit/glob/grep/bash/shell/web_search/skill/subagent/…);其余工具只显示名字 hideTools— 完全从检查点里去掉的内部管理工具 modelPolicies— 按 provider/model 单独覆盖 thresholdRatio/retain*(与官方配置格式一致) compactionRetries / maxOverflowRetries1 / 1重试次数,含义和官方引擎一样 summarizationProvider / summarizationModel— 仅为兼容官方配置而接受;不起作用 ——本引擎从不调用模型
recall 工具和命令插件各自接受 { maxRecallTokens?: 16000, maxSearchHits?: 50 } 配置。
Cordis 配置坑: 插件行的配置要经过 schemastery schema 校验,它的 ~standard 适配器会给每个没写的数组项注入 [] (toolArgTools、hideTools、noisePatterns、toolKeyFields、modelPolicies)。本引擎把空数组当作"没设置",会回退到默认值——所以不写 toolArgTools 就自动用内置白名单(千万别用 toolArgTools: [] 想关掉它;空 = 默认)。debug: true 会把每次压缩的诊断写进 debugLogPath 指定的文件(默认 $DSH_HOME/compaction-debug.log)。
预算有两道保险:按 token 数限制,再按"预算 × 4"的字符数限制——所以再长的连续字符串(base64 大块、压缩过的文件)也绕不过去。工具调用永远是单行 :不会缩放,预算不够时只压缩对话文本(每条最少留 32 token )。如果压缩结果还是超过(缩放后的)预算,先删最旧的工具行 ([N tool/result entries elided: seqs a-b]),再删其余最旧的条目([N earlier entries elided: seqs a-b])——工具调用永远挤不掉对话。最新的内容总能保住。
浏览器设置卡片(设置 → 插件) 从 0.1.4 起,引擎在任何装配了 settings 域 的部署(标准 web/desktop profile 都有)上暴露一个用户设置命名空间(compaction-instant)。可编辑子集持久化到 settings.yaml,叠加在 插件行的 cordis 配置之上:
字段 含义 checkpointScale压缩预算 = 被压缩 token 数 × 此比例 checkpointCap缩放后预算的绝对封顶 maxTokens一次编译检查点的总 token 上限 auto注册步骤间自动压缩 debug向日志文件写入引擎调试行 debugLogPath调试日志路径(留空 = $DSH_HOME/compaction-debug.log)
其余字段(modelPolicies、toolArgTools 等)仍只由 cordis 配置管理。设置层永远弄不坏引擎:每次设置写入都会先经过完整配置解析器的重新校验才会持久化;未暴露的配置字段保持组合层的值。没有 settings 服务时引擎行为与之前完全一致(只看组合配置)。卡片注册在客户端 bundle 上,所以只要装上这个包就会出现,无需改任何部署配置——重启一次 dsh web 让启动图拾取 dsh.client bundle 即可。
分词与多语言 分词器是简单的字符规则:连续的英文字母算一个 token,连续数字算一个,标点一个字符一个,空格免费,其他每个字符算一个。具体:
内容 Tokens 中文(你好,世界!) 每个字 1(共 6) 西里尔 / 阿拉伯文 每个字符 1 带重音拉丁文(café) 英文部分成组(caf + é) Emoji(😀) 2(一个 emoji 占两个 UTF-16 单元)
所有截断都发生在字符边界 ——绝不会把一个 emoji 从中间切开(有 test/multilang.test.js 保证)。字符数上限按 UTF-16 长度算,对 emoji 这类字符偏保守。
另外,Harness 自带的 token 计量器(用于"压缩后必须变小"的检查、/compact 的用量报告)用的是另一套 字符数 / 4 + 固定开销 的估算,两套算法故意并存——详见设计说明。
保证
即时 ——把旧内容扫描一遍就完成;不联网、不调模型、不占 KV 缓存。
近无损 ——输出里只有原文;每处省略都有标记并注明出处 seq;之前的检查点原封不动保留。
完全兼容的替换 ——接口、事件、计费(走同一个 ctx.tokenMeter)和报错方式与官方引擎一致,包括"压缩后必须变小"的检查(如果压缩完反而没变小,会被拒绝)。
可选 pruner 兼容 ——和官方引擎一样会使用可选的 toolResultPruner 服务(它负责整理保留部分 ;被压缩的旧内容由本引擎自己处理)。
实测压缩率(真实会话、一条不丢) 数据来自真实会话日志(本项目的开发会话),编译时不丢弃任何一条 ——每条都保留,只做条目级截断和工具调用单行化。百分比是相对原文 token 数的比例。
负载 原文 tokens 编译后 保留 压缩 工具密集会话全量(3,181 节点:1,438 个工具调用 + 1,540 个工具结果) 2,523,012 226,205 9.0% 91.0% 另一个会话全量(864 节点) 685,088 62,705 9.2% 90.8% 同一个工具密集会话,最近 800 条消息 625,927 45,031 7.2% 92.8% 纯文本(同一会话去掉全部工具行) 160,963 109,945 68.3% 31.7%
工具结果零成本 ——结果不产生条目,靠 -> result N 指针一个 recall 就能取回,这是最大的来源。
工具调用一行化 ——每个调用压成一行(≤ 128 tokens,平均约 100)。
思考过程不保留 ——reasoning 增量整体省略(有标记,不是悄悄丢)。
对话文本近乎无损 ——纯文本对照组保留了 68.3%;文本上那约 1.5 倍压缩基本是剥掉 JSON 包装,外加只截断最长的几段。
预算扫描(同一个 252 万 tokens 的工具密集会话):从 cap ≈ 22.6 万 tokens(原文的 9%,正好接近默认 checkpointScale 0.1,但被 64K 硬顶截断)才开始丢条目。低于这个值代价是悬崖不是斜坡 :
Cap 编译后 保留 条目数 被丢 8,192 8,243 0.33% 111 2,090 32,768 22,263 0.88% 232 1,969 65,536(部署默认) 55,737 2.2% 325 1,876 65,536 55,737 2.2% 325 1,876 131,072 131,047 5.2% 1,142 1,058 226,205(一条不丢的临界值) 226,205 9.0% 2,199 0
安装 下面三种方法都用 Harness 自带的插件管理器安装(包发布在 npm,名字 dsh-compaction-instant;插件管理器会在 profile 目录里跑 pnpm,装完后宿主配置和每个 agent preset 都能找到它):
dsh plugin --profile web add
/compact 命令(dsh-command-compact)和用哪个引擎无关,任何安装方式下都照常工作。
方法 1 —— 顶替内置引擎(别名安装) dsh plugin --profile web add "@deepseek-ai/dsh-compaction-basic@npm:dsh-compaction-instant"
dsh 目前没法让你选压缩引擎 ,内置预设(standard、code、cordis)在配置里写死了包名 @deepseek-ai/dsh-compaction-basic。要让这些内置预设用上本引擎,就顶替 内置插件:预设配置里的包名是从 profile 的 node_modules 解析的(优先级高于 Harness 自带的安装),所以把本包装到内置这个名字下面,所有内置预设就会自动加载本引擎——不动任何预设文件,预设以后升级也不受影响。
这样顶替是天然安全的:本引擎和官方引擎对外完全兼容——同一个 ctx.compaction 接口、完全相同的依赖注入列表 (llm、tokenMeter、sessions)、相同的事件和报错方式,官方配置里的每一个键也都接受。把别名依赖删掉就恢复官方的引擎。
这种安装方式不会被识别成 bundle (Harness 会从自己的安装目录解析 @deepseek-ai/dsh-compaction-basic 这个名字,那里是官方包,没有 dsh.bundle 声明),所以没有任何自动化——需要把 recall 工具和 /recall 命令自己加进 profile 的 cordis.patch.yml(新行必须放在 insert 列表里;这个文件热重载,不用重启)。行名必须用别名包名 (这种安装方式下只有它能解析);引擎行可选,只在需要给"没有压缩配置的预设"(如 minimal)提供宿主兜底时才加:
- id: compaction-basic
disabled: true # 宿主层替换(可选兜底)
- insert:
- id: compaction-instant
name: '@deepseek-ai/dsh-compaction-basic' # 给没有压缩配置的预设兜底
- id: tool-recall
name: '@deepseek-ai/dsh-compaction-basic/tool'
- id: command-recall
name: '@deepseek-ai/dsh-compaction-basic/command'
方法 2 —— 直接安装 + 让 AI 复制一份预设(dsh 创作模式) dsh plugin --profile web add dsh-compaction-instant
然后用"预设创作"预设(内置的 cordis 预设,即「创造模式」)开一个会话,让 AI 执行:
复制 standard 预设,把它的压缩引擎行换成 dsh-compaction-instant。
AI 会用 agentPresets.copy('standard', '') 创建一份本地预设,在副本里改掉压缩行的 name,用 standingKeyFor('') 校验能不能正常挂载,还可以通过改 agent-presets 行(config.default: )把它设为默认。新预设会出现在 UI 选择器里;内置预设不受影响。
从 v0.1.1 起,本包还声明了 dsh.bundle,所以直接安装会自动注册成 profile 的配置层:自动禁掉内置的摘要引擎行、自动插入本引擎和 recall 工具(见包内 cordis.patch.yml)。宿主这边不用手动配置,只需复制预设。
方法 3 —— 直接安装 + 手动配置预设 dsh plugin --profile web add dsh-compaction-instant
mkdir -p "$DSH_HOME/.agent-presets/"
# 从你想作为基础的内置预设复制配置和元数据
# (预设列表里能看到每个预设的真实路径):
cp /agent.cordis.yml "$DSH_HOME/.agent-presets//agent.cordis.yml"
# 在旁边写 preset.yml,包含 name + description
然后手工编辑副本里的压缩组——只改一行 name,仍在同一个隔离域(realm)里:
- id: compaction
name: cordis:group
group: true
isolate:
compaction: true
toolResultPruner: true # pruner 必须和引擎在同一隔离域
config:
- id: compaction-instant
name: dsh-compaction-instant # 原来是 '@deepseek-ai/dsh-compaction-basic'
- id: command-compact
name: '@deepseek-ai/dsh-command-compact'
# ... 保留 pruner 行
规则:绝不改内置预设的安装文件;保留 isolate 隔离域;真正的检验是 standingKeyFor 挂载成功(或直接在预设上开一个会话)——预设列表里的 broken 标记只能发现解析错误。
方法 2 和 3 不需要任何宿主配置行 :上面提到的 dsh.bundle 会自动注册好一切。
方法 内置预设里的引擎 要改预设文件吗 选择器里多出预设 安装成本 1. 别名替换 ✅ 自动(standard/code/cordis) 否 否 一条命令 + 手动 patch 2. AI 复制副本 只有新预设 副本 是 一句提示 3. 手动预设 只有新预设 副本 是 手动编辑
每个上下文只能挂载一个 ctx.compaction 实现(接口文档写明"每个上下文加载一个实现");预设挂载各自有独立的隔离域,所以宿主和预设的实例永远不会冲突。
开发 npm test # node --test(编译器单元测试、配置校验、会话集成、引擎)
npm run check # 对所有源码做 node --check
本包依赖很少:@deepseek-ai/schemastery 用于配置校验;其余依赖都是 Harness 自己提供的。src/compiler.js 刻意零依赖,没有运行中的 Harness 也能单独跑单元测试。
和官方引擎的区别
不调摘要模型 → 压缩从几秒变成几毫秒;不花摘要的 token。
不改写 → 事实、文件路径、命令、变量名都一字不差;模型继续用自己的话接着聊。
确定性 → 同样的内容永远压缩出同样的检查点。
之前的检查点原样保留,而不是重新摘要一遍(又快又无损)。
手动 /compact 会保留最近的一小段原文(manualRetainRatio,默认保留当前对话的 0.05)而不是压缩全部历史,正在聊的内容永远不会被收走;只有更早的部分进检查点。
compaction/summary 事件携带压缩后的条目本身 ——UI 里可展开的检查点行显示的就是模型实际看到的内容,外面包一层能自动变长的代码框 (框线永远比内容里的 ``` 长,所以含 markdown 的消息也能整齐地显示成一个代码块),检查点开头还有一段简短的使用指南,告诉模型怎么用 recall / search 找回被省略的内容。
权衡:对以长对话、叙述为主的历史,检查点的信息密度可能不如 LLM 摘要(长句是截断而不是合并)。正在进行的对话有逐字保留的尾部(自动 retainRatio 和手动 manualRetainRatio)兜底,其余内容都能通过 (seq N) 指针 + recall 找回来。