
1. 账单爆炸的第一个月大模型API的钱到底花在了哪里1.1 从几百到上万费用失控的真实路径做AI应用开发的同行应该都有过这种体验一开始调大模型API做Demo跑几个请求看账单也就几块钱心里完全不设防。等到产品真正上线、开始有真实用户涌进来之后月账单突然变成几千甚至上万整个人是懵的。我们当时做的是一个面向企业内部的知识问答系统底层接的是某大厂的对话模型API前期联调阶段每天消耗量大概几万token一个月的费用不到两百块谁都没把这个当回事。上线之后一个月财务截图甩过来当月API费用一万三。当时团队的第一反应是“是不是被恶意刷接口了”但查了调用日志之后发现请求量翻了大概四十倍费用却翻了六十多倍。这个非线性增长才是真正让人警觉的地方。为什么请求量只涨了四十倍、费用却涨了六十倍因为API计费不光是看请求次数更要看输入输出的token量级。用户在真实使用中会把越来越多的上下文内容带进请求里导致单次请求的token数越变越大。更麻烦的是我们为了追求“回答效果好”给系统内置了一个非常长的系统提示词system prompt再加上每次都会把历史对话全量拼接传给模型单次请求的消耗量从联调期间的几百token涨到了实测时段的四千到八千token。所以成本控制的第一个核心认知必须建立起来大模型API的账单不是由“调用次数”决定的而是由“总token消耗量”决定的。每一次看似无害的小请求都是把一次性token成本放大了几十倍再发给模型。如果你连自己的token消耗分布都说不清那后面所有优化手段都是盲人摸象。1.2 算清token这笔账计费维度与隐形成本说到大模型API的计费不同厂商之间的具体规则会有差异但主流模型基本都遵循一套相似的框架输入token和输出token分开计价通常输出token的单价是输入token的3到5倍。也就是说你让模型写一大段总结比给模型发一大段资料要贵得多。为了把账算明白我当时建了一个非常简单的成本模型公式是这样的单次调用成本 输入token数 × 输入单价 输出token数 × 输出单价在这个公式里面输入token数取决于三块内容系统提示词的长度、用户问题本身的长度、以及拼进去的上下文内容长度。输出token数则跟任务复杂度强相关比如让人家直接输出一个最终答案可能只需要一两百token但如果你让它“详细分析并给出理由”输出量轻轻松松翻到八百到一千token。我们的排查结果是系统提示词占到了总输入token的18%左右历史对话拼接占到了60%以上用户问题本身只占不到10%。换句话说大量的钱花在了“模型读一遍历史”这件事上而不是花在“帮你解决问题”上。这就引出了一个很反直觉的结论用户问得越多、对话越长系统越流畅但你的成本就越失控。除了显性的token费用还有几个被大多数团队忽略的隐形成本。第一是重试成本。模型偶发报错之后我们的老代码会直接原样重发一次请求而模型并没有“记住”上一次重试的输入内容于是重试的那次请求照样收全款。如果触发了一个循环重试机制一次成功的调用背后可能赔上了三四次失败的调用费用。第二是输出截断。模型生成了很长的回答但是被UI截断展示了一部分剩下的内容我们根本没用上可输出token的钱已经扣完了。这类开销在日志里都看不出异常只有把“输出token分布”拉出来和“实际展示文本长度”做对比才能发现端倪。第三是无效调用。比如用户连续点了三次“重新生成”模型其实生成了三份回答但用户可能只看了第一份。这种“没看完也扣钱”的浪费往往占了整张账单的10%到15%是成本审计最值得先动刀的地方。1.3 排查工具把每一分钱追到调用链路上在动手优化之前必须先解决“看不见”的问题。不知道钱具体花在哪条调用链路上就谈不上控制。我们把当时服务里的所有大模型API调用入口做了一次全面盘点用中间层记录每一笔请求的关键元数据。记录的核心字段包括调用时间戳和业务场景ID比如是文档问答、摘要生成还是标题改写输入token数、输出token数、模型名称响应是否被业务正常消费成功/截断/超时重试触发的函数或者提示词版本号加了这个日志之后我们做的第一件事就是按业务场景聚合token消耗量算每一个场景的“成本贡献率”。结果非常有意思三个最耗钱的场景加在一起贡献了92%的API费用——其中一个是因为每轮都把整个文档库的检索结果切成大块拼进上下文另一个是因为给每个问题都附加了一段很长的“角色扮演式提示词”还有一个是后台异步批处理任务的频率设置得过密。这个结果看似简单但信息量很大API成本问题往往不是均匀分布的它高度集中在极少数的调用场景里。你不需要对全部功能做改造只要把头部几个场景拎出来优化整个账单就会发生肉眼可见的变化。我们当时的行动顺序很简单先修重试逻辑和无效调用这两个“零技术含量”的浪费再动提示词和上下文管理最后才考虑模型层面的替换。这套从易到难、从低风险到高风险的顺序保证了每一步都能独立验证效果不会出现“优化了一堆东西但不知道是哪步起了作用”的情况。2. 提示词瘦身不换模型也能省掉三成费用2.1 system prompt的“体重”比你想的更贵在做成本优化之前我一直觉得系统提示词写长一点无所谓反正是写给模型看的又不是写给人看的多几个字能费多少钱。实际情况打脸了在对话类的模型API里system prompt会在每一轮请求中都完整发送一次。也就是说只要用户在这个会话里多聊几句这段系统提示词就会被反复计费很多次。当时我们某功能的系统提示词写得特别“丰满”包含了详细的角色设定、回答风格规范、步骤说明、禁忌清单还带了一些few-shot示例总长度大约1200个token。按照当时主流模型的价格核算这段提示词每次请求就要花掉大约几厘钱。听着不多但当我们把日请求量放到十万级时光是system prompt这一个固定项一天就是几百块一个月下来过万。而且这些内容里实际对回答质量有贡献的可能只有三成。比如有一段“你必须表现得像一个经验丰富的行业顾问语气要专业而亲切回答要逻辑清晰”这种话在模型眼里并没有太多有效信息——模型的风格不是靠“夸它一句”来改变的而是靠具体规则和输入输出的模式来约束的。我们做了几轮压缩之后把那段1200token的提示词压到了350个token方法是删掉所有“礼貌性描述”和风格定性的废话只留硬性约束把几条长句规则改写成“关键词表否定项”的形式模型理解起来更直接把few-shot示例从三个缩减到一个因为那三个示例的上下文高度重复动态拼接把那些只在小部分场景中用到的约束逻辑改成按条件注入而不是全局固定。压缩后的效果是单次请求的整体输入token平均降了约30%而回答质量在我们内部的人工评测里不降反升——因为冗长的提示词反而干扰了模型对核心指令的注意力。这个发现让我后来在做所有提示词工程时都默认把“提示词越短越好”当成一个硬性原则。2.2 结构化输出与重试策略对费用的双重影响另一个被低估的浪费源头是输出长度控制。我们早期的实现为了“让模型回答得更自然”几乎所有场景都让模型自由发挥。自由发挥的结果就是回答冗长、废话多输出token经常冲到七八百以上。而同一问题的“干货答案”可能只需要200到300个token。解决思路是在提示词层面明确限定输出的格式和长度。比如在知识问答场景里我们强制要求模型按三段式结构输出一句话结论、要点列表、参考来源说明在摘要场景里直接设置“不要超过150字”的硬约束。这里有一个小技巧模型的字数控制能力其实不稳定你说“不超过150字”它可能给你输出180字甚至250字。我们后来改进成“请用不多于三句话完成回答”效果比单纯限制字数要好得多因为模型对“句数”的把握比“字数”更准。另外一个必须提的是重试策略的成本设计。我们最初的代码逻辑很简单for attempt in range(3): response call_api(payload) if response.is_success: return response.data time.sleep(2)表面看这只是在失败时多试几次问题是很多失败是“内容审核拦截”或“服务端超时”这类场景重试同样的payload大概率还是同样的失败。每一次重试都在烧钱烧的还是全价。我们把重试逻辑改成了“按失败类型区分”的策略网络超时可以重试但最多一次HTTP 429限流等待之后重试次数限制一次内容审核类报错直接返回友好提示不做重试模型侧异常5xx重试一次若仍失败则降级到备用模型。这个改动看似只是代码层面的防御性编程但实际上对费用影响很大。因为之前那种盲目重试在很多并发高峰期几乎等于给API厂商“白送钱”高峰期越是报错多、越是要重试费用就越是雪上加霜。2.3 上下文压缩给对话瘦身的实用套路对话历史拼接是成本的大头也是最难处理的部分因为“保留多少上下文”直接关系到回答的连贯性。我们中途试过“只保留最近两轮对话”结果用户上一轮提到的关键词下一轮模型就忘了体验立刻崩掉。问题的关键不是“少保留”而是“保留什么”。我们最后采用的方案是一个经典的三层上下文管理策略短期缓冲层保留最近的4到6轮原始对话这部分保证对话的即时连贯性。中期摘要层当对话超过6轮之后把更早的对话交给模型做一次“压缩摘要”生成一段200到300字的会话要点然后丢弃这些原始轮次。摘要本身也调用API但它的成本是一次性的、可控的之后的每一轮请求都不需要再携带那些冗长的历史原文。长期事实层从对话中抽取关键实体和用户偏好存成结构化的“用户画像字段”。这些字段非常精简比如“用户所在部门市场部”“关心的产品线A/B/C”“偏好简洁回答是”。这部分内容替换掉大段对话原文既能保证个性化又能把token量压到极低。这套策略上线之后长对话场景下的单次输入token从平均六千多降到了两千不到而且回答体验没有明显下滑。这个方案比“无脑截断历史”高级很多因为它不是靠牺牲信息来省钱而是靠把信息从冗余格式转置成紧凑格式来省钱。换句话说模型根本不需要知道用户第七轮说的每一句话原文它只需要知道“用户七轮前提过预算问题预算上限是十万”这个事实就足够了。3. 模型分级调度让便宜模型干80%的活3.1 路由策略怎么判断哪些任务“不需要聪明模型”在提示词和上下文都已经瘦身之后成本大头就变成了“所有请求都用了同一个旗舰模型”这件事。大模型API的价格差异非常大旗舰模型和轻量模型之间单价可能差出5到10倍。很多任务的难度根本不需要旗舰模型出手但默认配置把所有流量都导到了最贵的模型上。要改变这个现状第一步是先建立一套“任务难度分级”的意识。我们把业务里的所有模型调用场景全部列出来逐个问一个问题这个任务如果换一个更弱的模型来做用户能感知到差别吗结果分成了四类高难度推理类比如复杂代码生成、跨文档逻辑推理必须用旗舰模型中等理解类比如总结提炼、信息抽取中档模型完全可以胜任简单生成类比如标题改写、文案润色、格式化输出轻量模型就行模板填充类比如从文本里提取工单编号、把时间地点字段规范化甚至不需要大模型规则和本地小模型就能解决。分类的结果是真正必须动用旗舰模型的场景大约只占全部请求量的18%而此前所有请求都流向了最贵的那一个模型。换句话说我们至少有超过80%的流量是用超规格的“豪华配置”在跑“普通任务”。明白这个道理之后路由逻辑的设计就是一道送分题不让业务代码自己选模型而是在统一的API入口处设置一个“模型路由器”。它会根据调用场景ID、输入长度、任务类型标签自动把请求分发到不同档位的模型上。3.2 双阶段调用粗筛精修的组合拳只按场景静态分级还是不够灵活。有些任务表面上看起来很简单但用户输入的复杂度波动很大。比如同样是“写一段产品介绍”有的输入是几个零散关键词有的输入是三页产品说明文档。后者明显需要更强的理解能力。为了处理这种波动我们在最高频的问答场景里尝试了双阶段调用架构先用轻量模型做一次粗回答如果任务被判定为“简单”就直接返回给用户如果判定为“有复杂度”再调用旗舰模型做一次精修。判断“是否有复杂度”的方法我们一开始想得很复杂又是算文本复杂度、又是预测token长度后来回归到最简单的方案让轻量模型在返回答案的同时给回答打一个自信心分置信度低于阈值就升级到旗舰模型重跑。这个方案看起来好像比原来多调用了一次API好像是增加了成本但实际上因为轻量模型的价格只有旗舰模型的十分之一到六分之一绝大多数“简单任务”在粗筛阶段就被低成本完成了只有大概25%的请求会升级到旗舰模型。整体成本直接降了一半还多。这个模式还有一个额外的好处它天然形成了一条质量兜底机制。轻量模型回答得好的任务直接快速返回回答得可疑的任务让旗舰模型重答一遍用户体验反而是更稳的而不是更差的。3.3 模型降级的灰度验证质量不掉、成本腰斩直接换模型团队里最担心的一件事就是“回答质量是不是会崩”。这个担心很正常但我们用了灰度验证的方式让数据来回答这个问题。灰度验证的四步流程我强烈建议所有团队照抄第一步建立评测集。我们从历史真实请求中抽了200条典型问题覆盖高频场景和边界情况人工标注好标准答案要点。这个评测集不需要很大但必须有代表性。第二步离线对比评测。把同样的200条问题分别用轻量模型和旗舰模型跑一遍逐个对比输出质量。这里不是简单看“谁答得更好”而是看“轻量模型在哪些任务上出现了实质性错误”。第三步小流量线上灰度。把某个场景的流量切5%到轻量模型上额外加一道“用户满意度信号”比如用户是否点了追问、是否点了重新生成、是否在答案下面停留了很久没有操作。通过这些行为指标间接判断体验是否受损。第四步逐步放量。如果灰度阶段的质量指标和满意度指标没有显著下降就把流量比例逐步提到30%、60%最后全量切换。一旦发现某个场景的异常率升高立即回滚该场景的模型路由规则。我们当时做完这四步之后的结果是大约80%的场景流量从旗舰模型降级到了中档或轻量模型整体的API费用下降了将近40%内部人工抽评的质量分几乎持平。那段时间财务那边还专门问了一句“你们是不是偷偷停掉了一些功能”证明优化在体验层面确实做到了“无感”。4. 缓存架构与批处理把重复请求拦截在API之外4.1 语义相似度缓存让重复提问不再重复烧钱很多应用里的用户提问本质上是高度重复的。尤其是企业内部系统不同用户问的可能是同一份制度文件、同一条报销流程、同一个产品功能说明。按我们最初的实现每个用户问一次就调用一次API完全不做缓存等于同一道题反复交全款。要解决这个问题最朴素的做法是“文本完全匹配缓存”用户问过一模一样的问题就直接返回缓存结果。但真实场景里用户问法五花八门“报销标准是什么”“报销限额是多少”“出差报销可以报多少”文本不一样、语义却一样完全匹配缓存基本没什么用。我们后来加了一层语义相似度缓存对每次用户提问生成一个句向量embedding然后在缓存池里做向量相似度检索如果与历史问题的向量距离小于某个阈值我们用的是余弦相似度阈值为0.95就直接返回历史缓存答案。这个方案有一个关键前提embedding本身也要调用API但如果用专门的向量模型价格远低于对话模型而且可以通过批量方式进一步摊薄。实测下来加上语义缓存之后大约18%的用户问题会命中缓存这一部分请求的API费用直接降为零。缓存命中后的答案质量也要考虑时效性。知识库里如果更新了文档缓存里的旧答案就可能是错的。我们的处理方式是给缓存答案加一个时间戳同时在知识库内容变更时按文档来源批量清空相关缓存。这样既能享受到缓存的降本收益又不会因为缓存过期数据而牺牲正确性。4.2 批次合并与异步调度把并发单价打下来除了把重复问题拦截在API之外还有一类场景可以“化零为整”。我们的后台有一些异步批处理任务比如每天定时给一批文档生成摘要、给一批列表做关键词提取。早期实现是逐个文档循环调用API每个请求都是全价而且串行执行不仅慢费用也高。后来我们做了两个方向的改造第一个是请求合并。很多模型API支持在同一请求里批量传入多个输入片段统一生成结果。这种方式比逐个调用便宜不少因为请求头、系统提示词这些固定开销只用支付一次而且厂商对批量请求往往有更优惠的定价策略。第二个是时间窗口排程。把散落在全天的定时任务统一收敛到凌晨的低峰时段执行。因为API定价有时段差异部分厂商对夜间请求有折扣价或者有资源包策略我们把不紧急的批处理任务全部挪到低峰时段跑单价又下降了一截。这两个改动都是典型的“花时间省钱的工程”改造量不大但落地之后后台批处理这一块的费用下降了差不多六成。如果你现有的应用里有大量跑批任务优先去做这块优化的性价比非常高。4.3 本地小模型兜底简单任务根本不出门在成本控制这件事上很多人忽略了一个思路有些任务压根不需要大模型API来跑本地就能解决。把这一层拦截做好这部分的成本就是零。我们统计了一下业务里有很多请求本质上是“把非结构化文本里抽几个字段出来”比如从一段留言里提取用户姓名、电话号码、日期信息。这类任务用正则表达式加一些简单的规则就能搞定或者用一个很小的本地文本模型处理根本不用发给云端大模型。于是我们在API入口前面加了一个“本地预处理器”。它先判断任务的类型标签如果是“实体抽取类”且输入文本长度不超过一定阈值就直接在本地完成如果是“格式转换类”就用本地规则库处理只有那些确实需要语义理解和开放式生成的请求才会真正走到云端API。这个“本地兜底”层上线后我们整体请求量里大概有14%不再出网直接从源头砍掉了这部分费用。加上这层还有一个额外收益——响应速度变快了用户对系统“秒回”的感知也明显提升。踩了这个坑之后我对所有“AI应用成本方案”都保留了一个偏见最省钱的请求是根本不会发出的请求。5. 成本优化之后的复盘数据、陷阱与下一步的方向5.1 优化前后的费用对比与ROI把上面几套方案全部落地之后我们做了一次完整的复盘。需要说明的是这些方案不是一次性全上线的而是经过了大概两个月的分期推进每一步都有独立的验证。整体费用变化可以用一组简单数字来概括优化动作上线前月费用占比上线后月费用占比实际降幅提示词瘦身25%16%约35%场景内成本下降上下文压缩42%24%约43%场景内成本下降模型分级调度71%44%整体模型支出减少约38%语义缓存10%5%约18%请求不再调用API本地模型/规则兜底5%2%约14%请求不再出网最终月度API总费用从之前的一万三左右降到了五千出头降幅将近60%。而随后的一个月用户请求量又涨了15%费用却只涨了4%左右。这个对比说明我们的优化不只是“一次性省钱”而是把单位请求的平均成本从根上压低了让它能随业务量增长继续维持低位。整个优化过程的人力投入主要就是我和另一位后端工程师各投入了约两周时间加上产品同学帮忙做人工评测。按当时每月的费用差额来算这个优化的投入产出比大概在15到18之间也就是投入一个月的研发成本换来至少五个月的持续降本收益。对于绝大多数有API依赖的AI应用团队来说这笔账是值得认真算的。5.2 那些看似省了钱、实则埋雷的“伪优化”在成本优化这条路上我们也踩过不少坑其中有一些看起来“省钱立竿见影”的做法实际是在给未来埋雷。把这些写出来是希望大家少走弯路。第一个雷无脑降低模型参数档位。有些同类模型的“轻量版”和“标准版”看起来是同一个系列但实际能力差异不小。我们曾试图把某个中等复杂度的总结任务直接切到最便宜的档位结果模型开始频繁漏掉关键信息点人工抽检的错误率从3%飙升到了12%。省下的钱还不够客服处理投诉的时间成本。最终我们把这类任务提到了中档模型才找回平衡。第二个雷过度压缩上下文导致记忆丢失。有段时间我们把上下文摘要压缩得特别狠每轮的摘要只有一两句话结果用户在连续提问时经常出现“答非所问”——系统忘记了用户五分钟前提到过的关键约束。这类问题在评测集里很难被发现因为评测集是单轮问答但真实用户都是多轮连续咨询。最终我们把摘要的“事实保留率”作为硬指标要求每轮摘要必须包含用户提到的所有实体和数值信息才解决了这个问题。第三个雷缓存命中率虚高但保真度不够。语义缓存的阈值测试初期我们为了追求更高的命中率把相似度阈值调到了0.90结果经常把“报销标准是什么”和“报销流程是什么”这两类不同的问题当成同一个题目返回缓存导致答案牛头不对马嘴。后来把阈值调回0.95并在缓存答案里附加了原始问题摘要供前端展示用户能清楚地看到回答对应的问题是哪一个歧义和误读才真正被控制住。这三个坑的共同点是它们都是在“成本指标”上表现优异、但在“用户体验指标”上掩盖问题的陷阱。所以我在团队里定了一个铁律——任何成本优化方案上线前必须同时提交“质量影响评估”没有质量兜底的省钱方案一律不准上线。5.3 接下来可以继续深挖的降本方向成本优化这件事不是一锤子买卖而是一个持续迭代的过程。API价格本身就在快速变化新模型、新定价策略层出不穷。完成了第一轮的降本之后我手里还留着几个后续可以继续深挖的方向。一个是更细粒度的请求级路由。现在我们的路由是按业务场景和任务类型来分的后续可以考虑根据输入内容的长度、复杂度做动态定价预估让路由器在发请求之前先“算一笔账”预测这次的token消耗大概是多少再决定用哪个档位的模型。本质上就是给流量增加一个成本感知层。另一个是开源本地模型的进一步替代。现在我们已经把一部分简单任务放到了本地小模型上但目前覆盖的任务类型还比较窄。随着开源模型能力的提升和本地推理优化的成熟一些“中等理解类”的任务也有机会从云端迁回到本地。这个方向的技术难度高一些但潜在收益也大一旦跑通那部分流量的边际成本基本趋近于零。最后一个是与合作方重新谈判资源包。当消耗量稳定下来之后我们可以根据近三个月的实际token消耗曲线测算合适的预付费资源包或阶梯价格方案把单价再压低一截。此外开发环境的API调用也是一笔容易被忽视的成本给开发环境接入一套低配模型或者统一mock接口也能省下不少钱。说到底大模型API成本控制不是一道“省着用”的保守题而是一道“聪明地用”的工程题。能让便宜模型干的事绝不让贵模型干能让缓存回答的答案绝不让模型重想一遍能不出网的请求绝不出网。把这几个原则刻进团队的技术决策里费用和用户体验是可以同时拿下的。