前言¶
在 DeepSeek Harness(DSH)里跑长工具时,agent 循环会卡在 bash、job_output、wait_agent 等调用上,这段时间里会话往往不再向模型发请求。若上游提供商的 prompt cache 在这段时间内过期,工具返回后下一轮对话会按 cache miss 计费,并重新预填动辄数万 token 的前缀,TTFT 也会拉长。
常见做法是空闲会话也周期性 ping 模型保活,但维护者在实测中发现:多数会话并不会被再次打开,这类 idle warming 反而净亏。dsh-warm 把 warming 收窄到「仅在工具阻塞期间」执行,并配合按提供商配置的 TTL 网格、日志与 UTC 日预算,在可核对的数据下做成本与延迟权衡。
这是什么¶
dsh-warm 是 DSH 的 host 插件(分类:模型推理),由 JanEickholt 维护,当前 npm 包版本为 0.2.0(MIT)。它在会话的 agent 循环 阻塞在工具执行内部 时,在提供商 cache 即将过期前,把该会话 最后一次对话请求 经宿主 llm/stream waterfall 以 maxTokens: 1 重放一次,丢弃 1 token 响应,使工具结果仍落在温热的前缀上,后续真实请求可走 cache hit。
空闲会话与用户输入类工具(如 ask_user_question)不会被 warming。
核心功能¶
仅在工具阻塞时 warming¶
TTL 因提供商而异(维护者在其环境中对 Mistral 等做过 live probe)。工具或队友等待结束后循环会立刻继续,因此只在阻塞窗口内 ping 在维护者 50 天账本、350 会话的样本里表现为正收益;对从未恢复的 idle 会话做 warming 在该样本中为净负。
重放保持字节一致¶
循环构建的请求在进入 llm/stream 时已深冻结。warmer 捕获该对象,稍后发送浅拷贝,仅改 maxTokens: 1 与 signal(与用户中断链式 AbortSignal.any)。同一 adapter 序列化 ping,输入前缀与真实调用一致,提供商可从 cache 命中。ping 走完整 waterfall,dsh-cost-meter 会像普通调用一样记账。
按提供商调度与预算¶
providers 表按提供商配置 intervalMs、ttlMs、marginMs 等;有 ttlMs 时按过期锚点调度(例如在测得 302 s TTL、60 s margin 下约每 242 s ping)。内置 mistral、openai、anthropic 默认项;deepseek 默认不列入(disk cache 时长不确定,盲目 ping 易浪费)。支持 dryRun、每工具块 maxPings、dailyPingBudget(UTC 日)、maxConcurrentPings、excludeTools、minPrefixChars 等。
统计与 HTTP 快照:stats.enabled 时写 stats.json,并提供 /api/dsh-warm/stats。
安装与启用¶
插件以当前 DSH 进程权限运行;安装前请自行查看 GitHub 源码 与许可证。需要 Node.js >= 20。
从 npm 或 GitHub 安装(命令来自官方 README):
dsh plugin --profile web add dsh-warm # from npm
dsh plugin --profile web add github:JanEickholt/dsh-warm # from GitHub, no npm needed
本地 link 方式:在 profiles/<profile>/package.json 的 dependencies 中加入 "dsh-warm": "link:/absolute/path/to/dsh-warm",并在 dsh.profile.bundles 中加入 "dsh-warm",在 profile 目录执行 pnpm install,再从终端重启 harness(例如 systemctl --user restart <your-dsh-unit>)。不要在会话内触发重启。插件的 cordis.patch.yml 会自动插入 loader 行,一般无需手改 cordis.patch.yml。
配置¶
首次加载会写入默认配置;编辑后需重启。路径:
$DSH_HOME/storages/dsh-warm/config.json
示例(字段含义见 README 表格):
{
"enabled": true,
"dryRun": false,
"maxPings": 5,
"providers": {
"mistral": { "intervalMs": 240000, "ttlMs": 302000, "marginMs": 60000 },
"openai": { "intervalMs": 240000, "ttlMs": 300000, "marginMs": 60000 },
"anthropic": { "intervalMs": 240000, "ttlMs": 300000, "marginMs": 60000 }
},
"excludeTools": ["ask_user_question"],
"minPrefixChars": 12000,
"maxConcurrentPings": 2,
"dailyPingBudget": 300,
"pingTimeoutMs": 90000,
"stats": { "enabled": true }
}
首次部署可设 dryRun: true,通过 journal 观察 would-be ping,再改为正式派发。日志与预算数据位于 $DSH_HOME/storages/dsh-warm/。
典型用法¶
无需在会话里单独调用 API:启用插件并配置 providers 后,当 agent 在长工具阻塞中且前缀长度不低于 minPrefixChars、提供商在表中、工具不在 excludeTools 时,warmer 自动按调度发 ping。
若使用 README 未列出的提供商或代理,应先实测 TTL,再添加类似 "opencode-go": { "intervalMs": 120000 } 的条目;空 {} 仅对三个内置已知提供商采用默认规则,未知名称会 warn 并丢弃。
适用场景与注意¶
适合:经常跑长 bash、等待子 agent 或 job_output,且对话前缀较大、提供商对 prompt cache 有 TTL 与 hit 折扣的 DSH 部署。
注意:
- 插件不是 DeepSeek 或幻方官方组件;社区目录 SkillHub 条目 为独立站点。
- 成本取决于你的提供商定价与前缀规模;README 给出了维护者环境下的量级说明(例如某提供商 hit 相对 miss 的折扣、单次 ping 与前缀 token 的关系),你的账户需自行核对。
dailyPingBudget与maxPings用于限制 tail 风险;pingTimeoutMs可中止卡住的流。- 调试可开
debug,事件写入storages/dsh-warm/debug.jsonl。
结尾¶
dsh-warm 把 prompt-cache warming 限定在工具阻塞窗口,用 1 token 重放保持前缀一致,并配合 per-provider TTL、journal 与 UTC 日预算,面向 DSH 长工具场景下的 cache miss 与 TTFT 问题。进一步了解可看目录页与仓库:
- https://www.skillhub.cn/plugins/JanEickholt/dsh-warm
- https://github.com/JanEickholt/dsh-warm