Token Usage(LLMDSHPlugin_token-usage)
DeepSeek Harness (DSH) 插件:在桌面端/Web 端侧边栏左下角增加 Token 统计。所有统计只读本机 Session 日志,不访问外部服务、不上传数据;除了历史总量和每日热力图,还能看到输入+输出、缓存读写、轮次/步骤和平均 tok/s,会话归档或删除后历史仍然保留。
仅本地 · 只读 · 不上传 · 不挑后端。
亮点
- 仅本地,安全:只读本机 Session 日志,不访问外部服务、不上传任何数据,也不修改 Session 或配置。
- 按实际用量:按 provider 上报的 usage 统计,不做字符数估算。
- 不挑后端:DeepSeek、GLM、Kimi 等只要在 Session 中留下 provider usage,就统一计入,不绑定单一模型或供应商。
- 安全可靠:账本用临时文件 + 原子替换写入,文件损坏时保留
.corrupt-*备份。 - 一眼看全:左下角常驻今日用量;面板第一行是全部历史总量,下面是 365 天 GitHub 风格热力图。
- 明细够用:每天可看总量、输入+输出、缓存读取、缓存写入和会话数。
- 不只 token:全部历史的轮次、步骤和平均生成速度(tok/s)。
- 删了也不丢:Host 把每个 Session 的日汇总持久化到
~/.dsh/token-usage-ledger.json,Session 归档或删除后历史仍然保留。 - 打开即用:优先本地缓存;自动刷新最快 1 小时一次,手动刷新立即重新扫描。
- 增量刷新:已归档的 Session 不重复扫描,只有 live 或新增 Session 重新读取;首次扫描后手动刷新通常秒回。
- 纯只读:不修改任何 Session 或配置;fork 继承的事件不会重复计数。
关键指标
- 按 provider 上报的 usage 统计,包含
inputTokens、outputTokens、cacheReadTokens、cacheWriteTokens。 - 不区分 provider:所有在 Session 中记录 usage 的模型/后端统一汇总。
- 中文界面下大数字用「万 / 百万 / 千万 / 亿 / 万亿」显示,悬停明细同时保留精确数字。
- 日历显示最近 365 天;顶部总量覆盖全部历史。
安装
要求 DSH Desktop / Web 已安装,且 profile 中已启用 @deepseek-ai/dsh-base。
从本地目录安装到 Desktop profile:
dsh plugin --profile desktop add D:\WORK\ai-v5\LLMDSHPlugin_token-usage
或直接从 GitHub 安装:
dsh plugin --profile desktop add github:ai-v5/LLMDSHPlugin_token-usage
安装后重启 DSH Desktop。插件会出现在左侧栏底部 Settings 上方(同一区域还有 Cordis 入口)。如果终端里没有 dsh 命令,可使用 DSH Desktop 安装目录下的 resources\runtime\cli\bin\dsh.cmd。
从旧的 LLMDSHPlugin monorepo 迁移:重新执行上面的
add命令指向本仓库,旧的plugins\token-usage链接会失效。
卸载:
dsh plugin --profile desktop remove llm-dsh-token-usage
统计口径
- 数据来自 DSH 的
ctx.sessionQuery:先listSessions(),再读取每个 Session 的完整事件日志。 - 每个
assistant/message或assistant/attempt的 provider usage 都会计入;同一 turn/step 的后续样本会替换前一样本,llm/retry-started之后的 attempt 单独累计。 compaction/summary自带的 usage 也会计入(压缩调用不在 agent loop 的 step 内,日志里只有这一条记录)。- 日期按 Host 本地时区划分。
totalTokens = inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens,其中包含 prompt cache 命中读取;面板同时展示不含 cache read 的inputOutputTokens。- 子 Session 与父 Session 都是独立 Session,会各自计入;fork 继承的前缀通过
inheritedEventCount排除。
接口
Host 端注册只读路由:
GET /api/llm-token-usage/stats?range=all&refresh=1
也兼容 ?days=7|14|30|90 的有界范围。返回:
{
"generatedAt": 1760000000000,
"days": 366,
"rangeKind": "all",
"seriesTruncated": false,
"range": { "from": "2025-10-19", "to": "2026-10-18" },
"today": { "date": "2026-10-18", "inputTokens": 0, "outputTokens": 0, "cacheReadTokens": 0, "cacheWriteTokens": 0, "totalTokens": 0, "inputOutputTokens": 0, "sessions": 0 },
"totals": { "...": "same shape as today" },
"allTime": { "...": "same shape as today" },
"series": [{ "date": "2025-10-19", "...": "same shape as today" }],
"sessionCount": 0,
"skippedSessions": 0,
"incomplete": false,
"activity": {
"turns": 0,
"steps": 0,
"generationMs": 0,
"timedOutputTokens": 0,
"tokensPerSecond": 0
}
}
activity 为全部历史汇总:turns/steps 来自 turn/start/step/start;tokensPerSecond = timedOutputTokens / (generationMs / 1000),只统计带流式时间戳的 Assistant 调用。
Host 结果缓存 1 小时;refresh=1 跳过缓存并重新扫描。浏览器端在 localStorage 缓存最近一次成功结果:面板打开时优先显示缓存,缓存不足 1 小时不发请求,超过 1 小时才后台刷新;手动刷新不受此限制。
已知限制
- AI 会话标题(session title)等辅助调用不写入 Session 日志,因此不会计入;如果部署把这些调用计费,面板总量会略低于账单。
- 读取失败的 Session 会被跳过,面板会显示
skippedSessions提示。 - 统计是 provider 上报 usage 的汇总,不是计费账单;不同 provider 对缓存读/写的上报口径可能不同。
- 首次打开或账本升级后需要完整扫描一次全部 Session 日志;之后只重读 live 或新增 Session,手动刷新通常秒回。
- 单个 Session 读取超过 15 秒,或整次扫描超过 45 秒,会跳过该部分并标记统计可能不完整,避免面板永久卡在刷新中。
- 插件首次成功扫描前就已经删除的 Session 无法追溯;删除
~/.dsh/token-usage-ledger.json会重置历史汇总。
开发
node --test tests/stats.test.mjs
node --check lib/stats.js
node --check index.js
node --check client.js
项目本身不需要构建:index.js 是 Host 半部,client.js 是浏览器半部,locale/*.json 提供插件管理页显示名称。
参考
设计上参考了 MIT 许可的 HaoyueQin/dsh-usage-statistics-panel 的按天口径与 footer 面板布局;本仓库代码是独立实现,没有复制其源码。
License
MIT
No comments yet. Be the first to write one.