dsh-answer-timing
Per-answer timing breakdown: splits each reply into model, tool and other time, with first-token, decode and per-tool totals, and keeps a local JSONL ledger. Needs Node 24 or newer in the DSH runtime.
Install
dsh plugin --profile web add dsh-answer-timing
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
dsh-answer-timing


把「这次回答到底花了多少时间、花在哪」变成可查的数据。
给 DeepSeek Harness(DSH)用的耗时统计插件。
纯 host 端:不注入任何 client 代码、不改 UI,只旁听会话事件流。
输出长什么样
每次回答结束,末尾一行:
⚡ 本次 1m23s = 模型 58s(首字 1.2s · 生成 41s)+ 工具 19s(pwsh 12s · read 4s · grep 3s)+ 其它 6s
需要明细时(detail: true),给三张表:阶段构成 / 工具累计 / 逐步骤。
它算什么
对每一次回答(turn),拆成三段:
段 · 含义 · 来源
模型 · 思考 + 生成的总时间;内部再分「首字」和「生成」 · step/start → assistant/message
工具 · 每个工具的实际执行时间,按工具名累加 · tool/call → tool/result(按 callId 配对)
其它 · 总时长减去上面两项:调度、审批等待、排队 · turn 起止差 − 模型 − 工具
- 首字(ttft):从
step/start到这个 step 第一个推理/文本 chunk 的时间(读stream里的time0)。 - 生成(decode):首个 chunk 到
assistant/message落定的时间。 - 总时长:这一轮第一个带
data.turn的事件到最后一个事件的时间差。
安装
前置
- DSH
>=0.2.1-rc.2 <0.3.0 - Node.js
>=24
一条命令(从源码)
git clone https://github.com/liuzhihao-min/dsh-answer-timing cd dsh-answer-timing node install.mjs
脚本会做四件事(全部可重复执行,幂等):
1. <profile>/.dsh-answer-timing-source → 本仓库(Windows 用 junction,macOS/Linux 用 symlink)
2. <profile>/node_modules/dsh-answer-timing → 本仓库
3. dependencies["dsh-answer-timing"] = "link:.dsh-answer-timing-source"
4. dsh.profile.bundles 末尾追加 dsh-answer-timing
写 package.json 前会自动备份成 package.json.bak-<时间戳>。然后完全退出 DSH 再启动(改 profile 不热加载)。
常用参数:
参数 · 作用
--dry-run · 只打印将要做什么,不写文件
--profile web · 指定其它 profile(默认 desktop)
--dsh-home D:\x · 指定 DSH 目录(默认 ~/.dsh 或 $DSH_HOME)
--force · 目标位置是真实目录时,改名备份后继续
--uninstall · 卸载:摘掉 bundles / 依赖 / 两个链接
卸载时 DSH 必须先退出。 否则 node_modules 里的链接被占用删不掉(脚本会警告并跳过,注册信息仍会清干净,退出后再跑一次即可)。
从 npm 安装
包已发布: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 再启动。
两种来源的区别
来源 · 命令 · 要 junction 吗 · 适合
npm · npm install dsh-answer-timing · 不用 · 只想用,不打算改代码
源码 · git clone + node install.mjs · 要(脚本自动建) · 想改代码、跟着仓库更新
手动注册(不想跑脚本时)
# 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 再启动(改 profile 不会热加载)。
验证
对话里问一句「刚才那轮花了多久」,或直接调用 timing_report。
工具存在即安装成功;~/.dsh/timing/turns.jsonl 会在第一轮结束后出现。
使用
工具:timing_report
参数 · 说明
scope · last(默认)/ turn / session / turns
turn · 指定轮次(配合 scope: "turn")
limit · scope: "turns" 取最近几条,默认 10
detail · true 时给「阶段构成 / 工具累计 / 逐步骤」三张表
配套技能 answer-timing 会让 agent 在每次回答末尾自动附上那一行。
落盘与隐私
- 路径:
$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"读落盘账本。 - 这是观测插件:不改变任何调度、超时或重试行为。
目录结构
.
├── index.js # 插件入口:订阅事件 + 注册工具
├── install.mjs # 安装/卸载脚本(幂等,自动备份 package.json)
├── cordis.patch.yml # bundle 插入声明
├── lib/
│ ├── fold.mjs # 纯函数:事件流 → 逐轮耗时
│ ├── format.mjs # 单行摘要 + 三张明细表
│ └── store.mjs # JSONL 账本(去重、保留期)
├── test/
│ └── fold.test.mjs # node:test,9 个用例
└── .github/workflows/
└── test.yml # CI:ubuntu + windows × node 24
开发与测试
node test/fold.test.mjs
用node --test在某些受限沙箱里会因子进程spawn EPERM失败,直接执行测试文件即可(node:test在进程内跑)。
调试插件加载:设DSH_ANSWER_TIMING_DEBUG=1,启动时会往 stderr 打一行[answer-timing] loaded。
兼容性
依赖 DSH 的会话事件字段(step/start、assistant/message、tool/call、tool/result、turn/end)。
这些是 DSH 的内部接口,随版本可能变动;升级 DSH 后若数字异常,先在这里排查字段名。
许可
MIT
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::3,最后更新 2026-10-24