☰
Token成本优化:从上下文压缩到按需选模型的实战指南
2026/10/20 16:07:27 网站建设 项目流程

说实话,大部分人第一次意识到 token 成本失控,都不是在测试阶段,而是产品上线后打开账单的那一刻。我上个月就经历了一次:一个自动摘要功能跑了一周,token 消耗量比前面整个开发周期加起来还多,跑到后台一看日志,问题根本不出在模型输出上,而是每次请求都在反复把一整套固定上下文喂给模型,相当于每次花钱之前先烧掉一大半燃料。

所以这期“半古法”更新,我想认真聊聊两个被绑在一起的问题:节省 token,还有按需选择模型。很多人觉得这是两件事,一个管省钱,一个管效果,但实际做下来你会发现,真正有效的方案永远是同时设计这两层的。如果你也在做接入大模型 API 的产品,不管是个人的小工具、团队内部系统,还是面向外部的应用,这篇文章应该能帮你把成本结构看清楚,顺便避开我踩过的几个坑。

1. 先算明白账:token 到底烧在哪些环节

1.1 你以为贵的是模型,其实贵的是输入

大模型 API 的计费方式有两种常见结构:一种是输入和输出分开计价,输入通常比输出便宜不少;另一种是把两者折算成统一单价。不管哪种,大家第一反应都是“输出贵,所以要控制回答长度”,这个直觉没错,但放到真实应用里往往不是主要矛盾。

你可以自己做一个简单测算。假设你的系统每次请求都会带上:系统提示 1500 token、工具描述 800 token、最近对话历史 3000 token,再加上用户本次输入 200 token。只看输入部分,就已经是 5500 token。如果这条链路每天被调用 1 万次,光输入部分就烧掉了 5500 万 token。哪怕输入单价只是输出单价的四分之一,总账单里输入也占了绝对大头。

所以第一步不是急着换更贵的模型,而是把每次请求“喂进去的东西”称一称。做任何优化之前,先搞清楚钱是不是花在了这些不起眼的固定内容上。

1.2 一次真实请求的 token 分布长什么样

我之前在某客服机器人项目里抓过一份用量分布,典型的一问一答长这样:

组成部分大致 token 数备注
系统提示800角色设定、回答规则、禁止事项
业务知识片段2000从知识库检索后拼入
对话历史2800默认保留最近 20 轮
工具/函数定义600涉及 5-6 个内部接口
用户输入120本次提问
模型输出350最终回复
合计6670输入 6320,输出 350

看到这个分布,你就明白为什么单纯限制回复长度是杯水车薪:输出只占 5%,剩下 95% 都是你主动投喂进去的。只要能把输入总量压缩一半,成本立刻降一半,效果却未必打折。

1.3 “半古法”的立场:不堆框架,先把该省的地方省掉

我这套更新叫“半古法”,意思是不太迷信现成的重型框架,能用手写的最小逻辑解决就不引入额外依赖。省 token 和按需选模型这件事尤其适合这种思路:它不需要复杂的调度系统,每个环节都可以用非常直白的方法做,但前提是你知道每个方法适用于什么场景、有什么代价。接下来每一节,我都会先说做法,再说为什么这样做。

2. 节省 token 的三个硬动作:裁剪、摘要、模板化

2.1 滑动窗口加优先级保留,比“无脑截断”高明得多

最常见也最危险的省 token 做法,就是简单粗暴地“只保留最后几轮历史”。这种做法在短会话里问题不大,但一旦用户中途确认过某些信息,比如“我地址是北京朝阳”,然后在第十轮突然说“那就按刚才那个地址寄”,模型会因为中间历史被截断而一脸茫然。

我现在的做法是给上下文分优先级:

  • 永远保留:系统提示、用户的核心目标、需要长期记住的结构化信息。
  • 优先保留:最近 4 到 6 轮对话,因为即时上下文最重要。
  • 可丢弃:和当前任务无关的寒暄、过长的报错日志、已经被摘要覆盖的旧历史。

实现上就是一个简单的字符串拼接函数,按优先级拼回去。如果你用现成的对话框架,对应参数可能叫 memory 或 context_window,但原理都一样:不是均匀地砍,而是保住信息密度最高的部分。

2.2 用递归摘要换掉原始会话日志,长对话的救命稻草

对话一长,历史 token 就会指数级膨胀。最实用的解法是做“递归摘要”:当对话轮数超过阈值,先把前面的内容丢给一个轻量模型,让它生成一段 200 字以内的进展摘要,之后请求里只用这段摘要,不再塞原始日志。

我的做法分三步:

  • 设定阈值,比如超过 12 轮就触发摘要。
  • 用轻量模型对前 10 轮生成结构化摘要,包括用户已确认的信息、已解决的问题、待办事项。
  • 把摘要拼进系统提示,同时清掉原始历史,只保留最近几轮。

这条思路用到“对话摘要”类 API 或自建摘要 Prompt 都可以。核心心法是:摘要本身也要结构化。比如“用户偏好:价格敏感”“已确认:周五发货”“未解决:退款方式”,这种格式比一句自然语言描述更容易被主模型准确读取。

2.3 提示词模板化与 few-shot 的克制使用

另一个隐蔽的浪费是把系统提示写得像小说。很多人担心模型听不懂,于是把需求翻来覆去地描述,甚至加一堆例子。这个担心可以理解,但对大多数任务来说,模型理解能力已经足够,真正缺的是明确约束。

我的经验是遵守“三短一少”:

  • 规则短:每条指令尽量一句话说清。
  • 角色短:设定角色一句话,不铺陈背景故事。
  • 全文短:系统提示尽量控制在 500 token 内。
  • 示例少:few-shot 控制在 2 到 3 个,能用零样本就不要硬塞例子。

具体到 few-shot,还需要克制。每多一个示例,就意味着每个请求多花几百 token。如果你的任务本身明确,比如“把这段文字翻译成英文”,直接零样本就够了;只有输出格式容易跑偏时,才给一个标准示例和最典型的一个反例。

2.4 输出约束:既是省钱也是省心

控制输出 token 不只是调低 max_tokens,更要约束它的结构和长度。让模型自由发挥,它可能在结尾补两句废话或重复内容。我通常在提示词里明确“只输出 JSON,不要解释”,同时在 API 参数里设置 response_format 或 JSON Schema 校验。这一招能同时带来三个效果:token 更少、解析更稳、用户等待时间更短。

3. 按需选择模型:把任务分类,而不是一种模型打天下

3.1 模型能力分层与场景对照

“按需选择模型”的第一步,是建立一份适合自己业务的模型分层表。不用纠结各家模型排名,关键是在自己的能力边界内做取舍。

任务类型建议模型档位原因
关键词抽取、文本分类轻量级语义简单,小模型足够稳定
打标签、实体识别轻量级输出格式固定,错误率可控
摘要生成长文档中端到旗舰需要理解长文逻辑,但不需要太强推理
客服对话、多轮任务中端以上需要记忆与意图识别,错误代价高
代码生成、复杂推理旗舰一步错步步错,返工成本远超模型差价
润色、改写中端质量要求弹性大,可按场景调整

做这张表的意义在于:你不是在“省”和“好”之间二选一,而是知道每个任务的“下限”在哪。低于下限会返工,等于白省;高于下限,就是浪费。

3.2 路由判断的三种方式,从简单到进阶

按需选模型的落地,核心是一个路由层。路由的复杂度可以从小到大分三层:

  • 静态规则路由:最简单。不同接口、不同按钮背后固定挂不同模型。比如“翻译接口”固定走轻量模型,“代码解释接口”固定走旗舰模型。零额外成本,确定性强,适合场景边界清晰的产品。
  • 关键词规则路由:在入口处用关键词判断。比如用户提问里包含“帮我算”“分析一下”“为什么”这类词,就升级到中端模型;否则走轻量模型。实现成本低,能解决大部分问题。
  • 动态预分类路由:先用轻量模型花几十 token 给任务做个“难度评分”,再决定主模型。比如让它输出 1 到 5 分,分数高的才用旗舰模型。这个方案对模糊场景很有效,但要注意预分类这一步本身也可能出错,需要设置兜底。

3.3 一个“先小后大”的兜底链路

我最常用的是“先小后大加兜底”的策略,整体思维是这样的:

请求进来之后,先走静态规则,规则无法确定时用轻量模型预判难度;低难度任务直接用轻量模型处理并做格式校验,校验不过就升级中端模型;高难度任务直接走旗舰模型,但旗舰模型结果也过同一套校验,失败还会触发重试或报错反馈。整个过程看起来不复杂,但能挡住大多数“用大模型处理小儿科任务”的浪费。

你可以把它理解成一个带宽分配器:高价值才走高速,普通流量走普通通道,但所有通道出口都有检查关卡,不合格再重新分流。

3.4 按需选择的真正难点:不是技术,是心态

很多人以为按需选模型就是技术实现,其实不是。真正让人纠结的是心态:明明知道简单任务走轻量模型就行,但总担心出错,于是所有请求都挂旗舰模型,省 token 就成了一句空话。

这里分享一个我自己用过的判断标准:一个小模型如果单次成功率是 85%,但它便宜 80%,那么对允许重试的任务来说,它的性价比依然高于旗舰模型。你需要担心的不是“失败率”,而是“失败后补救要花多少钱”。如果补救只是重新调用一次,那完全可以通过重试策略解决;如果补救会导致用户流失或商业损失,那才应该直接上旗舰模型。

4. 简化实现:一版看得懂、能改动的路由与压缩骨架

4.1 包装函数的核心逻辑

我习惯把所有成本和路由逻辑收敛到一个入口函数里,而不是散落在业务各处。用 Python 伪代码展示大概是这样:

def chat_with_router(user_input, conversation): route = classify_task(user_input) # 规则或轻量模型预分类 if route == "simple": messages = compact_context(conversation) # 滑动窗口+摘要压缩 resp = call_api("lightweight_model", messages, max_tokens=200) if validate(resp): # 格式/关键字段校验 return resp # 校验不通过,降级到中端模型再试一次 resp = call_api("mid_model", messages, max_tokens=300) elif route == "hard": messages = compact_context(conversation) resp = call_api("flagship_model", messages, max_tokens=800) validate(resp, required_fields=["answer", "reason"]) return resp

这样一个函数把所有请求都串起来,后续不管加缓存、加摘要、加路由规则,都只改这一处。小项目维护起来没有负担,等流量大了要拆成微服务也不难。

4.2 参数设置里容易被忽略的几个点

  • temperature:简单分类任务建议调低到 0 到 0.3,减少随机输出;创意写作才建议调高。
  • max_tokens:别只设一个笼统值,按任务给上限。摘要给 300,翻译给 500,代码生成给 800。
  • 停止符:设置好 stop 序列,避免模型把无关内容也续写出来。
  • 超时与重试:轻量模型偶尔会超时,重试时要使用指数退避,别再叠加一次无谓成本。

4.3 给每个请求打 tag,否则优化无从谈起

这一点我特别想强调:任何 token 优化都必须在日志里能看得见。我给自己定的规矩是,每个请求都记录这些字段:模型档位、输入 token 数、输出 token 数、路由原因、是否命中缓存、校验是否通过。

只有把这些数据攒下来,你才能知道“轻量模型到底省了多少”“摘要有没有帮到我们”“路由规则误判率有多高”。否则你优化了一个月,最后只能凭感觉说“好像便宜了一点”,这是不行的。

5. 踩坑实录:那些省了 token 却亏更多的操作

5.1 我差点把客服机器人做成“失忆机器”

第一个坑来自上下文压缩过度。最开始我把客服场景的历史直接压缩到最近 2 轮,token 确实降了一大截,但代价是用户一旦在第三轮问“我之前说的地址你知道了吧”,机器人就开始胡编乱造,用户满意度直线下降。后来加上优先级保留和递归摘要,才把成本压住的同时保住关键信息。这个经历告诉我:token 优化不能看单一指标,要看整条链路的成功率。

5.2 小模型“看起来成功,实际错了”的 JSON 陷阱

第二个坑是让小模型做结构化输出。加了 JSON Schema 约束后,轻量模型确实能输出合法 JSON 了,但内容层面经常悄悄出错。比如字段 A 明明该是“退款中”,它给了“退款成功”,语法完全正确,业务含义却错了。解决办法是给关键字段加枚举校验和规则判断,不合法就重试一次;仍不合法再升级模型。校验这层成本很低,但能把隐性错误拦在外面。

5.3 一个比 token 更烧钱的常客:重复请求

还有一类浪费不在模型参数里,而在业务层。用户刷新页面、前端重复提交、任务重跑,都会导致完全一样的请求反复调用模型。我在一个内部工具里加了一层简单的请求缓存:相同业务 ID 和相同输入命中缓存就直接返回历史结果。这个改动比调整模型路由带来的收益还大,是最被低估的省 token 手段。

5.4 小模型错级使用,可能比大模型更贵

最后一个是关于“错级使用”的隐性成本:为了让某个任务省钱,强行用轻量模型,结果总是出错,每次错误都要人工介入。人工维护成本一旦折算进来,平均单次成本可能比一开始就用旗舰模型还高。所以我现在的原则是:小模型用在“错得起”的任务上,大模型用在“错不起”的任务上,这个边界要在路由规则里写清楚。

6. 把“按需选模型”变成团队习惯,而不是个人技巧

6.1 模型选择要写进配置,不要写死在代码里

如果你的项目只有一个人维护,模型写死在代码里没问题。但一旦有第二个开发者加入,事情就会变形:有人不敢随便改代码,于是一个简单任务也沿用旗舰模型;有人贪图省事,全局换个轻量模型,结果某条关键链路质量崩了。我建议在项目里把模型档位和各任务的默认值写进配置文件,路由规则也集中在同一处。这样调整成本极低,每个人都能按任务自行决定用哪档模型,不会互相干扰。

6.2 我的“四问法”:每个任务上线前先问自己

做模型路由决策时,我习惯问四个问题,顺序固定:

  1. 这个任务需不需要多步推理?需要,就直接上高能力模型。
  2. 错误会带来多大代价?代价高,用旗舰模型加校验;代价低,用轻量模型加重试。
  3. 能否先用规则完成?能走规则的路径就不要交给模型,最省的 token 是不消耗的 token。
  4. 输出能被自动校验吗?能校验,就可以放心用小模型;不能校验,再考虑升级。

这四个问题走完,大多数任务的模型档位都能定下来。你不会再纠结于“最强模型”和“最便宜模型”,而是自然形成一个梯度结构。

6.3 性价比测试:先跑一周日志再做决定

最后的落地建议是:任何路由策略都不要上线前拍脑袋,先灰度一两天,收集那批 tag 日志,对比一下同样任务在不同模型档位下的成功率、失败率、平均 token 数和平均延迟,再拍板。我见过太多团队凭“感觉”选模型,结果要么花了冤枉钱,要么偷偷降低了质量。

最后说点个人体会

“半古法”更新的核心,其实不是技术有多高级,而是看待成本与质量的方式:不要神化旗舰模型,也不要神化省钱。一次调用能不能省钱,取决于你有没有把任务拆细、把校验补齐、把路由规则写清楚。这套逻辑放在个人项目和团队项目里都能用,只是规模不同。

我后续的更新里,应该还会继续沿着这条线展开,比如更细的路由策略、缓存层的设计、以及不同业务场景下的失败兜底方案。如果你也在做类似的优化,建议先按上面那套配置跑两周,把账单和成功率的底数摸清楚,再动手改细节。

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

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

立即咨询