- 新增 docs/USAGE-QUERY-ADAPTATION.md:cc-switch/OpenCode/官方 API 账单查询适配调研(含 Kimi 余额 API 缺口 P0、OpenCode Go 不可查结论、遗漏盘点) - opencode-zen 预设 apiKeyUrl 补推荐链接 ref=DFCNADQCEM(Zen 控制台页无 ref 参数)
22 KiB
账单查询(用量查询)适配调研报告
调研日期:2026-07-31 调研范围:
D:\AIGC\cc-switch(参考实现)、D:\AIGC\KimiSwitch(当前项目)、OpenCode(sst/opencode)订阅套餐定义、Kimi / 智谱官方用量查询 API 状态:调研完成,未动代码
1. 结论速览
- KimiSwitch 的账单查询不是空白:已移植 cc-switch 的「余额查询(Balance)+ 套餐查询(Coding Plan)」两大块,共 8 种
usageKinds,Rust 侧闭环 +UsageFooter展示,错误通道、keep-last-good、缓存、detect_provider自动识别等核心设计均与 cc-switch 对齐。 - OpenCode 本身不提供账单/额度查询。它只负责"定义"供应商与订阅套餐的接入方式(provider id、base URL、认证、模型清单,数据源为 models.dev),"套餐还剩下多少"需要查各家官方 API——这正是 cc-switch(及 KimiSwitch 已移植部分)做的事。
- 本次调研发现 2 个值得补的能力缺口:
- Kimi 开放平台余额查询(
GET https://api.moonshot.cn/v1/users/me/balance,Kimi 官方 2026-07 新增公开 API,cc-switch 尚未实现)→ KimiSwitch 也缺。 - OpenCode Go 订阅套餐额度(5h / 周 / 月 三窗口)→ 无公开查询 API,只有控制台,暂不可程序化。
- Kimi 开放平台余额查询(
- 其余缺口(ZenMux / 火山方舟 / 智谱团队版 / JS 脚本引擎 / 官方 OAuth 订阅)为 cc-switch 独有能力,与"做好现有账单查询"的目标匹配度分层,见 §6 路线。
2. 现状盘点:KimiSwitch 已实现的账单查询
2.1 架构
ProviderList (前端)
└─ UsageFooter ── invoke("query_provider_usage", { agent, providerName, forceRefresh })
└─ Rust commands.rs:590 ── services::query_kind(kind, base_url, api_key)
├─ balance.rs (余额,5 家)
└─ coding_plan.rs (套餐,3 家)
- 前端永不持有 API key、不直连 HTTP;所有请求在 Rust 侧用 reqwest 完成(无浏览器 CORS 问题)。
Provider.usageKinds(前端src/config/providerPresets.ts预设字段)→ 保存时写入 SQLite settingsusage_kinds:<provider_name>(commands.rs:152)→ 加载时merge_usage_kinds(commands.rs:33),缺失时按 base_url host 自动detect_provider。- TS/Rust 双端枚举防漂移:
SUPPORTED_USAGE_KINDS运行时断言(providerPresets.ts:563)检查预设的usageKinds都在 RustUsageKind覆盖内。
2.2 已有能力对照表
| UsageKind | 供应商 | 端点 | 认证 | 实现 |
|---|---|---|---|---|
balance:deepseek |
DeepSeek | GET https://api.deepseek.com/user/balance |
Bearer | ✅ |
balance:siliconflow |
SiliconFlow (.cn/.com) | GET https://api.siliconflow.cn|.com/v1/user/info |
Bearer | ✅ |
balance:openrouter |
OpenRouter | GET https://openrouter.ai/api/v1/credits |
Bearer | ✅ |
balance:stepfun |
StepFun | GET https://api.stepfun.com/v1/accounts |
Bearer | ✅ |
balance:novita |
Novita AI | GET https://api.novita.ai/v3/user/balance(÷10000 转 USD) |
Bearer | ✅ |
plan:kimi_coding |
Kimi For Coding | GET https://api.kimi.com/coding/v1/usages |
Bearer | ✅ |
plan:zhipu |
GLM Coding Plan(bigmodel.cn / z.ai) | GET {open.bigmodel.cn|api.z.ai}/api/monitor/usage/quota/limit |
Raw key(无 Bearer) | ✅ |
plan:minimax |
MiniMax Token Plan (.com/.io) | GET https://api.minimaxi.com|.io/v1/api/openplatform/coding_plan/remains |
Bearer | ✅ |
已有预设(providerPresets.ts):kimi-coding(plan:kimi_coding)、zhipu-coding / zai-coding(plan:zhipu)、minimax / minimax-token-plan(plan:minimax)、deepseek / stepfun / siliconflow / novita / openrouter(余额)。
2.3 统一返回契约(Rust → 前端)
src-tauri/src/services/usage_types.rs(camelCase serde):
interface UsageData {
planName?: string | null; // 套餐名:five_hour / weekly_limit
remaining?: number | null; // 余额:金额(balance)或剩余百分比(plan)
total?: number | null; // 总量(plan 恒为 100)
used?: number | null; // 已用百分比 0-100(plan)
unit?: string | null; // CNY / USD / %
isValid?: boolean | null;
resetsAt?: string | null; // ISO 8601 重置时间
}
interface UsageResult { success: boolean; data?: UsageData[] | null; error?: string | null; }
错误通道语义(与 cc-switch 一致):Err(invoke reject)= 瞬时失败(网络/超时,前端重试 + 保留 last-good);Ok(success:false) = 确定性失败(无 key / 401 / 非 2xx / 坏 JSON,立即透出并清 last-good)。实现要点:先 bytes() 再 serde_json::from_slice 以区分读体失败(瞬时)与解析失败(确定性)。
3. OpenCode 如何"定义" Kimi / 智谱订阅套餐(重点)
3.1 OpenCode 的 provider 体系
OpenCode(sst/opencode)通过 ~/.config/opencode/opencode.json 的 provider 段注册供应商,用 AI SDK + Models.dev 提供 75+ 提供商。一个"订阅套餐"在 OpenCode 里不是一个独立概念,而是一组 provider 定义 + 模型引用:
| provider id | 对应产品 | 默认 base URL(API 端点) | 说明 |
|---|---|---|---|
zhipuai |
GLM Coding Plan(订阅) | https://open.bigmodel.cn/api/coding/paas/v4 |
套餐专属端点,与按量 PaaS 端点不同 |
zai |
z.ai(按量) | https://api.z.ai/api/paas/v4 |
|
kimi |
Kimi For Coding(订阅) | https://api.kimi.com/coding/v1 |
OpenAI 兼容;Anthropic 兼容为 https://api.kimi.com/coding/ |
moonshot |
Moonshot / Kimi 开放平台(按量) | https://api.moonshot.ai/v1(国际) |
国内站 api.moonshot.cn/v1 |
opencode-zen |
OpenCode Zen(充值余额) | https://opencode.ai/zen/v1 |
按量 |
opencode-go |
OpenCode Go($10/月订阅) | https://opencode.ai/zen/go/v1 |
5h/周/月 额度 |
关键事实:
- 套餐与按量是不同 provider id、不同 base URL(
zhipuaivszai;kimivsmoonshot)。/connect时按选择的 provider 存 key。 - 认证均为 API Key(多数
Authorization: Bearer);智谱 Coding Plan 的额度查询不含 Bearer(见 §4.2)。 - 模型清单来自 Models.dev(OpenCode 编译内置),模型 id 形如
zhipuai/glm-5.2、moonshotai/kimi-k2.7-code;OpenCode Go 的模型走独立命名空间opencode-go/<model>(如opencode-go/kimi-k3),其额度不消耗各家套餐,只消耗 Go 的 5h/周/月窗口。
3.2 OpenCode Go 套餐额度(当前 opencode.ai 官方数据)
| 窗口 | 额度 |
|---|---|
| 5 小时 | $12 用量 |
| 每周 | $30 用量 |
| 每月 | $60 用量 |
额度按美元计费价值计算(不同模型折算请求数不同)。超出限额后可选"Use balance"回退到 Zen 余额。
查询方式:仅控制台(console),无公开 REST API。OpenCode 项目本身不做用量查询(无 usage/billing 命令),社区工具(如 cc-switch 的 usage_script)也无法覆盖 Go 套餐——这是目前的技术边界,适配时只能提示用户"网页控制台查看"或把 Go 归入"不可查询"类。
3.3 OpenCode 定义 → KimiSwitch 预设的对应关系
KimiSwitch 的 providerPresets.ts 已镜像这套体系(baseUrl 与 OpenCode 一致):
| KimiSwitch 预设 | baseUrl | billingMode | usageKinds | 备注 |
|---|---|---|---|---|
kimi-coding |
https://api.kimi.com/coding/v1 |
subscription | plan:kimi_coding |
✅ 可查套餐 |
zhipu-coding |
https://open.bigmodel.cn/api/coding/paas/v4 |
subscription | plan:zhipu |
✅ 可查套餐 |
zai-coding |
https://api.z.ai/api/coding/paas/v4 |
subscription | plan:zhipu |
✅ 可查套餐 |
opencode-go |
https://opencode.ai/zen/go/v1 |
subscription | (空) | ❌ 不可查,见 §4.4 |
opencode-zen |
https://opencode.ai/zen/v1 |
pay_as_you_go | (空) | ❌ 不可查 |
moonshot |
https://api.moonshot.ai/v1 |
pay_as_you_go | (空) | ❌ 未挂余额查询,见 §4.3 |
4. 各订阅 / 余额查询 API 详细方案
4.1 Kimi For Coding 套餐(✅ 已实现,无需改动)
- 端点:
GET https://api.kimi.com/coding/v1/usages - 认证:
Authorization: Bearer <kimi-code-api-key>(Kimi Code 控制台签发,与开放平台 key 不互通) - 响应(cc-switch 实测 + 社区验证):
{
"limits": [
{ "detail": { "limit": 100, "remaining": 40, "resetTime": 1754000000000 } }
],
"usage": { "limit": 1000, "remaining": 900, "resetTime": "2026-08-01T00:00:00Z" }
}
- 解析(
coding_plan.rs::parse_kimi_coding):limits[].detail→ 5 小时窗口(5h 滚动,resetTime毫秒);usage→ 周限额。used = limit - remaining,换算百分比。 - 官方端点确认:Kimi Code 文档服务地址
https://api.kimi.com/coding/v1(OpenAI 协议),模型 IDkimi-for-coding。
4.2 GLM Coding Plan 套餐(✅ 已实现,无需改动)
- 端点:
GET https://open.bigmodel.cn/api/monitor/usage/quota/limit(国内)/GET https://api.z.ai/api/monitor/usage/quota/limit(海外) - 认证:
Authorization: <api-key>—— 裸 key,不带Bearer前缀(cc-switch 实测;智谱官方glm-plan-usage插件query-usage.mjs同样如此) - 响应:
{
"success": true,
"data": {
"level": "pro",
"limits": [
{ "type": "TOKENS_LIMIT", "percentage": 35, "unit": 3, "nextResetTime": 1754000000000 },
{ "type": "TOKENS_LIMIT", "percentage": 80, "unit": 6, "nextResetTime": 1754500000000 }
]
}
}
- 解析(
coding_plan.rs::parse_zhipu):只取type == "TOKENS_LIMIT"的条目;unit: 3→ 5 小时窗口,unit: 6→ 每周窗口(缺失时按nextResetTime升序启发式兜底);percentage即已用百分比。 - 套餐等级(Lite / Pro 等)在
data.level,当前实现未透出(UsageData无该字段,可后续扩展)。
4.3 Kimi 开放平台余额(❌ 未实现 —— 建议新增,优先级 P0)
这是本次调研最重要的新发现。Kimi 官方 2026-07 新增公开余额 API(platform.kimi.com/docs/api/balance),cc-switch 也尚未实现(issue #4455 提议中)。
- 端点:
GET https://api.moonshot.cn/v1/users/me/balance - 认证:
Authorization: Bearer <MOONSHOT_API_KEY> - 响应:
{
"code": 0,
"data": {
"available_balance": 49.58894, // 可用余额 CNY(= 现金 + 代金券)
"voucher_balance": 46.58893, // 代金券余额
"cash_balance": 3.00001 // 现金余额(可为负,欠费)
},
"scode": "0x0",
"status": true
}
- 业务错误:
code != 0或status == false→ 确定性失败。 - 适配点:
moonshot预设 baseUrl 为https://api.moonshot.ai/v1(国际站),而该端点固定api.moonshot.cn(国内站)。需按 base_url 消歧:host 含moonshot.cn→ 查 CN 端点;moonshot.ai→ 查https://api.moonshot.ai/v1/users/me/balance(国际站对应端点,待实测确认;官方文档仅给出 CN 示例)。 - 新增
balance:kimikind 即可复用现有 balance 路径,前端UsageFooter自动生效(余额形态显示💰 余额 ¥49.59)。
4.4 OpenCode Go / Zen(❌ 未实现 —— 无公开 API,建议标注"不可查")
- Go 套餐:额度窗口见 §3.2,仅控制台可看;
opencode.ai/zen/go/v1只有推理端点(/chat/completions、/responses、/models),无 usage/balance 端点。 - Zen 余额:充值制,同样仅控制台。
- 可选替代(不推荐投入):通过调用推理端点时服务端返回的 402/429/额度错误头做被动感知,无法拿到数值,价值低。
- 适配结论:
opencode-go/opencode-zen预设维持usageKinds为空;可在预设note/UI 上提示"额度请在 opencode.ai 控制台查看"。
4.5 其他 cc-switch 独有、KimiSwitch 未移植的能力(按目标匹配度排序)
| 能力 | cc-switch 实现 | KimiSwitch | 匹配度与建议 |
|---|---|---|---|
| 通用 JS 脚本引擎(custom/general/newapi) | usage_script.rs(rquickjs)+ UsageScriptModal |
❌ | 覆盖"任意中转站",工程量大(新增 rquickjs 依赖 + ~1000 行引擎);若"现有账单查询"只服务已知供应商则非必须。若要支持 new-api/one-api 类中转站,可优先用声明式配置方案替代(见 §6 P2) |
| ZenMux 套餐 | coding_plan.rs::query_zenmux(base_url 即查询端点,Bearer) |
❌ | 简单可搬(~50 行 + 测试),P1 |
| 火山方舟 Coding Plan | coding_plan.rs::query_volcengine(AK/SK 签名 V4 变体,控制面网关) |
❌ | 中等(~200 行签名逻辑,照搬注释坑位),P1 |
| 智谱团队版 | query_zhipu_team(bigmodel-organization/bigmodel-project header) |
❌ | 需前端表单存组织/项目 ID + Rust 凭据扩展,P2 |
| 官方订阅额度(Claude/Codex/Gemini/Grok OAuth) | subscription.rs / subscription_grok.rs(读 CLI 凭据文件) |
❌ | 与 KimiSwitch 目标 CLI(Kimi Code / Pi)不匹配,不建议 |
| GitHub Copilot / Codex-OAuth / xAI-OAuth 配额 | 自管 OAuth | ❌ | 同上,不建议 |
| 托盘用量摘要 + UsageCache 事件桥 | tray.rs + usage_cache.rs |
❌ | KimiSwitch 托盘无用量入口,低价值 |
4.6 盘点中新发现的「订阅预设但不可查」项
| 预设 | billingMode | 现状 | 说明 |
|---|---|---|---|
stepfun-plan(StepFun Plan) |
subscription | usageKinds 为空 |
StepFun Plan 走 https://api.stepfun.com/step_plan/v1 推理端点;未发现公开的套餐用量查询 API(cc-switch 也无)。balance:stepfun 查的是按量账户余额(/v1/accounts),两者不互通。标注"不可查"即可 |
bailian(阿里云百炼) |
pay_as_you_go | usageKinds 为空 |
百炼 2026-07 上线 Coding Plan(专属 key 格式 sk-sp-,按调用次数扣额度,与 token 无关);官方文档仅提供"控制台 Coding Plan 页面查看",未发现公开查询 API。预留为待跟踪项(套餐上线早期,API 可能随后开放) |
moonshot(Kimi 开放平台) |
pay_as_you_go | usageKinds 为空 |
→ 即 P0 的 balance:kimi,见 §4.3 |
5. 新增能力实现清单(改动点)
以 P0:Kimi 开放平台余额(balance:kimi) 为例,完整改动点如下(严格套用现有四步模式,前端展示零改动):
- Rust
src-tauri/src/services/balance.rs- 新增
pub async fn query_kimi(api_key: &str, is_cn: bool) -> Result<UsageResult, String>:- 端点:
https://api.moonshot.cn/v1/users/me/balance(CN)/https://api.moonshot.ai/v1/users/me/balance(EN,待实测) - 复用
get_json(url, key, AuthStyle::Bearer);新增parse_kimi:code == 0 && status == true时取data.available_balance,unit: "CNY";code != 0走确定性失败。
- 端点:
- 单元测试:正常解析 /
code!=0/ 缺字段。
- 新增
- Rust
src-tauri/src/services/mod.rsUsageKind加BalanceKimi;as_str→"balance:kimi";ALL变 9 项;FromStr匹配;query_kind路由按 host 消歧(moonshot.cn→ CN,moonshot.ai→ EN);detect_provider加api.moonshot.cn/api.moonshot.aihost 匹配 + 测试。
- 前端
src/config/providerPresets.tsUsageKindunion 与SUPPORTED_USAGE_KINDS各加"balance:kimi";moonshot预设加usageKinds: ["balance:kimi"](防漂移断言会强制两侧同步)。
- i18n:无需新 key(
usageBalance等已存在)。
若同时做 P1 的 ZenMux / 火山,则除第 3 步外再加预设(zenmux、火山套餐基 URL 或 AK/SK 凭据存储)。注意:火山 / 智谱团队需要 Provider 模型新增凭据字段(AK/SK、组织/项目 ID),会触及 models.rs、db.rs 的 SQLite 表结构与前端 ProviderEdit 表单,改动面明显更大,建议单独排期。
6. 建议路线
| 优先级 | 事项 | 改动面 | 工作量 | 风险 |
|---|---|---|---|---|
| P0 | Kimi 开放平台余额 balance:kimi |
balance.rs + mod.rs + providerPresets.ts | 小(~1 天) | 低;EN 端点待实测 |
| P1 | ZenMux 套餐(照搬 cc-switch) | coding_plan.rs + mod.rs + 预设 | 小 | 低 |
| P1 | 火山方舟 Coding Plan(AK/SK 签名 V4) | coding_plan.rs + 凭据存储 + 表单 | 中 | 签名细节易错,需单测 |
| P2 | 智谱团队版 / 中转站声明式配置(new-api 类) | 架构决策后实施 | 中-大 | 需先定方案 |
| P3 | JS 脚本引擎 / 官方 OAuth 订阅 / 托盘用量 | — | 大 | 与目标 CLI 不匹配,建议不做 |
| P3 | 查询请求走代理(见 §6.1) | balance.rs 共用 Client 改造 | 小-中 | 依赖全局代理设置是否已存在 |
6.1 遗漏盘点(首轮调研未覆盖,本次补查确认)
- 代理支持缺失(建议 P1-P2):KimiSwitch 的
balance.rs::get_json每次新建reqwest::Client,没有配置代理;cc-switch 的crate::proxy::http_client::get()继承全局代理。用户若经代理访问海外站(SiliconFlow.com / z.ai / OpenRouter / Novita / api.moonshot.ai),账单查询会直连失败。适配时建议把 Client 构造提升为共用函数并支持代理(项目已依赖 reqwest,无新增依赖)。 - 无自动轮询(P3 可选):cc-switch 有
autoQueryInterval+ react-query 轮询 + 托盘摘要;KimiSwitch 的UsageFooter仅在挂载时查询 + 手动刷新。低价值(窗口额度重置倒计时可手动刷新),不做不影响正确性。 - 智谱套餐等级未透出(P3 可选):
data.level(Lite/Pro)已在响应中但UsageData无字段承接;如需展示需扩契约。 - 多 agent 已覆盖:
UsageFooter挂在两个 agent(Kimi Code / Pi)的ProviderList,cacheKey 含 agent,无遗漏。 - 相关文档衔接:项目已有
docs/PROPOSAL-presets-and-usage.md、docs/VERIFICATION-CHECKLIST.md随功能迭代更新;本文档为独立调研稿,实施时按项目约定把改动项回写上述文档。
说明:以上为调研结论与建议,尚未实现任何代码;若确认方向,可先落 P0。
7. 风险与坑位备忘
- 智谱裸 key:
monitor/usage/quota/limit的Authorization不带Bearer,且要带Content-Type: application/json、Accept-Language(cc-switch 实测)。 - Kimi 三套凭据不互通:Kimi 开放平台(开放平台 key)、Kimi Code(
api.kimi.com/coding专属 key)、Kimi 会员是三个独立产品,余额/权益/key 均不通用(官方 FAQ 确认)——UI 文案需区分"开放平台余额"与"For Coding 套餐"。 - base_url 消歧:SiliconFlow
.cn/.com、MiniMax.com/.io、智谱bigmodel.cn/z.ai、Kimi 开放平台moonshot.cn/.ai均靠 host 子串区分;detect_provider命中即注入,注意别把api.kimi.com(非/coding路径)误判为套餐。 - 响应读体与解析分离:所有查询先
bytes()再 parse,保持瞬时/确定性错误通道不混淆(已统一在balance.rs::get_json)。 - 金额单位:Novita ×0.0001 USD;Kimi 余额为 CNY;Go 套餐按 USD 计。
- TS/Rust 枚举漂移:新增 kind 必须同时改
UsageKindunion +SUPPORTED_USAGE_KINDS+ Rust 枚举三处,否则 dev 断言报错。
8. 附:OpenCode 预设"获取 API Key"推荐链接检查(2026-07-31)
用户反馈:OpenCode 预设的"获取 API Key"链接没有走自己的推荐链接。排查结果如下:
| 预设 | 字段 | 当前值 | 是否带推荐码 |
|---|---|---|---|
opencode-go |
websiteUrl |
https://opencode.ai/go?ref=DFCNADQCEM |
✅ 带 ref=DFCNADQCEM |
opencode-go |
apiKeyUrl |
https://opencode.ai/go?ref=DFCNADQCEM |
✅ 带 ref=DFCNADQCEM |
opencode-zen |
websiteUrl |
https://opencode.ai/zen/ |
❌ 不带 ref |
opencode-zen |
apiKeyUrl |
https://opencode.ai/zen/ |
❌ 不带 ref |
- 位置:
src/config/providerPresets.ts:417-458(opencode-go/opencode-zen两个预设)。 - 渲染链路:
src/components/ProviderEdit.tsx:325—— 编辑页"获取 API Key"按钮 =preset?.apiKeyUrl ?? provider.official_url;预设选择后即带出该 URL。 - 历史:
ref=DFCNADQCEM于 v0.6.2(提交bee981a"OpenCode Go/Zen 预设")加入opencode-go;opencode-zen自始未带 ref。 - 结论:推荐链接确认为
https://opencode.ai/go?ref=DFCNADQCEM(用户确认)。opencode-go预设两处均已带该 ref,无需改动;opencode-zen的apiKeyUrl已修复为推荐链接(websiteUrl保持https://opencode.ai/zen/官网展示不变),这样两个 OpenCode 预设的"获取 API Key"入口都走推荐链接。
9. 参考资料
- Kimi 开放平台余额 API:https://platform.kimi.com/docs/api/balance
- Kimi Code 文档(服务地址 / 环境变量 / 错误参考):https://www.kimi.com/code/docs/ 、 https://www.kimi.com/code/docs/kimi-code-cli/configuration/env-vars.html
- Kimi 帮助中心(余额与用量、会员权益):https://www.kimi.com/zh-cn/help/kimi-api/api-balance-and-usage 、 https://www.kimi.com/zh-cn/help/kimi-code/membership-guide
- 智谱 GLM Coding Plan 额度 API(cc-switch issue 社区确认):https://github.com/farion1231/cc-switch/issues/1588 、 https://github.com/seakee/CPA-Manager-Plus/issues/379
- Kimi 余额查询(cc-switch issue,官方 API 引入):https://github.com/farion1231/cc-switch/issues/4455
- OpenCode Go 套餐额度:https://opencode.ai/docs/go/
- OpenCode providers / 配置:https://opencode.ai/docs/providers/
- cc-switch 源码(MIT):
src-tauri/src/services/balance.rs、src-tauri/src/services/coding_plan.rs、src-tauri/src/usage_script.rs - KimiSwitch 现有实现:
src-tauri/src/services/{mod,balance,coding_plan,usage_types}.rs、src/config/providerPresets.ts、src/components/UsageFooter.tsx