基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
  • 知识卡片碎片时间过考点
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
    • AI 热点每日 AI 资讯与动向
AI 工作台
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
7.0
热点
AI SCORE
编程提效2026-04-30 20:14

自建成本监控系统,发现OpenAI账单上的100倍差异

DEV Community · Ali Afana #成本监控#OpenAI#可观测性
Editor brief · 编辑速览

开发者因OpenAI官方账单缺乏细节而自建监控系统,发现两个功能的成本差异达100倍。这个真实案例暴露了API成本的隐性问题,对使用AI API的程序员有直接警示价值。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

确定 100 倍成本差异

更新(2026 年 5 月 4 日):一位读者(Gary Stupak,评论区)指出 Cloudflare AI Gateway 支持自定义元数据头(cf-aig-metadata),让你可以从应用中将租户/功能/会话 ID 传播到网关日志。

如果你已经在 Cloudflare 技术栈上,从那里开始——Gateway 成为你的信息源,自定义仪表板则是验证而非主要工具。

如果你不在 Cloudflare 上(或想理解应该记录什么),这篇文章的其余部分仍然适用——在公众面前出错正是经验教训能留下来的方式。

简述:OpenAI 的账单页面显示总支出。不显示是哪个功能、哪个租户、哪个对话造成的。对多租户 AI 产品来说,那就像在闭眼飞行。我构建了一个 3 文件的监控系统——一个包装层、一个表、一个仪表板——给我精确到 8 位小数的单次调用成本。我第一次打开时,就发现了两个我一直认为相似的功能之间的 100 倍成本差异。

OpenAI 仪表板的不足

现在打开 platform.openai.com/usage。你会看到:

  • 按模型分解(gpt-4o、gpt-4o-mini 等)
  • 这些 tokens 花在了哪个功能上

你看不到的:

  • 哪个用户或租户触发了它们
  • 哪次具体对话超过了预算
  • 失败的调用是否仍在花你的钱
  • 延迟与成本的相关性

对于副业项目,还好。对于生产级 AI 产品,你就是在瞎蒙。

我在构建一个多租户 AI 销售聊天机器人——每家店铺是一个独立客户,每家店铺有多个功能:聊天完成、嵌入、图像分析、资料提取。单个客户消息可能触发 1–3 次 OpenAI 调用。

当我上线时,OpenAI 告诉我昨天花了 $4.27。

这个数字毫无用处。是一次昂贵的图像分析?某家店铺疯狂发送数千条消息?某个循环重复调用同一个 API?没办法知道。

所以我自己构建了可观测性。三个文件。一个下午。

文件 1:包装层(openai-logger.ts)

核心思路:不直接调用 OpenAI。调用一个包装层,它度量一切并异步记录。

OpenAI 的 API 返回 token 计数,但不返回成本。你从一个硬编码表自己计算:

// Last checked: 2026-04-15 — https://openai.com/pricing
const PRICING: Record<string, { input: number; output: number }> = {
  "gpt-4o":      { input: 2.50,  output: 10.00 },   // per 1M tokens
  "gpt-4o-mini": { input: 0.15,  output: 0.60  },   // per 1M tokens
};

这里是核心比例:

gpt-4o 对于相同 token 数大约比 gpt-4o-mini 贵 16 倍。如果你用 gpt-4o 处理 gpt-4o-mini 能处理的任何任务,你在烧钱。仪表板让这个可以逐次调用地看到——这正是你决定哪个模型用在哪里时需要的。

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 };
}

关键模式:火速前发

这一行让它对生产环境来说是安全的:

.then(() => {}).catch(() => {}); // Silent fail

日志插入不被 await。如果数据库宕机、网络打嗝、表还不存在——用户的响应仍然能返回。

在我的测试中,日志插入耗时 15–40ms。聊天完成耗时 800–2500ms。如果我 await 日志,我就给每个请求增加 2–5% 的延迟,对用户没有任何好处。

监控绝对不能拖慢它正在监控的东西。这是这里唯一重要的规则。

我运行这个模式已有好几周,在数千条中丢失了大概 2–3 条日志。可以接受的权衡。

改动之前:

const response = await openai.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: customerMessage }],
});

改动之后:

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",
  }
);

接口相同,多一个参数。全代码库查找替换:10 分钟。

文件 2:表(api_logs)

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),
  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);

列就是你能切片的维度。每一个都回答了 OpenAI 仪表板无法回答的问题:

store_id → "哪个租户花钱最多?" 在多租户 SaaS 中,一家店铺的成本可能是另一家的 10 倍。没有这一列你永远看不到。

endpoint → "昂贵的部分是聊天,还是图像分析?"

conversation_id + lead_id → "这次对话花了多少钱?这个客户花了多少?"

function_called + search_query + products_found → 调试列。当客户说"给我显示红色裙子",机器人什么都没返回时,你可以检查:它调用了搜索函数吗?用什么查询?返回了多少产品?这给了我数小时的调试时间。

duration_ms → 延迟。仪表板中色码显示:绿色 <1.5s,黄色 1.5–3s,红色 >3s。

error → 失败的调用仍然消耗 prompt tokens。OpenAI 对它们收费。追踪它们。

一个细节容易被忽视:cost DECIMAL(10,8)。8 位小数。

单个 gpt-4o-mini 聊天完成大约花费 $0.00013。用 DECIMAL(10,2),每个调用都舍入到 $0.00,你的合计数据就一文不值。分数便士在规模上很重要。

文件 3:仪表板

API 路由(/api/admin/logs/route.ts)采用过滤条件(startDate、endDate、endpoint、storeId)并返回聚合数据:

{
  summary: {
    totalRequests, totalTokens, avgTokensPerRequest, avgLatency, totalCost
  },
  dailyTokens:       [{ date, prompt, completion, total }, ...],
  hourlyActivity:    [{ hour, count }, ...],
  endpointBreakdown: [{ endpoint, count, cost, percentage }, ...],
  modelBreakdown:    [{ model, count, cost, percentage }, ...],
  storeBreakdown:    [{ storeId, storeName, count, cost }, ...],
}

UI 故意保持无聊:

  • 顶部 5 张统计卡——总请求数、总 tokens、平均 tokens/请求、平均延迟(色码)、总成本
  • 日期过滤——今天、7 天、30 天、全部、自定义范围
  • 下拉菜单——endpoint、store
  • 实时模式切换——每 5 秒自动刷新
  • 两个图表——日均 tokens(prompt vs completion)、每小时活动
  • 可展开的日志行——点击一个看完整详情:模型、tokens、成本、延迟、搜索查询、发现的产品

API 做了繁重工作。UI 只是渲染预聚合数据。没有客户端计算,没有惊喜。

某个生产日期的真实数据:

按功能分解的成本:

打开这个视图的瞬间,两件事跳了出来:

其一。用 gpt-4o 做图像分析的成本大约比用 gpt-4o-mini 聊天每次调用贵 100 倍。尽管只有大约 1% 的调用是图像分析,它们却吃掉了大约 10% 的预算。这改变了我对哪些功能值得用 gpt-4o vs 哪些可以用 gpt-4o-mini 的看法。

其二。聊天 endpoint 的平均 prompt tokens 每次调用远高于我的估计。仪表板显示了症状;调查发现我在每个单次响应中都把整个对话历史作为上下文发送。那是我写过文章的一个单独架构修复——这篇文章的重点是,如果仪表板没有向我展示症状,我永远不会去寻找这个 bug。

这就是循环。你无法优化无法测量的东西。你无法测量无法检测的东西。而通用账单仪表板不会检测你的应用。

构建这个系统我学到的 5 件事

1. OpenAI 的仪表板是账单工具,不是可观测性工具

它告诉财务部门应该收费什么。它不告诉工程部门应该修复什么。工作不同。

2. 火速前发不可妥协

如果你的监控阻塞了请求路径,你就让产品变差了。可观测性的整个意义在于它是不可见的,直到你查看它。永远非 await 插入。登录错误上永远静默失败。

3. 八位小数,不是两位

把成本存为 DECIMAL(10,2),每个调用都舍入为零。AI 成本是每次调用分数便士。把它们当分数便士对待。

4. 维度就是产品

总成本是个数字。单租户成本、单功能成本、单对话成本才是洞察。你记录的列决定了你能回答什么问题。当你构建功能时就添加列,不要等到有问题了再加。

5. 硬编码定价。手动更新它。

没有 OpenAI 定价 API 可以查询。硬编码费率并加上你最后检查的日期注释,当 OpenAI 改变时更新它。两行代码,一个月三分钟。

// Last checked: 2026-04-15 — https://openai.com/pricing
const PRICING = {
  "gpt-4o":      { input: 2.50,  output: 10.00 },
  "gpt-4o-mini": { input: 0.15,  output: 0.60  },
};

当你准备好时要添加的东西

一旦基础版本到位,这是升级路径:

延迟百分位数。平均延迟会撒谎。追踪 p50、p95、p99。平均可能是 1.2s,但如果 p99 是 8s,100 个用户中有 1 个在经历糟糕的体验。

单租户预算告警。每家店铺每天 $1 的阈值。超过时发送 Slack/邮件。捕捉失控循环、生成巨大输出的 prompt injection,或意外使用量激增的店铺。

endpoint 的错误率。总错误率隐藏分布。聊天 2% 错误和图像分析 15% 错误与两者都 8% 是不同的问题。

转化成本。如果你的 AI 存在是为了驱动业务成果(销售、注册、完成),把日志连到成果表。现在你有每次对话的 ROI,而不仅是每次对话的支出。

模型迁移追踪。当你把一个功能从 gpt-4o 切换到 gpt-4o-mini,成本下降应该是可见的。model 列让迁移前后比较变成琐碎的事。

总结

三个文件。一个下午。大约 400 行代码。

一个拦截每个 API 调用的包装层。一个有足够维度来切片数据的表。一个把它聚合成你可以作用的东西的页面。

你不需要 LangSmith 或 Helicone 或 Datadog(如果你倾向于它们,它们很好)。你需要最小可能的工具来回答"是哪个功能、哪个租户、哪个对话"——因为那是你的账单仪表板无法回答的问题。

我第一次打开我的时,我捕捉到了两个我一直认为相似的功能之间的 100 倍成本差异。我捕捉到它因为我构建了能看到它的镜头。

在你上线前构建镜头。或者——更诚实地说——在你上线那天构建它,在你忘记前。

我在构建 Provia——一个为阿拉伯语电商店铺设计的 AI 销售聊天机器人。关注更多关于在加沙以紧张预算构建 AI 产品的文章。

一些评论可能仅对已登录访客可见。登录查看所有评论。

如需进一步行动,你可以考虑屏蔽此人和/或报告滥用。

Original source

本文由 AI 翻译整理,来源 DEV Community · Ali Afana ,原文版权归原作者所有。

阅读原文
上一篇
Claude Code 对特定项目标识的请求限制
下一篇
Zig 语言禁用 AI 生成代码的立场与理由

资讯速览

DEV Community · Ali Afana · 2026-04-30 20:14

AI 评分 7.0 / 10

相关标签

#成本监控#OpenAI#可观测性

继续阅读

  • 别用剪贴板给AI Agent传代码,有更好办法
  • Claude Code 对特定项目标识的请求限制
  • Zig 语言禁用 AI 生成代码的立场与理由
  • Demis Hassabis剖析AGI与智能体的真实进展
  • Cursor推出常驻AI安全审查功能