# P5.1→NS3 缺失项 #6：Token 用量监控和成本控制

## 简要结论
- 状态：⚠️ 部分解决
- 风险等级：🟠 中
- 已实现消息级 token 记录和 Prompt 长度截断，但缺少日/月预算控制、单次调用上限校验、超限熔断机制

## 详细审查

### 审查范围
- `apps/backend/app/ai/bailian_client.py` — 百炼 API 封装层
- `apps/backend/app/ai/conversation_service.py` — 对话持久化服务
- `apps/backend/app/ai/dispatcher.py` — AI 调用链调度器
- `apps/backend/app/ai/apps/app5_tactics.py` — 典型 App 调用流程
- `apps/backend/app/ai/cache_service.py` — 缓存服务
- `docs/database/ddl/zqyy_app__biz.sql` — biz schema DDL 基线
- `db/zqyy_app/migrations/` — 迁移脚本

### 发现

#### ✅ 已实现部分

1. **消息级 token 记录**：`bailian_client.chat_json()` 返回 `(parsed_json, tokens_used)` 元组，从 `response.usage.total_tokens` 提取。所有 App（3-8）在调用后将 `tokens_used` 写入 `biz.ai_messages` 表。

2. **Prompt 长度截断**：各 App 的 `build_prompt()` 均实现了 system message 内容长度控制（如 App5 的 `_MAX_SYSTEM_CONTENT_LEN = 8000`），超长时截断服务记录、消费记录、备注等。

3. **API 层 max_tokens 参数**：`chat_json()` 默认 `max_tokens=4000`，`chat_stream()` 默认 `max_tokens=2000`，限制了单次调用的输出 token 上限。

4. **数据库持久化**：`biz.ai_messages` 表有 `tokens_used integer` 字段，每条 assistant 消息都记录了 token 消耗量。

#### ❌ 未实现部分

1. **无日/月预算控制**：代码中无任何按时间窗口（日/月）汇总 token 用量并与预算阈值比较的逻辑。
2. **无单次调用上限校验**：`max_tokens` 是硬编码默认值，无基于配置表或环境变量的动态上限。
3. **无超限熔断机制**：当 token 消耗达到阈值时，无拒绝服务或降级处理逻辑。
4. **无 token 用量汇总表**：数据库中无 `ai_token_usage`、`ai_budget` 等汇总/预算表。
5. **无成本告警**：无日志告警或通知机制在 token 消耗异常时触发。

### 证据

**token 记录（bailian_client.py L138）**：
```python
tokens_used = response.usage.total_tokens if response.usage else 0
return parsed, tokens_used
```

**消息写入（conversation_service.py L77）**：
```python
INSERT INTO biz.ai_messages
    (conversation_id, role, content, tokens_used)
VALUES (%s, %s, %s, %s)
```

**DDL 基线（zqyy_app__biz.sql）**：
```sql
CREATE TABLE biz.ai_messages (
    ...
    tokens_used integer,
    ...
);
```

**搜索 `token.*budget|cost.*control|usage.*limit|日预算|月预算` 无匹配结果**（仅匹配到缓存清理的"超限"字样，与 token 成本无关）。

### 建议

1. **新增 token 用量汇总视图或定时任务**：按 `site_id + app_id + 日期` 汇总 `biz.ai_messages.tokens_used`，写入 `biz.ai_token_daily_usage` 表
2. **新增预算配置**：在环境变量或配置表中定义 `AI_DAILY_TOKEN_LIMIT`、`AI_MONTHLY_TOKEN_LIMIT`
3. **在 dispatcher._run_step 前增加预算检查**：调用 AI 前查询当日/当月累计用量，超限则拒绝并记录日志
4. **告警机制**：当日用量达到预算 80% 时记录 WARNING 日志，达到 100% 时记录 ERROR 并熔断
