# 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 配置化。
