Bundle
dsh-call-shrink
把 N 次 LLM 调用压成 1 次 —— DeepSeek Harness(DSH)的极致调用压缩插件:标题短路 + 飞行去重 + 24h 回放缓存 + 批量归并。
- Source
- zhuzichen362
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 6 days ago
Readme
# dsh-call-shrink
**把 N 次 LLM 调用压成 1 次 —— DeepSeek Harness(DSH)的极致调用压缩插件。**
[](https://dsh-plugin.org/plugins/zhuzichen362/dsh-call-shrink) · [GitHub](https://github.com/zhuzichen362/dsh-call-shrink)
> 一句话:在不改变对话结果的前提下,把「去重、缓存、批量归并」做到调用数维度的极限,直接砍掉冗余 API 调用 —— 省 token、省预算、省时间。
## 它解决了什么
在 DSH 这类「一个模型回合会同步发起多路独立子任务」的代理环境里,每一次 `llm/stream` 都是一次真实上游调用。并发会话、平行子代理、标题生成、重复工具流,都会产生大量内容相近甚至完全相同的请求。call-shrink 在 Stream 层拦截这些请求,用三层压缩把它们归并到最少的上游调用:
1. **缓存(Cache)** — 相同指纹的请求直接回放,24 小时 TTL、4096 条、落盘持久化。
2. **去重(Dedup)** — 飞行中的同指纹请求共享同一个上游结果。
3. **批量归并(Batch-Merge)** — 10 秒窗口内把 N 个独立请求拼成 1 次上游调用(**条数无上限、不按字符拆批**)。
外加两个「极端化」细节:
- **标题生成短路**:`purpose === 'title'` 直接返回空,0 次上游调用。
- **提示词注入**:向系统提示词挂入一条 API 经济性约束,让模型自己也会把可并行的工具调用一次发全。
## 特性
| 特性 | 说明 |
| --- | --- |
| ⚡ 极致归并 | 窗口 10s · 条数无上限 · 不拆批 · 单次输出上限 1 亿 token |
| 🧬 稳定指纹 | 规范化序列化(剔除 `sessionId`/`signal`/`id`/`tool_call_id`/`source`),跨会话命中相同工具流 |
| 🎯 协议化合并 | `[[TASK n]]` / `[[ANSWER n]]` 分隔 + JSON 应答;解析失败自动降级 STRICT MODE 重试 1 次 |
| 🛡 失败熔断 | 连续 2 次合并失败自动退化为单发,10 秒后复位 |
| 📊 实时面板 | 会话头「调用压缩」开关:今日用量/预算、单发+合并均摊、去重、缓存命中、省下的调用数 |
| 🧾 用量持久化 | 每日预算 500,跨重启记录每日与每会话用量 |
| 🔌 一键开关/重置 | `host.call` RPC:`state` / `session-stats` / `set-enabled` / `reset` |
## 工作原理
```
ctx.on('llm/stream')
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
title 短路 缓存命中(回放) 指纹去重(飞行中)
(0 次上游) (0 次上游) (0 次上游)
│
▼
剩余请求进入 10 秒归并窗口
│
▼
N 个请求 → 拼成 1 个上游流(任务分隔协议)
│
┌────────────┴────────────┐
▼ ▼
解析成功 解析失败
按 [[ANSWER n]] 拆回 STRICT 重试 → 仍失败
N 路原始流 逐个降级为单独调用
└────────────┬────────────┘
▼
全部写入 24h 回放缓存 + 用量统计
```
合并协议:一次上游调用中,每个待答任务用 `[[TASK n START]]…[[TASK n END]]` 包住完整对话,模型需在每个 `[[ANSWER n START]]…[[ANSWER n END]]` 之间输出恰好一个 JSON —— `{"kind":"text","text":"…"}` 或 `{"kind":"tool_calls","tool_calls":[…]}` —— 再按序拆回 N 路原始流。
## 安装(标准 DSH 插件包 · 推荐)
call-shrink 同时打包成符合 [DSH Plugin 规范](https://dsh-plugin.org/submit) 的标准插件(`package.json` 声明 `dsh.bundle`,由 profile boot 自动应用),可被 DSH 内置插件市场 / dsh.market 目录收录:
```sh
dsh plugin --profile web add dsh-call-shrink
```
或未发布 npm 前,从本仓库直接安装:
```sh
dsh plugin --profile web add https://github.com/zhuzichen362/dsh-call-shrink
```
重启 `dsh web`(桌面端请先把内置 dsh 更新到 0.1.0-rc.6 及以上),会话头会出现「调用压缩」状态点;服务端拦截逻辑在 `index.cjs`(内部加载 `src/host.js`),浏览器端在 `client.js`。
## 安装(动态 Cordis 插件 · 源码注入)
call-shrink 的原始形态是 DSH 的**动态 Cordis 插件**(`code.host` + `code.client`),源码即 `src/host.js` 与 `src/client.js`。
在 DSH 中让代理执行:
- `code.host` ← `src/host.js` 全文
- `code.client` ← `src/client.js` 全文
- 名称 / 用途(可选附带)
主机侧声明了 `inject: ['timer']`,并读取 `llm`、`fs`、`systemPrompt`、`harness` 等服务;服务缺失时安全降级、不影响运行。
## 调参(`src/host.js` 顶部「调参区」)
| 参数 | 默认 | 说明 |
| --- | --- | --- |
| `CACHE_TTL_MS` | `86400000` | 回放缓存有效期(24 小时) |
| `MAX_ENTRIES` | `4096` | 缓存条数上限 |
| `BATCH_WINDOW_MS` | `10000` | 归并收集窗口 |
| `MAX_BATCH` | `Infinity` | 单次合并条数上限 |
| `MERGE_COOLDOWN_MS` | `10000` | 合并连续失败后的熔断时长 |
| `MERGE_MAX_CHARS` | `Infinity` | 不再按字符拆批 |
| `MERGED_MAX_TOKENS` | `100000000` | 单次合并输出上限 |
| `DAILY_BUDGET` | `500` | 每日预算看板阈值 |
## 面板指标
- **今日** `api/budget`:是否超预算(绿 / 黄 / 红)。
- **本对话**:`steps`、API 次数(单发 `apiSingle` + 合并 `apiMerged`)、省 `steps-api`、去重 `dedup`、缓存命中 `cacheHit`、参与合并 `merged`。
- **全局**:`requests` / `upstream` / `dedup` / `cacheHit` / `batches(batched)` / `fallbacks` / `cacheEntries` / `restored`。
## 注意
- 批量归并改变了「并发独立请求各自一次调用」的形态,聚合上游输出依赖模型遵守协议;解析失败会自动降级,不会丢答案。
- 上游调用按 `1/N` 均摊计入参与合并的各会话。
- 缓存与用量写入工作目录的 `.dsh-shrink-cache.json` / `.dsh-shrink-usage.json`,已列入 `.gitignore`。
## License
[MIT](./LICENSE)Install
dsh plugin --profile web add github:zhuzichen362/dsh-call-shrink
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-call-shrink from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.