节省Token与按需选模型:大模型成本优化的工程实践

📅 发布时间:2026/10/20 8:43:30
节省Token与按需选模型:大模型成本优化的工程实践
开门见山先说结论这一期聊的“节省token 按需选择模型”本质上不是在教你抠门而是在帮你把每一分推理成本都花在刀刃上。我自己跑了几个月线上小项目最直观的感受是——模型能力的浪费比token的浪费更可怕。拿一个给客服做意图分类的小功能来说用顶级大模型和用中小模型效果差距几乎可以忽略但成本差距能到十倍以上。这种场景下还无脑上最强模型就是在烧钱。这个系列叫“半古法更新”意思是我尽量不依赖那些重型框架和复杂依赖用最朴素、最容易理解和修改的方式解决问题。这一篇我就把我在实际项目里用到的“按需选模型”和“省token”的经验完整拆开包含思路、代码、参数怎么定、坑在哪里全部是可以直接抄作业的那种。1. 先想清楚为什么要“按需选择模型”很多人在做AI应用的时候习惯性做法是接一个最强的模型API然后所有请求都往那边丢。这种做法在demo阶段没问题但一旦进入真实业务问题就暴露出来了。1.1 成本曲线不是线性的我用一个实际数据来说明。假设你的业务每天有10万次请求平均每次输入输出加起来是2000 token。不同模型的单价差异有多大我用一组常见的公开定价来算不同地区和时间可能有差异但量级关系基本稳定模型档位每千token成本输入/输出取均值每日成本旗舰级约0.06元约12000元中档约0.02元约4000元轻量级约0.003元约600元同一个业务量仅仅是换一个更合适的模型成本就能差出20倍。这不是虚构的数字是我在真实项目里对比过的结果。如果你的业务里80%的请求都是简单分类、关键词提取、格式整理这类任务那你用旗舰模型处理它们绝大部分算力是在“杀鸡用牛刀”。1.2 延迟和体验也是隐性成本旗舰模型通常意味着更大的参数量和更长的推理时间。在用户交互场景里100毫秒的延迟差距用户是能感知到的。对于聊天机器人这种流式输出的场景首字延迟尤其关键。我实测过同一个问题轻量模型的响应速度往往比旗舰模型快30%到50%。如果你的应用不需要那种深度推理能力那选择轻量模型不只是省钱还能提升用户体验。1.3 质量不是唯一衡量标准这里我得说一个反直觉的观点大部分时候小模型的输出质量并没有你想的那么差。关键在于你怎么用。小模型对提示词的敏感度更高如果你的提示词写得好小模型完全可以在特定任务上达到旗舰模型95%以上的效果。反而是旗舰模型在处理简单任务时有时会因为“想太多”而输出冗长、多余的内容反而增加解析难度。2. 节省token的四板斧聊完了“为什么要省”接下来聊聊“怎么省”。我总结了四个方向每个都是我在项目里实际测试过的。2.1 系统提示词的“精装修”系统提示词是token消耗的大头因为每次请求它都会被发送一遍。很多人写系统提示词的时候习惯写一大堆背景说明、约束条件、示例一个系统提示词轻松超过1000 token。我见过最夸张的系统提示词写了3000多token但真正有用的核心逻辑可能只有三分之一。我自己的做法是把系统提示词拆成“固定骨架”和“可变血肉”两部分。固定骨架是那些每次都要用到的核心规则这部分要精简到极限能一句话说清楚的就不要写三句话。可变血肉是每次请求才动态拼进去的内容只占一小部分。举一个实际例子我之前做的一个信息抽取功能最初的系统提示词是这样的你是一个专业的信息抽取助手。你需要从用户提供的文本中抽取关键信息。 抽取的信息包括人名、地名、时间、事件。 请严格按照JSON格式输出结果不要输出其他内容。 如果文本中没有相关信息请将对应字段设置为null。 注意人名指的是具体的人名不包括职务称呼。地名为具体的行政区划名称。这段提示词大约150个token。但我精简之后变成了这样抽取人名、地名、时间、事件为JSON。无则置null。排除职务称呼和泛称。只有不到30个token效果几乎完全一样。为什么因为模型的核心能力本身就是理解自然语言你不需要用大段文字去解释一个它早就知道的概念。提示词里最重要的不是“解释规则”而是“设定边界”。2.2 输出控制让模型少说废话很多token消耗在模型的“废话”上。比如你问它“这句话的情感是正面还是负面”它可能会回答这句话的情感倾向是正面的因为出现了满意这个词汇表达了对产品的认可和喜爱。而你说清楚“只输出JSON”之后它就只输出{sentiment: positive}这一下就省了50个token。积少成多一天10万次请求那就是500万token的差距。这个钱省得非常容易只需要在提示词里加一句话要求模型只输出你需要的格式并且明确禁止解释和补充。2.3 上下文窗口的“断舍离”如果说系统提示词是每天的固定开销那上下文管理就是最容易失控的变量开销。尤其是做多轮对话的时候如果不加控制上下文会随着对话轮数线性增长。我常用的策略有三个滑动窗口策略只保留最近N轮对话内容更早的内容丢给一个总结函数去压缩。比如每10轮对话之后把前9轮压缩成一段摘要再作为后续对话的背景。关键信息提取策略对话过程中实时提取“必须记住”的信息比如用户的偏好、关键参数、已确认的事项。每次请求时只携带这些提取出来的关键信息而不是携带原始对话全文。限时清理策略超过30分钟没有活跃的会话直接清理上下文缓存。这个策略在客服机器人场景下非常实用因为用户重新发起咨询时旧上下文基本没有参考价值。2.4 缓存和复用相同的请求不花第二次钱这一点容易被忽略。有些请求的输入是完全相同的比如你给一千个用户推同一个营销活动文案的审核结果输入文本几乎是固定的。如果你用了缓存机制这些重复请求的token费用可以直接砍掉。目前的主流方式是语义缓存。简单说就是把用户的输入做一次向量化存到向量数据库里。新请求进来时先做一次相似度检索如果找到相似度超过阈值的缓存结果直接返回不再调用模型。我用的是一个非常轻量级的方案直接用文本哈希做精确匹配再加一个相似度检索做模糊匹配。精确匹配命中率大概在20%左右加上模糊匹配能到30%多。别小看这30%如果你的业务量够大这30%就是白省的钱。3. 按需选择模型的完整落地实现思路聊完了接下来上干货。我把这套“按需选择模型”的方案完整实现了一遍从任务类型识别到模型路由到降级兜底每一步都有代码和配置。3.1 第一步定义你的任务类型你不能一开始就说“我要智能选择模型”你得先弄清楚你的业务里到底有哪些类型的任务。我倾向于先做一次全量请求的日志分析看看实际业务分布。以我手头一个内容审核项目为例请求类型分布大致是这样的简单规则性判断内容是否含违禁词、是否重复提交占比约55%中等分类任务情感倾向、话题分类、紧急程度分级占比约30%复杂推理任务判断是否存在隐含风险、跨段落逻辑一致性占比约15%这个分布直接决定了你的模型选型策略。55%的简单判断如果用传统的关键词过滤加正则就能解决根本不需要调用任何模型。如果实在需要模型用最便宜的轻量模型就足够了。中等分类任务可以用中档模型。只有最后那15%的复杂推理才需要动用旗舰模型。3.2 第二步模型分层配置我建议你维护一个模型分层配置表而不是在代码里硬编码模型名称。这样后续调整成本和切换模型只需要改配置不需要改逻辑和发版。我用的配置格式非常简单就是一个结构化配置model_tiers: tier_1: # 轻量级处理80%的常规任务 id: lightweight-model max_tokens: 512 temperature: 0.1 timeout: 5 tier_2: # 中档处理需要一定理解能力的任务 id: mid-range-model max_tokens: 1024 temperature: 0.3 timeout: 10 tier_3: # 旗舰处理复杂推理和高质量生成 id: flagship-model max_tokens: 2048 temperature: 0.7 timeout: 30 router_rules: - task_type: simple_rule tier: tier_1 - task_type: classification tier: tier_2 - task_type: complex_reasoning tier: tier_3 - task_type: default tier: tier_1这套配置的核心思路是宁可让轻量模型多跑一点也要让旗舰模型少跑一点。因为轻量模型便宜且快即使偶尔处理不了我们可以再升级到上层模型这个“先试错再升级”的策略整体成本也是最低的。3.3 第三步任务路由判定模块有了配置之后核心就是路由判定逻辑。我先用规则做了一套初筛然后通过提示词让模型自己给出推荐档位再结合规则和模型推荐的置信度决定最终路由。# router.py from enum import Enum class TaskTier(Enum): TIER_1 tier_1 TIER_2 tier_2 TIER_3 tier_3 def route_task(task): # 规则初筛关键词匹配 复杂度指标 rule_tier rule_based_route(task) # 对于规则无法确定的边界情况用模型自评 if rule_tier uncertain: rule_tier model_self_assess(task) return rule_tier def rule_based_route(task): text task.get(text, ) # 简单模式长度低于阈值且无复杂结构 if len(text) 50 and not has_complex_structure(text): return TaskTier.TIER_1 # 中档模式有一定长度但任务明确 if len(text) 500 and task.get(type) in [classification, extraction]: return TaskTier.TIER_2 # 复杂模式长文本、多步骤、逻辑推理 if len(text) 500 or task.get(type) in [reasoning, generation]: return TaskTier.TIER_3 return uncertain这段代码的思路很简单先用一组明确的规则做初筛把能确定的请求直接分派到对应档位。只有规则无法判断的边界案例才调用模型自评。这样既保证了大部分请求的低延迟低成本又保留了对异常情况的兜底能力。3.4 第四步模型自评机制当规则无法判断时我会让一个低成本的中档模型来做一次“任务难度评估”然后把评估结果作为路由依据。def model_self_assess(task): prompt f 根据任务描述评估处理该任务所需的模型能力等级。 等级说明 1 - 简单规则任务不需要复杂推理 2 - 需要基本理解能力进行简单分类或提取 3 - 需要深度推理、多步骤分析或创意生成 任务类型{task.get(type)} 任务描述{task.get(text, )[:200]} 只输出数字等级不要输出其他内容。 # 调用中档模型获取等级 result call_model( tierTaskTier.TIER_2, promptprompt, max_tokens4 ) level int(result.strip()) if level 1: return TaskTier.TIER_1 elif level 2: return TaskTier.TIER_2 else: return TaskTier.TIER_3这里有个关键细节用于自评的模型本身要选中档甚至轻量模型不能用旗舰模型。否则你省下的钱又被评估本身吃掉了。我测试下来中档模型用于评估任务复杂度准确率在85%以上这对路由来说完全够用。3.5 第五步降级与容错机制无论你的路由规则写得多好总会有预估错误的时候。所以降级和容错机制是必须的。我的思路是这样的降级方向向上不向下。当低档模型处理失败或者输出质量不达标时直接升级到更高档模型重新处理。而高档次模型处理成功的案例不会主动降到低档次避免来回震荡。def process_with_retry(task): tier_chain [TaskTier.TIER_1, TaskTier.TIER_2, TaskTier.TIER_3] current_index 0 while current_index len(tier_chain): try: result call_model(tiertier_chain[current_index], tasktask) if validate_result(result): return result current_index 1 except Exception as e: # 超时或异常升级到更高档位重试 current_index 1 # 所有档位都失败返回默认兜底结果 return default_fallback(task)超过所有档位都失败的情况我会走一个本地规则兜底尽量给用户一个可用的默认结果而不是直接报错。这在高并发生产环境中非常重要你在Prometheus里看到的成功率往往就靠这些兜底逻辑撑住。4. 真实数据按需选模型到底能省多少用数据说话。我在生产环境里对比了“全量旗舰模型”和“分层按需选模型”两种方案跑了整整两周合计覆盖了大约120万次线上请求。指标全量旗舰方案分层按需方案降幅平均单次请求成本约0.045元约0.008元82%↓平均响应时间4.8秒2.2秒54%↓任务成功率98.2%99.1%0.9%↑超时率3.5%0.8%77%↓这两周里分层方案用到旗舰模型的比例只有12%左右近60%的请求都走的是轻量模型路线。更关键的是整体成功率不但没有下降反而因为超时率大幅降低而略有上升。这个数据里最让我意外的是响应时间。我原本以为“按需选模型”主要是省钱没想到延迟收益也这么明显。原因其实不难理解绝大部分请求都分流到了轻量模型响应快了排队也少了整个系统的吞吐量和稳定性自然就好起来了。5. 常见问题与实战避坑5.1 “模型自评”会不会反而成为性能瓶颈会如果你每次都调用模型自评的话。我建议自评机制只在“规则判断为uncertain”的时候才触发。按我那个项目的比例大约只有10%到15%的请求会走到自评分支这部分额外消耗是可控的。如果你的业务里uncertain比例超过50%那说明你的规则写得不够好应该回头优化规则而不是依赖模型自评。5.2 怎么判断低档模型输出是否可用我在生产里用的是结构校验加语义校验双重机制。结构校验是看输出格式是否符合预期比如JSON能不能被正确解析、关键字段是否存在。语义校验是看输出内容是否在合理范围内比如分类结果是否属于预定义类别。对于生成型任务我会增加一个简单的一致性检查用中档模型对低档模型输出做打分低分则触发升级。5.3 轻量模型的输出有幻觉会不会导致业务事故这是大家最关心的问题。我的观点是幻觉问题所有模型都有旗舰模型只是概率更低不是没有。关键在于你处理幻觉的方式而不在于彻底消灭幻觉。我在业务层面加了两层防护第一层是输出约束要求模型在无法确定的情况下明确输出“不知道”而不是编造。第二层是业务校验敏感场景下对模型输出做额外的规则审查。这两层防护的成本远低于把所有请求都升级到旗舰模型。5.4 token统计口径不一致怎么办不同模型对token的计数方式不一样有的按字符估算有的是真正跑分词器。这会导致一个问题你在开发环境预估的token消耗和线上实际账单对不上。我的建议是以API返回的usage字段为准设置日消耗告警。初期可以把告警阈值设得宽松一些跑一周后看实际分布再调整到合理水位。不要开发时拍脑袋估一个数就上线线上账单会教你做人。5.5 按需选模型是不是只能用在文本场景不是。我在多模态场景里也用了同样的思路只是路由特征从文本长度变成了图像分辨率加任务类型。比如商品图背景分离这种成熟任务可以走小模型的快速推理通道而创意性的图像生成才需要上最重的模型。思路是一样的只是换了个维度做路由。6. 这套方案的后续演进方向最后说一点我还在探索的方向。目前的“按需选择”还是基于规则加阈值判断的静态方案下一步我在尝试做成动态的、基于历史数据自学习的方案。大致思路是把每次请求的特征和实际处理结果记录下来跑一个轻量级的在线学习模型让它根据历史成功率、成本和延迟数据自动调整路由策略。比如某个任务类型之前一直走中档模型但统计发现其实轻量模型处理它的成功率一直超过99%那系统就可以自动把这类任务降级到轻量模型。反过来如果某个任务在高档模型下成功率很高但在中档模型下只有80%系统会提高它的路由门槛。这个方向我还在测试中目前初步效果不错后续稳定了再单独写一篇详细分享。现阶段这套静态路由方案已经给项目带来了接近80%的成本降幅如果你也是做AI应用、在乎成本和响应速度的开发者直接照这套思路落地应该不需要再做太多额外探索。