diff --git a/README.md b/README.md index 93056c5..706b339 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,66 @@ 每个 Key 同时拥有独立的美元额度账户。管理员可以分配本周期额度、设置日/周/月自动重置和并发上限,并查看不可变的扣费、额度调整与重置账目。额度采用请求结束后结算的软限制:余额为正时放行,实际 Usage 到达后扣费,最后一个或多个在途请求可能产生负余额,之后的新请求返回 429。 +## 一次请求如何通过 CPA + +```mermaid +sequenceDiagram + autonumber + participant Client as 用户 / Codex + participant CPA as CLIProxyAPI + participant Ext as cpa-ext + participant DB as SQLite + participant Upstream as 实际模型服务 + + Client->>CPA: 携带下游 Key 发起模型请求 + CPA->>Ext: frontend_auth.authenticate + Ext->>DB: 查询 Key 与状态 + DB-->>Ext: 用户访问配置 + + alt Key 无效或已停用 + Ext-->>CPA: 认证失败 + CPA-->>Client: 401 Unauthorized + else 认证成功 + Ext-->>CPA: 返回用户身份(稳定 Key ID) + CPA->>Ext: request.intercept_before + Ext->>DB: 检查模型权限、余额与并发并占用名额 + + alt 模型、额度或并发不允许 + Ext-->>CPA: 终止请求(403 / 429 / 503) + CPA-->>Client: 返回结构化错误 + else 请求准入 + Ext-->>CPA: 允许继续 + CPA->>Ext: scheduler.pick(可用上游候选) + + alt 自动路由 + Ext-->>CPA: 委托 CPA 内置调度 + else 严格路由 + Ext->>DB: 读取该用户绑定的上游账号 + Ext-->>CPA: 指定唯一 Auth ID + end + + CPA->>Ext: request.intercept_after + Ext-->>CPA: 复核价格配置与实际上游 + + alt 价格缺失或严格路由失效 + CPA-->>Client: 503 Service Unavailable + else 复核通过 + CPA->>Upstream: 使用选定凭证转发请求 + Upstream-->>CPA: 模型响应 / 流式输出 + CPA-->>Client: 返回模型结果 + + CPA->>Ext: request.complete(请求终态) + Ext->>DB: 释放并发名额,保存成功、失败或取消结果 + CPA->>Ext: usage.handle(如有最终 Token 用量) + Ext->>Ext: 按模型价格计算成本 + Ext->>DB: 保存用量、扣减余额并写入账目 + end + end + end +``` + +CLIProxyAPI 负责 HTTP 接入、协议转换、上游凭证和实际请求执行;`cpa-ext` 通过插件回调参与请求决策与记录,不直接连接模型服务。`request.complete` 与 `usage.handle` 是独立事实回调,实际到达顺序不作为数据正确性的前提。 + ## 当前兼容目标 - CLIProxyAPI 源码:`CLIProxyAPI/`,检查时 revision 为 `f43aad7637ad813745bf7d341acb5663617570c5` diff --git a/docs/modules/admin-console.md b/docs/modules/admin-console.md new file mode 100644 index 0000000..e63f464 --- /dev/null +++ b/docs/modules/admin-console.md @@ -0,0 +1,153 @@ +# 管理台 + +## 模块定位 + +管理台是 cpa-ext 各业务模块的统一操作和查看入口。它不单独保存业务事实,而是通过 CLIProxyAPI 受保护的 Management API 读取或修改 SQLite 中的真实配置与记录。 + +当前管理台采用单页、紧凑布局,直接作为插件资源嵌入,不依赖 CDN、外部前端框架或独立构建服务。 + +## 页面结构 + +| 页面 | 主要用途 | +| --- | --- | +| 用户 Key | 管理用户、访问策略、路由、额度和并发,查看用户汇总与账目 | +| 请求明细 | 分页查看请求结果、上游、Token、性能和成本,执行组合筛选 | +| 价格配置 | 维护模型基础价格、长上下文价格和 Fast 倍率 | + +页面顶部统一提供实时/测试模式切换和 CPA 管理密钥输入。 + +## 用户 Key 页面 + +页面顶部展示今日请求、今日 Token、今日成本、各用户今日用量以及近 7 日 Token 趋势。 + +Key 列表展示: + +- 用户名称和完整 Key; +- 启用、禁用或归档状态; +- 当前余额和额度; +- 活跃并发与并发上限; +- 自动或严格上游路由; +- 允许的模型规则。 + +管理员可以创建 Key、显示已归档项、刷新列表,并通过侧边抽屉完成以下操作: + +- 修改名称和状态; +- 选择自动路由或指定上游账号; +- 允许全部模型或填写逗号分隔的模型规则; +- 设置额度、并发上限、重置周期和下一次重置时间; +- 立即重置额度; +- 查看最近计费账目; +- 永久归档 Key; +- 查看该用户累计、今日和最近请求。 + +业务规则和拒绝条件分别由“用户与访问管理”“额度与计费”模块执行,管理台只负责提交和呈现。 + +## 请求明细页面 + +请求明细默认每页显示 100 条,页码、上一页、下一页、选择列和刷新操作位于同一顶部工具区。 + +当前筛选项包括: + +- 开始和结束时间; +- 用户; +- 模型; +- 成功、失败、拒绝或取消; +- 实际上游; +- Responses、Compact 或 Chat 端点; +- 完整 Request ID。 + +筛选和分页由服务端执行。应用新筛选会返回第一页;刷新保持当前页和筛选条件。只有页面可见、位于请求明细且处于第一页时,实时模式才每三秒自动刷新,避免用户查看历史页时列表自行跳动。 + +“选择列”用于控制明细表可见字段,不改变服务端保存的数据。 + +## 价格配置页面 + +价格页面采用左侧模型列表、右侧编辑区: + +- 新增或选择一个精确模型名称; +- 设置输入、缓存读取、缓存写入和输出的基础价格; +- 可选启用长上下文价格; +- 设置长上下文输入门槛及“大于/大于等于”比较方式; +- 可选启用 Fast 价格并设置倍率; +- 保存或删除模型价格。 + +价格单位统一显示为 `$ / 1M Token`。保存前由管理接口完成严格字段校验,页面不会自行推断缺失价格。 + +## 实时模式 + +实时模式连接当前 CLIProxyAPI 实例: + +- 需要输入 CPA Management Key; +- 所有读取来自真实管理接口; +- 创建、编辑、归档、重置和价格保存会修改真实数据; +- 请求明细和汇总反映真实请求事实。 + +管理台资源本身可以被 CPA 加载,但敏感管理接口仍由 CLIProxyAPI 的管理认证保护。 + +## 测试模式 + +测试模式用于管理员熟悉页面和验证交互,与真实数据完全隔离: + +- 不需要管理密钥; +- 不访问任何真实 cpa-ext 管理接口; +- 使用浏览器本地的模拟 Key、上游、请求、价格和账目; +- 创建、编辑、归档、重置和删除只修改本地模拟状态; +- 提供放大的请求记录量,便于测试分页、筛选和表格布局; +- 可以一键恢复初始测试数据。 + +测试数据保存在浏览器本地存储中,当前选择的实时/测试模式保存在当前会话。切换模式不会把测试数据导入真实数据库,也不会用真实数据覆盖测试样例。 + +## 管理接口 + +管理接口统一挂载在: + +```text +/v0/management/plugins/cpa-ext +``` + +| 路径 | 方法 | 用途 | +| --- | --- | --- | +| `/keys` | GET、POST、PATCH、DELETE | 查询、创建、更新和归档 Key | +| `/key-stats` | GET | 查询单个 Key 的统计和最近请求 | +| `/upstreams` | GET | 同步并查询 CPA 上游账号 | +| `/model-suggestions` | GET | 查询已知模型名称建议 | +| `/billing-reset` | POST | 立即重置指定 Key 的额度 | +| `/billing-ledger` | GET | 查询指定 Key 的计费账目 | +| `/usage` | GET | 查询分页请求明细 | +| `/usage-summary` | GET | 查询今日、用户和每日汇总 | +| `/prices` | GET、PUT、DELETE | 查询、保存和删除模型价格 | + +管理台 HTML 由以下插件资源提供: + +```text +/v0/resource/plugins/cpa-ext/ui +``` + +管理接口返回结构化 JSON 和明确的 HTTP 状态码;未知路径返回 `not_found`,数据库不可用、请求字段错误等情况返回对应错误码和消息。 + +## 界面与数据原则 + +- 管理台不直接操作 SQLite,只调用公开管理接口。 +- 统计卡片和图表使用服务端汇总,不从当前明细页推算。 +- 业务校验由服务端完成,前端校验只用于尽早提示。 +- 完整 Key 仅在受管理认证保护的 Key 接口和页面中显示。 +- 上游 Token、Cookie 和原始凭证不进入管理台。 +- 界面保持单个嵌入资源,避免运行时依赖外部 CDN。 +- 窄屏下表单和工具栏自动重排,明细表保留横向滚动能力。 + +## 模块边界 + +本模块负责: + +- 提供统一管理页面; +- 调用并呈现 cpa-ext Management API; +- 管理实时和测试数据模式; +- 提供紧凑、可筛选、可分页的操作界面。 + +本模块不负责: + +- 绕过 CLIProxyAPI 管理认证; +- 在浏览器中直接执行业务扣费或访问控制; +- 保存真实业务数据; +- 提供普通用户自助页面; +- 提供登录、角色和多管理员权限体系。 diff --git a/docs/modules/billing-and-pricing.md b/docs/modules/billing-and-pricing.md new file mode 100644 index 0000000..ef72ecd --- /dev/null +++ b/docs/modules/billing-and-pricing.md @@ -0,0 +1,166 @@ +# 额度与计费 + +## 模块定位 + +额度与计费负责回答三个问题:一次请求是否还可以开始、请求实际产生了多少成本、该用户当前还剩多少可用额度。 + +每个用户 Key 拥有独立的美元额度账户、重置周期和并发上限。系统没有套餐、订阅或充值订单,管理员直接分配额度。 + +## 当前能力 + +| 能力 | 当前实现 | +| --- | --- | +| 用户额度 | 每个 Key 独立设置本周期美元额度 | +| 请求扣费 | 根据最终 Token Usage 和模型价格结算 | +| 自动重置 | 支持不重置、每日、每周和每月 | +| 手动重置 | 管理员可立即开始新额度周期 | +| 并发限制 | 每个 Key 独立限制同时执行的请求数 | +| 价格规则 | 支持基础价格、长上下文价格和 Fast 倍率 | +| 计费账目 | 永久记录扣费、额度调整和周期重置 | +| 请求拦截 | 余额、并发或价格不满足时在上游调用前拒绝 | + +## 额度账户 + +每个 Key 创建时同时创建一个额度账户,默认值为: + +| 属性 | 默认值 | +| --- | --- | +| 本周期额度 | `$0` | +| 已用金额 | `$0` | +| 可用余额 | `$0` | +| 自动重置 | 不重置 | +| 并发上限 | 4 | + +三项金额的关系始终为: + +```text +可用余额 = 本周期额度 - 本周期已用金额 +``` + +金额在数据库中以微美元整数保存,管理接口使用最多六位小数的美元字符串,避免浮点累计误差。 + +修改额度只改变本周期额度,不会清空已经产生的消费。例如额度为 `$10`、已用 `$3` 时,将额度改为 `$5`,余额会变为 `$2`。 + +## 请求准入与结算 + +计费采用“请求前准入、请求后结算”的软限制: + +1. 请求开始前读取当前额度周期。 +2. 如果已经到达重置时间,先执行周期重置。 +3. 余额必须大于零。 +4. 当前并发必须小于用户并发上限。 +5. 为 Request ID 创建并发占用后放行请求。 +6. 请求终态到达时释放并发占用。 +7. 最终 Usage 到达后计算成本、增加已用金额并写入扣费账目。 + +系统不会在请求开始前估算并冻结最大费用,因此最后一个或多个并发请求可能让余额变成负数。负余额会被保留,之后的新请求不再放行,直到管理员提高额度或开始新周期。 + +同一个 Request ID 的重复准入不会重复占用并发;同一条 Usage 的重复回调也不会重复扣费。插件重新启动时会释放上次进程遗留的未关闭并发占用。 + +## 并发限制 + +并发上限可以设置为 1–64。计数基于已经准入且尚未收到请求终态的 Request ID。 + +- 达到上限时,新请求返回 HTTP 429 和 `billing_concurrency_exceeded`。 +- 成功、失败、拒绝或取消的请求进入终态后都会释放名额。 +- 重复或迟到的终态回调不会重复释放或破坏计数。 + +并发限制只控制同时执行数量,不限制单位时间请求次数或 Token 数量。 + +## 额度重置 + +| 重置方式 | 行为 | +| --- | --- | +| `none` | 永不自动重置 | +| `daily` | 按天开始新周期 | +| `weekly` | 每七天开始新周期 | +| `monthly` | 按月开始新周期 | +| 手动重置 | 立即结束当前周期并开始新周期 | + +未指定首次重置时间时,系统以 Key 创建时间作为周期锚点计算下一次重置。周期计算使用 `Asia/Shanghai` 时区;月度锚点在较短月份不存在时使用该月最后一天。 + +重置后: + +- 本周期已用金额归零; +- 新周期额度沿用当前额度设置; +- 可用余额恢复为完整额度; +- 旧周期余额不结转; +- 历史周期和账目继续保留。 + +自动重置在读取额度状态或执行请求准入时检查,不依赖常驻定时任务。 + +## 模型价格 + +每个模型使用精确模型名称维护一套价格策略,价格单位为 `$ / 1M Token`。 + +### 基础价格 + +| 价格项 | 计费对象 | +| --- | --- | +| 输入 | 排除缓存读取和缓存写入后的普通输入 Token | +| 缓存读取 | Cache Read Token | +| 缓存写入 | Cache Write/Creation Token | +| 输出 | Output Token | + +普通输入 Token 的计算方式为: + +```text +普通输入 = 输入 Token - 缓存读取 Token - 缓存写入 Token +``` + +### 长上下文价格 + +价格策略可以设置输入 Token 门槛,并选择“大于”或“大于等于”。请求达到门槛时,输入、缓存读取、缓存写入和输出四项价格整体切换到长上下文价格,不与基础价格混用。 + +### Fast 价格 + +当请求标记为 Fast、Priority 或同等快速服务档位,并且该模型启用 Fast 计价时,系统对完整请求成本应用一次倍率。倍率以精确分数保存,默认界面值为 `2.5`。 + +系统先选择基础或长上下文档位,再应用 Fast 倍率,最后对整次请求执行一次四舍五入。 + +## 价格缺失 + +允许访问的模型必须存在价格配置。系统在 CPA 已经选择上游后、真正访问模型服务前再次检查实际模型价格。 + +价格不存在时返回 HTTP 503 和 `billing_price_unavailable`,不会把未知成本的请求发送到上游。历史迁移数据仍可能因为当时没有价格而显示为成本不可用。 + +## 不可变账目 + +| 账目类型 | 含义 | 金额方向 | +| --- | --- | --- | +| `charge` | 一次最终 Usage 产生的扣费 | 负数 | +| `quota_change` | 管理员修改本周期额度 | 增加为正,减少为负 | +| `cycle_reset` | 自动或手动开始新周期 | 新周期完整额度 | + +每条账目保存用户 Key、额度周期、变动金额、变动后余额和发生时间。请求扣费还会保存 Request ID、Execution ID 和模型。 + +账目只追加、不修改、不删除,并通过唯一事件标识避免重复写入。额度状态用于快速读取当前余额,账目用于解释余额变化过程。 + +## 拒绝结果 + +| 条件 | HTTP 状态 | 错误码 | +| --- | --- | --- | +| 余额小于或等于零 | 429 | `billing_quota_exhausted` | +| 并发达到上限 | 429 | `billing_concurrency_exceeded` | +| 额度数据库不可用 | 503 | `billing_unavailable` | +| 模型没有价格 | 503 | `billing_price_unavailable` | + +这些拒绝发生在访问实际模型服务之前,并进入请求终态记录。 + +## 模块边界 + +本模块负责: + +- 模型价格和确定性成本计算; +- 用户额度、余额和额度周期; +- 并发请求准入; +- 请求结束后的实际扣费; +- 不可变计费账目。 + +本模块不负责: + +- 套餐、订阅、充值、支付和退款; +- 按分钟、按日或按月的额外速率限制; +- 请求开始前的费用预估或资金冻结; +- 用户 Key 的身份认证和模型权限; +- 上游服务本身的账单对账。 diff --git a/docs/modules/usage-and-statistics.md b/docs/modules/usage-and-statistics.md new file mode 100644 index 0000000..666aaa2 --- /dev/null +++ b/docs/modules/usage-and-statistics.md @@ -0,0 +1,137 @@ +# 用量与统计 + +## 模块定位 + +用量与统计负责记录一次请求发生了什么,并将请求结果、实际使用的上游、Token、性能和成本整理成可查询的请求明细与汇总数据。 + +该模块以 CLIProxyAPI 的请求终态和最终 Usage 为事实来源,不解析客户端响应内容,也不依赖管理页面当前加载的记录。 + +## 当前能力 + +| 能力 | 当前实现 | +| --- | --- | +| 请求终态 | 记录成功、失败、拒绝和取消 | +| Token 用量 | 记录输入、输出、推理、缓存读取和缓存写入 | +| 实际执行 | 记录模型、上游 Auth ID、端点和执行信息 | +| 性能指标 | 记录首字延迟、总延迟、生成速度和缓存率 | +| 成本事实 | 保存计算结果、价格档位和 Fast 倍率 | +| 请求归并 | 将请求终态与 Usage 整理为一条可读明细 | +| 查询 | 支持服务端分页、数字页码和多条件筛选 | +| 汇总 | 提供今日指标、各用户用量和近 7 日 Token | + +## 两类事实 + +CLIProxyAPI 会通过两个独立回调提供请求信息: + +| 事实 | 来源 | 主要内容 | +| --- | --- | --- | +| 请求终态 | `request.complete` | Request ID、开始与结束时间、成功/失败/拒绝/取消、状态码和错误 | +| 最终用量 | `usage.handle` | Execution ID、实际上游、模型、Token、延迟和 Usage 结果 | + +这两个回调可能乱序、重复或只到达其中一个,因此数据库分别保存原始事实,再建立请求明细查询投影。管理台看到的一行是查询结果,不会为了合并展示而修改原始事实或计费账目。 + +## 请求与重试 + +- Request ID 用于关联一次下游请求的生命周期。 +- Execution ID 用于区分该请求的具体上游执行。 +- 同一次请求发生上游重试时,每次真实执行继续分别展示,不会把多个执行的 Token 或成本错误相加为一次执行。 +- 没有 Usage 的拒绝、取消或失败请求仍然显示请求终态。 +- 只有 Usage、暂时没有终态的记录也可以单独显示,终态到达后投影会自动更新。 + +部分旧版回调可能缺少 Request ID。系统仅在请求时间足够接近且匹配关系唯一时,将 Usage 与终态合并;存在并发歧义时宁可保留为两条,也不会错误关联到其他用户的请求。 + +## 请求结果 + +| 结果 | 含义 | +| --- | --- | +| `succeeded` | 请求正常完成 | +| `failed` | 执行失败或上游返回错误 | +| `rejected` | 请求在认证、权限、额度、并发、价格或路由阶段被拒绝 | +| `canceled` | 客户端断开或请求被取消 | + +如果终态尚未到达,界面根据现有 Usage 事实展示当前可确定的结果;终态到达后以请求生命周期结果补全。 + +## 明细字段 + +请求明细当前可以展示: + +- 请求时间、Request ID、Execution ID、Trace ID; +- 用户 Key 名称; +- 客户端请求模型和实际计费模型; +- 推理强度、服务档位和速度模式; +- 请求结果、HTTP 状态码和错误; +- 请求类型与端点; +- 实际上游 Auth ID、Auth Index 和认证类型; +- 首字延迟、生成速度; +- 输入、输出、推理、缓存读取、缓存写入和总 Token; +- 缓存率、成本、价格档位和 Fast 计价结果; +- 客户端 IP。 + +并非每种端点都能提供所有字段。字段无法由 CPA 回调可靠获得时保留为空,不使用猜测值。一次性 JSON/Compact 响应不展示不可比较的首字延迟和生成速度。 + +## 服务端分页 + +请求明细由 SQLite 分页查询,而不是先把全部历史加载到浏览器。 + +- 默认每页 100 条,单页上限也是 100 条。 +- 默认按照请求时间和稳定记录 ID 倒序排列。 +- 数字页码用于直接跳转。 +- 连续上一页、下一页使用游标保持翻页稳定。 +- 游标与当前全部筛选条件绑定,修改筛选后不能继续使用旧游标。 +- 新请求写入时,已经打开的连续翻页不会因为列表头部变化而重复或遗漏原有记录。 + +当前支持的筛选条件为: + +| 条件 | 说明 | +| --- | --- | +| 开始、结束时间 | 使用 RFC3339 时间范围 | +| 用户 Key | 按稳定 Key ID 查询 | +| 模型 | 按模型名称查询 | +| 结果 | 成功、失败、拒绝或取消 | +| 上游 | 按实际 Auth ID 查询 | +| 端点 | 例如 Responses、Compact 或 Chat | +| Request ID | 使用完整 Request ID 精确定位 | + +## 汇总统计 + +汇总由数据库独立计算,不受请求明细当前页或筛选条件影响。 + +| 汇总 | 当前内容 | +| --- | --- | +| 今日总览 | 请求数、输入 Token、输出 Token、总 Token 和成本 | +| 用户汇总 | 各用户今日请求、Token、成本和最近使用时间 | +| 近 7 日趋势 | 每个自然日的总 Token | +| 单用户统计 | 累计、今日指标和最近 50 条请求 | + +“今日”按照 `Asia/Shanghai` 自然日计算。成本只汇总已经得到有效价格计算结果的 Usage。 + +## 持久化与规模 + +原始请求、Usage 和轻量查询投影均保存在 SQLite。升级旧数据库时,插件会自动创建投影、回填历史数据并建立分页和筛选索引。 + +查询投影只保存明细检索所需的关联和排序字段,Token、成本、生命周期和账目仍以原始事实表为准。当前分页与组合筛选已按百万级记录场景设计,不要求将全部记录读入内存。 + +## 数据一致性 + +- Usage 插入使用稳定事件标识,重复回调不会重复记录或扣费。 +- 请求终态按 Request ID 幂等更新。 +- 回调乱序时,后到达的事实会重新同步查询投影。 +- 失败、取消和孤立 Usage 不会为了界面整齐而被删除。 +- 历史迁移只建立查询关系,不改写既有用量和计费事实。 + +## 模块边界 + +本模块负责: + +- 请求终态与 Usage 持久化; +- 请求明细归并、分页和筛选; +- Token、成本、上游和性能展示; +- 今日、用户和每日趋势汇总。 + +本模块不负责: + +- 用户认证、模型权限和上游选择; +- 模型价格的维护规则; +- 额度准入和余额扣减; +- 修改或重放历史请求; +- 替代上游服务提供商的正式账单。 diff --git a/docs/modules/user-access-management.md b/docs/modules/user-access-management.md new file mode 100644 index 0000000..111258c --- /dev/null +++ b/docs/modules/user-access-management.md @@ -0,0 +1,145 @@ +# 用户与访问管理 + +## 模块定位 + +用户与访问管理负责识别调用者,并决定该调用者可以使用哪些模型、请求应由哪个上游账号处理。 + +本项目不建立独立的用户账号体系,而是采用最小模型: + +> 一个 Key 代表一个用户。 + +管理员直接管理 Key;Key 的稳定 ID 用于关联用量、额度和历史记录,Key 名称用于界面识别,Key 值用于请求认证。 + +## 当前能力 + +| 能力 | 当前实现 | +| --- | --- | +| Key 创建 | 支持自动生成或手动指定 Key 值 | +| Key 状态 | 支持启用、禁用和归档 | +| 下游认证 | 支持 `Authorization: Bearer ` 和 `X-Api-Key` | +| 模型权限 | 支持允许全部模型、精确模型名和 `*` 通配符 | +| 上游路由 | 支持 CPA 自动选择或严格绑定一个上游账号 | +| 默认迁移 | 首次启动自动创建 `default` Key,兼容现有调用配置 | +| 历史关联 | Key 的请求、用量、额度和账目均按稳定 ID 关联 | + +## Key 数据模型 + +每个 Key 包含以下访问属性: + +| 属性 | 说明 | +| --- | --- | +| ID | 系统生成的稳定标识,用于内部关联,不随名称变化 | +| 名称 | 管理员可读的用户名称,长度为 1–64 个字符 | +| Key 值 | 下游请求凭证;创建后不可修改 | +| 状态 | `active`、`disabled` 或 `archived` | +| 路由模式 | `auto` 或 `strict` | +| 上游账号 | 严格路由时绑定的 CPA 上游账号 | +| 模型规则 | 允许全部模型,或一组模型匹配规则 | + +Key 值允许 1–256 个非空白、非控制字符。未手动填写时,系统生成以 `cpa_` 开头的随机值。 + +## 状态规则 + +| 状态 | 是否可以调用 | 是否可以编辑 | 是否保留历史 | 是否可以恢复 | +| --- | --- | --- | --- | --- | +| `active` | 是 | 是 | 是 | 不适用 | +| `disabled` | 否 | 是 | 是 | 可以重新启用 | +| `archived` | 否 | 否 | 是 | 不可以 | + +禁用用于临时停止用户访问;归档用于永久退出管理。归档不会删除请求、用量、额度或计费账目,默认 Key 列表不再显示已归档项。 + +## 模型权限 + +模型匹配不区分大小写,并忽略规则首尾空白。 + +- “允许全部模型”开启时,不再读取单独的模型规则。 +- “允许全部模型”关闭时,至少需要一条模型规则。 +- 不含 `*` 的规则执行精确匹配,例如 `gpt-5.6-sol`。 +- `*` 可以匹配任意长度的文本,例如 `deepseek-*`、`*-flash` 或 `gpt-*-codex`。 +- 空模型名不能通过模型准入。 + +请求模型不符合规则时,请求在到达上游前被拒绝,返回 HTTP 403 和错误码 `model_not_allowed`。 + +## 上游路由 + +### 自动路由 + +`auto` 模式不绑定具体账号,由 CLIProxyAPI 根据当前可用候选、优先级和自身调度规则选择上游。 + +切换到自动路由后,Key 原有的上游绑定会被清空。 + +### 严格路由 + +`strict` 模式必须选择一个已经由 CLIProxyAPI 发现的上游账号。插件在调度阶段只选择该账号,不允许静默回退到其他账号。 + +出现以下情况时,请求返回 HTTP 503 和错误码 `bound_upstream_unavailable`: + +- 绑定的账号已经不存在; +- 绑定的账号被禁用或处于不可用状态; +- 绑定账号不在本次请求的可用候选中; +- 调度完成后的实际上游与绑定账号不一致。 + +上游账号信息来自 CLIProxyAPI 的账号列表和实际调度候选,插件只保存路由所需的账号标识、提供商、显示名称和状态,不读取或保存上游 Token、Cookie 等凭证内容。 + +## 默认 Key 与新建 Key + +首次启动且数据库中没有任何 Key 时,插件根据配置创建第一个 Key: + +- 默认名称:`default` +- 默认 Key 值:`000000` +- 默认状态:启用 +- 默认路由:自动 +- 默认模型权限:允许全部模型 + +该行为用于让已有 Codex/CLIProxyAPI 调用配置无需修改即可迁移到插件管理。 + +之后创建新 Key 时,系统先复制 `default` 当时的模型权限和上游路由,再应用管理员本次明确填写的设置。复制只发生在创建时,后续修改 `default` 不会影响已经创建的 Key。 + +如果数据库中已经存在 Key,启动配置不会覆盖或重新创建 `default`。 + +## 请求处理流程 + +| 阶段 | 模块行为 | +| --- | --- | +| 1. 提取凭证 | 从 Bearer Token 或 `X-Api-Key` 读取 Key | +| 2. 身份认证 | 查找 Key,并确认状态为 `active` | +| 3. 建立调用身份 | 使用稳定 Key ID 作为下游调用者身份 | +| 4. 模型准入 | 使用请求模型匹配该 Key 的模型规则 | +| 5. 上游调度 | 自动委托 CPA,或选择严格绑定的账号 | +| 6. 路由复核 | 严格模式下确认实际选择的账号与绑定一致 | + +认证失败不会进入后续访问判断。Key 在请求过程中被停用时,后续拦截仍会再次检查状态,避免仅依赖认证阶段的旧状态。 + +额度、并发和价格检查发生在同一条请求准入链路中,但分别属于“额度与计费”和“价格配置”模块,不在本文展开。 + +## 管理操作 + +管理员页面当前支持: + +- 查看有效 Key,按需包含已归档 Key; +- 创建并复制 Key; +- 修改名称、启用状态、模型规则和上游路由; +- 临时禁用或重新启用 Key; +- 永久归档 Key; +- 同步并选择 CLIProxyAPI 当前可见的上游账号; +- 根据历史请求和价格配置获得模型名称建议; +- 查看该 Key 的累计、今日和最近使用记录。 + +管理操作通过受 CLIProxyAPI Management Key 保护的管理接口完成。测试模式使用独立模拟数据,不读取或修改这里描述的真实 Key 和路由配置。 + +## 模块边界 + +本模块负责: + +- Key 身份与生命周期; +- 下游请求认证; +- 模型访问规则; +- 上游账号选择策略。 + +本模块不负责: + +- 用户注册、密码、登录会话和角色权限; +- 套餐、充值、支付和订单; +- 额度扣减、周期重置和并发计数; +- 模型价格维护与成本计算; +- CLIProxyAPI 上游账号本身的登录、刷新或凭证维护。