# H5 计量计费网关设计 ## 背景:当前计费的问题 当前计费内联在 `tkmind-proxy.mjs` 里,靠嗅探上游 SSE 的 `Finish` 帧扣费。100 服务实测发现三类问题: 1. **定价与成本脱钩,约 20× 超收**:默认 flat `2分/1k input` 对 DeepSeek 中继(goose `custom_tkmind_relay_deepseek`)严重偏贵。对账每条会话 H5 实扣 / goose 自报 `accumulated_cost × 7.2` 稳定落在 ~20×。换 provider 又会反向亏——单一硬编码 token 单价无法跟随模型。 2. **计量点分散**:只覆盖走 `tkmind-proxy` 的 H5 会话;`mindspace-agent-runner` 等其他 LLM 出口可能未计费。 3. **可靠性弱**:`onFinish` 为 fire-and-forget(`sse-billing.mjs` 的 `.catch(()=>{})`),扣费失败即漏计;`requestId` 全程传 `null`,无幂等键、无流水对账;读 `previous` 在事务外存在并发双扣竞态(`user-auth.mjs:943`)。 ## 已落地的止血改动(本次) `billing.mjs` 扩展 `H5_USE_BACKEND_COST` 成本路径,新增 `H5_MARGIN_MULTIPLIER`: ``` 最终扣费 = 上游 accumulated_cost(USD) 增量 × H5_USD_CNY_RATE × H5_MARGIN_MULTIPLIER ``` - 自动跟随 provider/模型,换模型不需重调 token 单价。 - 仅当上游回传 `accumulatedCost` 时生效;缺失则**回退**原 flat token 路径,不破坏现有计费。 - 生产启用:`.env` 设 `H5_USE_BACKEND_COST=1` + `H5_MARGIN_MULTIPLIER=<目标毛利>`。 > ⚠️ 上线前需确认:一帧真实 SSE 的 `token_state` 是否带 `accumulated_cost`(goose `sessions.db` 有该列,但要确认 SSE Finish 事件也序列化了它)。确认前 multiplier 改动是安全的(无 cost 即回退)。 ## 目标架构:独立计量网关 把"计量 + 定价 + 扣费 + 对账"从 H5 代理里抽出,成为所有 LLM 出口的统一收口点。 ``` H5 session ─┐ agent-runner ┤→ [计量网关] → upstream(goose/...) → usage+cost cover-ai 等 ─┘ │ ├─ 定价引擎(按 provider/模型,cost × margin) ├─ 幂等扣费(requestId 去重 + 事务内读写钱包) └─ ledger 流水(每次调用一条,可对账/审计/退款) ``` ### 关键设计点 1. **统一收口**:所有发往 LLM 的调用都经网关,拿 provider 回传的真实 `usage` + `cost`,而非各出口各自实现。 2. **定价引擎按 provider 配置**:`{ provider, model } → { 计价基准, marginMultiplier }`。DeepSeek 与未来的 Claude 成本差几十倍,必须差异化,不能一个 flat 单价打天下。优先用成本基准(cost × margin),无 cost 的 provider 才退回 token 单价表。 3. **幂等扣费**:每次调用带 `requestId`;ledger 以 `requestId` 唯一约束,重放/重连不重复扣。当前 SSE 重连靠"accumulated 单调 → delta 0"兜底,脆弱,应换显式幂等键。 4. **事务内读写**:钱包扣减与计费状态读取在同一事务 + `FOR UPDATE`,消除并发双扣。 5. **ledger 流水表**:`(request_id, user_id, session_id, provider, model, input_tokens, output_tokens, upstream_cost_usd, charged_cents, margin, created_at)`。支撑对账(H5 扣费 vs 上游成本)、用户账单明细、纠纷退款。 6. **失败可恢复**:扣费写库失败要可重试/补偿,不能像现在 fire-and-forget 直接吞掉。 ### 落地阶段 - **P0(已做)**:成本模式 + margin,env 切换止血 20× 超收。 - **P1**:补 `requestId` 幂等 + 修事务竞态 + ledger 流水表(仍在 proxy 内,先把可靠性和对账补齐)。 - **P2**:抽出独立计量模块/服务,纳入 agent-runner 等其他出口,定价引擎按 provider 配置化。