OpenAI API 成本监控实战:如何把「乱收费」变成「清清楚楚」
"OpenAI 告诉你花了多少钱,但不告诉你花在哪。所以我自己写了一套监控系统。"
这是开发者 alimafana 在构建多租户 AI 产品时遇到的真实痛点。他的产品 Provia 是一个面向阿拉伯电商的 AI 销售机器人,每天触发大量 OpenAI API 调用。某天他看到账单显示花了 $4.27,但完全不知道这笔钱是怎么产生的——是某次昂贵的图片分析?某个店铺的异常调用?还是某个对话陷入了死循环?
没有答案。
本文记录我复盘这个方案的全过程,聊聊怎么用三个文件搭起一套完整的 OpenAI API 成本监控系统。
1. 问题本质:OpenAI 账单为什么「看不清」
登录 platform.openai.com/usage,你能看到的只有:
- 每天的总花费
- 按模型分类的 token 数量(gpt-4o、gpt-4o-mini 等)
- Token 总数
没了。
对于个人项目,这够用。对于 production 环境,缺的东西太多了:
| 你想知道 | OpenAI 给你的 |
|---|---|
| 哪个功能产生了这笔费用 | ❌ 不知道 |
| 哪个用户/租户触发了调用 | ❌ 不知道 |
| 哪次对话超出了预算 | ❌ 不知道 |
| 失败的调用是否还在收费 | ❌ 不知道 |
| 延迟和成本之间的关联 | ❌ 不知道 |
这不是 OpenAI 的锅——它本来就是个通用的 API 提供商,没有义务理解你的业务逻辑。但作为开发者,如果你不做这层监控,就等于在瞎子摸象。
2. 方案概览:三文件监控架构
alimafana 的方案出奇地简洁,一共三个文件:
openai-logger.ts ← 包装 OpenAI 调用,记录一切
api_logs ← Supabase 数据表,存储每次调用的明细
dashboard ← 可视化界面,按租户、功能、模型分析成本
核心思路:不要直接调用 OpenAI,通过一个 wrapper 代理所有请求,把每次调用的元数据全部记下来。
3. 文件一:Wrapper 的设计
3.1 定价表是关键
OpenAI API 返回 token 数量,但不直接返回费用。你需要自己查表计算:
// 最近检查:2026-04-15 — https://openai.com/pricing
const PRICING: Record<string, { input: number; output: number }> = {
"gpt-4o": { input: 2.50, output: 10.00 }, // 每 100 万 token
"gpt-4o-mini": { input: 0.15, output: 0.60 }, // 每 100 万 token
};
这里有个关键数字:gpt-4o 比 gpt-4o-mini 贵约 16 倍。如果某个场景 gpt-4o-mini 就能搞定,你用了 gpt-4o,那就是在烧钱。监控的目的之一就是让这种浪费变得可视化。
费用计算公式:
const cost = (
tokens.prompt_tokens * rates.input +
tokens.completion_tokens * rates.output
) / 1_000_000;
3.2 Wrapper 的实现
import OpenAI from "openai";
import { createAdminClient } from "@/lib/supabase/admin";
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const PRICING: Record<string, { input: number; output: number }> = {
"gpt-4o": { input: 2.50, output: 10.00 },
"gpt-4o-mini": { input: 0.15, output: 0.60 },
};
interface LogMeta {
storeId: string;
conversationId?: string;
leadId?: string;
endpoint: string;
functionCalled?: string;
searchQuery?: string;
productsFound?: number;
}
export async function loggedChatCompletion(
params: OpenAI.Chat.Completions.ChatCompletionCreateParams,
meta: LogMeta
) {
const start = Date.now();
const result = await openai.chat.completions.create(params);
const duration = Date.now() - start;
const tokens = result.usage;
const rates = PRICING[params.model as string] || PRICING["gpt-4o-mini"];
const cost = tokens
? (tokens.prompt_tokens * rates.input +
tokens.completion_tokens * rates.output) / 1_000_000
: 0;
// Fire-and-forget log — never blocks the response
const supabase = createAdminClient();
supabase
.from("api_logs")
.insert({
store_id: meta.storeId,
conversation_id: meta.conversationId,
lead_id: meta.leadId,
endpoint: meta.endpoint,
model: params.model,
prompt_tokens: tokens?.prompt_tokens,
completion_tokens: tokens?.completion_tokens,
total_tokens: tokens?.total_tokens,
cost,
duration_ms: duration,
function_called: meta.functionCalled,
search_query: meta.searchQuery,
products_found: meta.productsFound,
status: "success",
})
.then(() => {})
.catch(() => {}); // Silent fail — monitoring never breaks the app
return { result, cost, duration };
}
3.3 最重要的设计模式:Fire-and-Forget
这行代码是整个监控系统的精髓:
.then(() => {}).catch(() => {}); // Silent fail
日志插入是不等待的。如果数据库挂了、网络抖了、表还不存在——用户的响应照常返回。
实测数据:
- 日志插入耗时:15–40ms
- Chat completion 耗时:800–2500ms
如果你 await 日志,每次请求增加 2–5% 的延迟,而用户完全感知不到这个监控的价值。
监控永远不能拖慢它要监控的东西。 这是唯一重要的原则。
alimafana 运行这套系统几周下来,千次调用中大约丢失 2–3 条日志。这个损失可以接受。
3.4 迁移成本:10 分钟
使用方式几乎没变:
// Before
const response = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: customerMessage }],
});
// After
const { result, cost, duration } = await loggedChatCompletion(
{
model: "gpt-4o-mini",
messages: [{ role: "user", content: customerMessage }],
},
{
storeId: store.id,
conversationId: conversation.id,
leadId: lead.id,
endpoint: "chat",
}
);
同一个接口,加一个 meta 参数。全局搜索替换,10 分钟搞定。
4. 文件二:数据表设计
CREATE TABLE api_logs (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
store_id UUID REFERENCES stores(id),
conversation_id UUID,
lead_id UUID,
endpoint TEXT NOT NULL,
model TEXT,
prompt_tokens INT,
completion_tokens INT,
total_tokens INT,
cost DECIMAL(10,8), -- 8位小数,单次调用约 $0.00013
duration_ms INT,
function_called TEXT,
search_query TEXT,
products_found INT,
status TEXT DEFAULT 'success',
error TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_api_logs_store ON api_logs(store_id);
CREATE INDEX idx_api_logs_created ON api_logs(created_at);
CREATE INDEX idx_api_logs_endpoint ON api_logs(endpoint);
4.1 每一列回答一个业务问题
store_id → "哪个租户最贵?"
多租户 SaaS 里,一个店铺的费用可能是另一个的 10 倍。不记录这个维度,你永远发现不了。
endpoint → "是聊天贵,还是图片分析贵?"
拆开看才知道资源消耗在哪里。
conversation_id + lead_id → "这个对话/客户花了多少钱?"
精细化到单个用户维度的成本分析。
function_called + search_query + products_found → 调试列
当客户说"给我看红色裙子"但返回空结果时,你可以查:搜索函数调用了吗?用的什么 query?返回了多少商品?这省了我好几个小时的调试时间。
duration_ms → 延迟
Dashboard 里用颜色标记:绿色 < 1s,黄色 1–3s,红色 > 3s。
error → 失败调用也在收费
OpenAI 对失败的调用仍然收取 prompt token 的费用。这个字段让你知道"哪些错误在烧钱"。
4.2 DECIMAL(10,8) 不能省
这是最容易忽略的细节:
gpt-4o-mini 单次调用 ≈ $0.00013
如果用 DECIMAL(10,2),所有调用都会 round 到 $0.00,你的总和永远是一片 0。
到了规模化阶段,分分厘厘都是钱。
5. 文件三:Dashboard 要展示什么
alimafana 没有给出完整的 Dashboard 代码,但根据数据表的字段设计,核心视图应该包括:
5.1 必看指标
| 指标 | 业务含义 |
|---|---|
| 每日/每周/每月总成本 | 整体花费趋势 |
| 按租户拆分的成本分布 | 找到"贵的那个店铺" |
| 按 endpoint 拆分的成本 | 聊天 vs 搜索 vs 图片分析 |
| 按模型拆分的成本 | gpt-4o vs gpt-4o-mini 是否用对了 |
| 失败调用的成本占比 | 错误是否在持续烧钱 |
| P99 延迟 vs 成本 | 贵是否因为慢 |
5.2 一个真实发现
第一次打开 Dashboard,他发现两个功能(本来以为成本差不多)的实际费用相差 100 倍。
这就是监控的价值——你以为的和你以为的,往往不是真相。
6. 这个方案的扩展思路
alimafana 的实现针对的是 Supabase + TypeScript 环境,但思路可以迁移到任何技术栈:
6.1 日志存储选型
| 方案 | 适用场景 |
|---|---|
| Supabase/PostgreSQL | 已有 Supabase 或习惯 SQL 查询 |
| MongoDB | 需要快速迭代字段 |
| ClickHouse | 调用量极大,需要 OLAP 能力 |
| Prometheus + Grafana | 已有 K8s 监控体系 |
| 纯文件 + cron 聚合 | 轻量级,不想加数据库依赖 |
6.2 多模型支持
如果你的产品同时接入了 OpenAI、Anthropic、Google 的 API,可以统一日志格式:
interface UnifiedLog {
provider: "openai" | "anthropic" | "google";
model: string;
inputTokens: number;
outputTokens: number;
cost: number; // 统一换算成美元
latencyMs: number;
status: "success" | "error";
errorType?: string;
}
6.3 告警能力
在成本监控之上加一层告警:
// 当单日成本超过阈值时告警
if (dailyCost > threshold) {
await sendAlert({
channel: "slack",
message: `⚠️ OpenAI 今日成本已达 $${dailyCost},超过阈值 $${threshold}`
});
}
7. 我的感受
读完 alimafana 的方案,我最强烈的感受是:这才是工程师应该做的事——把看不见的东西变透明。
很多团队抱怨 AI 成本高,但连最基本的 per-call 成本数据都没有。你说成本高,高在哪?哪个功能?哪个用户?哪个模型?答不上来。
监控系统不需要多复杂。三个文件,一个下午,就能让你从"看天吃饭"变成"心里有数"。
如果你也在做 AI 产品,还没有监控 API 成本的手段,今天就可以开始搭。 从包装一个 OpenAI 调用开始,从一张记录每次调用的表开始。
8. 相关资源
- 原文链接:OpenAI Tells You What You Spent. Not Where. So I Built a Dashboard.
- OpenAI 官方定价:https://openai.com/pricing
- Supabase:https://supabase.com/
标签: AI, OpenAI, 成本优化, 监控, 实战, DevOps
字数: 约 3200 字
预计阅读: 10 分钟