这两年我见过不少AI产品团队,demo做得漂亮,用户量也在涨,就是月底一结算利润是负的。问题通常不在模型效果,而在没人把“一次对话到底花多少钱、用户付多少钱、中间还能剩多少”这笔账算清楚。AI产品和传统SaaS有一个本质区别:边际成本不为零。用户每点一次按钮,你都在为token付费,为GPU付费,为每一次失败重试额外付费。所以成本模型和计费系统不是“上线之后再补”的财务模块,而是决定AI产品能不能活下来的地基。
如果你正在做AI工具、AI客服、AI写作助手这类产品,或者准备把大模型能力封装成可售卖的服务,这篇文章基本就是为你写的。我会从成本模型的搭建讲起,用真实可套用的公式和代码把单次请求成本算明白,然后进入定价策略的选择,再落地一套从额度消耗到账单生成的计费系统代码骨架,最后分享我在成本监控和踩坑过程中的个人经验。内容偏向工程实现,但我会尽量把每个决策背后的原因也讲透,让你不是照着抄代码,而是真正理解为什么要这么设计。
1. 先说句大实话:大部分AI产品死在“算不清账”上
过去一年我接触了不少做AI产品的团队,有独立开发者,也有拿了融资的小团队。大家聊起来都很兴奋,今天接入了哪个新模型,明天又优化了什么prompt,但一问到“单次调用成本多少”“每个付费用户的毛利多少”就含糊了。最典型的一个项目,产品上线三个月,日活做到几千,模型账单一个月烧掉几万美元,付费转化却不到1%。最后项目砍掉复盘时才发现,产品团队从来没做过一次完整的成本测算,所有人都以为“用户多了自然能摊薄成本”。
问题就出在传统软件思维的惯性上。以前做SaaS,服务器和带宽成本是固定开销,用户多用一点、少用一点,对你的边际成本几乎没有影响。所以大家习惯了先免费跑量,再慢慢变现。AI产品完全不是这样——每一次模型调用都直接产生费用,用户用得多,你的成本就跟着涨,而且是线性涨。收不到钱的高增长,本质上是拿现金流去买日活,买得越多亏得越多。
成本模型的意义,就是把这笔账在产品设计阶段就算清楚。它不是财务部门月底用来“报丧”的报表,而是产品和技术决策的输入条件:选哪个模型、prompt怎么压缩、免费额度给多少、定价定多少,这些事都和成本模型绑定。只有把“每千token的价格”换算成“你产品里一次真实操作的单价”,团队里的产品经理、工程师、老板才能在同一张纸上讨论问题。
另一个必须做计费系统的原因,是AI产品的消耗天然适合“按量计费”。传统SaaS按席位卖你还能靠人情谈判,AI产品每个用户的实际资源消耗差异巨大,同一个功能,有人一次生成50字,有人一次生成5000字,成本可能差十倍。如果只按统一月费卖,要么高消耗用户把你的利润吃光,要么低消耗用户觉得不划算。所以从成本模型到计费系统,是一条完整的链路:成本模型解决“你花多少”,计费系统解决“你收多少并且怎么保证不亏”。这篇文章后面讲的就是这条路。
2. 搭建成本模型的底层逻辑:一次对话到底烧了多少钱
2.1 先盘点:AI产品的成本不只是模型调用费
很多团队做成本估算时只盯着大模型的token价格,这是一个常见误区。一次完整的AI功能请求,成本通常来自四个层级。
- 模型推理成本:主模型调用的输入和输出token费用,这是绝对大头。
- 中间链路成本:如果你的产品是RAG架构,知识库文档要做embedding向量化,检索时要调用向量数据库,还可能用rerank模型重排,每段都会产生独立费用。
- 基础设施成本:应用服务器、数据库、Redis、对象存储、日志服务、带宽,这些传统成本不会消失,只是被AI费用抢了风头。
- 治理与兜底成本:内容安全审核接口、人工抽检、客服处理退款、以及被刷接口造成的损失。
以典型的RAG问答产品为例,我见过的大致比例是:模型推理占60%到70%,中间链路占15%到20%,基础设施占10%到15%,治理兜底占5%左右。但比例会随产品形态剧烈变化。如果你做的是批量文档处理,embedding的成本占比会明显上升;如果你做的是实时对话,主模型推理会占得更多。所以别照搬别人的比例,要按自己的链路逐项估算。
2.2 核心公式:单次请求成本怎么从token换算成钱
先确定一个真实场景。假设你在做一个AI写作助手,用户平均每次请求包含:system prompt约400 token、历史对话约800 token、用户传入的参考文档约1500 token,合计输入约2700 token,模型平均输出600 token。假设你接的某主流云端模型API价格是输入每百万token 3美元、输出每百万token 15美元,这个价位属于目前中等规格模型API的常见水平,实际价格因供应商和套餐差别很大,但不影响我们理解计算逻辑。
单次调用成本 = 输入价格 + 输出价格
输入部分:2700 / 1000000 × 3 = 0.0081美元 输出部分:600 / 1000000 × 15 = 0.009美元 单次成本:0.0171美元,约1.7美分。
如果每个活跃用户每月调用200次,单用户每月模型成本就是3.42美元。再叠加embedding、向量库和服务器费用,一个用户每月的综合成本很可能到5到6美元。这时候你的订阅价如果定在10美元,毛利率大约40%到50%;如果定6美元,基本就是给云厂商和模型厂商打工。
再换个思路算一下高端模型的账。假设某旗舰模型的API价格是输入每百万token 30美元、输出每百万token 60美元,同样的2700输入加600输出,单次成本就是0.081加0.036等于0.117美元,是刚才那个模型价格的7倍。如果产品功能没有强到让用户愿意付高价,用旗舰模型又按普通价格卖,做一单亏一单。这也是为什么我特别强调:模型选型不是一个纯技术问题,它直接决定了你的成本结构。
2.3 把成本模型固化成代码:一个可扩展的估算器
光靠手算肯定不行,用量一上去就得靠工具。我在项目里习惯把成本模型写成一个小类,每次请求的token用量都会喂给它,按功能模块和模型维度聚合。这样过一段时间你就能回答很多关键问题:哪个功能最烧钱?哪个模型性价比最差?某个新上线的prompt让成本涨了多少?下面是一个可以直接跑的Python原型。
# cost_model.py class CostItem: def __init__(self, name, unit_price, quantity): self.name = name self.unit_price = unit_price # 每百万单位的美元价格 self.quantity = quantity def compute(self): return self.quantity / 1_000_000 * self.unit_price class AICostEstimator: def __init__(self): self.items = [] def add_item(self, item): self.items.append(item) def estimate_request(self, input_tokens, output_tokens, input_price_per_m, output_price_per_m): self.items.append(CostItem("input", input_price_per_m, input_tokens)) self.items.append(CostItem("output", output_price_per_m, output_tokens)) return self.total() def total(self): return sum(item.compute() for item in self.items) # 示例用法 estimator = AICostEstimator() cost = estimator.estimate_request( input_tokens=2700, output_tokens=600, input_price_per_m=3, output_price_per_m=15 ) print(f"单次调用模型成本: ${cost:.4f}")实际生产环境里,我会把模型价格表单独抽出来放到配置中心或数据库,因为供应商调价太频繁了。更重要的是,成本估算器要和请求日志打通,做到每个功能模块、每个用户都能单独聚合。将来要判断“这个用户值不值得保留”“这个渠道带来的用户是赚是亏”,靠的都是一手的成本数据。
这里还有一条经验:不要只跟工程师讨论“每百万token价格”,一定要把这个数字换算成业务的自然语言。比如“生成一篇小红书文案的成本是2分钱”“解析一份简历的成本是4分钱”。当你的运营和产品经理也能随口说出这类数字时,成本意识才算真正建立起来。
3. 从成本到价格:AI功能定价的实战取舍
3.1 定价三要素:成本下限、毛利目标、付费意愿上限
有了成本模型,定价就不是拍脑袋。价格下限由成本和目标毛利率决定:价格下限 = 单位成本 / (1 - 目标毛利率)。比如一个用户每月综合成本5美元,你期望的毛利率是60%,那么价格下限就是5除以0.4等于12.5美元。
价格上限由用户愿意支付的钱决定,这个要靠竞品分析、用户访谈和真实的付费测试来逼近。我见过很多团队在定价时直接抄竞品,却不看自己的成本结构。竞品卖10美元,那是因为人家可能跑在更便宜的模型上,或者用量比你低得多,你跟人家定同一个价,利润空间完全不同。
现实情况是,大多数AI产品最终执行的价格落在成本和意愿之间偏下的位置,因为产品还在增长期,需要压低门槛。这时候你必须接受一个事实:早期用户带来的收入很薄,一旦增长放缓,成本会迅速吞掉利润。这就是为什么我建议团队每月至少复盘一次“单用户毛利”,别等半年后才发现商业模式不成立。
3.2 三种常见定价模式怎么选
AI产品的定价模式大体有三种,我整理了一个对比表,方便你按自己的产品阶段做选择。
| 定价模式 | 典型形态 | 适合场景 | 计费复杂度 | 对成本模型依赖 |
|---|---|---|---|---|
| 按量付费 | 按次、按token、按积分消耗 | C端小工具、API开放平台 | 中 | 高 |
| 订阅制 | 按月或按年固定费用 | B端SaaS、高频刚需工具 | 低 | 中 |
| 混合模式 | 免费额度加付费加量包 | 获客型产品、试用驱动转化 | 高 | 高 |
按量付费的优点是公平,用户按实际消耗付费,你的成本与收入天然同步。缺点是用户对价格波动敏感,容易产生“用不起”的感觉,需要做好余额提醒和消耗明细。
订阅制的优点是现金流稳定、用户心理负担小,适合调用高频且规律的产品。但如果你用户的使用量方差特别大,订阅制一定会被重度用户薅羊毛。这时候要么在订阅档位里加入用量上限,要么干脆转混合模式。
混合模式是我比较推荐的新产品起步方案:给一定免费额度让用户体验核心价值,付费后解锁更多额度和高级功能。它把获客和变现放在同一个漏斗里,但也是最考验成本模型的一种模式——免费额度给多了,转化收益盖不住成本;给少了,用户没体验到价值根本不会付费。
3.3 免费额度不是拍脑袋:用成本模型反推获客预算
免费额度本质上是一笔营销费用,所以它的上限应该由转化收益决定。我给一个简化但非常实用的计算框架。
假设普通用户平均每次调用成本是1.7美分,你每月免费额度是50次调用,那么单个免费用户的月成本大约是0.85美元。如果免费转付费的转化率是5%,付费用户的生命周期价值LTV是30美元,那么每个免费用户的期望收益就是30乘以5%等于1.5美元。减去免费成本0.85美元,每个免费用户仍然贡献0.65美元的正期望。这种额度设置就值得保留。
反过来,如果转化率只有1%,期望收益才0.3美元,免费额度成本却到了0.85美元,那就要么降低免费次数,要么把免费资源集中到转化率最高的核心功能上。很多产品的免费策略失败,不是功能不好,而是把免费额度分散在所有功能上,用户用了一堆花里胡哨的能力,却没在你最赚钱的核心场景里形成依赖。
4. 计费系统核心设计与代码落地:从额度消耗到账单生成
4.1 计费不是“在请求里扣余额”:先拆清四个环节
计费系统听起来复杂,拆开就只有四件事:计量、计价、账单、支付。
计量是记录用户消耗的原始用量,比如一次AI请求消耗了多少输入token、输出token,调用了哪个模型,属于哪个功能。计价是把原始用量按规则换算成金额或积分额度。账单是按自然周期聚合并生成对账单。支付是真正的资金收付,接第三方支付渠道,处理退款和开发票。
核心原则是:计量和计价必须异步化,不能在用户请求的同步链路上扣费。一次大模型调用已经花了用户几百毫秒到几秒的时间,你的服务还要查余额、写流水、算价格,这会明显拖慢响应。而且同步扣费意味着和用户请求强耦合,一旦计费服务抖动,AI功能也跟着挂,这是不可接受的。正确的做法是请求链路上只做简单的额度预检,真正消耗的用量丢到消息队列里异步处理和入账。
4.2 数据模型设计:用量事件、订阅计划和账单
下面是一套经过简化的PostgreSQL表结构,覆盖了从用户、套餐、用量事件到账单的核心实体。
CREATE TABLE users ( id UUID PRIMARY KEY, email TEXT UNIQUE NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE plans ( id UUID PRIMARY KEY, name TEXT NOT NULL, -- Free / Pro / API price_cents INTEGER NOT NULL, -- 月费(美分),0表示免费 included_credits BIGINT NOT NULL, -- 每月包含的额度,统一用credits计量 currency TEXT NOT NULL DEFAULT 'USD' ); CREATE TABLE usage_events ( id BIGSERIAL PRIMARY KEY, user_id UUID NOT NULL REFERENCES users(id), plan_id UUID REFERENCES plans(id), credits_used BIGINT NOT NULL, -- 本事件消耗的credits feature TEXT NOT NULL, -- 功能模块,用于成本分析 model TEXT NOT NULL, -- 使用的模型标识 input_tokens INT NOT NULL DEFAULT 0, output_tokens INT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE invoices ( id UUID PRIMARY KEY, user_id UUID NOT NULL REFERENCES users(id), period_start DATE NOT NULL, period_end DATE NOT NULL, amount_cents INTEGER NOT NULL, status TEXT NOT NULL DEFAULT 'pending', -- pending/paid/void created_at TIMESTAMPTZ NOT NULL DEFAULT now() );我特别想解释一下为什么用credits统一计量而不是直接存金额。第一,模型调价是常态,如果历史事件都存美元金额,调价后会出现新旧账单口径不一致的问题;用credits,你只需要调整当前计价规则,历史流水不用动。第二,多模型、多功能要统一计算,credits让不同消耗可以相加。第三,运营活动送积分、邀请奖励、退款补偿都基于credits更容易实现。定价调整本质上就是调整“1美元等于多少credits”的汇率以及每个功能消耗credits的数量。
4.3 计量与计价核心代码:异步记录、定期汇总
用FastAPI写一个简化的计量和计价模块,核心是把任何一次模型调用换算成credits并异步记账。
# usage.py import time from fastapi import FastAPI, HTTPException app = FastAPI() CREDITS_PER_DOLLAR = 1000 # 1美元 = 1000 credits def convert_usage_to_credits(input_tokens: int, output_tokens: int, model_meta: dict) -> int: """把一次模型调用的token用量折算成credits。 折算规则必须基于成本模型,保证售出的credits能覆盖模型成本。 """ input_cost = input_tokens / 1_000_000 * model_meta["input_price_per_m"] output_cost = output_tokens / 1_000_000 * model_meta["output_price_per_m"] total_cost_usd = input_cost + output_cost # 注意:这里建议设置一个防亏系数,比如1.2,确保利润空间 return int(total_cost_usd * CREDITS_PER_DOLLAR * 1.2) def enqueue_usage_event(payload: dict): # 生产环境替换为生产者客户端,写入Kafka/RabbitMQ/Pulsar print("enqueue usage event", payload) def charge_usage(user_id: str, feature: str, model: str, input_tokens: int, output_tokens: int, model_meta: dict): credits = convert_usage_to_credits(input_tokens, output_tokens, model_meta) enqueue_usage_event({ "user_id": user_id, "feature": feature, "model": model, "credits_used": credits, "input_tokens": input_tokens, "output_tokens": output_tokens, "created_at": int(time.time()), })消费者进程从队列里批量拉取事件,攒够一定批次或者每隔几秒批量写入usage_events表。批量写不只是性能考虑,也方便你稍后做对账。这里有一个容易忽略的细节:credits的折算系数要定期校准,别让“1美元等于1000 credits”变成拍脑袋的固定值。每次模型供应商调价,或者你切换了不同的模型规格,都要重新计算这个系数,否则会出现“用户花了额度,你实际亏钱”的小漏洞。建议在代码里给系数加一个有效期,配合配置中心做热更新。
4.4 额度检查与限流:软警告和硬限制
异步计费解决的是事后记账,但用户调用前你还是得快速判断他还有没有额度。这一步不能查数据库,因为延迟高且容易被并发打爆。我习惯用Redis做配额预扣,通过Lua脚本保证原子性。
-- balance_quota.lua -- KEYS[1]: 用户额度key,例如 user:123:credits -- ARGV[1]: 本次需要消耗的credits local current = tonumber(redis.call('GET', KEYS[1]) or '0') if current < tonumber(ARGV[1]) then return -1 end redis.call('DECRBY', KEYS[1], ARGV[1]) return current - tonumber(ARGV[1])用法大致是:每次请求进来,用当前用户ID和预计消耗的credits执行这个脚本。返回-1就立刻拒绝请求,返回剩余额度就继续放行。为什么用Lua而不是先GET再DECR?因为两步操作在多线程同时请求时有竞态条件,可能两个请求都读到余额足够,然后一起扣费导致余额变成负数。Lua脚本在Redis单线程模型里是原子执行的,这是最简单可靠的方案。
这个扣费只是“预扣”,不是真实账单。用户真正消耗的tokens以usage_events为准,所以月底结算时可以多退少补。为了方便对账,我在预扣时会把usage_request_id带进去,同一个请求ID不会重复扣费,这是幂等性的关键。
5. 压垮利润的隐性成本:上下文膨胀、重试风暴与并发设计
5.1 把prompt做瘦:token优化的实际收益
很多AI产品上线后成本飙升,问题往往不在模型价格,而在prompt太胖。我见过一个AI客服产品,用户输入只有几十个字,但system prompt里塞了一份几千字的产品知识库,每次请求光是输入token就五六千,成本自然高得离谱。
如果你把上下文从4000 token压缩到1500 token,输出还是600 token,模型API价格按输入每百万token 3美元、输出每百万token 15美元算,单次成本会从0.021美元降到0.0135美元,节省约36%。对一个每天5万次调用的产品,一年的节约量非常可观,几十万美元级别。
具体手段有三个:一是对RAG召回的文档做摘要或只保留高相关片段,不要整篇塞进上下文;二是精简system prompt,去掉那些“你是一名专业的...”式的长篇设定,用直接指令替代;三是对历史对话做滑动窗口截断,只保留最近几轮,而不是把整个会话都带进去。如果API供应商提供上下文缓存功能,对重复前缀可以打折计价,这是最省钱的优化,但也意味着你要把稳定不变的部分尽量放在前缀靠前的位置。
5.2 别让失败重试放大成本
模型API在高峰期不稳定,超时、5xx错误都很常见。如果客户端无脑重试5次,一次本来只花1美分的请求,可能变成5美分,还让用户体验更差。重复查询、重复生成、重复计费的问题全都冒出来了。
正确的策略是有限重试:只对可重试的临时错误做2到3次重试,使用指数退避加随机抖动,避免所有实例在同一时刻发起重试造成雪崩。对429这种限流错误,不值得立即重试,因为对方明确告诉你“太快了”;对部分4xx错误也不要重试,因为重试也会失败。下面是一个标准的带退避的重试示例。
import random import time class RetryableError(Exception): pass def call_with_retry(call_fn, max_retries=3): for attempt in range(max_retries): try: return call_fn() except RetryableError: if attempt == max_retries - 1: raise sleep_secs = 2 ** attempt + random.uniform(0, 0.5) time.sleep(sleep_secs)还有一点容易被忽视:重试导致的重复请求要在业务层做幂等控制。尤其是做内容生成时,用户点了一次“生成”,前端可能因为超时自动重发,你的服务如果不做请求ID去重,同一个prompt会重复计费两次。用Redis的SETNX命令以request_id为key,第一次放行,后续相同请求直接返回第一次的结果,成本能省不少,用户体验也更好。
5.3 用缓存挡住重复请求
我做过一个产品,上线后发现用户的问题重复度超过30%。很多用户问“怎么写周报”“公众号开头怎么写”这类高度相似的问题,模型每次都重新生成一遍,纯属烧钱。
解决思路是语义缓存:在Redis里保存用户问题的向量表示和对应的生成结果,新请求进来先做向量相似度计算,超过阈值就认为这是重复问题,直接返回缓存结果,不再调用大模型。
这个方案只适合答案相对稳定、不依赖实时信息的场景,比如FAQ、固定格式的文案模板、代码解释;不适合新闻资讯、实时数据类、强个性化内容。而且打缓存前一定要想清楚合规边界,如果生成内容涉及个性化隐私,就不能让用户A的答案命中用户B的问题。
实现上,缓存key可以设计成问题文本的哈希,但文本语义缓存需要向量检索能力,工程复杂度会高一些。一个折中方案是先做精确匹配缓存,比如同一用户、同一feature、同一prompt哈希,在短时间内直接返回缓存结果。这种缓存实现简单,已经能挡住很多重复请求。
5.4 并发与队列:把突发流量拉平
如果瞬间有100个用户点击生成,你的服务立刻向模型供应商发起100个并发请求,响应不一定更快,反而更容易触发限流,成本也会被推高。而且高并发下每次请求的上下文如果独立构建,缓存命中的概率也低。
更成熟的做法是把AI生成任务入队,消费者按一个合理的速率去请求模型API。用户端通过轮询或SSE看到任务进度。这样做的额外收益是:排队任务之间可以共享缓存、批量复用公共上下文,甚至可以让相同业务类型的请求走同一个模型实例,降低整体成本。
当然,这个方案不适用于所有场景。如果你的产品是对话式实时交互,用户等不了几秒,就必须做流式输出,并配合更精细的并发控制和速率限制。我一般建议产品上线初期先做同步流式,等遇到明显的成本或限流问题后再演进到任务队列模式。
6. 上线后的成本监控与告警:别等月底账单出来才发现亏钱
6.1 三个必须盯的指标
上线的第一天,就要把成本监控搭起来,别等月底收到供应商账单才大吃一惊。我长期盯的有三个指标。
第一个是单用户月毛利。这个指标把收入端和成本端放在一起看:平均每个付费用户每月贡献多少收入,减去模型成本、中间链路成本和均摊的基础设施成本,剩下才是毛利。单用户毛利持续为负,产品越做越大亏得越多。
第二个是单请求成本P95。平均成本容易被少量超大请求拉平,看不出问题;P95成本能暴露那些上下文特别长、生成内容特别多的“重请求”。如果P95明显高于平均值,说明有一小撮用户在你产品里消耗了不成比例的资源,需要研究他们的使用模式,或者调整计价策略。
第三个是成本收入比,也就是每月模型及基础设施总成本除以总收入。这个比值在20%到40%之间算相对健康,超过50%就要高度重视。传统SaaS公司的基础设施成本占比通常只有10%到20%,AI产品因为token成本的存在,天然偏高。所以成本收入比必须按月拆线,趋势比单月数字更重要。
6.2 用一次SQL把每天的成本收入算清楚
为了让成本和收入对得上,每次请求都要带上feature和model标签,这样聚合起来非常方便。假设你已经把usage_events表里的输入输出token存了下来,同时维护了一张model_price表记录每个模型的单价,下面这条SQL就可以按天、按功能、按模型汇总成本和请求量。
SELECT date_trunc('day', created_at) AS day, feature, model, COUNT(*) AS request_cnt, SUM(input_tokens) AS total_input_tokens, SUM(output_tokens) AS total_output_tokens, ROUND( SUM( input_tokens / 1000000.0 * mp.input_price_per_m + output_tokens / 1000000.0 * mp.output_price_per_m )::numeric, 2 ) AS model_cost_usd FROM usage_events ue JOIN model_price mp ON mp.model = ue.model GROUP BY 1, 2, 3 ORDER BY model_cost_usd DESC;我特别建议把model_price建成独立表而不是在代码里写死常量。因为供应商价格变动频繁,如果单价写死在SQL里,改价格要改一遍所有聚合逻辑;独立表只需要更新一行数据。每天跑一次这个聚合,存到一张日汇总表里,再用BI工具画成趋势图。成本趋势图的斜率一旦变陡,通常意味着上级在生产环境改了prompt、用户突然暴增、或者有人在大量刷接口。
6.3 成本异常时的紧急处置SOP
成本虽然可能因为业务增长而上涨,但很多时候上涨原因并不健康。我踩过最典型的一次:某个AI客服产品连续三天成本环比上涨50%,排查下来居然是产品经理偷偷在system prompt里加了一大段新的产品介绍文案,导致每个请求的输入token从800涨到2400,成本翻了三倍。
所以每次prompt版本变更、模型切换、上下文长度调整,都应该做一次成本影响评估。我自己的处理流程是这样的:发现单日成本异常上涨后,先按feature和model维度拆数据定位来源;然后判断上涨是用户量自然增长、单请求上下文膨胀、重试风暴还是接口被刷;再按影响面执行降级,常见手段包括切换到价格更低的模型、降低免费用户的速率限制、暂时关闭实验性功能;处置完成后保留审计记录,复盘根因并补上监控告警。
降级操作要有预案,否则事故发生时大家只会手忙脚乱。我在配置中心里维护了每个feature的模型路由,一键可以把高成本模型降级为低成本模型,同时降低生成轮数和上下文长度。虽然效果会变差,但至少服务不会因为成本失控而停摆。
7. 一些踩坑后的个人建议:计量口径与长期运营
7.1 计量口径、token预估与内部环境这些坑
先说计量口径。一个AI产品团队里,产品说“我们按次数收费”,工程师说“我们按token计费”,运营又搞了一套“积分”。三种口径并存,对账时一定乱成一团。我建议最终决策层全公司就认准一种内部计量单元,也就是上文说到的credits,其余口径只作为报表展示,不能作为计费依据。
再就是token数的偏差问题。不同模型的tokenizer不一样,真正计费时必须以模型供应商接口返回的usage字段为准,不要自己在前端数token来扣费。自己数的token只能用来预估成本,差距通常有10%到20%,甚至更大。
内部环境最好也走一遍计费链路,只是按100%折扣执行。很多人为了省事让测试环境绕过计费,结果就是测试数据混入真实报表、灰度发布时用量异常但没人发现、内部员工滥用高级功能。走了计费链路但打了100%折扣后,你既保留了完整审计记录,报表又不会被内部流量污染,员工还能真实感知额度消耗,一举多得。
7.2 让计费体系变成产品长期运营的杠杆
计费系统不要理解成“收钱工具”,它其实是产品运营的杠杆。有了credits体系,你可以在活动时送体验积分,可以做邀请奖励,可以在用户流失前做“回归赠送”。这些操作如果发生在计费体系之外,就会变成一笔糊涂账;在体系之内,每一分赠送都有成本归属,可以算回本率。
长期运营中,我最想提醒的是不要过度设计。MVP阶段用Redis扣额度加每日定时同步数据库,完全足够。如果一开始就上实时账单、消息队列、微服务拆四个子系统,团队会陷入计费系统自身的复杂度里,连主功能都顾不上。我见过好几个项目因此拖了两三个月上不了线。先跑通一版,验证了成本和收入的闭环,再逐步升级成更完整的计费平台。
最后分享一个我自己的习惯:每个月第一个工作日,我会手动检查一遍上个月的“成本收入比趋势线”和“高成本用户清单”,哪怕所有自动化报表都正常。因为自动化只能捕获已经设置的规则,而真正让你亏钱的往往是没被规则覆盖的新情况——比如某个用户突然把AI功能当批处理工具用,或者某个模型悄悄改了计费方式。保持数据敏感,比任何高级系统都重要。希望这套从成本模型到计费系统的思路和代码骨架,能帮你把AI产品的账真正算明白。