Usage, Quota & Spend Tracking (中文 (简体))
每个流经 OmniRoute 的请求都会生成一条用量记录,其中包含:
- 身份信息:使用了哪个 API 密钥、提供者、模型和组合
- 令牌:提示词令牌、补全令牌、缓存令牌和总令牌数
- 成本:美元金额(根据定价数据计算)
- 时间信息:延迟、开始/结束时间戳
- 状态:成功、错误、受到速率限制等
这些记录会被聚合为分析数据,持久化为配额快照,并用于强制执行每个密钥的预算限制。
请求 ──▶ chatCore ──▶ usage.record() ──▶ SQLite │ ┌───────┼───────┐ ▼ ▼ ▼ 分析数据 配额 计费 (仪表板)(强制执行)(导出)usage.ts 服务会为每个请求捕获一个用量事件:
| 字段 | 类型 | 来源 |
|---|---|---|
id |
string | 记录时生成的 UUID |
apiKeyId |
string | 发起请求的 API 密钥 |
provider |
string | 提供者 ID(openai、anthropic 等) |
model |
string | 模型 ID(gpt-5、claude-opus-4-6 等) |
comboId |
string? | 如果通过组合路由,则为组合 ID |
promptTokens |
number | 来自上游响应 |
completionTokens |
number | 来自上游响应 |
cachedTokens |
number | 缓存命中令牌(Anthropic 提示词缓存等) |
totalTokens |
number | 提示词令牌 + 补全令牌 |
costUsd |
number | 根据定价数据计算 |
latencyMs |
number | 端到端请求持续时间 |
status |
enum | success、error、rate_limited、timeout、cancelled |
errorClass |
string? | status != success 时的错误类别 |
timestamp |
string | ISO 8601 UTC |
metadata |
object | 插件注入的自定义数据 |
令牌是在响应处理器中从上游提供者的响应里提取的:
// 来自 open-sse/handlers/chatCore.tsconst response = await providerExecutor.execute(provider, request);const usage = response.usage || { prompt_tokens: 0, completion_tokens: 0, cached_tokens: 0,};对于不返回用量数据的提供者(例如某些 Web Cookie 提供者),OmniRoute 会使用 ~4 chars per token 启发式规则估算令牌数(请参阅 open-sse/services/autoCombo/pipelineRouter.ts)。
OmniRoute 会将 cached_tokens 与 prompt_tokens 分开跟踪,原因如下:
- Anthropic 提示词缓存对缓存令牌收取较低的费率(正常费率的 10%)
- 某些提供者会返回
cache_read_input_tokens,这类令牌应采用不同的定价方式 - 分析数据可以显示缓存命中率 =
cached_tokens / prompt_tokens
成本根据从 LiteLLM 同步的定价数据计算(src/lib/pricingSync.ts):
| 模型 | 输入 $/1M | 输出 $/1M | 缓存 $/1M |
|---|---|---|---|
| gpt-5 | $2.50 | $10.00 | — |
| claude-opus-4-6 | $15.00 | $75.00 | $1.50 |
| claude-sonnet-4-5 | $3.00 | $15.00 | $0.30 |
| gemini-2.5-pro | $1.25 | $10.00 | — |
成本公式(src/lib/usage/costCalculator.ts):
cost = (prompt_tokens - cached_tokens) * input_price + cached_tokens * cached_price + completion_tokens * output_price;为什么要从 prompt 中减去 cached? 缓存部分会单独计价;如果对整个 prompt 收取输入费用,将导致重复计费。
定价数据会通过 /api/pricing/sync 端点从 LiteLLM 自动同步(由内置 cron 任务触发,而不是通过面向用户的环境变量触发):
# 手动触发curl -X POST http://localhost:20128/api/pricing/sync对于没有定价数据的模型,OmniRoute 会回退为使用内部平均费率(来源于 LiteLLM 的定价数据)来估算成本。
日期范围聚合
Section titled “日期范围聚合”usageAnalytics.ts 模块根据原始使用情况数据计算仪表板组件。它支持 7 种时间范围:
| 范围 | 时间窗口 | 使用场景 |
|---|---|---|
1d |
最近 24 小时 | 检测每小时成本峰值 |
7d |
最近 7 天 | 每周审查 |
30d |
最近 30 天 | 月度计费 |
90d |
最近 90 天 | 季度分析 |
ytd |
自当年 1 月 1 日起 | 年度预算跟踪 |
all |
全部时间 | 全生命周期统计 |
custom |
用户定义的开始/结束时间 | 审计、临时查询 |
计算的仪表板组件
Section titled “计算的仪表板组件”对于任意日期范围,分析层都会计算:
| 组件 | 描述 |
|---|---|
| 摘要卡片 | 请求总数、总成本、token 总数、成功率 |
| 每日趋势图 | 每日成本和 token 数量,按模型堆叠 |
| 活动热力图 | 小时 × 星期几网格,颜色 = 请求数量 |
| 模型明细 | 按模型统计成本的饼图 |
| 提供者明细 | 按提供者统计请求数量的条形图 |
| 热门 API 密钥 | 按成本排名前 10 的密钥表格 |
| 错误分析 | 随时间变化的错误率、主要错误类别 |
编程方式访问
Section titled “编程方式访问”import { computeAnalytics } from "@/lib/usageAnalytics";
const analytics = await computeAnalytics( history, // 使用情况历史记录 "7d", // 时间范围:"1d" | "7d" | "30d" | "90d" | "ytd" | "all" | "custom" connectionMap, // 提供者连接映射(connectionId → 账户名称) { startDate: "2025-01-01", // 可选:用于 "custom" 范围 endDate: "2025-06-01", // 可选:用于 "custom" 范围 });
console.log(analytics.summary.totalCost); // 12.34(美分)console.log(analytics.byModel[0]); // { model, cost, requests, promptTokens, completionTokens }
---
## 配额强制执行
每个 API 密钥的配额在两个位置强制执行:
1. **软限制**(`quotaWarnAt`):当使用量超过阈值时在仪表板中显示警告2. **硬限制**(`quotaLimit`):超过限制时拒绝请求并返回 HTTP 429
### 配置
```ts// 每个 API 密钥await updateApiKey(keyId, { quotaWarnAt: 5_00, // $5.00 — 显示警告 quotaLimit: 10_00, // $10.00 — 硬性停止 quotaWindow: "month", // "day" | "week" | "month" | "all"});强制执行流程
Section titled “强制执行流程”请求 ──▶ quotaCheck() │ ├── 未超过限制? ──▶ 允许 │ └── 超过限制? ──▶ 429 请求过多 并带有 Retry-After 标头quotaSnapshots 表存储用于趋势分析的历史配额状态:
| 字段 | 描述 |
| ———– | –––––––––––––––– | —— | —–– |
| apiKeyId | 正在跟踪的密钥 |
| window | “day” | “week” | “month” |
| used | 此窗口内已使用的成本(美分) |
| limit | 限制(美分) |
| resetAt | 窗口重置时间 |
| createdAt | 快照生成时间 |
系统会为成本 > 0 的每个请求生成快照,并将其用于:
- 在仪表板中呈现配额进度条
- 显示 30 天配额趋势图
- 当使用量接近限制时触发警报
REST API
Section titled “REST API”列出使用记录
Section titled “列出使用记录”GET /api/usage?range=7d&limit=100GET /api/usage?apiKeyId=key-123&range=30dGET /api/usage?provider=openai&range=1d响应:
{ "records": [ { "id": "uuid", "apiKeyId": "key-123", "provider": "openai", "model": "gpt-5", "promptTokens": 1234, "completionTokens": 567, "totalTokens": 1801, "costUsd": 0.005, "latencyMs": 1234, "status": "success", "timestamp": "2026-06-08T12:00:00Z" } ], "total": 1234, "nextCursor": "..."}获取分析摘要
Section titled “获取分析摘要”GET /api/usage/analytics?range=7d&groupBy=model响应:
{ "summary": { "totalCost": 12.34, "totalRequests": 5678, "totalTokens": 12345678, "successRate": 0.987, "avgLatencyMs": 1234 }, "models": [ { "model": "gpt-5", "cost": 8.5, "requests": 1234, "tokens": 4567890 }, { "model": "claude-opus-4-6", "cost": 3.84, "requests": 234, "tokens": 234567 } ], "daily": [ { "date": "2026-06-01", "cost": 1.5, "requests": 800 }, { "date": "2026-06-02", "cost": 2.0, "requests": 1000 } ]}查询使用情况分析
Section titled “查询使用情况分析”使用数据通过仪表板或 MCP 工具访问,而不是通过直接的 REST 导出端点访问。可用的分析功能包括:
/api/usage/analytics— 聚合使用指标(按模型、提供者、密钥分组)/api/usage/quota— 每个 API 密钥的当前配额状态/api/usage/history— 请求历史日志
MCP 工具
Section titled “MCP 工具”两个 MCP 工具向代理公开使用数据(请参阅 open-sse/mcp-server/tools/):
| 工具 | 描述 |
|---|---|
omniroute_cost_report |
生成给定时间段内每个密钥的成本报告 |
omniroute_check_quota |
返回 API 密钥的当前配额状态 |
代理调用示例:
{ "tool": "omniroute_cost_report", "args": { "period": "week" }}每个请求产生的使用情况数据约为 1-10KB。大规模使用时,数据量可能会非常可观。
使用情况历史记录的保留期限可通过 UI 中的数据库设置或 /api/settings/database 进行配置。
默认情况下,使用情况历史记录保留 90 天。
旧记录由 src/lib/db/cleanup.ts 清理:
- 由后台 cron 进程触发
- 删除
usage_history中早于已配置usageHistory保留期限的记录
存储空间估算
Section titled “存储空间估算”| 请求速率 | 30 天存储量 | 90 天存储量 |
|---|---|---|
| 100 个请求/天 | ~3MB | ~9MB |
| 1,000 个请求/天 | ~30MB | ~90MB |
| 10,000 个请求/天 | ~300MB | ~900MB |
| 100,000 个请求/天 | ~3GB | ~9GB |
对于流量非常高的情况,请考虑:
- 通过数据库设置缩短保留期限
- 使用
aggregated_metrics而不是原始记录(仅用于分析)
成本优化技巧
Section titled “成本优化技巧”1. 使用合适的模型
Section titled “1. 使用合适的模型”# 快速回答 — 使用低成本且快速的模型curl -d '{"model":"auto/fast","messages":[...]}'
# 复杂任务 — 使用高质量模型curl -d '{"model":"auto/smart","messages":[...]}'2. 启用缓存
Section titled “2. 启用缓存”Anthropic 提示词缓存可为重复上下文节省 90% 的成本:
// 缓存是自动完成的 — 只需包含相同的大型系统提示词const response = await openai.chat({ model: "claude-sonnet-4-5", system: longSystemPrompt, // 将自动缓存 messages: [{ role: "user", content: "..." }],});3. 使用压缩
Section titled “3. 使用压缩”RTK + Caveman 压缩可在大量使用工具的会话中节省 15-95%:
const config = { compression: { engine: "rtk", intensity: "aggressive", },};4. 设置每个密钥的配额
Section titled “4. 设置每个密钥的配额”始终设置 quotaLimit,以防止成本失控:
await updateApiKey(keyId, { quotaLimit: 10_00 }); // 每月上限为 $105. 审查使用量最高的用户
Section titled “5. 审查使用量最高的用户”使用仪表板或 /api/usage/analytics 按 API 密钥分组并按成本排序:
GET /api/usage/analytics?groupBy=apiKey“成本高于预期”
Section titled ““成本高于预期””- 检查
/api/usage/analytics?groupBy=model— 找出成本高昂的模型 - 检查
/api/usage/analytics?groupBy=apiKey— 找出使用量大的用户 - 验证定价数据是否为最新:
POST /api/pricing/sync
“记录缺失”
Section titled ““记录缺失””- 检查 Dashboard → Database → Cleanup 下的数据库保留设置 — 旧记录会由定期清理任务(
src/lib/db/cleanup.ts)删除 - 检查
src/lib/db/usage*.ts中是否存在错误 — 数据库写入失败会被记录,但不会显示给用户 - 验证请求是否确实到达
chatCore— 检查组合路由
“配额未生效”
Section titled ““配额未生效””- 检查密钥的
quotaLimit设置 - 验证
quotaWindow是否设置正确 - 查找
quotaSnapshots记录 — 每个请求都应创建一条记录
- DATABASE_GUIDE.md — 使用情况表的架构
- ENVIRONMENT.md — 定价同步环境变量
- AUTO-COMBO.md —
auto/fast、auto/cheap如何降低成本 - API_REFERENCE.md — 完整的
/api/usage/*参考文档 - 源代码:
open-sse/services/usage.ts、src/lib/usageAnalytics.ts、src/lib/db/usage*.ts
HagiCode
HagiCode 是一套智能体编码工作台:结构化工作流、多 Agent 并行执行与 Hero Dungeon 视图,把想法变成真正交付的软件。
让想法更快变成好用的软件,让智能编码更聪明、更高效,也更有趣。

- Smart结构化工作流将意图转化为从想法到交付的可执行路径。
- Efficient多 Agent 工作流让调研、实现与审阅并行推进。
- FunHero Dungeon 让长时间编码协作更直观、更有参与感。