跳转到内容
OmniRoute source

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.ts
const 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 的定价数据)来估算成本。


usageAnalytics.ts 模块根据原始使用情况数据计算仪表板组件。它支持 7 种时间范围:

范围 时间窗口 使用场景
1d 最近 24 小时 检测每小时成本峰值
7d 最近 7 天 每周审查
30d 最近 30 天 月度计费
90d 最近 90 天 季度分析
ytd 自当年 1 月 1 日起 年度预算跟踪
all 全部时间 全生命周期统计
custom 用户定义的开始/结束时间 审计、临时查询

对于任意日期范围,分析层都会计算:

组件 描述
摘要卡片 请求总数、总成本、token 总数、成功率
每日趋势图 每日成本和 token 数量,按模型堆叠
活动热力图 小时 × 星期几网格,颜色 = 请求数量
模型明细 按模型统计成本的饼图
提供者明细 按提供者统计请求数量的条形图
热门 API 密钥 按成本排名前 10 的密钥表格
错误分析 随时间变化的错误率、主要错误类别
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"
});
请求 ──▶ quotaCheck()
│
├── 未超过限制? ──▶ 允许
│
└── 超过限制? ──▶ 429 请求过多
并带有 Retry-After 标头

quotaSnapshots 表存储用于趋势分析的历史配额状态:

| 字段 | 描述 | | ———– | –––––––––––––––– | —— | —–– | | apiKeyId | 正在跟踪的密钥 | | window | “day” | “week” | “month” | | used | 此窗口内已使用的成本(美分) | | limit | 限制(美分) | | resetAt | 窗口重置时间 | | createdAt | 快照生成时间 |

系统会为成本 > 0 的每个请求生成快照,并将其用于:

  • 在仪表板中呈现配额进度条
  • 显示 30 天配额趋势图
  • 当使用量接近限制时触发警报

终端窗口
GET /api/usage?range=7d&limit=100
GET /api/usage?apiKeyId=key-123&range=30d
GET /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": "..."
}
终端窗口
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 }
]
}

使用数据通过仪表板或 MCP 工具访问,而不是通过直接的 REST 导出端点访问。可用的分析功能包括:

  • /api/usage/analytics — 聚合使用指标(按模型、提供者、密钥分组)
  • /api/usage/quota — 每个 API 密钥的当前配额状态
  • /api/usage/history — 请求历史日志

两个 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 保留期限的记录
请求速率 30 天存储量 90 天存储量
100 个请求/天 ~3MB ~9MB
1,000 个请求/天 ~30MB ~90MB
10,000 个请求/天 ~300MB ~900MB
100,000 个请求/天 ~3GB ~9GB

对于流量非常高的情况,请考虑:

  • 通过数据库设置缩短保留期限
  • 使用 aggregated_metrics 而不是原始记录(仅用于分析)

终端窗口
# 快速回答 — 使用低成本且快速的模型
curl -d '{"model":"auto/fast","messages":[...]}'
# 复杂任务 — 使用高质量模型
curl -d '{"model":"auto/smart","messages":[...]}'

Anthropic 提示词缓存可为重复上下文节省 90% 的成本:

// 缓存是自动完成的 — 只需包含相同的大型系统提示词
const response = await openai.chat({
model: "claude-sonnet-4-5",
system: longSystemPrompt, // 将自动缓存
messages: [{ role: "user", content: "..." }],
});

RTK + Caveman 压缩可在大量使用工具的会话中节省 15-95%:

const config = {
compression: {
engine: "rtk",
intensity: "aggressive",
},
};

始终设置 quotaLimit,以防止成本失控:

await updateApiKey(keyId, { quotaLimit: 10_00 }); // 每月上限为 $10

使用仪表板或 /api/usage/analytics 按 API 密钥分组并按成本排序:

终端窗口
GET /api/usage/analytics?groupBy=apiKey

  1. 检查 /api/usage/analytics?groupBy=model — 找出成本高昂的模型
  2. 检查 /api/usage/analytics?groupBy=apiKey — 找出使用量大的用户
  3. 验证定价数据是否为最新:POST /api/pricing/sync
  • 检查 Dashboard → Database → Cleanup 下的数据库保留设置 — 旧记录会由定期清理任务(src/lib/db/cleanup.ts)删除
  • 检查 src/lib/db/usage*.ts 中是否存在错误 — 数据库写入失败会被记录,但不会显示给用户
  • 验证请求是否确实到达 chatCore — 检查组合路由
  • 检查密钥的 quotaLimit 设置
  • 验证 quotaWindow 是否设置正确
  • 查找 quotaSnapshots 记录 — 每个请求都应创建一条记录


OmniRoute 源码 (a58000c7685f)

HagiCode

HagiCode 是一套智能体编码工作台:结构化工作流、多 Agent 并行执行与 Hero Dungeon 视图,把想法变成真正交付的软件。

让想法更快变成好用的软件,让智能编码更聪明、更高效,也更有趣。

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