# billing `billing` 是 CLIProxyAPI 的收敛式计费插件,提供持久化用量与价格展示、下游 Key 管理、模型准入和上游凭证定向路由。一个 Key 代表一个调用用户;管理员可以创建、禁用或永久归档 Key,并按 Key 查看统计。 每个 Key 同时拥有独立的美元额度账户。管理员可以分配本周期额度、设置日/周/月自动重置和并发上限,并查看不可变的扣费、额度调整与重置账目。额度采用请求结束后结算的软限制:余额为正时放行,实际 Usage 到达后扣费,最后一个或多个在途请求可能产生负余额,之后的新请求返回 429。 ## 一次请求如何通过 CPA ```mermaid sequenceDiagram autonumber participant Client as 用户 / Codex participant CPA as CLIProxyAPI participant Billing as billing participant DB as SQLite participant Upstream as 实际模型服务 Client->>CPA: 携带下游 Key 发起模型请求 CPA->>Billing: frontend_auth.authenticate Billing->>DB: 查询 Key 与状态 DB-->>Billing: 用户访问配置 alt Key 无效或已停用 Billing-->>CPA: 认证失败 CPA-->>Client: 401 Unauthorized else 认证成功 Billing-->>CPA: 返回用户身份(稳定 Key ID) CPA->>Billing: request.intercept_before Billing->>DB: 检查模型权限、余额与并发并占用名额 alt 模型、额度或并发不允许 Billing-->>CPA: 终止请求(403 / 429 / 503) CPA-->>Client: 返回结构化错误 else 请求准入 Billing-->>CPA: 允许继续 CPA->>Billing: scheduler.pick(可用上游候选) alt 自动路由 Billing-->>CPA: 委托 CPA 内置调度 else 严格路由 Billing->>DB: 读取该用户绑定的上游账号 Billing-->>CPA: 指定唯一 Auth ID end CPA->>Billing: request.intercept_after Billing-->>CPA: 复核价格配置与实际上游 alt 价格缺失或严格路由失效 CPA-->>Client: 503 Service Unavailable else 复核通过 CPA->>Upstream: 使用选定凭证转发请求 Upstream-->>CPA: 模型响应 / 流式输出 CPA-->>Client: 返回模型结果 CPA->>Billing: request.complete(请求终态) Billing->>DB: 释放并发名额,保存成功、失败或取消结果 CPA->>Billing: usage.handle(如有最终 Token 用量) Billing->>Billing: 按模型价格计算成本 Billing->>DB: 保存用量、扣减余额并写入账目 end end end ``` CLIProxyAPI 负责 HTTP 接入、协议转换、上游凭证和实际请求执行;`billing` 通过插件回调参与请求决策与记录,不直接连接模型服务。`request.complete` 与 `usage.handle` 是独立事实回调,实际到达顺序不作为数据正确性的前提。 ## 当前兼容目标 - CLIProxyAPI 基线:`v7.2.139` / `0a14eb70ce19fac1d114bcdb4a476d61adc819e2`,由 `.externals/CLIProxyAPI` submodule 锁定,需依次应用 `patch/` 中三项宿主补丁 - 插件版本:`0.1.0` - Native ABI:`1` - RPC schema:最高 `4`,注册时按宿主版本向下协商;schema v4 提供 Usage 请求身份 - 插件 ID / 动态库文件名:`billing` - 已声明能力:`frontend_auth_provider`(独占)、`scheduler`、`request_interceptor`、`request_lifecycle_plugin`、`usage_plugin`、`management_api` 契约来源以本仓库内 `.externals/CLIProxyAPI/sdk/pluginabi/types.go`、`.externals/CLIProxyAPI/sdk/pluginapi/types.go`、`.externals/CLIProxyAPI/internal/pluginhost/rpc_schema.go` 为准。 ## 环境与构建(WSL/Linux) 需要支持 toolchain 自动切换的 Go 1.24+ 和 GCC;项目固定使用已包含安全修复的 Go 1.26.6 构建。Ubuntu/Debian 可先准备 C 工具链: ```bash sudo apt-get update sudo apt-get install -y build-essential ./scripts/check-env.sh ./scripts/build.sh ``` 从 PowerShell 也可调用 WSL 构建入口: ```powershell ./scripts/build.ps1 ``` 生成 Linux/amd64 发布包和 SHA-256 校验文件: ```bash bash ./scripts/package.sh 0.1.0 ``` 产物位于 `dist/billing_0.1.0_linux_amd64.tar.gz`,只包含动态库、版本元数据、README 和示例配置。 产物为 `bin/billing.so`,适用于运行在 WSL/Linux 的 CLIProxyAPI。SQLite 驱动依赖 CGO,普通开发测试也应在已经安装 GCC 的 WSL/Linux 环境执行: ```bash CGO_ENABLED=1 go test ./... ``` ## 加载到 CLIProxyAPI 1. 将 `bin/billing.so` 放进 Linux CLIProxyAPI 配置的插件目录(默认 `plugins/`)。 2. 合并 `config.example.yaml` 中的 `plugins` 配置。 3. 重启宿主,确认日志中成功加载插件 `billing`。 4. 首次启动会创建名称为 `default`、值为 `000000` 的下游 Key,保持现有 Codex 配置可用。 5. 发起一个 Codex 请求,确认管理页面出现该 Key 的用量和实际上游 Auth ID。 ## Key 管理与路由 管理页面提供: - 自动生成或手动输入至少 6 位的 Key,列表脱敏显示,点击脱敏文本可复制完整 Key; - `active` / `disabled` 状态切换,以及不可恢复但保留历史的归档; - CPA 自动选择上游,或严格绑定一个 OAuth/API Key 上游凭证; - 按客户端请求模型配置允许列表; - 模型允许列表支持精确名称和 `*` 通配符,例如 `deepseek-*`; - 分配美元额度、设置自动重置时间和每用户并发上限; - 查看当前额度、已用、余额以及最近扣费账目; - 累计、今日和最近请求统计。 管理页面资源可以直接反向代理。未填写 Management Key 时展示脱敏后的真实只读数据并隐藏全部修改入口;输入有效 Management Key 后才显示完整管理操作。匿名只读接口不会返回完整下游 Key,历史 Usage 的旧 `api_key` 字段也会被清空。只读展示仅需代理 `/v0/resource/plugins/billing/ui`(数据请求复用同一路径的查询参数);若要在外部页面执行管理操作,还需同源代理 `/v0/management/plugins/billing/*`。 严格绑定的账号不可用或不支持目标模型时请求直接失败,不回退到其他账号。新 Key 在创建时复制 `default` 当时的路由与模型规则,之后独立维护。 现有和新建 Key 的初始额度都是 `$0`,默认不自动重置、并发上限为 4。管理员分配额度后才能发起模型请求。金额以微美元整数保存;修改额度不会清空本周期已用金额,手动或自动重置不会结转旧余额。允许模型没有价格配置时,请求会在触达上游前以 503 拒绝。 价格页面可以手动从 `models.dev/catalog.json` 更新供应商级参考目录,并把任意参考模型的价格导入任意本地模型。例如本地的 `deepseek-v4-flash` 可以显式采用 `OpenAI / gpt-5.6-sol` 价格。目录和本地有效价格彼此独立;刷新只展示变化,管理员确认后才更新已关联价格,人工保存则解除目录关联。全零目录项不作为免费价格导入,下载失败继续保留上次缓存且不影响请求链路。 `config_yaml` 中包含宿主补充的 `enabled` 和 `priority`;插件会解析 `codex_only`、数据库路径、`models_dev_url`、目录缓存路径和首次导入 Key。目录缓存默认与 SQLite 数据库放在同一目录。完整下游 Key 只通过受 CPA Management Key 保护的 Key 管理接口返回,不写入普通日志或错误消息;上游 Token、Cookie 和原始凭证不会由插件读取或保存。 ## 请求明细与汇总 请求明细由服务端分页,每页 100 条,默认按请求时间和稳定 ID 倒序展示。管理接口支持时间范围、用户 Key、模型、结果、上游 Auth ID、端点和完整 Request ID 筛选;连续翻页使用与筛选条件绑定的游标,数字页码跳转使用 SQLite 索引定位。用户页的今日汇总、各用户用量和近 7 日 Token 由数据库独立聚合,不受当前明细页影响。 升级已有数据库时,插件会从原始 Usage 和请求终态事实自动建立轻量查询投影。事实表、计费账目和历史统计保持不变;没有 Usage 的取消或失败请求仍然可见。patched CPA 使用 RPC schema v4 向 billing 传递 Usage Request ID 和 Trace ID,可以按 Request ID 精确关联请求终态。旧宿主或旧 schema 没有请求身份时,只有模型和时间足够接近且匹配关系唯一才关联;存在并发歧义时保留为独立记录。 ## 工程布局 - `cmd/billing`:仅负责 C ABI、请求字节复制和 C 内存释放。 - `internal/plugin`:RPC dispatcher、契约 DTO、原子配置与 Usage 接入。 - `internal/modelcatalog`:models.dev 下载、规范化、搜索和最后可用缓存。 - `scripts`:环境检查与可复现构建。 - `.externals/CLIProxyAPI`:锁定官方基线的宿主 submodule,用于构建、契约核对和集成测试;本项目的宿主改动由 `patch/` 维护。