← 返回列表
未验证
面向 DeepSeek Harness 的、对 Agent 安全的工具结果压缩。
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/16 · 已提供中文文档
为 DeepSeek Harness 设计的一个对 Agent 安全的上下文压缩器。它以语义方式保留关键工具输出,例如错误、文件路径、JSON 负载和命令结果,而不是机械地截断上下文。
综合分
29.2
GitHub 分
29.2
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add rootkiller6788/dsh-context-compressor该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
信任档位:已验证本站已于 1 天前真实安装成功
- 是什么
- dsh 原生插件 · chat
- 装得上吗
- 本站已真实安装成功(非静态推断)
- 安全吗
- 本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
- 还在维护吗
- 活跃:最近一次提交在 9 天前
档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →
🟢实装验证通过· 2026/9/25
由本站实装验证器在真实 dsh 环境安装成功,非静态推断。
数据截至 2026/9/24(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/cordis-plugin-include@deepseek-ai/cordis-plugin-loader@deepseek-ai/dsh-agent@deepseek-ai/dsh-attachment@deepseek-ai/dsh-compaction@deepseek-ai/dsh-compaction-basic@deepseek-ai/dsh-invariants@deepseek-ai/dsh-llm@deepseek-ai/dsh-session@deepseek-ai/dsh-subprocess用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
由 DeepSeek 最新模型翻译生成dsh-context-compressor
面向 DeepSeek Harness 的、对 Agent 安全的工具结果压缩。
随附的 dsh-compaction-tool-result-pruner 是刻意基于语法的:它保留开头的 4096 个码点,插入一个省略标记,再保留末尾的 1024 个——正如其自己的 README 所说,“保留开头和结尾,而不去解释中间哪些行在语义上重要”。这对散文来说没问题,但对编码 Agent 真正需要的东西却是破坏性的:构建日志中间的报错、携带退出码的 JSON 成员、下一次编辑将要针对的路径。
本包注册相同的服务名并满足相同的契约,但依据内容而非位置来决定保留什么。
它做什么
segment → classify → select → gate
lines critical mandatory first size ≤ threshold
reference then by score critical spans present
structure (LLMLingua-2 structural braces balanced
compressible for prose, when warm)
四个保护级别,在任何评分运行之前就已确定:
| 级别 | 处理方式 | 示例 |
|---|---|---|
| critical | 永不丢弃;如果它放不下,则完全不进行任何裁剪 | JSON 成员与分隔符、代码围栏、diff 头、shell 命令、错误行 |
| reference | 高优先级,在预算压力下可丢弃 | 文件路径、源码位置 |
| structure | 优先于散文,在预算压力下可丢弃 | JSON 区域内部 |
| compressible | 参与评分,并可选地由 LLMLingua-2 进行 token 压缩 | 散文、无显著特征的输出 |
这一安全属性是刻意分级处理的。 丢失一行错误会把 Agent 引向错误的方向;丢失一个路径只会让它多花一次工具调用。这两者不是同一种损失,因此它们不共用同一套策略。
这种分级的存在还因为拒绝裁剪并非安全的兜底方案。dsh-compaction-basic 在 null 之后会重新测量,若仍超过阈值,就把整个范围交给 LLM 摘要——而摘要也会重写受保护的内容。因此,拒绝会升级为比丢弃几行 reference 严格来说损失更大的东西。只有那些仅其 critical 片段本身就超出预算的内容才会拒绝。
⚠️ 上述论断经不起测量——见
ADR-0001。
“100% critical retention”是由写在选择器旁边的正则表达式评定的,而且位置对比是在更小的预算下运行的——5159 个字符,而本包是 8192——所以本包是因为保留得更多而得分,而不是因为选择得更好。
改为对照 Agent 自身的行为来测量,即 Agent 随后复用了工具结果中的哪些字符串,在相同预算下:
| 预算 | 位置式 | 本包 |
| ---: | ---: | ---: |
| 8192 | 81.2% | 76.3% |
| 4096 | 79.4% | 72.6% |
| 2048 | 68.8% | 69.2% |
启发式选择路径已关闭。使用
node benchmark/bench-utility.mjs --control 复现。
/compact [low|medium|high|max]
随附的 dsh-command-compact 刻意不接受参数——任何输入都会返回用法错误——并且其处理函数调用 compactNow,而后者不接受策略,因此保留多少历史记录是由服务配置决定的,且在整个会话期间固定不变。它无法接受深度参数。
本捆绑包禁用该行,并以相同的命令名注册一个带参数的版本:
/compact 默认(medium)
/compact low 折叠可压缩历史中最旧的四分之一
/compact medium 一半
/compact high 四分之三
/compact max 测试框架所能接受的全部内容
该级别通过 compactRegion(start, end) 选择压缩回溯的距离——这是该接缝提供的唯一按调用可调的旋钮。使用级别而非 token 计数,是因为在不知道模型窗口和当前使用量的情况下,绝对预算毫无意义:同样的 4096 在 32K 模型上是“大部分”,而在 128K 模型上则“几乎不算什么”。
切割边缘来自测试框架自身的 toolPairingBalancedBefore / After 谓词,因此没有任何有效边缘能满足的切割会被报告,而不是被强制执行。此路径有两件事是 compactNow 会做而它不会做的:它无法将压缩标记为手动来源(它不接受 sourceCommandId),并且它不强制执行忙碌/空闲括号——compactRegion 会直接抛出异常。
该命令仅在 ctx.compaction 存在时挂载。 没有压缩引擎的组合会静默地推迟此插件:不会出现命令,也不会报错。
服务 API
注册 ctx.toolResultPruner。dsh-compaction-basic 通过其可选的 ctx.get('toolResultPruner') 查找来找到它,因此消费者无需更改——只有组合行不同。
pruneSession(session) 重写超出预算的 tool/result 表面节点:每个替换都通过 surfaceOp 和 sourceEventSeqs 引用被遮蔽的节点,前面是 compaction/prune 影子价格事件,并保留除 content 之外的每个字段。原始事件保留在仅追加日志中。
measureContent(blocks)、pruneContent(blocks) 和 config 与随附的契约一致。stats 是附加的。
配置
无法识别的键会在插件构造时失败。
| 键 | 必需 | 含义 |
|---|---|---|
| thresholdChars | 否(默认 8192) | 当合并文本超过这么多 Unicode 码点时进行修剪。 |
| headChars | 否(默认 4096) | 由 envelope 策略及其回退方案保留的前导码点。 |
| tailChars | 否(默认 1024) | 由 envelope 策略保留的尾随码点。 |
| strategy | 否(默认 semantic) | semantic 或 envelope。 |
即使在 semantic 下,headChars + marker + tailChars 也必须能容纳在 thresholdChars 之内,因为它们为回退路径提供参数。
用法
替换随附的行。要么将 cordis.patch.yml 作为捆绑包应用,要么将
同样的两处手动编辑:
移除随附的语法剪枝器——两者都注册 toolResultPruner。
- id: tool-result-pruner
disabled: true
- id: context-compressor-pruner
name: 'dsh-context-compressor'
config:
thresholdChars: 8192
没有 LLMLingua-2 sidecar 时,确定性语义策略会自行运行,这是受支持的默认方式,且不需要 Python。
附加模型(可选)
该接缝的入口点是同步的,因此无法在 pruneContent 内部进行模型调用。因此,模型输出会被预先计算到一个有界缓存中,并在剪枝时同步读取;冷区域会回退到确定性策略。
import { LlmlinguaSidecar, ModelCompressor } from 'dsh-context-compressor'
const sidecar = new LlmlinguaSidecar(ctx.subprocess, {
argv: [pythonPath, sidecarScript, '--device', 'cpu'],
cwd: pluginDir,
requestTimeoutMs: 120_000,
graceMs: 5_000,
})
prune.useModel(new ModelCompressor({ sidecar, params: { rate: 0.5 } }))
minRegionChars(默认 200)是决定 sidecar 是否值得其开销的调节参数。真实的工具结果会将其散文内容碎片化:在 138 个真实的超阈值结果中,一个 29 189 字符的结果包含 81 个可压缩区域,平均 141 个字符。按每次往返约 0.88 秒计算,逐个压缩这些区域将花费 73 秒来移除几百个字符。低于下限的区域会原样返回——不会被视为未命中——因此一段散文碎片永远不会迫使整个结果走确定性路径。
useModel 还会订阅 session/event,因此内容在落地时就会被压缩,下一次剪枝会发现一个热缓存。分离(useModel(undefined))会释放该订阅。
sidecar 是 Python 的,因此它必须能够访问到 llmlingua 安装:
python -m venv --system-site-packages .venv
.venv/Scripts/pip install llmlingua # POSIX: .venv/bin/pip
只有 compressible 区域会被发送到模型。 受保护区域会逐字节重建。
诊断
prune.stats
// {
// prunes, charsRemoved, declined,
// declineReasons: { 'no-budget', 'critical-over-budget', 'nothing-dropped',
// 'size-contract', 'quality-gate' },
// model: { hits, misses, warmed, failed, inferenceSeconds },
// }
declined 统计的是因剪枝会损坏受保护内容而保持原样的超预算结果。declineReasons 说明了原因,因为不同的原因需要采取相反的应对措施:
| 原因 | 含义 | 应对措施 |
|---|---|---|
| critical-over-budget | 仅强制内容就已超出预算 | 提高 thresholdChars——该配置不适合此工作负载 |
| quality-gate | 一次重写在选择后被拒绝 | 进行调查——这是缺陷信号,而不是调优信号 |
| no-budget | 阈值无法覆盖省略标记 | 提高 thresholdChars |
| nothing-dropped | 每个片段都适合或是强制内容 | 无 |
| size-contract | 重建未满足大小限制 | 调查 |
这一区分很重要:单纯的 declined 计数无法区分“你的阈值太小”和“选择器坏了”,而上一次调查还需要一个外部脚本来重建决策路径。
模型体验
修剪后的工具结果
模型按原始顺序看到保留的行,在内容被丢弃的位置有一个 [... tool result middle pruned ...] 标记;当模型路径处于热状态时,可压缩区域会显示为经过 token 压缩的文本。错误、路径、JSON 成员和命令均原样保留。
Token 影响
仍像之前一样受 thresholdChars 限制,但保留的预算花在信息上,而不是位置上。修剪在请求路径上不消耗模型调用;LLMLingua-2 推理提前进行,且仅针对超过阈值的内容。
KV 缓存影响
与已发布的修剪器相比没有变化:替换较早的结果会使从第一个变化的 token 开始的重用失效。由于此包丢弃的 token 与位置切片丢弃的 不同,二者在运行中的会话里不可互换——每次部署选择其一。
已知限制
- reference 行不保证保留。 当预算紧张时,路径和源位置可能被丢弃。这是分层设计的刻意代价;早先的全有或全无规则仅通过完全拒绝压缩来保留它们,而这会升级为摘要化。
- 压缩率低于已发布的修剪器。 在真实会话中为 1.9–3.9 倍,而后者为 3.1–7.0 倍。已发布的修剪器通过无论内容如何都丢弃固定的 4096–1024 字符窗口来达到其压缩率;差异恰恰在于它丢弃了什么。在默认 8192 阈值下,压缩率为 1.94 倍。
- 拒绝仍会升级。 当仅 critical 片段就超出预算时,内容将不被修剪,compaction-basic 可能回退到 LLM 摘要化。实测占超阈值结果的 1.4–3%,低于分层前的 55–64%,但并非为零。
- 行粒度。 单个超长行(压缩后的 bundle、200 KB 的 JSON 单行)是一个片段,无法通过评分部分保留;信封仍能处理它。
- 评分是启发式的。 src/score.ts 中的权重表达的是一种排序主张,而不是经过校准的模型。目前还没有与问题的相关性信号——该接缝没有向 pruneContent 传递任何可用于条件判断的问题。
- 区域级缓存粒度。 模型预热对每次修剪是全有或全无:一个冷区域会使整个内容走确定性路径,因此输出不依赖于缓存时序。
- 边车需要一个可用的 llmlingua 安装和约 900 MB 常驻内存。 权重是内存映射的(model_config={'low_cpu_mem_usage': True}),这正是使其可行的原因——没有它,同样的加载在 Windows 上会直接失败并报 OSError 1455。大部分占用并非模型本身:
~430 MB 是在接触任何权重之前 torch/transformers/llmlingua 的导入开销,而 709 MB 权重文件中的 367 MB 是一个 119k token 的多语言嵌入表。
- sidecar 的边际价值经过测量,而且很小。 这一点曾悬而未决;node benchmark/compare-model.mjs --threshold=8192 --rate=R 在真实会话上给出了结论。模型路径会替换整个结果,并且仍必须适配 thresholdChars,而受保护区域会逐字节重建。在 12 个真实的超阈值结果(98,092 个字符的确定性输出)上测得:
| rate | 采用 | 相对确定性的边际增益 |
|---|---|---|
| 0.5 | 0 / 12 | 0.0% |
| 0.3 | 2 / 12 | 4.0% |
| 0.15 | 5 / 12 | 9.5% |
在文档所述的 rate: 0.5 下,模型的输出每次都被丢弃:在该集合中最有利的结果上,649 个受保护字符和 11,852 个可压缩字符在压缩后仍总计 8,977,超出 8,192 阈值 785。只有激进得多的 rate 才能越过门槛,而在 0.15 下模型保留 15% 的 token——这是摘要级别的散文重写,正是该插件原本要避免的有损行为。代价是约 900 MB 常驻内存、约 14 秒的冷启动 torch 导入,以及每个区域约 0.5 秒。
确定性策略才是产品;sidecar 只是一个实验。
只有在使用你在自己语料上测量过的 rate 时才启用它。
- sidecar 显式使用 UTF-8,并且必须继续如此。 在 Windows 上,管道会继承 ANSI 代码页(此处为 cp936),因此宿主将 UTF-8 写入流,而 sidecar 将其按 cp936 解码,并以 cp936 回复一个按 UTF-8 读取的宿主。仅 ASCII 的测试数据无法发现这一点——两种编码在 ASCII 上一致——而症状(分词器错误、200 字符输入上 30 秒挂起)指向的是模型而非传输层。configure_streams() 正是防止该问题复发的手段;benchmark/probe-real-regions.mjs 是守卫,如果任何真实区域出现该问题,它就会失败。
许可证
MIT。接缝协议、影子价格契约以及移植的测试套件源自 MIT 许可的 @deepseek-ai/dsh-compaction-tool-result-pruner。