360 Secure SkillHub
360 安全技能中心

Token Usage Tracker

该技能读取 WorkBuddy 客户端落盘的本轮 LLM 调用 trace 文件,聚合每次回答的输入/输出/缓存 token 与耗时,结合本地价格表估算费用,并通过 Windows 系统通知或回复末尾文本展示;附带 DeepSeek 余额查询与每日价格刷新,需 Node.js 运行并手动配置 hooks。

abc1317679842-ui
abc1317679842-ui
热度 18.85
最近更新 2026-08-06 13:03:48
分类:数据依赖:代码执行 / 读写文件 / 第三方 API应用场景:报告撰写 / 数据处理 / 自动化脚本

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add workbuddy-token-tracker
Metadata
name
token-usage-tracker
description
在每次回答后显示真实 token 消耗与耗时。【仅适配 WorkBuddy 桌面客户端(Windows),不适用于其他 AI 工具/平台——数据源是 WorkBuddy 每轮调用后落盘的 trace 文件,依赖其 hooks 机制】WorkBuddy 客户端不显示 token(内置模式只显示积分、自有 API 模式也不显示),但每轮 LLM 调用结束都会把真实 token/耗时落盘成一个新 trace 文件(~/.workbuddy/traces/<pid>/trace_*.json)。本技能读取该数据,在每次最终回复的最后单独一行附上「耗时 + 输入/输出 token」。当用户说「显示 token」「看消耗」「这次用了多少 token」「统计用量」或任何希望看到每次回答成本时触发。
type
skill

Token Usage Tracker(每轮 token 消耗追踪)

环境要求(新用户先看)

  • 仅适配 WorkBuddy / CodeBuddy 桌面端(Windows 10/11):本技能的数据源是客户端落盘的 ~/.workbuddy/traces/<pid>/trace_*.json(每轮模型调用结束自动生成)+ 客户端 hooks 挂载点——其他 AI 工具/平台(Claude Code、Cursor、ChatGPT 桌面版、其他 OpenClaw 客户端等)没有这套机制,装上也不会工作,请勿在其他环境安装。
  • Windows 10/11:系统通知(toast)仅 Windows 支持;macOS/Linux 可正常手动使用(方式 A),但不弹通知。
  • Node.js ≥ 20:脚本零依赖单文件,无需 npm install。

安装与启用(新用户必读:装完必须配 hooks 才自动弹通知)

从技能市场安装 = 文件拷入 skills 目录,不会自动挂 hook。请让 WorkBuddy 助手帮你把下面配置合并进 settings.json(或手动添加):

{
  "hooks": {
    "UserPromptSubmit": [
      { "matcher": ".*", "hooks": [ { "type": "command", "command": "node <技能目录>/token-tracker.js --hook" } ] }
    ],
    "Stop": [
      { "matcher": ".*", "hooks": [ { "type": "command", "command": "node <技能目录>/token-tracker.js --stop" } ] }
    ]
  }
}

<技能目录> 替换为实际安装路径(如 C:/Users/你的用户名/.workbuddy/skills/token-usage-tracker)。效果:

  • 挂好 Stop hook → 每轮回答结束自动弹「本条消耗」Windows 通知(核心体验)
  • 挂好 UserPromptSubmit hook → 下轮提问时自动注入上一轮用量
  • 不挂 hooks 也能用:手动运行 node <技能目录>/token-tracker.js --stop 查看最近一轮消耗(方式 A)
  • 不需要通知:只删 Stop 段即可,其余功能不受影响

为什么需要

WorkBuddy 客户端 UI 不显示每轮对话的 token 用量:内置模型只显示「积分」,自有 API 模式也不展示 token。但平台在每次模型调用整轮结束后都会把真实用量写进一个新的 traces/<pid>/trace_*.json(含 totalTokens / totalInputTokens / totalOutputTokens / totalCachedTokens / duration / startedAt / endedAt)。本技能把这些数据读出来,让你每轮都能看到真实消耗。

触发条件

  • 用户明确要求看 token / 消耗 / 用时
  • 或作为默认习惯:每次生成最终回复时,都在末尾附上最近一轮用量

使用方式(两种,任选/并用)

方式 A:手动(技能指令驱动,最贴合「回复末尾」)

在生成最终可见回复时,先运行读数脚本,把其输出作为回复的最后单独一行:

node ~/.workbuddy/skills/token-usage-tracker/token-tracker.js

脚本输出形如: GLM-4.6V | 耗时 3m 43s | 输入 287.9万 / 输出 1.2万 tokens(该轮累计 289.1万,缓存命中 287.2万)

模型名完整显示(去括号说明,不截断);未识别到模型名时省略模型段。数字自动用「万/亿」单位(保留 1 位小数),低于 1 万显示原值,方便速读。

把这行原样贴在回复最末尾(独占一行,前面空一行与其它内容隔开)。2026-08 起以系统通知(方式 C)为准:每次回答结束 Stop hook 已自动弹「本条 Token 消耗」通知,回复末尾的「上一轮」行时效性差且冗余——默认省略;仅在用户明确要求("贴一下用量/这次用了多少")时才运行脚本贴出。

方式 B:自动(hook 注入,不依赖记得)

settings.json 的 hooks.UserPromptSubmit 已挂接本技能的 --hook 模式,会在你提交下一轮时自动把「上一轮」的 token 注入上下文,无需手动跑脚本。

方式 C:Stop 事件 + Windows 系统通知(目标:本条回答显示本条消耗与费用)

WorkBuddy 是 Claude Code fork,支持 Stop 事件(回答结束后触发)。settings.json 的 hooks.Stop 已挂接本技能 --stop 模式:回答结束时本轮 trace 已落盘(实测 Stop 比落盘早 ~15ms,脚本会轮询等待最多 3 秒),读到最新文件即为本条回答的精确统计,然后:

v2.19(2026-08-06 修复):旧逻辑只在 sameRound || !snap 时等待;若入口文件恰是"另一个旧文件"(如会话起标题的 terminalTitleGenerator 小 trace)且 ≠ 快照文件,会被误判为"本条"直接弹 toast(曾把 744 tokens 当成本轮展示,真实 122.3 万)。现改为:入口文件非"刚落盘"(≤1s)时一律轮询等待"比入口更新的有效 trace"(≤3s);超时且入口明显是旧文件(落盘 >3s 前)→ 标"上一轮"不冒充本条。备份:token-tracker.js.bak-20260806。

v2.20(2026-08-06,完整消耗聚合):一个用户轮次会落盘多个 trace(起标题内部调用 + 主任务,实测 744 + 122.3 万),v2.19 仍只取最新一个——用户明确要求完整数据。现增加整轮聚合:--hook(用户提交时)把本轮起点时间戳 lastUserMsgAt 写入快照;--stop 聚合「起点之后、同 pid 目录、(无 sessionId 的内部调用 或 sessionId 与 Stop payload 一致)」的全部有效 trace,累加 in/out/cached/total,耗时 = 窗口内最早 startedAt → 最新 endedAt;无起点记录(手动运行)退化为单 trace(v2.19 行为)。快照保存时保留 lastUserMsgAt。备份:token-tracker.js.v2.19-20260806。

v2.21(2026-08-06,多会话并发快照隔离):v2.20 的 .snapshot.json 是全局单文件、不带 sessionId,hook matcher 为 .* 全局触发——同时开多个会话时,后提交的会话会把 lastUserMsgAt 覆盖成自己的时间 → 先结束的会话 Stop 聚合起点错乱(用户问"多任务并发时 token 计算是不是没用了")。现改为快照按 session_id 拆分:hook/stop 都从 payload 读 session_id(WorkBuddy 所有 hook payload 均带此字段,实测/官方文档确认),有 sid → .snapshot-<sid>.json(各会话隔离);无 sid(手动运行)→ 全局 .snapshot.json(行为不变)。sid 来自外部 payload,只留 [a-zA-Z0-9_-] 防路径注入。备份:token-tracker.js.v2.20-20260806。验证:隔离测试 7/7 通过(A/B 双会话互不覆盖、起点先后正确、手动全局快照兼容、单会话聚合回归)。已知限制(P1 沿用):无 sessionId 的内部调用(起标题等)在同一 pid 目录同时活跃多会话时无法归属会话,理论上会串入窗口内的其他会话——仅限"同进程多会话真并发",日常单会话/顺序多会话不受影响。

v2.22(2026-08-06,内部调用按最近主任务归属):v2.21 遗留 P1——无 sessionId 的内部调用(起标题等)只看"起点之后",B 会话在 A 任务中途提交时,A 的内部调用时间戳落在 B 起点之后会被 B 误收。用户洞察:"各会话任务结束时间不可能在同一秒"。现改为最近主任务归属:对无 sessionId 的内部调用,找到时间距离最近的主任务 trace(有 sessionId 的,窗口内距离=0,否则取端点最近者),归属该会话;只有归属本会话的才累加。这样利用任务时间线天然分隔并发会话,比"±N 秒容差窗口"精确。备份:token-tracker.js.v2.21-20260806。验证:隔离测试 10/10 通过(含核心 S4:真并发交错时 A 的内部调用归 A、B 不误收;S5 反向验证)。剩余极限:两个会话的内部调用与各自主任务时间线完全重合(同秒级真并发)时仍无法区分——数据源无 sessionId 标记,属平台限制。

  • Windows 系统通知(toast,两行,Windows 通知默认只显示两行):调用 PowerShell WinRT Toast API 弹出
    DeepSeek-V4 Flash | 高峰 | 4m 26s 余额¥2.77
    输入 391.2万 / 输出 1.9万|缓存99.74%|¥0.25
    
    ——布局原则(避免 ToastText02 正文超长自动换行变 3 行;v2.6 起行1 带时段标注、行2 去「约」字、v2.7 输入/输出写完整、v2.8 余额移至行1、v2.11 余额紧跟时间、v2.15 去「¥」符号、v2.16 分隔符全角→半角、v2.17 实测上限 47u + 分隔符两侧加空格、v2.18 恢复「¥」符号):行1 = 模型完整名(去括号说明,不截断)** | 时段标注 | 耗时 + 余额¥X(耗时↔余额 1 空格)。⚠️ v2.17 实测修正(关键):行1 标题大字真实上限 = 47u**——用户弹 5 个通知逐步加空格定位:测试四(模型名后 4 空格=47u)不换行、测试五(5 空格=48u)换行 → TOAST_ROW1_MAX_W=47(此前 42u 是保守估算,低估 5u;放宽后分隔符两侧可加空格提升可读性)。时段标注 periodNote():模型声明 peak_multiplier>1(DeepSeek 原厂系=2)且当前在高峰时段(工作日 9-12/14-18)→ 高峰(两字,v2.14 用户拍板:不带 ×N;v2.12「峰×N」太简被否、v2.13「高峰×N」实测 1 分钟+耗时余额必丢被否);其余模型统一定价不显示;预留 night_discount 夜间折扣字段。耗时保持 1m 40s 单位格式(用户要求,不压缩;分钟可为 2-3 位如 12m/123m,fmtDur 上限 999m 59s=9u)。v2.17 分隔符规则(定稿):半角 |(dispWidth 1u,禁止全角「|」2u),两侧各 1 空格——模型名 | 时段 | 耗时(用户反馈"模型名和分隔符挨太近像一体",加空格后 DeepSeek-V4 Flash | 高峰 | 12m 34s 余额¥123.45);无时段 → 模型名 | 耗时;余额带「¥」符号(v2.18 恢复:实测上限 47u 后空间充裕,峰值场景 45u+1u=46u 仍有富余;v2.15 曾去符号省宽度)。极限宽度矩阵(v2.18 定稿验证,上限 47u):高峰场景 12 组合 9 个 ≤47u 含余额(用户峰值场景"12m 34s 几十分钟+余额¥123.45 上百块"=46u ✅;1m 40s+万位=47u 卡线;仅"长耗时+万位余额"丢,现实不存在);无高峰最坏 42u。行2 = 输入 X / 输出 Y|缓存NN.NN%(两位小数)|¥费用(不带「约」字,未收录显示「未收录」;行2 保持全角「|」正文小字视觉统一,有空间)。余额放行1:行2 在 输入/输出+缓存+费用 后已无空间(实测约 49u/上限 52u),追加余额会折叠变 3 行。布局演进(用户多轮实测纠正):v2.8 行2 追加 → 折叠;v2.9 行1 对齐行中线 → base 长时 pad=1 贴死;v2.10 剩余空间居中 → 标题大字超宽变 3 行;v2.11 紧跟时间 + 行1 上限 42u(保守);v2.15 去「¥」;v2.16 全角「|」→半角 |(省 2u);v2.17 用户弹 5 通知实测极限 47u → 上限放宽 + 分隔符两侧加空格;v2.18 恢复「¥」符号(用户:极限有富余就加回)。宽度压力测试(用户要求算极端,含时间变长维度):行1 标题大字上限 47u(v2.18 高峰 43-47u / 无高峰 34-42u);行2 正文双千万级(1e8 以下最坏 10000万)输入+输出 + 缓存99.99% + 价格 ¥3000 级 = 49u / 上限 52u,余 3u + 保护兜底(丢缓存占比);行1 超宽(长模型名)余额自动让位不折叠。说明:Windows toast 第二行默认即「正文小字号」(ToastText02=标题大字+正文小字);更小字号(Caption)需 AdaptiveGroup+HintStyle 自定义 XML(Win10 周年更新+),兼容性有风险,暂未采用。这是当前唯一确认有效的"本条可见"通道(UI 内 systemMessage 通道实测不显示,已放弃)。
  • 时段折扣数据(2026-08-05 搜索核验):目前仅 DeepSeek 原厂系有峰谷定价(V4 起推出,工作日北京时间 9-12/14-18 高峰,所有计费项 ×2,含缓存价;原因=算力挤兑削峰填谷;2025 年的「夜间错峰优惠」已被高峰溢价模式取代)。智谱 GLM / MiniMax / Kimi / 混元均为统一定价无峰谷;小米 MiMo 是 2026-05 永久降价 99%(非时段折扣)。新模型自动补录时默认 peak_multiplier:1,提示里会要求搜索核验时段折扣策略。
  • 仍同时输出 hookSpecificOutput.systemMessage(保留,若未来平台支持即生效,无副作用)。
  • 探针 .stop-probe.json 记录每次触发:sameRound=false+waited=ok = 成功拿到本条;waited=timeout = 3 秒内 trace 未落盘,退化为「上一轮」且不弹通知。
  • 若用户不需要系统通知,可删除 settings.json 中 hooks.Stop 配置(--hook/手动模式不受影响)。

费用估算(pricing.json + 高峰时段 + 每日自动刷新)

  • 模型名读取:trace.modelInfo.models[0](空壳 trace 从 spans 的 toolOutput[].model 取);带厂商前缀的模型名(如 moonshotai/kimi-k2.7-code、deepseek/deepseek-v4-flash)由 findModel() 做包含匹配,自动落到本地 key。
  • 价格缓存:~/.workbuddy/skills/token-usage-tracker/pricing.json(官方人民币价:输入/缓存命中输入/输出,元每百万 tokens;peak_multiplier 高峰倍率;or_id 关联 OpenRouter 模型 id;usd_input_price/usd_output_price 为自动刷新写入的 USD 参考价)。
  • 已收录模型(2026-08-04 官方定价页 + OpenRouter 交叉核对):deepseek-v4-flash(1/0.02/2,峰谷×2)/v4-pro(3/0.025/6,峰谷×2)/v3.2/v3.1/r1、glm-5.2(8/2/28)/5.1(8/2/28)/5-turbo(7/1.8/26)/5(6/1.5/22)/5v-turbo(8.6/1.7/28.8)/4.7/4.7-flash(免费)、kimi-k3(20/2/100)/k2.7-code(6.5/1.3/27)/k2.7-code-highspeed(13/2.6/54)/k2.6(6.5/1.1/27)/k2.5(4/0.7/21)、minimax-m3(≤512k 标准 4.2/0.84/16.8,>512k 翻倍,促销五折 2.1/0.42/8.4)/m2.7(2.1/0.42/8.4)、hy3(1/0.25/4)/hy3-preview/hunyuan-a13b。
  • 新模型自动补录(用户要求"检测到未收录模型立即联网查"):trace 读到未收录模型(pricing.json 无匹配且无 input_price)时,token-tracker.js 自动执行:
    1. 立即联网查 OpenRouter(openrouter.ai/api/v1/models,无需 key)按模型名精确/包含匹配;
    2. 找到 → 按 USD×汇率(7.2)补入 pricing.json(auto_converted: true,缓存价按输入 10% 估算,标 note "待人工核验官方价"),同时 hook/手动输出附提示「已自动补录估算价」;
    3. OpenRouter 确认无此模型 → 记入 pricing._lookedup_models(同一模型当天不再重复联网),输出提示「请用 unified-search 搜官方定价页补录」;
    4. 联网失败 → 不记已查(下次重试),输出提示「联网查价失败」。
    • 维护原则:不追求收录所有模型,只维护应用内置 + 用户常用模型;新模型由上述自动补录 + 人工核验(unified-search 搜厂商官方定价页)补齐。
  • 高峰时段(仅 DeepSeek 原厂系):北京时间 9:00-12:00、14:00-18:00 价格翻倍;其余模型无峰谷。
  • 计费公式:未命中输入×输入价 + 命中输入×缓存价 + 输出×输出价,按当前时段取倍率;结果不足 ¥0.01 显示 ¥<0.01。
  • toast 为两行:行1 模型名 | 时段标注 | 耗时[ 空格]余额¥X(半角 | 两侧各 1 空格),行2 输入 X / 输出 Y|缓存NN.NN%|¥费用(详见方式 C)。

余额显示(v2.8 新增,v2.10 改为"默认隐藏 + 变化检测",仅自定义 API 的 DeepSeek 官方模型)

  • 原理(NIX 客户端同款):DeepSeek 官方接口 GET https://api.deepseek.com/user/balance + Authorization: Bearer <API key> 即可查询账户余额,无需网页登录——这就是 NIX 等 DeepSeek 客户端"只给 API key 就能显示余额"的原因。
  • 启用条件:仅当 ~/.workbuddy/models.json 里存在 url 指向 api.deepseek.com 的模型(即用户自己的 DeepSeek API key)时启用;无 key → 不显示余额,不影响其他功能。
  • 模式识别(v2.10,用户定调"默认不显示、抓到变化才显示"):积分模式与自定义 API 模式无法从本地数据区分——官方文档证实内置模型列表就有 Deepseek-V4-Flash(与自定义 id 同名);trace/hook payload/transcript 无模式标记;进程级探测(tasklist/wmic/netstat)被本机安全策略禁用。"密钥是否在用"信号抓不到,但 余额变化 = 账户在真实消耗 是其等价信号(有密钥才有消耗)。判定规则:每次查询与上次观测对比(toFixed(2) 字符串比较避免浮点陷阱)——
    • 余额变了(降=消费 / 升=充值)→ 显示 余额¥X(自定义 API 模式,或其他处用同一 key,显示的是真实余额);
    • 余额不变 → 不显示(积分模式余额恒定 → 永不显示);
    • 首次观测只记录 baseline 不显示(用户:"宁愿先几轮不显示")。
  • 显示位置:Stop toast 行1 紧跟耗时(1 空格分隔)余额¥2.77(金额两位小数,带 ¥ 符号——v2.18 恢复:实测行1 上限 47u 后空间充裕,峰值场景 46u 仍有富余)。放行1 的原因:行2 已满(实测约 49u/上限 52u),追加余额会折叠变 3 行。行1 是标题大字,宽度上限 TOAST_ROW1_MAX_W=47u(v2.17 实测:47u 不换行 / 48u 换行);超宽(长模型名)时余额自动让位,不折叠。v2.17 定稿:行1 分隔符用半角 |(全角「|」dispWidth 算 2u 太浪费)且两侧各 1 空格——模型名 | 高峰 | 耗时 余额¥X,模型名与分隔符不再贴死。
  • 缓存(实时性):余额写入 .balance.json(含 history 数组,保留最近 20 条观测),15 秒 TTL(v2.18 从 60s 压短:用户要求实时,接口实测 300ms 级,正常轮询间隔 >15s 即每轮拿实时数;15s 内连发 toast 才复用缓存秒回)——查询失败降级用旧缓存,无缓存则隐藏余额(不报错、不影响 toast)。
  • 隐私:API key 仅用于本机向官方 api.deepseek.com 发请求,缓存文件只存余额数值与观测历史、不存 key;脚本不打印、不上传 key。
  • 每日刷新策略(用户要求"当天第一次打开软件/第一次回答才搜,当天搜过就不搜"):
    • 脚本自动兜底:每次运行 token-tracker.js 时检查 pricing.json 的 date——过期才同步调用 refresh-prices.js 联网拉 OpenRouter 免费 API(openrouter.ai/api/v1/models,无需 key,每 12 小时更新)更新所有 or_id 匹配模型的 USD 参考价 + 补未收录模型的估算价,写回 date=今天;当天已刷新则直接跳过、不联网;拉取失败保留本地价、date 不变(次日重试),stderr 如实报错。
    • 人工权威核验:每日首次对话时,按 SKILL.md 数据源清单联网核对各厂商官方定价页(DeepSeek api-docs / 智谱 open.bigmodel.cn / Kimi platform.moonshot.cn / MiniMax platform.minimaxi.com / 混元 cloud.tencent.com),把变化的官方人民币主价更新进 pricing.json(自动刷新只动 USD 参考字段,不覆盖本地权威主价)。
    • 开源/实时价格源清单(供每日核验):OpenRouter API(首选自动源)、LiteLLM model_prices_and_context_window.json(BerriAI/litellm,静态聚合)、Portkey https://configs.portkey.ai/pricing/<provider>.json(免费 API 每日更新)、厂商官方定价页(权威)。

⏱️ 时序限制(务必理解,不要对用户造假)

  • 一个 trace 文件 = 一轮完整 LLM 调用,整轮结束后才落盘。因此在「回答生成完毕」那一刻,本轮自己的 trace 还没写出来——手动/--hook 模式读到的永远是最新已完成的一轮(即上一条回答,精确但滞后一轮)。回答末尾贴出的行不可能显示本条(本条尚未落盘),必须如实标注「上一轮/最近完成轮」,不许冒充"本条"。
  • 例外(方式 C):Stop 事件在本轮回答完全结束后触发,此时(等待后)本轮 trace 已写完,--stop 模式能拿到本条精确数据,通过 Windows 系统通知展示——这是唯一能显示「本条」的通道。
  • 首次运行(无快照)或新轮次:直接显示该轮统计,无"上一轮"前缀。
  • 同一轮被第二次读到(例如 hook 刚记录过、或上一条回复末尾已贴过):输出会带「上一轮」前缀,避免同一行重复出现。

数据源与准确性

  • 数据:最新 traces/<pid>/trace_*.json 的 trace.modelInfo / trace.duration。
  • 轮次识别:脚本用 ~/.workbuddy/skills/token-usage-tracker/.snapshot.json 记录「上次已统计的 trace 文件路径 + 该轮统计」,只用于去重;不做总量 diff,因此换会话 / 清空上下文导致总量变小也不会出现负数或 0。
  • 适用范围:自有 API 与内置积分模式都统计——只要走了模型调用就有 trace。
  • 统计口径:该轮累计 是该 trace 内多次模型调用的合计;duration 为平台记录的该轮总耗时(含工具调用等)。

注意事项

  • 不要伪造数字:脚本读的是平台真实落盘数据,直接输出即可;读不到/解析失败时如实显示"暂无数据/尚未完成写入",绝不编造。
  • 若输出显示「上一轮」,说明这一轮已统计过(数字与上次相同属正常)。
  • 本技能不修改任何平台文件,仅读取 traces 与维护自身快照。