☰
大模型API成本暴涨?RAG与多轮对话场景下的Token优化与省钱实战
2026/10/10 7:17:57 网站建设 项目流程

账单是凌晨三点推送过来的。我盯着那串数字看了整整两遍,确认自己没看错小数点:一个月,6个人的小团队,光是大模型API调用就烧掉了将近一万两千块,比我们全组一个季度的团建预算还多。这件事发生在一个相当常见的业务场景里——我们做的是一个面向垂直行业的智能问答产品,底层接了主流的大模型API,用RAG(检索增强生成)的方式给用户提供带参考资料的回答。听起来不复杂,对吧?可就是这个看起来人畜无害的功能,让我们的账单一路狂奔。

这篇文章不打算晒一张冷冰冰的账单就完事。我想做的是把这张账单彻底拆开:钱到底是从哪几个口子出去的,哪些是必要的支出,哪些是纯属我们自己把API用贵了,以及最后我们做了什么调整,把下一个月的成本压掉了三成以上。如果你也是小团队,也在跑大模型API,尤其在做RAG或者多轮对话类产品,那这篇复盘应该能帮你避开不少坑。

1. 账单全景:一个月一万二,钱从哪几个口子出去

1.1 我们到底做了什么业务,为什么会产生这么多调用

先交代一下背景,不然数字没有参照系就没意义。

我们团队一共6个人,两个后端、一个前端、一个算法、一个产品、一个测试兼运维,做的是一款面向企业客户的文档问答系统。客户把自己的产品手册、售后文档、知识库传上来,我们做切片、向量化、存库,用户提问的时候走一遍“检索+拼接+大模型生成”的流程,输出带引用了来源的答案。

听起来很常规,但有一个关键点:这是个To B产品,企业客户喜欢多轮追问。用户问一句“这个设备的保修期是多久”,紧接着就会问“那电池算不算易损件”“换电池要多久”“费用谁承担”。每一轮新问题,我们都会把整个对话历史一起拼进上下文送给大模型。这个设计后来被证明是账单爆炸的元凶之一,后面会细说。

按量统计一下:当时生产环境平均每天有大约2600次完整问答请求,其中直接命中主模型的约占70%,剩下30%的简单问题被规则引擎或轻量模型拦截掉。再加上开发调试、离线评测、定时任务,一个月的总调用次数大概在9万次左右。这个量级放在互联网产品里根本不值一提,但大模型API的计费逻辑和普通接口完全不同,它按token收费,不是按调用次数收费。

1.2 用一张简化表把真实账单摊开

这是我把某个月的原始账单按成本口径重新整理后的结果。金额已经取整过,但结构和占比是真实的:

成本项月费用(元)占比说明
主模型问答(生产环境)6,80057%多轮对话+RAG上下文拼装,输入token占了绝对大头
主模型重试与无效输出1,20010%JSON解析失败、超时重试、用户端中断导致的浪费
轻量模型(意图识别/粗筛)8007%用来做问题分类和简单问答,单价低
嵌入模型与向量存储1,0008%文档切片向量化+向量库存储费用
开发调试与离线评测9008%测试环境的key也在烧钱,而且烧得毫无心理负担
日志传输与网关计算3003%消息中间件、日志检索,体量小但别忽略
其他(超时补拉、边缘case)7006%各种说不清道不明的零碎费用
合计11,700100%

看到这张表的第一反应是“主模型问答肯定要优化”,但真正把账算明白之后发现,更该优化的是我们自己的调用姿势。

1.3 日均调用量与单次成本的手工测算过程

这节把当时手工测算的过程写出来,方便你自己对着算。

假设某个业务使用了主力模型Z,我们拿到的单价大概是:输入token每千个0.03元,输出token每千个0.12元(以我们自己签的合同价为例,仅作参考)。一次典型的多轮问答,用户历史消息经过系统拼装后,输入token平均在2800左右,输出答案token平均在420左右。那么单次调用的成本就是:

  • 输入成本:2800 ÷ 1000 × 0.03 = 0.084元
  • 输出成本:420 ÷ 1000 × 0.12 = 0.0504元
  • 单次合计:约0.134元

看起来单次才一毛三分钱,但按日均2600次来算,一天主模型就是350元,一个月22个工作日就是7700元。这还只是理想情况,没有算重试、上下文膨胀和无效调用。所以当月账单直接飙到一万二,一点都不意外。

提醒一下:如果你们的产品也是这种多轮问答形态,别只看单次调用的价格,一定要用“日均请求数 × 单次token消耗”来估算月成本,否则预算一定会超。

2. 账单里最贵的几个隐性黑洞

这节专门讲我们账单里最出乎意料的三块费用,也是我认为所有跑大模型API的团队都容易忽略的地方。

2.1 上下文无限膨胀:多轮对话的输入token在悄悄翻倍

这是所有黑洞里最凶的一个。

我们的产品为了支持多轮追问,把整个对话历史一股脑塞进上下文。产品经理的原话是“用户问前面问题时,模型需要知道上下文才能回答好”,这个需求没问题,问题出在我们没有做任何裁剪。一个聊了10轮的会话,前面9轮的问答原文全都堆在那里。第1轮用户可能贴了一大段产品描述,第2轮模型输出了一长串表格,到了第10轮,这些内容原封不动地继续作为输入token被计费。

我拉过一个极端案例:某用户一个会话里聊了14轮,最后一次请求的输入token是18000多。一次请求的输入成本就从0.08元变成了0.54元,涨了差不多7倍。更扎心的是,真正对当前回答有帮助的上下文往往只有最近两三轮。

后来我们做了一版粗略统计,去掉过期的历史消息后,平均输入token从2800降到了1300左右,主模型那块直接省了将近一半费用。这个数据我到现在都记得很清楚。

2.2 思维链token:模型“思考”也要按token收费

第二个黑洞是我们升级到某个支持思维链(CoT)的模型版本后才发现的。

那个版本默认启用思维链推理,模型会在输出正式答案前先生成一大段“内部推理过程”。从产品体验角度来说,推理过程确实能提升复杂问题的回答准确率,但问题是——逻辑推理的中间过程也是按输出token计费的,而且这部分用户根本看不到。

我们做了一次对比测试:同样一批测试问题,关闭思维链后,输出token从平均420降到了220左右。这意味着,光是模型“内心戏”就花掉了我们差不多一半的输出费用。这是个很容易被忽略的地方,因为你在API返回的字段里不仔细看,根本意识不到还有这么一大块隐形token。

当然不是要你无脑关掉思维链,复杂推理、多步计算任务确实需要它。但常规问答、知识库检索这种场景,大多数情况下模型根本不需要深度推理,关掉之后质量和成本都能兼顾。

2.3 JSON模式与重试:结构化输出失败的连锁成本

我们的答案是走后端渲染的,所以要求大模型必须返回严格JSON格式。模型有JSON mode选项,但并不是100%稳定。特别是上下文很长、对话历史很乱的时候,偶尔会在JSON里多输出一个逗号,或者把结束括号吃掉。

每个解析失败都会触发重试,重试意味着同样的输入token再计费一次,而且因为上下文没有变化,模型很可能在同一个地方再次出错。那个月我们数了一下,大约有3.5%的请求经历过至少一次重试,仅这一项就吃掉了一千多块。

后来我们做了两个调整:一是后台加了JSON修复层,针对常见的截断和末尾多余字符做自动修复,不直接重试;二是对连续失败两次的会话强制开启“简化模式”,让模型只输出不带嵌套的扁平JSON。两个改动加起来,重试率从3.5%降到了0.8%以下。

2.4 调试期调用:开发环境也在烧真金白银

这个坑说出来有点丢人,但确实是我们账单里不容忽视的一部分。

开发调试、联调测试、离线评测直接复用生产环境的模型API key,这是当时图省事留下的习惯。结果就是一次普通的Bug排查,可能发出去几十次真实API请求;一次批量回归测试,直接按线上价格跑掉上百块钱。9万次月调用量里,至少有1.5万次来自非生产环境,而这些调用产生的费用占比大概在8%左右。

我们后来专门开了一个测试专用的API key,配了独立的用量配额和低优先级路由,把开发和生产的账单彻底分开。这个动作的意义不只是省钱,更重要的是让生产账单变得干净、可分析,不然你永远分不清哪些成本是真实业务带来的,哪些是自家人不小心烧掉的。

3. 模型选型与路由策略:不是所有请求都配得上最贵的模型

3.1 三层模型架构:小模型分流,中模型兜底,大模型只做难活

一开始我们的架构非常简单粗暴:所有请求统一走主力模型Z,理由是“省心,效果最好”。省心是真的,贵也是真的。

后来我们把模型调用改成了三层结构,这个改动我认为是最重要的一次成本优化。

第一层是轻量模型Y,负责意图识别、关键词匹配、常见FAQ问答。这类请求上下文很短,不需要复杂的推理能力,Y模型的成本大约是主力模型Z的十分之一。第二层是中档模型M,负责有一定复杂度但不算刁钻的问题,比如需要简单推理的多轮问答,成本大约是Z的四分之一。第三层才是主力模型Z,只处理真正困难的问题——多文档交叉对比、复杂逻辑推理、需要引用多个来源并生成结构化答案的场景。

这个架构的收益很直接:月度主模型调用量从原来的70%降到了35%左右。总账单在业务量几乎不变的情况下,直接少了将近三成。最明显的变化是,主力模型Z的日均消耗token从原来的单日两百万出头,降到了不到九十万。

3.2 路由规则怎么设计,误伤率和成本一起降

模型路由的核心不是简单分层,而是得有一个不误伤效果的判断标准。我们的经验是把规则拆成两层。

第一层是硬规则:命中FAQ库的直接走轻量模型Y,不带任何犹豫;涉及多文档联合检索的、用户明确要求对比分析的,直接进主力模型Z;剩下不确定的进中档模型M试水。

第二层是动态兜底:当M模型的输出置信度评分低于某个阈值时,系统会自动升级到Z模型重新生成一版答案。这个兜底机制既保证了困难问题不会被低配模型糊弄过去,又避免了把所有请求都送进最贵模型。

我们给M模型设了一个动态指标:如果发现某个问题的回答长度明显偏离语料统计的合理区间,或者检索命中的片段之间关键词重叠度过低,就判定为低置信,触发升级。这套规则上线后,误伤率大约在2%左右,完全可以接受。

3.3 我们的选型踩坑:一开始“一个模型走天下”的代价

复盘的时候我们问过自己:为什么一开始不直接做分层路由?答案很现实——当时半个月就要上线Demo,团队里没人有精力设计路由逻辑,而且总觉得“大模型本身就能做意图判断,何必多此一举”。后来账单打脸了:模型确实能做意图判断,但它判断一次的成本,足够轻量模型跑十次。

还有一层原因是人情上的:主力模型的申请流程相对简单,而轻量模型当时在合同和合规上的流程反而卡了很久。这种“大模型反而更好落地”的错觉,在小团队里非常普遍。如果你也在做选型,我的建议是别只看单次价格和效果,多算一步:这个模型能不能被高频、低成本地用于基础分流任务。

4. 省钱的实操清单:这1.1万里至少能省下30%

4.1 Prompt瘦身:把输入从每轮900字压到300字

Prompt瘦身是被很多人低估的一项优化,因为它改动起来不难,但对账单的影响极其可观。

我们最初的系统Prompt写了两千多字,包含了各种约束和示例。其中一半的内容属于“防御性提示词”,就是那种为了防止模型胡编乱造而堆上去的警告文字。问题在于,这些字每调用一次就要按输入token计费一次。用户根本不会看到它们,但它们日复一日地消耗着预算。

我们把System Prompt做了一轮彻底精简:删掉大量重复说教式的规则描述,把可选的示例从固定拼接改为按需注入——如果检索结果里没有表格数据,就绝不把表格示例塞进Prompt。经过这一轮,系统Prompt从2400多字降到了700字左右,输入token整体下降了差不多22%。

这里有个细节值得说:Prompt精简后,回答质量并没有明显下降,反而因为无关信息变少,模型跑题的概率降了。很多提示词写得长,是因为写的人自己没想清楚要什么。你在砍Prompt的时候,本质上也是在逼自己理顺产品逻辑。

4.2 上下文缓存与持久化会话:重复输入token是不必要的燃烧

接着前面多轮对话上下文膨胀的问题说。我们当时做了一个最简单也最有效的优化:把每个会话维护成“最近N轮摘要+最近两轮原文”的结构。

怎么理解呢?就是不再把全部历史消息原文堆进上下文,而是用一个轻量模型M把聊过的内容压成一段摘要,每次新请求只需要带上“摘要+最后两轮原文+当前问题”。单次请求的输入token从2800降到了1400左右,而且这个数字不会随着对话轮数增加而一路暴涨。摘要生成会额外花一点成本,但相比每次请求都携带大量历史原文,省下来的钱可以覆盖摘要开销几十次。

如果你的API服务商带了上下文缓存功能,也可以进一步利用。我们试过把系统Prompt和历史消息做成带缓存key的固定前缀,命中缓存时输入token费用直接降了一个量级。这是目前对我来说性价比最高的一项优化,没有之一。

4.3 把非实时任务改走批处理与异步队列

我们有个需求,是每天早上对前一天新增的客户文档做批量摘要和质量检测。最初实现方法是写了个定时脚本,循环调用主模型逐条处理。一份文档摘要约3000 token,一天新增50份文档,一个月跑下来,光这个定时任务就烧了小一千。

这个场景其实完全不适合走实时对话API的定价体系。我们后来查了下,大部分API服务商都提供了离线批处理接口,同样的模型效果,批处理价格通常只有在线实时调用的一半甚至更低。我们把批量摘要和离线评测全部切到了批处理队列里,费用直接砍半。顺带还解决了一个之前没意识到的问题:批量任务跑在主模型key上,会挤占在线请求的配额,触发限流之后,用户端的问答体验也会跟着一起抖。

如果你有定时清洗、离线标注、批量评测这类非交互任务,一定要单独走批处理通道。别让“顺手跑一下”的习惯悄悄侵蚀你的核心预算。

4.4 限流、熔断与预算告警:防止一次线上事故烧穿月预算

账单飙升不一定是业务涨了,也可能是一次线上事故。

我们遇到过一回,某个客户的文档格式特殊,导致检索模块跑出了大量空结果。系统拿到空上下文后还是照样发给大模型,模型没有依据,就只能生成一堆“抱歉,我无法回答”的废话。本来应该被拦截的请求,全部变成了实打实的token消耗。那半天里我们的调用量暴涨了四倍,账单多出一千多块。

从那以后我们加了三条防线:

  1. 空上下文直接拦截:检索结果为空且没有缓存命中时,不回主模型,直接返回预设话术;
  2. 单用户调用频率熔断:同一用户一分钟内超过8次请求自动拒绝,这个阈值是按真实使用场景摸出来的;
  3. 预算告警:在API控制台和自建监控里同时配了告警——日消耗超过预估值的1.5倍时,钉钉机器人自动发警报;月消耗达到预算的70%时,核心成员都会收到提醒邮件。

预算告警这个点要尤其注意:别等月底开盲盒。把告警阈值设在月预估的70%而不是100%,因为当你看到告警的时候,实际花费往往已经比显示的数字高出一截了。

5. 如何让成本变成可见指标,而不是月底开盲盒

最后聊聊我们怎么把成本从“事后才知道”变成“实时可追踪”的。这不仅是工具问题,更是团队协作习惯问题。

5.1 在每个调用点埋token计数与成本标签

我们改造了底层API调用封装层,每次调用都会把模型名称、输入token、输出token、缓存是否命中、业务场景标签记录下来,同时根据合同单价换算成金额。这个数据通过消息队列实时写入日志平台,每天凌晨汇总成一张成本报表。

这里贴一个简化版的埋点统计伪代码,思路供参考:

def record_call(scene, model, input_tokens, output_tokens, cached=False): cost = { "input_cost": (input_tokens / 1000) * PRICE[model]["input"], "output_cost": (output_tokens / 1000) * PRICE[model]["output"], } log_entry = { "scene": scene, # 业务场景:问答 / 摘要 / 评测 / 调试 "model": model, # 模型名 "input_tokens": input_tokens, "output_tokens": output_tokens, "cache_hit": cached, # 是否命中上下文缓存 "cost": cost, "ts": int(time.time()), } send_to_log_center(log_entry)

有了这个之后的好处是,任何一次异常的成本波动都可以直接回溯到具体模型、具体功能和具体时间点,而不是对着账单猜。

5.2 按天/按功能/按用户维度的成本报表怎么搭

日志打点数据上来之后,我们配了三个维度的日报:

按天看趋势,重点关注有没有尖峰;按功能看占比,重点看摘要、问答、评测各自吃掉多少钱;按用户看TOP消耗,重点排查是不是有大客户在异常调用。第三个维度最实用,我们靠它抓出过两个情况:一个是某客户的爬虫脚本没配频率限制,半夜疯狂调用API;另一个是内部的回归测试case没有mock掉模型接口,每次都真实计费。

这三个维度不需要复杂的数据平台。我们用日志服务+一条SQL就能查出来,每天早上定时推送到群里。成本这种事,看得见才能管得住。

5.3 月度复盘模板与团队共识

每个月初的周一,我们固定花二十分钟过一遍上个月的模型成本复盘,基本就四个环节:

  • 对比上个月总成本与调用量变化,找出差异最大的功能模块;
  • 检查是否有新增的无效调用场景(比如测试环境费用占比是不是又上来了);
  • 评估上个月的优化措施实际省了多少钱,确认哪些动作值得继续;
  • 定下本月预算上限,以及如果超了优先砍掉哪块业务。

这套复盘机制跑了三个月之后,团队慢慢形成了一些共识:改提示词之前先看一眼它会让输入token涨还是跌;新增一个调用场景之前,先在开发环境试跑并估算成本再上生产。以前大家觉得“API费用是公司的事”,现在每个人都会主动关心自己那块功能的成本。

最后提一个教训:有些平台的账单展示会有延迟,实时控制台看到的数字往往不是最终账单。以月底的详细账单为准来回溯调优,不要因为某个下午看到数字很低就觉得万事大吉。

我自己的体会是,大模型API的成本问题本质上是工程问题,不是玄学。只要把每次调用的token消耗、模型选型、缓存策略、场景分层这几件事管明白,小团队完全可以把成本压到可接受的范围。账单没那么可怕,可怕的是你压根不知道账单为什么是这个数。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询