模型API用得越久,越会发现一个尴尬的事实:你花出去的钱,相当一部分在买“废话”。我自己做过一段时间的AI应用开发,把某款大模型API接入内部工具后,月底一拉账单,token消耗比预期高出将近一半。排查下来,问题不在用户问得多,而在回答太长、上下文太臃肿、重试太莽。这篇文章就围绕这三件事展开:怎么把无用回答压下去,怎么把上下文算明白,怎么让重试机制不再烧token。适合正在做AI应用、接大模型API、或者自己写工具类Agent的开发者参考,看完就能对着自己的调用逻辑做一轮体检。
1. 先搞懂token到底被谁吃掉了
1.1 token的基本认知误区
很多人对token的理解停留在“1个汉字约等于1个token”,这个估算在大方向没错,但实际计费的时候远比这复杂。同一句话,英文可能按单词拆分成多个token,中文则可能按字、按词、甚至按标点切分。同样是“你好世界”,不同分词器切出来的token数量可以差两倍。更隐蔽的是,标点符号、空格、换行符都占token,一段代码缩进多了,token数立刻爬升。
我在早期优化的时候犯过一个低级错误:拿字符数去估算token数,以为压缩了1000字就省了1000个token,结果一看账单只少了三分之一。后来才意识到,模型的分词器不是按字符数工作的,它是按词元频率和概率分布的。相同含义的内容,用词越常见、句子越规整,token数越少;口语化、碎片化、重复的表达,token数翻倍不奇怪。
还有一点容易被忽略:输入和输出的计费单价不一样。绝大多数商业API的定价都是输出比输入贵,有的甚至贵一倍以上。这意味着,同样减少1000个token,砍在输出上比砍在输入上省钱得多。所以第一优先级永远是压回答长度,其次才是压上下文。
1.2 三个隐藏的token黑洞
我把自己项目的调用记录拉出来做了个拆解,发现token消耗集中在三个地方,排序如下:
第一个,模型回答的冗余。默认参数下,模型倾向于把话说全、说满。你问“今天天气怎么样”,它能从“根据气象数据”开始铺垫,最后再加一句“希望这些信息对你有帮助”。这段附加内容在对话中看着没问题,但每次调用都多出几十上百token,量一大就是纯浪费。
第二个,上下文中塞了太多用不上的东西。很多人为了“让模型更懂我”,把几万字的历史文档、几十轮聊天记录一股脑塞进prompt。但模型处理输入时,每一轮都要把完整历史重新编码一次。换句话说,只要某条历史消息留在上下文里,它在之后每一次请求中都会被重复计费。哪怕用户只追问了一句“那后来呢”,模型也要把前面所有对话重新读一遍。
第三个,重试机制在重复烧钱。接口超时、限流、网络抖动,这些是API调用的家常便饭。常规做法是失败就重试,但如果你没做任何区分,遇到参数错误、内容过滤这类“重试一万次也没用”的错误也在傻傻重发,那每一轮重试都在把完整prompt重新计费一遍。更隐蔽的是,有些重试其实是成功的,只是响应慢了点,结果你超时判断太激进,把已成功的调用又重发了一次。
这三个黑洞叠加起来,月末账单翻一倍是常态。下面分别说怎么堵。
2. 缩短无用回答:从参数到输出格式的四层压缩
2.1 max_tokens不是越小越好,要够用且不浪费
先说最直观的参数:max_tokens。它的作用是限制生成结果的最大长度,超过就截断。很多人以为把它设得越小越省钱,这是大错特错。截断会导致回答不完整,模型给到一半就停了,用户只能再追问“继续”,于是又来一轮完整调用,一来一回反而花了更多token。
我踩过的坑是:把max_tokens设成100,让模型生成一段摘要,结果它写到第98个token突然断句,后面整整一段结论没了。用户看到的是残缺内容,我只能加一次“请补全”的请求,花的token比直接设成200还多。
正确做法是先做一轮“充分生成”测试,把典型问题的真实输出长度记录下来,然后取P90值加一点余量作为max_tokens。比如测试下来80%的回答在300 token以内,那设成350左右就比较稳妥。这样既不会频繁截断,也不会让模型在回答结束时继续画蛇添足。
另外要留意,max_tokens只是“上限”,不是“目标”。模型在到达上限之前就完成了回答,剩余token不会产生费用。真正让模型保持简短的是指令和参数配合。
2.2 温度参数与长度惩罚的组合拳
temperature控制的是随机性。温度越高,模型越容易发散,句子越长、用词越飘。温度太低,回答会变得机械,但长度通常更可控。我自己的经验是:生成类任务(写文案、写代码注释)用0.7左右,问答和抽取类任务用0.2甚至0。降低温度对压缩token的效果是真实存在的,但不是因为它直接限长,而是因为它减少了模型“绕弯子”可能。
另一个有效参数是frequency_penalty(频率惩罚),它会让模型减少重复用词。之前我做过一个客服问答机器人,模型经常把“您的需求我们已经收到”这种话反复说三遍。加了0.5左右的频率惩罚后,重复啰嗦的情况明显减少,每次回答平均短了40个token。需要注意惩罚力度别太大,否则模型会为了避开常用词而改用生僻表达,反而增加token。
还有一种做法是通过prompt直接约束长度,比如在系统提示里写“回答不超过150字,只给结论,不要客套话”。实测下来,语言模型的“听话程度”超过多数人的预期,你明确不给它发挥空间,它就真的会简短很多。但要注意,模型的字数感知并不精确,你说150字它可能给你200字,所以字数约束要和max_tokens做双重保险。
2.3 stop序列是性价比最高的压缩手段
stop序列是我强烈推荐的一个工具。它告诉模型:一旦生成到指定标记就立刻停止。最常见的用法是设置“\n\n”作为停止符,因为模型在完成一个完整段落总结时,经常以换行收尾,然后又开始继续补充“总之”“综上”之类的废话。设了停止符,废话直接掐断。
更精细的玩法是配合结构化模板。比如要求模型输出JSON,我在prompt里规定好格式,把“}”作为stop序列。模型输出完JSON对象就戛然而止,不会再多写任何一行解释。这个方法在抽取类和工具调用类场景里极其好用,既省token又方便程序解析。
我见过有些开发者把多个stop序列配合使用,一个是“\n\n”,一个是“再见”,一个是“END”。理论上都有效,但要先验证模型在正常回答里会不会提前触发这些标记。曾经我把“。”设成停止符,结果模型每句话结束后就停了,整段回答碎成好几片,用户只能手动拼接,体验很糟糕。
2.4 结构化输出:让模型只说你要的那部分
如果说前面几个办法还是“节流”,结构化输出就是“精准射门”。它的核心思路是:不要让模型自由发挥,而是把输出压缩成固定的字段格式。
举个例子,我之前做一个信息抽取功能,需要从一段长文本里提取公司名称、联系人、电话。如果直接问“请提取这段文本中的信息”,模型会一边提取一边给你讲解“根据文本内容,我们找到了以下信息……”,最后还可能加一句“希望对你有帮助”。但如果我规定格式为“仅输出JSON:{"company":"","contact":"","phone":""}”,模型就只会输出一行JSON,token消耗直接减少一半以上。
有个细节要注意:要求结构化输出时,模型可能会把回答截断在半个JSON处,尤其是max_tokens设小了的时候。我在实践中是用“prompt里给一个完整示例 + max_tokens设为示例长度的1.5倍 + stop序列设为‘}’”这套组合,基本能保证每次都输出完整、可解析的JSON。
再补充一个技巧:多用“是否式”问题的限定。把“请分析这段文本的问题并提出改进建议”改成“请先判断这段文本是否存在格式问题,若存在,仅列出问题类型,不输出建议”。命令越窄,输出越短,这是所有压缩手段里最没有学习成本的一条。
3. 算清上下文:从完整重发到按需裁剪
3.1 上下文的计费机制决定了裁剪的必要性
大模型的API有个和传统接口完全不同的特点:它在生成回答前,要把整个prompt从头到尾编码一遍。这意味着,不管历史对话里哪条信息跟当前问题有没有关系,只要它还在上下文里,就会被一起处理,并按输入token计费。
这个机制带来一个很反直觉的结论:你保留的“历史记忆”不是免费的,它每一轮都在产生费用。假设你维护了最近10轮对话,平均每轮500 token,那么用户每次追问,你都要为这5000 token的历史买单。10个用户各追问一次,就是50000 token的纯输入开销。
更严重的是上下文膨胀问题。对话时间越长,历史消息越多,prompt越塞越大。到后面,用户只是问了一个“那周五呢”,你也要把过去20轮的信息全部重新编码一遍。账单上涨的不只是总量,还有单次请求的平均成本。
所以,上下文管理的第一原则是:不必要留在上下文里的信息,坚决不留。它不是你想不想“记住”的问题,而是你付不付得起的问题。
3.2 滑动窗口:只保留最近N轮对话
最基础的裁剪策略是滑动窗口。保留最近N轮完整对话,更早的内容要么丢弃,要么压缩成一句摘要。N的取值没有绝对标准,取决于业务场景。我之前做客服机器人,保留5轮就够,因为用户的问题通常是独立的;做编程助手,要保留到10轮,因为用户会基于之前的代码反复修改。
滑动窗口要注意两个细节。第一个是“轮”的定义。用户说一句、模型回一句算一轮,还是以用户发起的一个完整意图算一轮?我建议按意图算,连续追问“这个功能怎么改”“报错信息在这里”“再试一下”应该算同一轮,拆开算会导致窗口里塞进重复的用户消息,浪费token。
第二个细节是别把系统提示和固定指令算在窗口里。系统提示是每轮都要用的基础信息,它不属于“历史对话”,但很多人会把整段系统提示随着历史一起拼接,造成重复计费。系统提示应该作为固定前缀单独处理,只在内容有变化时更新,而不是每一轮都重新拼一遍。
3.3 摘要压缩:给历史消息做瘦身
如果业务确实需要长期记忆,滑动窗口就不够用了,这时候需要对旧消息做摘要压缩。具体做法是:当对话超过窗口长度时,把最早的一部分消息发送给模型,让它生成一段200字以内的摘要,然后把摘要本身作为一条历史记录,替代那部分原始消息。
这个方案的效果我在实际项目里验证过。一组100轮的测试对话,原始消息约5万token,压缩成摘要后只有1500 token左右,减少了96%以上。代价是模型对早期细节的回忆变得模糊,但绝大多数场景下,用户关心的是近期内容,早期细节的丢失完全可以接受。
做摘要压缩有几个坑要避。首先是摘要也不是免费的,生成摘要本身要调用一次模型,消耗输出token。所以不能每轮都做,要设定一个触发阈值,比如超过20轮或者超过8000 token才做一次。其次是摘要应该逐段压缩,不要一次性把所有旧消息塞给模型让它总结,那样输入token先爆了,得不偿失。
另外,摘要的质量直接影响后续对话的效果。我在实践中发现,让模型以“用户关注点+待办事项+关键决策”三个维度来压缩,比笼统地说“概括之前对话”要好用得多。因为用户真正需要的长期记忆不是聊天内容本身,而是那些“说到一半还要继续办的事”。
3.4 系统提示瘦身和固定片段复用
系统提示是另一个容易被忽视的token大户。很多人喜欢在系统提示里写长篇大论的“角色设定”“行为规范”“知识库内容”,一次塞进去几千上万个token。这部分内容在每轮请求里都会被完整计费,而且往往只有其中一小部分对当前问题有用。
我的做法是把系统提示拆成两层:一层是固定身份指令,尽量压到100 token以内,只写身份和输出格式要求;另一层是可变业务信息,按需注入。比如客服机器人的知识库文档,只有在用户问到相关产品时才把它附加到上下文里,而不是默认全量带上。
还有一个进阶技巧是留意API服务商是否支持prompt caching,有些平台允许以较低价格重复使用相同的前缀。如果服务商支持,把大型的、不常变化的系统提示或知识库内容作为“固定前缀”放在prompt最前面,多次调用时命中缓存,成本能大幅下降。这个功能在不同服务商处名称不同,但原理类似,值得在选型时纳入考量。
3.5 换个思路:把大上下文拆成小任务
比压缩上下文更彻底的办法,是避免产生大上下文。与其让模型一次性处理一份10万字的文档并回答三个问题,不如把文档切分成章节,先让模型对每个章节做独立摘要,再对摘要做二次汇总。这样做的好处是,每次请求的输入token都控制在一个很小的量级,虽然调用次数变多了,但总token数反而更低。
这个思路适合文件分析、长文总结、代码审查等场景。我做过一个财务报告分析工具,原始方案是把整份报告塞进prompt、要求模型给出分析结论,报告一长,单次请求的token就飙到几万,成本完全压不住。后来改成按章节摘要、再逐层汇总的多级处理,总token消耗降低了六成,回答质量还更稳定,因为模型不会被无关章节干扰。
当然,拆任务不是没有代价。多轮调用意味着更多网络延迟和更多潜在的失败点,需要配合下面说的重试机制一起设计。
4. 重试机制的token优化:别让失败请求反复烧钱
4.1 先判断错误类型:哪些值得重试,哪些重试也是白搭
API调用的错误类型,大致分三类。第一类是暂态错误,比如网络超时、服务端限流(429)、瞬间抖动(5xx)。这类错误重试是合理的,稍等几秒再发一次,大概率能成功。第二类是参数错误,比如prompt格式不对、max_tokens非法、结构化输出解析失败。这类错误重试多少次都不会成功,纯粹是浪费token。第三类是内容触发拦截,比如请求的内容或生成的答案命中了过滤策略。这个要分情况,有时候换一种表述就能过,有时候则无论如何都会被拦。
我的建议是:给重试逻辑做一张错误分类表。对参数类错误,直接抛出异常让调用方排查,不重试。对内容过滤类错误,可以换prompt措辞重试一次,但绝不超过两次。对网络抖动类错误,才启动指数退避重试。
很多人的重试代码是“无脑重试三次”,这在平时看不出问题,但一旦遇到参数错误,三次都是白烧钱。我见过一个线上事故,模型接口返回参数超限的错误,程序自动重试了5次,每次把完整的超长prompt又重新计费一遍,账单翻了不少,结果全部失败。如果把错误分类做好,这笔钱完全不会产生。
4.2 指数退避不是越大越好,关键是控制重试成本上限
指数退避是重试机制的标准做法:第一次失败等1秒,第二次等2秒,第三次等4秒,以此类推。它的好处是给服务端恢复时间,同时避免请求雪崩。但在token成本上,它有自己的代价:每次重试都是一次完整的API调用,都要对完整prompt重新编码。
所以在设计退避策略时,除了时间间隔,还要设定重试次数上限。我自己的经验是:超时类错误最多重试2次,限流类错误最多重试3次,其他错误一律重试不超过2次。这样做的理由很简单,重试的价值是“可能成功”,如果两次都失败了,第三次成功的概率并不会显著提高,而每次失败都在烧token。
另外,要把“重试”和“部分成功”区分开。如果模型在生成中途超时了,有些服务商支持流式传输并允许继续。这种情况下,你可以先尝试从断点继续获取剩余内容,而不是重新发起一次完整请求。这个能力需要在接入时确认,但一旦支持,省下的token相当可观。
4.3 一次请求失败,不代表之前的回答全废
在流式输出的场景里,有个经常被忽略的省钱技巧:如果你用的是流式接口,模型是逐字返回内容的。如果生成到一半网络断了,你手里已经有半截回答。这时候别急着把整个请求重新发一遍,而是先看看这半截回答能不能用。对于长文本生成任务,前半段往往是背景铺垫,后半段才是关键结论,但如果前半段里面已经有用户需要的信息,那就可以直接复用,不再重试。
我做过一个长文生成功能,输出往往要一两千个token。有一次网络抖动,生成到800个token时断了。按老逻辑,整个请求重发,光输出就浪费了2000多的token。后来改成“断点续传”方案:把已生成的内容作为新prompt的一部分,让模型“接着写”,虽然输入多了800个token,但输出省了2000多,综合算下来还是划算的。
这个方案的实现要小心一点:让模型接着写之前,一定要在prompt里说清楚“这是之前已生成的内容,请从结尾处继续,不要重复开头”。否则模型很可能从头再来一遍,那前面省的就全白费了。
4.4 请求去重和结果缓存:重试之外的双保险
在重试机制之外,还有一层的优化空间:缓存。如果两个用户的请求完全相同,或者同一个用户在短时间内重复调用了相同内容的接口,完全可以复用上一次的结果,而不是让模型重新生成一遍。
我给项目加过一个简单的缓存层:把prompt和参数的hash作为key,把生成结果存起来,有效期设成10分钟。实测下来,客服机器人和FAQ查询场景的重复率在15%左右,这15%的调用直接被消掉,一分钱都不花。更激进一点的做法是做语义相似度判断,意思相近的问题也直接返回缓存结果,但这对系统开销有一定要求,而且匹配不准会伤体验,我只在低频场景里开启。
还有一个小技巧:对批量任务做合并。如果要在短时间内处理10条相似的数据,与其分成10次调用,不如把10条数据拼在一个prompt里让模型一次处理。单次请求的token会比单条高好几倍,但总token数比10次单独调用少很多,因为重复的系统提示、格式指令都只算一次。
4.5 离线压测是省token的最后一道闸门
前面说的都是代码层面的优化,但代码合入之前,最好先做一轮离线压测。压测的目的不是看吞吐量,而是看平均每次业务操作消耗了多少token。我自己的习惯是:人为构造一组覆盖主流程的测试用例,跑一遍脚本,统计单次请求的平均输入token、平均输出token和请求失败率。用这些数据乘以预期的用户量,能比较准确地估算出月度成本。
压测过程里经常发现意外问题。我第一次压测就发现,某个功能平均每单消耗了8000多token,其中输入占了6500,输出只有1500。顺着数据反向排查,发现一个没注意到的循环里重复拼接了同一段知识库内容,修掉这个bug后,单均成本直接从8000降到3500。这类问题靠肉眼审查代码很难发现,只有用token统计才能暴露。
建议在压测脚本里加一个“等价token估算”函数,用字符数粗略估算输入输出,做不了精确计费但能暴露异常。看到某个调用路径的数据明显偏高,就顺着查,多数时候都能找到重复拼接或该裁没裁的历史消息。
5. 把三招串起来:一套完整的token优化配置参考
5.1 一个可直接抄的优化版调用配置示例
下面是我在项目里最终定型的调用配置,以某主流商业API为例,参数做了脱敏处理,适用于大多数文本生成场景:
import time import hashlib import json def build_prompt(user_input, history, kb_docs): # 固定身份指令,限定在100 token内 system = "你是客服助手,只回答用户问题,不客套,不超过800字,用中文。" # 滑动窗口:只保留最近6轮对话 recent = history[-6:] # 摘要信息:超出窗口的旧对话,用已生成的摘要代替 old_summary = summarize_history(history[:-6]) prompt = [ {"role": "system", "content": system}, ] if old_summary: prompt.append({"role": "system", "content": f"历史摘要:{old_summary}"}) for item in recent: prompt.append(item) # 知识库内容:只有命中关键词时才附加 if kb_docs: prompt.append({"role": "system", "content": f"参考文档:{kb_docs}"}) prompt.append({"role": "user", "content": user_input}) return prompt def call_model(prompt, max_tokens=800): params = { "temperature": 0.2, "max_tokens": max_tokens, "stop": ["\n\n"], "frequency_penalty": 0.5, } # 这里是伪代码,实际按你所用的API格式调整 return client.chat.completions.create( messages=prompt, **params )有几个参数值得单独解释。第一,temperature设成0.2而不是默认的0.7,因为在问答类场景里,低温度能让回答更收敛、更短。第二,stop设成“\n\n”是为了截掉模型在答案结束后追加的内容。第三,frequency_penalty设0.5,压制重复表达。这三个参数加在一起,单次输出的平均token能压掉30%-40%。
5.2 不同场景的参数选型参考
不是所有场景都适合同一套参数,我把常见场景做了个对照表,方便按需取值:
| 场景 | 推荐温度 | 推荐max_tokens | 推荐stop | 特殊设置 |
|---|---|---|---|---|
| 客服问答 | 0.2 | 800 | \n\n | 加知识库命中再注入 |
| 信息抽取 | 0 | 300 | } | 强制JSON格式输出 |
| 代码生成 | 0.4 | 1200 | 无 | 给完整示例 |
| 长文生成 | 0.7 | 2000+ | 无 | 断点续传,不轻易重试 |
| 摘要压缩 | 0.3 | 300 | \n\n | 按三维度输出 |
这个表不是铁律,但方向是对的。同一个模型,在不同任务里对参数的反应差异很大,一定要在各自场景里用真实数据做一次校准。特别是max_tokens,一定要基于实际测试的输出长度来定,不要拍脑袋。
5.3 优化前后的成本对比:一组真实的账单数据
我在内部项目上做了一轮完整优化,优化前后的数据对比是这样的:
优化前:输入平均3500 token,输出平均1200 token,单次综合成本约0.06元(按输入30元/百万token、输出60元/百万token估算)。每天1万次调用,日成本约600元。优化后:输入平均1800 token,输出平均700 token,单次综合成本约0.024元。配合缓存命中率15%,每天1万次调用的日成本约200元。整体降幅达到了66%。
这个数字里的关键变量是输入token砍了一半左右。来源主要是三块:历史窗口从10轮降到6轮,旧对话改为摘要,知识库不再全量注入。输出token之所以能砍掉四成,靠的是低温度、频率惩罚和stop序列的三重配合。
值得强调的是,优化没有以牺牲回答质量为代价。我做了50条测试用例的回归对比,回答质量的主观评分基本持平,部分抽取类任务的准确率反而提高了,因为prompt更干净、干扰更少。这说明token优化的核心并不是“让模型少干活”,而是“让模型不要干多余的活”。
6. 常见问题与排查技巧实录
6.1 问题速查表
我在调优过程中遇到的高频问题,整理成一张速查表,方便大家对照排查:
| 现象 | 根因 | 解决方案 |
|---|---|---|
| 账单高但调用量不大 | 历史消息未裁剪 | 加滑动窗口,超窗做摘要 |
| 回答经常断句不完整 | max_tokens设太小 | 用P90输出长度+余量重设 |
| 模型输出前后重复 | 温度偏高+无频率惩罚 | 降温度到0.2-0.4加惩罚 |
| 失败重试后账单翻倍 | 未区分错误类型 | 参数错误不重试,超时最多2次 |
| 同一问题反复花钱 | 缺乏结果缓存 | 加hash缓存层,算好过期时间 |
| 长文档分析成本爆炸 | 一次性塞入全文 | 改多级摘要合并处理 |
| 模型回答太啰嗦 | 缺少格式约束 | 强制JSON或规定字数上限 |
6.2 最容易被忽略的三个细节
第一个细节是“超时时间设置”。很多API封装库默认超时是10秒或30秒,但大模型生成长回答时,耗时很容易超过这个值。超时设置太短,会导致“其实还在正常生成却判定失败”,然后你发起重试,等于一笔费用变两笔。我建议把超时时间至少设为60秒,并开启流式传输,边生成边接收,避免因等待过长而误判。
第二个细节是“system prompt更新时,连坐重发”。有些开发者为了省事,每次请求都动态生成一份新的system prompt,哪怕只是改了一个字的版本号,也会让整个固定前缀失效,无法命中平台的缓存机制。我的做法是system prompt一旦稳定就基本不动,改动集中在一个常量配置里,只改这一层,尽量保住能复用的前缀部分。
第三个细节是“token统计不能只算一次调用”。一个业务功能往往要调用多次模型接口才能完成,比如先摘要、再抽取、最后生成。很多人只看单次请求的token,没把整套流程的token加总。我加了一个统计埋点,每次业务操作结束就打印一次总消耗,这样能直接看出哪个环节是成本大头,再针对性地优化。
6.3 排查token消耗异常的标准路径
如果你发现自己的账单异常,别急着改代码,先按这条路径排查:
第一步,把调用日志捞出来,按产品功能维度分组,统计每组的输入token和输出token总和。第二步,找出占比最高的前三个功能,分别看它们的平均单次请求token。第三步,对异常偏高的功能,打印完整prompt,目测哪部分最臃肿。多数时候一眼就能看出问题,比如系统提示占了2000字、历史记录有十几轮、知识库全文堆在中间。
如果目测看不出问题,就做减法验证:把可疑部分从prompt里去掉,用相同测试集跑一遍,对比token和输出质量。几次减法做下来,消耗异常见鬼的地方基本就水落石出了。
6.4 我个人的体会
踩过几轮坑之后,我最大的感受就是,token优化不是一次性的事,而是一套需要持续盯着的成本管理体系。模型服务商的计费规则、模型的输出习惯、业务的数据分布都在变,今天调好的参数,过两个月可能就又不合适了。所以养成良好的埋点和统计习惯,比抄一套参数更值钱。每隔一段时间,翻一翻调用日志,看看有没有新的token浪费点,这比看什么成本优化文章都管用。
最后再分享一个小技巧:给每一项“省下来的token”配上估算金额去登记,从数据里你会发现,真正值得折腾的永远是那两三个大头功能,其他边角省得再多,对总成本的影响也有限。把注意力放在大头,这套优化就够了。