| name | usage-probe |
| description | 为 PiDeck 的「用量查询」功能排查/扩展供应商支持。当用户想显示某个供应商的用量、余额或额度点数时,先判断是否已内置支持(内置无需配置);不在内置时引导用户使用「用量查询」弹窗里的通用模板 / New API 模板;两种模板都覆盖不了的接口,帮用户写出 usage-probes.json 的旧版探针数组。 |
用量查询辅助(usage-probe)
这是什么
供应商的用量/余额显示在「设置 → 配置管理 → 模型/认证」的 供应商卡片底部
(学 cc-switch:所有卡片同一位置、右对齐:相对时间 + 彩色数值 + 刷新按钮)。
支持分三层:
- 内置模板(零配置):命中内置候选的供应商开箱即用,弹窗里已识别、无需配置。
当前内置:
- 官方余额:DeepSeek(
/user/balance)、OpenRouter(/api/v1/key per-key 额度)、
Moonshot 官方余额(/users/me/balance);
- 套餐额度:Kimi For Coding(
/usages,含 Boost 点数)、智谱 GLM Coding Plan
(5h 滚动窗 / 周窗 / MCP 月度窗)、OpenCode Go(/usage 三档百分比);
- 官方订阅(登录态 OAuth,凭据来自 auth.json):Codex/ChatGPT(
/wham/usage)、
xAI Grok(billing 预检链);
- 通用 OpenAI 兼容网关兜底:实现了官方
/v1/usage({ balance, unit })的中转站自动显示余额。
- 声明式模板(弹窗内可选):不在内置列表时,弹窗提供两个模板——
- 通用模板:请求
/usage(OpenAI 兼容),API Key / 请求地址可覆盖(留空用供应商的);
- New API:New API / OneAPI 中转站,填 访问令牌 + 用户 ID(积分自动换算)。
- 旧版探针数组(AI 兜底):上面都覆盖不了的接口(如自建网关的自定义余额端点),
由 AI 写
~/.pi/agent/usage-probes.json 的 probes 数组(见下文),运行时按
baseUrl 关键字匹配合入探测。
配置文件位置(和 models.json 同一个目录):
~/.pi/agent/usage-probes.json
改完立刻生效(无需重启)。顶层 providers 映射由弹窗维护,AI 不要手改;
probes 数组才是开放给 AI 写的部分。
改完立刻生效(无需重启),下次打开供应商卡片就能读到新配置。
你(AI)的工作流程
当用户说「帮我让 XX 供应商显示用量」时,按下面顺序做:
- 先判断是否已内置:读
~/.pi/agent/models.json 找到该 provider 的 baseUrl,
对照上面的内置清单。命中就直接告诉用户「已内置,无需配置,卡片底部会自动显示」,
不需要写任何文件。apiKey 的位置不用读出来,也不要把 key 贴到任何地方。
- 没内置 → 引导弹窗模板:让用户在供应商卡片点「用量查询」打开弹窗:
- OpenAI 兼容站点(有
/usage 端点)→ 选「通用模板」,必要时填请求地址(留空用供应商的);
- New API / OneAPI 中转站 → 选「New API」,填访问令牌和用户 ID;
- 两个模板都覆盖不了 → 继续第 3 步。
- 写旧版 probes 数组:确认该供应商的「余额 / usage / balance / credits」接口
(拿不到文档时让用户 F12 抓包,把 URL 路径和返回 JSON 发给你;记得提醒用户
抹掉 key/token),确定「剩余额度」字段后按下面结构生成
probes 数组。
- 验证:让用户打开供应商卡片看底部用量行。不显示就继续对齐字段路径。
重要安全边界:配置文件里不要写 apiKey。鉴权统一走 Authorization: Bearer <key>,
主进程自动从 auth.json/models.json 取 key;只有个别接口用非标准鉴权头时才用
"headers": { "X-API-Key": "{{apiKey}}" } 占位。
配置文件结构
顶层 providers 映射由弹窗维护(开关/模板/超时/间隔),AI 不要手改。
下面这个 probes 数组是开放给 AI 写的兜底部分,每条是一个供应商。字段含义:
{
"probes": [
{
"name": "我的中转站",
"match": {
"baseUrlContains": ["api.myprovider.com"]
},
"request": {
"path": "/user/balance",
"method": "GET",
},
"parse": {
"kind": "balance",
"valuePath": "balance_infos[0].total_balance",
三种 parse 形态
1. balance(剩余额度,一个数字 + 可选币种)
"parse": {
"kind": "balance",
"valuePath": "data.available_balance",
"currencyPath": "data.currency"
}
2. credits(额度点数,总额 / 已用 / 剩余,至少给一个)
"parse": {
"kind": "credits",
"totalPath": "data.total_credits",
"usedPath": "data.total_usage",
"remainingPath": "data.remaining"
}
3. periods(三档百分比:滚动 / 周 / 月)
"parse": { "kind": "periods" }
periods 形态不需要写字段路径:解析器会自动找响应里的
usage.rolling / usage.weekly / usage.monthly,每档取 percent / resetsAt / status。
只要你的供应商接口返回类似 { "usage": { "weekly": { "percent": 68 } } } 的结构,
直接用 periods 即可,不用写路径。
字段路径怎么写
用「点号 + 方括号」从响应根一层层往下指:
data.balance → { "data": { "balance": 110 } } 里的 110
balance_infos[0].total_balance → 数组第一项的 total_balance
data.credits.total → 嵌套对象
数字可以是 number,也可以是能转成数字的字符串(很多网关余额字段是 "110.00" 这种字符串)。
完整示例
示例一:某 OpenAI 兼容网关返回 { data: { balance: 12.5, currency: "USD" } }
{
"probes": [
{
"name": "我的网关",
"match": { "baseUrlContains": ["gateway.example.com"] },
"request": { "path": "/v1/balance" },
"parse": {
"kind": "balance",
"valuePath": "data.balance",
"currencyPath": "data.currency"
}
}
]
}
示例二:OpenRouter(额度点数)
{
"probes": [
{
"name": "OpenRouter",
"match": { "baseUrlContains": ["openrouter.ai"] },
"request": { "path": "/credits" },
"parse": {
"kind": "credits",
"remainingPath": "data.total_credits",
"usedPath": "data.total_usage"
}
}
]
}
提示:不同网关字段名可能不同,以上示例里的字段名请以官方文档或实际抓包为准。
排查清单
- 供应商卡片底部用量行完全没显示:先看弹窗是否命中「已内置」;未命中就看模板选对没有;
- 显示「用量暂时不可用」:接口字段路径没对上,把脱敏后的响应 JSON 发给 AI 帮你对齐;
- 显示「用量查询未开启」:弹窗里的启用开关没开(或之前显式关闭过),打开即可;
- 显示「当前 provider 暂不支持用量查询」:说明没有匹配到任何探针。检查
match.baseUrlContains 里的关键字,是不是和 models.json 里那个 provider 的
baseUrl 完全不一致(注意大小写、是否带 /v1)。
- 配置写错了 JSON:主进程会忽略整条非法探针并在日志里提示,不会影响内置探针。
- 余额显示成「0」:可能字段取错了位置,或接口返回的字段本身是「已用」而不是「剩余」。