/admin/cost 是一个单页运营视图,告诉你 AI provider 现在在烧多少钱。它读
ai_call 表(你 app 的每一次 AI 调用都会写一行,记录 token 数、成本(微分)、
延迟),汇总过去 30 天,按 provider/model 拆开。layout 用 requireAdmin()
鉴权——只有 admin 能进。
前置条件
- AI 调用已经走 provider 抽象层了(Phase 2)。第一次调用前看板是空的。
- 你的 user 记录
role = 'admin'。用 SQL 或 admin user 页改。 ai_call表存在——pnpm db:push时根据src/db/ai.schema.ts创建。- 价格表里有该模型的条目(否则成本显示 0——见坑 3)。
一步步用
- 用 admin 账号在
/login登录,然后访问/admin/cost。 - 看顶部四张卡:
- 总调用数(过去 30 天)
- 总 token 数(输入 + 输出)
- 总花费(
<CostBadge>渲染,把微分转美元) - 成功率(
status = 'success'的占比)
- 下面是按模型拆分的表。按花费降序排。列:
provider/model、调用数、 输入 token、输出 token、成本(CostBadge)、平均 TTFT (ms)、错误率 (%)。 - 抓有问题的模型——错误率高、TTFT 慢、花费失控。
- 去
/admin/orders排查,或者用pnpm db:studio直接查ai_call。
汇总怎么算的
页面跑两条 SQL 聚合ai_call:
(provider, model),按 sum(cost_micro_cents) desc 排。
两条都按 createdAt >= now() - 30d 过滤。
验证生效
- 从 app 任意地方触发一次 AI 调用(比如跑个测试 prompt)。
- 刷新
/admin/cost——调用数 +1,token 数对应请求/响应的体量,成本非零 (前提是模型在价格表里)。 - 确认表里出现该模型,provider 字段对得上。
- 如果配了多个 provider,挨个跑几次调用;行按花费排,最贵的会冒到顶部。
常见坑
- 没调用就是空的。新装当然是空的——页面只读
ai_call,没行就没数据。 - 成本显示 0。你的
cost_micro_cents列是 0,因为该模型没在价格表里。 加到src/ai/pricing.ts(Phase 2)——或者你只关心 token 数也行。 - 微分换算。成本用微分存,避免浮点误差。
<CostBadge>除以 1,000,000 渲染美元。直接查表时要记得:cost_micro_cents / 1_000_000.0得到 USD。 - 大数据集查询慢。
ai_call行数过百万后 group-by 会变慢。给 Postgres 加(created_at, provider, model)索引,或者按月分区。 - 30 天窗口是硬编码的。想换时间窗口?改
src/app/[locale]/(app)/admin/cost/page.tsx顶部的WINDOW_MS。 目前没有 query-string 开关。
官方文档
- 架构与 provider 抽象:/docs/architecture
- Drizzle ORM(这里用的查询):orm.drizzle.team
- Postgres 窗口函数:postgresql.org/docs/current/functions-window.html
- Postgres 分区:postgresql.org/docs/current/ddl-partitioning.html