前言¶
DeepSeek Harness(DSH)在模型推理、工具调用等环节的耗时往往混杂在一起,开发者难以从单次会话中判断「哪一段花了多久」。常见的做法是凭感觉调整超时、重试策略,或通过日志人工统计,效率低且容易遗漏细节。
这里介绍一个给 DSH 用的耗时统计插件:dsh-answer-timing。它不注入任何客户端代码,也不改动 UI,只旁听会话事件流,把一次回答拆成「模型」「工具」「其它」三个阶段,并给出明细。
它是什么¶
dsh-answer-timing 是一个纯 host 端的 DSH 插件,由维护者 liuzhihao-min 维护,分类为「模型推理」。它通过订阅 DSH 内部事件(step/start、assistant/message、tool/call、tool/result 等),计算每轮回答的耗时分布,并提供工具 timing_report 和技能 answer-timing,方便查询与落盘。
核心功能¶
耗时分段¶
对每一次回答(turn),拆成三段:
| 段 | 含义 | 来源 |
|---|---|---|
| 模型 | 思考 + 生成的总时间;内部再分「首字」和「生成」 | step/start → assistant/message |
| 工具 | 每个工具的实际执行时间,按工具名累加 | tool/call → tool/result(按 callId 配对) |
| 其它 | 总时长减去上面两项:调度、审批等待、排队 | turn 起止差 − 模型 − 工具 |
- 首字(ttft):从
step/start到这个 step 第一个推理/文本 chunk 的时间(读stream里的time0)。 - 生成(decode):首个 chunk 到
assistant/message落定的时间。 - 总时长:这一轮第一个带
data.turn的事件到最后一个事件的时间差。
输出示例¶
每次回答结束,末尾一行:
⚡ 本次 1m23s = 模型 58s(首字 1.2s · 生成 41s)+ 工具 19s(pwsh 12s · read 4s · grep 3s)+ 其它 6s
需要明细时(detail: true),给三张表:阶段构成 / 工具累计 / 逐步骤。
工具:timing_report¶
| 参数 | 说明 |
|---|---|
scope |
last(默认)/ turn / session / turns |
turn |
指定轮次(配合 scope: "turn") |
limit |
scope: "turns" 取最近几条,默认 10 |
detail |
true 时给「阶段构成 / 工具累计 / 逐步骤」三张表 |
技能:answer-timing¶
配套技能 answer-timing 会让 agent 在每次回答末尾自动附上那一行。
安装与启用¶
前置要求¶
- DSH
>=0.2.1-rc.2 <0.3.0 - Node.js
>=24
最快:一条命令¶
推荐使用 npm 源(国内网络环境更稳定):
dsh plugin --profile <你的 profile> add dsh-answer-timing
或者直接把仓库地址给它:
dsh plugin --profile <你的 profile> add https://github.com/liuzhihao-min/dsh-answer-timing
两种写法底层都是 pnpm,装完会读取包里的 dsh.bundle 清单,自动把包写进 dsh.profile.bundles——不需要手动改 package.json,也不需要建 junction。然后完全退出 DSH 再启动。
桌面版 profile 名一般是
desktop,Web 版是web。
从源码安装(想改代码时)¶
git clone https://github.com/liuzhihao-min/dsh-answer-timing
cd dsh-answer-timing
node install.mjs
脚本会做四件事(全部可重复执行,幂等):
<profile>/.dsh-answer-timing-source→ 本仓库(Windows 用 junction,macOS/Linux 用 symlink)<profile>/node_modules/dsh-answer-timing→ 本仓库dependencies["dsh-answer-timing"] = "link:.dsh-answer-timing-source"dsh.profile.bundles末尾追加dsh-answer-timing
写 package.json 前会自动备份成 package.json.bak-<时间戳>。改完同样要完全退出 DSH 再启动。
常用参数:
| 参数 | 作用 |
|---|---|
--dry-run |
只打印将要做什么,不写文件 |
--profile web |
指定其它 profile(默认 desktop) |
--dsh-home D:\x |
指定 DSH 目录(默认 ~/.dsh 或 $DSH_HOME) |
--force |
目标位置是真实目录时,改名备份后继续 |
--uninstall |
卸载:摘掉 bundles / 依赖 / 两个链接 |
卸载时 DSH 必须先退出。 否则
node_modules里的链接被占用删不掉(脚本会警告并跳过,注册信息仍会清干净,退出后再跑一次即可)。
从 npm 手动安装(不用 dsh plugin add 时)¶
包已发布:dsh-answer-timing。
在当前 profile 目录(桌面版一般是 ~/.dsh/profiles/desktop)里装:
cd ~/.dsh/profiles/desktop
npm install dsh-answer-timing
然后在同一个 package.json 里补两处:
{
"dependencies": {
"dsh-answer-timing": "^1.0.0" // ① 依赖
},
"dsh": {
"profile": {
"bundles": [
"dsh-answer-timing" // ② 末尾追加这一项
]
}
}
}
从 npm 装的不用建 junction —— 包已经在 node_modules 里了。install.mjs 是给源码目录用的。改完同样要完全退出 DSH 再启动。
手动注册(不想跑脚本时)¶
# 1. 目录联接(换成你自己的实际路径)
cmd /c mklink /J "$env:USERPROFILE\.dsh\profiles\desktop\.dsh-answer-timing-source" "D:\plugins\dsh-answer-timing"
cmd /c mklink /J "$env:USERPROFILE\.dsh\profiles\desktop\node_modules\dsh-answer-timing" "D:\plugins\dsh-answer-timing"
// 2. package.json → dependencies 里加一行
"dsh-answer-timing": "link:.dsh-answer-timing-source"
// 3. package.json → dsh.profile.bundles 末尾追加
"dsh-answer-timing"
然后完全退出 DSH 再启动。
验证¶
对话里问一句「刚才那轮花了多久」,或直接调用 timing_report。工具存在即安装成功;~/.dsh/timing/turns.jsonl 会在第一轮结束后出现。
落盘与隐私¶
- 路径:
$DSH_HOME/timing/turns.jsonl(未设DSH_HOME时用~/.dsh/timing/turns.jsonl) - 一行一个 turn,按
sessionId + turn去重 - 只存:时间戳、各段毫秒数、输出 tokens、工具名、模型名
- 不存:提示词、回答正文、工具参数、任何对话内容
- 默认保留 30 天(读取时按
retentionDays过滤,不改写文件)
配置¶
| 键 | 默认 | 说明 |
|---|---|---|
dataDir |
空 | 自定义落盘目录 |
retentionDays |
30 | 历史保留天数 |
maxTurnsInMemory |
200 | 每会话内存里保留多少轮 |
口径与限制¶
- 一个 step 若产生多条
assistant/message(重试/多次 attempt),只记最后一次,其余不累加。 - 没有
step/start锚点的 step 不臆造耗时,只计入untimedSteps,这样能和官方sessionStats的口径对上。 - 工具审批等待发生在
tool/call与tool/result之间,因此算进「工具」而不是「其它」。 - 子代理是独立 session,各自统计;主会话里 subagent 调用的等待算在主会话的「工具」。
- 宿主重启后,内存里的逐轮状态从零开始;历史请用
scope: "turns"读落盘账本。 - 这是观测插件:不改变任何调度、超时或重试行为。
适用场景与注意¶
- 适合需要精细化分析模型推理耗时、工具调用成本、整体会话延时的场景。
- 插件以当前 DSH 进程权限运行,安装前建议阅读源码与许可证。
- 兼容性依赖 DSH 的会话事件字段(
step/start、assistant/message、tool/call、tool/result、turn/end),这些是内部接口,随版本可能变动。
短结尾¶
通过 dsh-answer-timing,可以把「这次回答到底花了多少时间、花在哪」变成可查的数据,方便持续优化推理与工具调用的成本。目录页与 GitHub 仓库见下:
- https://www.skillhub.cn/plugins/liuzhihao-min/dsh-answer-timing
- https://github.com/liuzhihao-min/dsh-answer-timing