大模型调用成本越来越高怎么办?从Token统计到缓存复用,搭建LLM成本管理系统

发布时间:2026/10/13 23:44:28
大模型调用成本越来越高怎么办?从Token统计到缓存复用,搭建LLM成本管理系统 一、引言Token 账单正在成为新的云成本黑洞过去两年大部分团队把 LLM 当作一个调用即付费的外部 API模型能力在涨、单价在跌似乎不需要精打细算。但真实账单往往给出相反的结论——单 token 价格下降了 90%总支出却涨了 10 倍。这不是幻觉而是典型的 Jevons 悖论成本下降激发了更多场景而每个场景的 token 消耗量远超预期。我们经历过一个非常典型的案例某团队 2023 年用 GPT-3.5 做客服问答月账单 3000 美元2024 年迁移到更强也更便宜的新模型还上线了 RAG 与 Agent 编排结果月账单直接冲到 40000 美元。模型单价降了业务量和单次请求的 token 量却涨了二十多倍。成本问题的本质从来不是单价而是消费者是谁、花了多少、值不值这三个问题无人回答。成本失控通常来自四个结构性原因输入 token 通胀。RAG 拼接知识库、Agent 携带工具 Schema、多轮对话携带完整历史一次请求的输入轻松从 500 token 涨到 20 万 token。更隐蔽的是很多团队每轮对话都把整段知识库原文塞进去而不是检索后的 Top-K 片段。Agent 循环放大。一次任务可能触发 10~30 次模型调用且每次都要重放全部上下文成本近似于 O(n²) 增长。一个帮我订机票的 Agent如果中间失败重试三次成本就是单一对话请求的几十倍。无法归因。财务只看到一张总账单研发不知道哪个业务线、哪个用户、哪个 Prompt 版本烧掉了钱。出了异常只能靠猜优化也无从下手。缺乏控制。没有预算熔断一次死循环重试或一个爬虫式的恶意请求就能在几小时内刷掉一个月的预算。真正的问题不在于模型太贵而在于缺少一套可观测、可归因、可优化的成本管理系统。本文从 Token 计量这一最小闭环出发逐层做到缓存复用与预算熔断给出一套可以在 1~2 周内落地的工程方案。二、核心原理成本模型、计量口径与缓存层次2.1 定价模型不止是 input/output 两个价格主流厂商的计费维度已经细化到四类忽略任何一项都会导致估算失真维度典型倍率说明输入 token1x常规 prompt输出 token3~5x生成成本最高是优化重点缓存写入1.25x前缀缓存首次写入缓存读取0.1x命中前缀缓存折扣最大Batch API0.5x异步批处理延迟换成本这里要强调一个经常被忽略的事实输出 token 的单价是输入的 3~5 倍。这意味着压缩 1000 个输入 token和让模型少写 250 个输出 token是等价的收益。很多团队把所有精力花在压缩 prompt输入却对输出 token 毫无约束比如要求模型输出冗长的 JSON、每轮都复述一遍完整推理过程。真正有效的做法是双向优化输入侧做检索裁剪输出侧限制max_tokens、约束 JSON Schema、禁止无意义的客套话。因此单个请求的成本应为cost fresh_input × p_in cached_input × p_cache_read cache_write × p_cache_write output × p_out举个具体数字假设gpt-4o输入 2.50 美元/1M、输出 10.00 美元/1M、缓存读取 1.25 美元/1M。一个 10000 token 输入的请求如果全部命中缓存输入成本从 0.025 美元降到 0.0125 美元如果一个对话有 20 轮、每轮重放历史未命中缓存的输入成本会累积到 0.5 美元——仅仅是输入就已经超过很多团队的单次预算预期。还有一个容易被漏算的成本失败的请求也是要计费的。超时、被限流、返回格式错误导致业务层重试只要模型产生了 token就要付钱。我们见过一个团队因为解析 JSON 失败就重试实际 token 消耗是成功请求的 3 倍。所以计量管道必须把status成功/失败/重试次数也记录进去。2.2 Token 统计的三种口径以及它们为什么对不上工程上能拿到 token 数的位置有三处本地估算用tiktokenOpenAI 系或官方count_tokens接口Anthropic 系在发送前预计算。响应回传response.usage字段是唯一的权威口径但只能在请求结束后拿到。网关计量在代理层解析请求体与响应体用于跨厂商统一。三者对不上是常态因为工具调用tool call的参数与结果会被重复计入、图片按 patch 折算 token、推理模型的思考 token 通常计入输出、system prompt 与函数定义有额外的封装开销。结论以usage为账本以本地估算为预算闸门两者偏差超过 15% 时告警。这里有个实战细节值得展开。我们上线计量系统后发现本地tiktoken估算和厂商usage的偏差在纯文本场景下通常只有 2%~5%但在下面几种场景会飙到 20% 以上带 tool/function calling 的请求。厂商会在 system 层注入函数定义模板指令里还有角色包装本地估算只算了messages漏掉了这层。多模态请求。一张高分辨率图片折算的 token 数取决于厂商的 patch 算法本地几乎不可能算准。推理模型reasoning model。思考 token 单独计费且不计入标准completion_tokens需要单独读取对应字段。流式响应。部分 SDK 在流式模式下最后一个 chunk 才带usage需要开启stream_options{include_usage: True}否则永远拿不到准确数字。所以正确做法是预算闸门用本地估算宁可高估防止超支账本用厂商usage两者定期做偏差回归一旦某模型的偏差持续超过阈值就说明该模型的计费规则变了需要更新估算器。2.3 缓存复用的四个层次缓存是降本杠杆最大的一环但需要分层设计L1 精确缓存对(model, messages, temperature, top_p)做哈希命中即返回。零误判适合事实性问答、SQL 生成等确定性场景。L2 语义缓存用 embedding 做近邻检索相似度超过阈值即复用。能吃掉换个说法问同一件事的流量但存在误判风险。L3 前缀缓存Provider 侧 Prompt Caching由厂商维护 KV Cache。要求前缀完全逐字节一致且通常有 1024 token 的最小长度门槛与 5 分钟~1 小时的 TTL。L4 上下文工程历史摘要、滑动窗口、结构化裁剪。它不叫缓存但收益往往比前三层加起来还大。四层的关系可以这样理解L1/L2 是业务级缓存直接替代一次模型调用收益是 100%L3 是引擎级缓存只降低输入单价到 10%但胜在无副作用、可普遍适用L4 是根治手段从源头减少要处理的 token。L2 语义缓存的阈值选择是最大的坑。阈值设 0.95 太严命中率低设 0.85 太松会把如何退款和如何取消订单混为一谈造成答非所问。工程上建议先设 0.92把每次命中都记录到日志人工抽样检查 200 条再逐步放宽。对于金融、医疗等高风险场景直接放弃 L2只用 L1L3。L3 前缀缓存有一个反直觉的约束前缀必须从第一个 token 开始连续一致。也就是说如果你把动态内容比如时间戳、“当前用户是张三”放在 prompt 最前面那么整段前缀就永远无法命中。正确做法是静态在前、动态在后system prompt、工具定义、知识库说明放最前用户的具体问题放最后。这一个排序的改动在我们一个项目里把前缀缓存命中率从 8% 拉到了 73%。三、实战搭建最小可用的 LLM 成本管理系统整体架构分四层统一调用入口 → 计量管道 → 存储与看板 → 预算熔断。下面给出关键模块的实现。3.1 统一入口与 Token 计量所有模型调用必须经过同一个 Client禁止业务代码直接import openai。# cost_tracker.pyimporttime,json,hashlibfromtypingimportCallable# 单价美元 / 1M tokens务必用配置文件维护并定期与官方价目表对账PRICING{gpt-4o:{in:2.50,out:10.00,cache_read:1.25},gpt-4o-mini:{in:0.15,out:0.60,cache_read:0.075},claude-sonnet:{in:3.00,out:15.00,cache_write:3.75,cache_read:0.30},}defestimate_cost(model:str,usage:dict)-float:根据一次响应的 usage 计算成本美元。 关键点 1. fresh_input 必须减去 cached否则命中缓存的部分会被重复计费 2. cache_write / cache_read 只在支持的厂商存在用 get 兜底 3. 单价都是每 1M token最后统一除以 1e6。 pPRICING[model]in_tokusage.get(prompt_tokens,0)out_tokusage.get(completion_tokens,0)cached(usage.get(prompt_tokens_details)or{}).get(cached_tokens,0)freshmax(in_tok-cached,0)writeusage.get(cache_creation_input_tokens,0)return(fresh*p[in]cached*p.get(cache_read,p[in])write*p.get(cache_write,p[in]*1.25)out_tok*p[out])/1_000_000上面这个函数只解决算一次成本但真正要落地的成本系统还需要把每次调用记录下来、可查询、可按维度聚合。为此我们再加一个薄薄的 Trackerimportsqlite3classCostTracker:def__init__(self,db_pathcost.db):self.connsqlite3.connect(db_path)self.conn.execute( CREATE TABLE IF NOT EXISTS calls ( id INTEGER PRIMARY KEY AUTOINCREMENT, ts REAL, model TEXT, tenant TEXT, feature TEXT, prompt_version TEXT, fresh_in INTEGER, cached_in INTEGER, cache_write INTEGER, out INTEGER, cost REAL, latency_ms INTEGER, status TEXT, cache_layer TEXT ))defrecord(self,*,model,usage,tenant,feature,prompt_version,latency_ms,statusok,cache_layerNone):costestimate_cost(model,usage)self.conn.execute(INSERT INTO calls (ts,model,tenant,feature,prompt_version,fresh_in,cached_in,cache_write,out,cost,latency_ms,status,cache_layer) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?),(time.time(),model,tenant,feature,prompt_version,usage.get(prompt_tokens,0)-(usage.get(prompt_tokens_details)or{}).get(cached_tokens,0),(usage.get(prompt_tokens_details)or{}).get(cached_tokens,0),usage.get(cache_creation_input_tokens,0),usage.get(completion_tokens,0),cost,latency_ms,status,cache_layer),)self.conn.commit()returncost这里四个业务标签tenant、feature、prompt_version、cache_layer是归因的核心。没有它们你只能看到总账有了它们你才能回答哪个客户、哪个功能、哪个 prompt 版本最烧钱这种真正能指导优化的问题。实战中踩过的坑早期我们只用feature一个维度后来发现某些大客户的功能成本高得不正常加了tenant之后才发现是两个大客户在疯狂调用同一个功能。如果不是按租户拆分这笔账会一直被平均掉。3.2 L1 精确缓存与 L2 语义缓存精确缓存实现简单用内存 Redis 两级即可。注意 key 必须包含所有影响输出的参数defcache_key(model,messages,temperature,top_p,toolsNone):payloadjson.dumps({model:model,messages:messages,temperature:temperature,top_p:top_p,tools:tools,},sort_keysTrue,ensure_asciiFalse)returnhashlib.sha256(payload.encode()).hexdigest()温度必须进 key。一个常见错误是缓存了temperature0.7的结果却给temperature0的确定性请求返回导致本该稳定的输出变得随机。同理tools、response_format、max_tokens都要进 key。语义缓存的实现依赖 embedding 向量检索核心是阈值与淘汰策略defsemantic_lookup(query_embedding,index,threshold0.92):# index 通常用 faiss / pgvector / redis-vectorhitsindex.search(query_embedding,k1)ifhitsandhits[0].scorethreshold:returnhits[0].cached_answerreturnNone语义缓存的三个坑1用错的 embedding 模型会让相似度不可比必须固定版本2缓存值要考虑时效性“今天天气这类问题必须按小时失效3必须加一个缓存旁路”当用户明确要求重新生成时跳过缓存。3.3 前缀缓存排序决定命中率前缀缓存的收益最大也最容易被浪费。核心原则只有一条把逐字节稳定的内容放在最前把动态内容放在最后。对比下面两种写法# 错误动态内容在最前导致所有请求前缀都不同 当前时间2024-06-01 10:23:01。用户问题如何退款 当前时间2024-06-01 10:23:02。用户问题如何退款 # 正确静态内容system、工具定义、知识库在前动态在后 [system: 你是一个客服助手...1500 token稳定] [tools: 退款/查询/取消的 schema800 token稳定] [user: 当前时间 2024-06-01 10:23:02问题如何退款]同时要注意前缀长度要超过厂商的最小门槛很多是 1024 token 或 2048 token否则不会触发缓存。如果你的 system prompt 只有 300 token可以通过补充更完整的角色说明、few-shot 示例来凑到门槛以上——这些内容本身也能提升输出质量一举两得。3.4 预算熔断防止一次事故烧掉一个月预算是最后一道防线必须在调用前检查、调用后扣减。粒度建议按租户 天和全局 小时双维度defcheck_budget(tenant,estimated_tokens,model):# 预估本次成本用本地估算宁可高估est_costestimate_cost(model,{prompt_tokens:estimated_tokens[in],completion_tokens:estimated_tokens[out],})ifspend_today(tenant)est_costDAILY_LIMIT[tenant]:raiseBudgetExceeded(f{tenant}日预算超限)ifspend_last_hour(__global__)est_costGLOBAL_HOURLY_LIMIT:raiseBudgetExceeded(全局小时预算超限)熔断之上还应有限速因为熔断是慢反馈要等预算接近耗尽而限速是快反馈。对单个用户的 QPS 做限制可以拦住爬虫式滥用。我们建议三层防护QPS 限速毫秒级→ 单次max_tokens上限请求级→ 日/小时预算熔断小时后级。3.5 看板只展示能指导决策的四个指标看板不要做成财务报表而要聚焦四个指标成本 / 请求按 feature 分组判断哪个功能在恶化。缓存命中率分 L1/L2/L3判断缓存是否真的在生效。平均输出 token 数输出失控是最常见的隐形浪费。失败重试率重试造成的重复计费往往被忽略。其中缓存命中率和平均输出 token是最灵敏的两个先行指标。当它们任一恶化时账单通常会在一两天后反映出来——这就是可观测性带来的提前量。四、常见问题 FAQQ1本地估算和厂商 usage 差得太多怎么办先确认是否漏算了 tool schema、图片、system 封装。如果某个模型偏差持续超过 15%就把该模型的偏差系数固化进估算器比如估算值 × 1.18并设置定期回归任务。Q2语义缓存会不会导致答非所问会。所以高风险场景禁用 L2一般场景也必须加人工抽检和重新生成旁路。永远不要把 L2 用在需要精确数字、法律条款、医疗建议的场景。Q3前缀缓存写入了为什么还是没命中90% 的情况是前缀里有动态内容时间戳、用户 ID、session ID。剩下 10% 是前缀长度不足门槛或两次请求之间超过了 TTL。用前缀 diff工具打印两次请求的前 N 个 token一眼就能看出来。Q4Batch API 便宜一半为什么不用因为它是异步的不满足实时交互场景。正确的策略是分流实时对话走同步 API离线批处理日报生成、批量打标、数据清洗走 Batch API能省一半。很多团队把所有流量都走同步白白多花了一倍钱。Q5要不要为每个业务线单独设置预算要而且强烈建议。全局预算只能防止整个公司破产无法防止某个功能烧光所有人的配额。按 feature 设预算才能在事故初期就精准拦截。Q6成本优化会不会牺牲质量会所以每一次优化都要配一个质量回归集。压缩 prompt、减少检索片段、降低max_tokens都可能让效果下降。没有质量护栏的成本优化是危险的最终往往会因为返工而花更多钱。五、踩坑与优化建议踩坑一只统计不归因。一张总账单没有任何优化价值。上线第一天就要打上 tenant/feature/version 标签。踩坑二缓存 key 漏参数。温度、工具、输出格式任一漏掉都会产生错误复用。建议用白名单方式显式列出进 key 的字段。踩坑三把动态内容放在 prompt 开头。这一条就让很多团队的前缀缓存命中率停在个位数。踩坑四没有输出上限。一个死循环的 Agent 可以无限生成max_tokens是最便宜的保险。踩坑五忽略重试成本。重试要计入成本且要限制重试次数与指数退避否则故障期间成本会指数级放大。优化优先级建议按 ROI 排序上下文工程L4→ 前缀缓存排序L3→ 精确缓存L1→ 输出约束 → Batch 分流L2 语义缓存放最后因为风险最高。大多数团队做完前两项成本就能降 40%~60%。六、总结大模型成本管理不是一个省钱技巧而是一套工程能力统一入口保证可计量业务标签保证可归因分层缓存保证可优化预算熔断保证可控。这四件事缺一不可。不要一开始就追求大而全。更多硬核网安与AI工具包请扫码获取完整源码最务实的路径是第一周接入统一 Client usage 计量 业务标签先把账算清楚第二周加 L1 缓存与前缀缓存排序通常就能看到明显下降之后再逐步补齐语义缓存、Batch 分流与预算熔断。先看见再优化最后才是控制——顺序错了任何一步都会变成盲人摸象。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询