1. 调用大模型时Token到底花在了哪里很多人第一次认真看大模型账单的时候都会愣一下明明感觉没问几个问题怎么费用就上去了。我刚开始接大模型接口那会儿也一样总觉得“按量计费”应该很便宜结果一个月下来光是调试阶段的消耗就够呛。后来我把每一次调用的请求和响应都打出来逐条分析才发现问题根本不在“问了多少次”而在于每次请求里塞了多少没必要的东西。先把概念说清楚。Token不是“字数”它是模型处理文本的最小单位。英文里一个常见单词大约是1个Token中文里一个字可能是1到2个Token具体取决于分词方式。你发给模型的每一段文字——包括系统提示词、历史对话、用户当前问题、甚至你贴进去的一整篇文档——都会被切成Token计费。模型返回的每一个字同样计费。所以一次调用的总消耗等于输入Token加输出Token而输入部分往往是隐藏的大头。我做过一个很典型的测试同一个问题一次只发问题本身另一次带上完整的系统提示词、三轮历史对话和一段背景资料。结果后者的输入Token是前者的十几倍。问题本身没变答案质量也没明显提升多出来的钱全花在了“模型其实不需要看”的内容上。这就是绝大多数人Token浪费的根源——不是模型贵是我们喂给它的东西太杂。那Token具体浪费在哪些地方我把它归成几类你可以对照自己的调用日志看看。第一类是冗余的系统提示词。很多模板一上来就是几百字的角色设定、格式要求、注意事项每次调用都原封不动带上。如果这些内容对当前任务没有实质帮助那就是纯浪费。第二类是无节制的历史对话。多轮对话里很多人习惯把前面所有轮次都带上觉得这样模型“记得住”。但对话越长每轮新增的输入就越多而且是累加式的。聊到第十轮前面九轮的内容还在反复计费。第三类是过量的上下文资料。做检索增强或者文档问答时把整篇文档塞进去但模型真正需要的可能只是其中一两段。剩下的全是陪跑。第四类是输出不受控。没有限制输出长度模型洋洋洒洒写一大篇里面一半是客套话和重复表述。第五类是重复调用。同一个问题因为没做缓存换个说法又问一遍或者多个功能模块各自独立调用互不复用结果。把这五类看清楚节约Token的方向就明确了减少输入冗余、控制输出长度、复用已有结果。下面我按这个思路把每一块的具体做法拆开讲。2. 输入侧的Token压缩把每一分钱花在刀刃上输入Token是大多数人浪费最严重的地方也是最容易优化的地方。因为输入是你完全可控的——你决定发什么模型就处理什么。我自己的经验是光是把输入侧理顺整体消耗就能降一半以上。2.1 系统提示词的瘦身与动态化系统提示词是最容易被忽视的浪费源。我见过不少项目系统提示词写了五六百字里面包含角色设定、语气要求、输出格式、边界说明、示例等等每次调用都全量带上。问题是很多内容对当前这一次具体任务根本用不上。我的做法是把系统提示词拆成“固定核心”和“动态附加”两部分。固定核心只保留最必要的角色定位和基本约束控制在几十个Token以内。动态附加部分根据当前任务类型按需拼接——比如这次是摘要任务就只加摘要相关的格式要求下次是分类任务就换成分类的约束。这样每次实际发送的提示词都是精简过的。举个具体的对比。原来一个通用的系统提示词可能是这样你是一个专业的助手需要以严谨、客观、专业的态度回答用户问题。 回答时要条理清晰分点说明避免口语化表达。 如果涉及不确定的信息要明确说明不确定性。 输出格式要求先给结论再给理由最后给建议。 注意保持礼貌不要使用攻击性语言。这段话大概一百多个Token但其中“保持礼貌”“不要攻击性语言”这类约束在绝大多数正常业务场景里根本不会触发属于防御性冗余。精简后可以变成专业助手。输出结论-理由-建议分点。意思没丢Token降到原来的零头。当然具体精简到什么程度要看你的业务容错率但核心原则是只保留对当前任务有实际约束力的内容。注意精简系统提示词不是让你删掉所有约束而是把“每次都需要的”和“偶尔才需要的”分开。前者常驻后者按需加载。2.2 历史对话的裁剪策略多轮对话是Token消耗的隐形杀手。因为它是累加的——第一轮只有一问一答第十轮就带着前面九轮的全部内容。如果不做处理对话越长单轮成本越高而且是加速上升。我试过几种裁剪策略各有适用场景。滑动窗口是最简单的只保留最近N轮对话更早的直接丢掉。N一般取3到5。优点是实现简单缺点是如果用户很早之前提到过一个关键信息后面可能就丢了。摘要压缩更聪明一些把较早的对话用模型总结成一段简短摘要替代原始对话。比如前面八轮聊了很多细节压缩成两三句话保留核心信息。这样既省Token又不容易丢关键上下文。缺点是摘要本身也要消耗一次调用适合对话轮次较多、信息密度较高的场景。关键信息抽取是我用得最多的不保留对话原文而是从历史中抽取结构化信息。比如用户提到了预算、时间、地点就存成字段后续需要时直接拼进去。这样Token占用极小但要求你对业务字段有清晰定义。实际操作中我通常把这三者结合最近两三轮保留原文更早的做摘要再早的只留结构化关键信息。这样既保证连贯性又控制住成本。2.3 上下文资料的精准投喂做文档问答或者知识库检索的时候最容易犯的错就是“把找到的都塞进去”。检索系统返回了五段相关内容就五段全发给模型。但模型真正需要的可能只有其中一段。我的做法是在检索和生成之间加一层筛选。检索阶段多召回一些没关系但在送给模型之前用轻量规则或小模型做一次相关性排序只保留最相关的一到两段。这一步看起来多了一次处理但省下的输入Token远超这点开销。另一个技巧是对长文档做预处理。如果一篇文档要反复被查询不要每次查询都重新切分和投喂。提前把文档切成语义完整的段落建立索引查询时只取命中的段落。这样每次发送的都是精准片段而不是整篇文档。还有一个容易被忽略的点去掉资料里的格式噪音。从网页或PDF提取的文本往往带着大量换行、空格、页眉页脚、导航文字。这些内容对模型理解没有帮助但全部计费。我习惯在投喂前做一次清洗把连续空行合并、去掉明显无关的标记通常能再省一成左右的Token。2.4 输入格式的微调技巧除了内容本身输入的组织方式也影响Token数量。几个实测有效的细节用简洁的分隔符而不是大段说明文字来区分内容块。比如用###分隔不同部分比写“以下是第一部分内容请仔细阅读”要省得多。避免在输入里重复用户已经说过的话。有些模板会把用户问题复述一遍再问纯属浪费。数字和代码尽量用紧凑格式。比如列表用短横线而不是“第一点、第二点”这样的文字描述。这些细节单看省得不多但调用量大起来之后累积效果很明显。3. 输出侧的Token控制让模型少说废话输入省的是“你发出去的钱”输出省的是“模型回给你的钱”。输出Token通常比输入贵所以控制输出同样重要甚至更划算。3.1 明确输出长度上限最直接的办法就是设置max_tokens参数。很多人不设这个参数或者设得很大结果模型有时候会“刹不住车”写出一大段你根本不需要的内容。我的习惯是根据任务类型设一个合理的上限。比如分类任务输出就是一个标签设50足够了摘要任务设200到300需要详细解释的设500到800。设上限不是硬截断而是给模型一个信号别写太长。注意max_tokens设得太小会导致回答被截断影响可用性。建议先观察正常回答的长度分布取一个略高于平均值的数。3.2 用提示词约束输出风格除了硬性上限更优雅的方式是在提示词里明确输出要求。比如用一句话回答不超过30字。或者只输出JSON不要任何解释文字。这类约束能有效减少模型的“客套话”。模型默认倾向于写得完整、礼貌、面面俱到但这些对你未必有用。明确告诉它“要什么、不要什么”输出会精简很多。我常用的几个约束模板只要结果不要过程“直接给答案不要解释”限定格式“输出为逗号分隔的关键词”限定长度“三句话以内”禁止重复“不要复述问题”3.3 结构化输出的省Token写法如果你需要模型返回结构化数据用JSON通常比自然语言更省Token。因为JSON没有多余的连接词和修饰语。但JSON本身也有写法差异。比如{ result: positive, confidence: 0.95 }比下面这种要省{ 分析结果: 这条评论的情感倾向是正面的, 置信程度: 我非常有信心置信度为百分之九十五 }字段名用简短的英文值用最紧凑的表达能省不少。当然前提是你的下游系统能正确解析。3.4 避免让模型做“复读机”有些提示词设计会让模型先把输入复述一遍再回答比如“请阅读以下内容并总结……”。如果输入很长模型复述一遍就是双倍消耗。更好的做法是直接给指令“总结以下内容”然后紧跟内容。模型不需要复述也能理解任务。同理在多轮对话里不要让模型重复之前已经说过的内容。可以在提示词里加一句“不要重复之前的内容”。4. 缓存与复用同样的钱不花第二次前面两节讲的是“单次调用怎么省”这一节讲的是“怎么少调用几次”。很多时候Token浪费不是因为单次用得多而是因为同样的活儿干了好几遍。4.1 结果缓存的几种粒度最粗粒度的缓存是完全相同的请求直接返回缓存结果。比如用户问了同一个问题两次第二次没必要再调模型。实现上可以用请求内容的哈希做键存一份结果。细一点的是语义缓存不是完全一样的问题但意思相近也可以复用。比如“怎么退款”和“退款流程是什么”语义上是一回事。这需要用一个轻量模型或向量相似度来判断但省下的调用次数很可观。更细的是子结果缓存把一次复杂调用拆成几步每一步的结果都缓存。比如先分类再回答分类结果可以缓存下次同样类别的输入直接走对应分支。我用得最多的是第一种和第三种。第一种实现简单、命中率也不低第三种适合流程固定的业务场景。4.2 批量处理合并调用如果你有多个独立的小任务要处理不要一个一个调合并成一次调用。比如你要给十条评论分别打标签与其调十次不如一次发十条让模型返回十个结果。这样做的好处不只是省Token还省了十次网络往返的时间。当然前提是这些任务之间没有依赖关系且合并后的输入不超过模型的上下文限制。合并的时候注意格式要清晰让模型能区分每一条。我通常用编号或者分隔符隔开并在提示词里说明“对每一条分别处理按相同顺序返回结果”。4.3 预计算与离线处理有些内容是可以提前算好的不需要每次实时调用。比如固定的FAQ回答、常见的分类映射、标准化的文本转换。这些完全可以在离线阶段跑一遍把结果存起来线上直接查表。我做过一个项目把用户最常问的五十个问题提前生成好标准回答线上命中这些问题的直接返回不调模型。光是这一项就砍掉了将近四成的调用量。预计算的关键是识别哪些内容是高频且稳定的。高频保证值得提前做稳定保证预计算的结果不会很快过时。5. 模型选型与参数调优不是所有任务都需要大模型这一节可能是最容易被忽略、但省Token效果最猛的一环。很多人默认所有任务都用同一个模型但实际上不同任务的难度差异很大用大模型处理简单任务就像开卡车送外卖——不是不行是浪费。5.1 按任务难度分层选模型我的做法是把任务分成三档简单任务分类、抽取、格式转换、简单问答。这类任务用小模型完全够用Token单价可能只有大模型的几分之一甚至更低。中等任务需要一定推理的问答、摘要、改写。可以用中等规模的模型。复杂任务多步推理、代码生成、复杂分析。这类才需要上大模型。关键是要先验证小模型能不能满足要求而不是默认上大模型。我通常会拿一批测试样本分别用不同模型跑一遍对比效果和成本。很多时候小模型的效果差距在可接受范围内但成本差了好几倍。5.2 参数调整对Token的影响除了模型选择几个参数也直接影响Token消耗。temperature影响输出的随机性。温度高的时候模型更可能生成多样化的表达有时候会更啰嗦。对于需要稳定、简洁输出的任务把温度调低一些输出会更紧凑。top_p类似控制采样的范围。配合温度一起调能找到效果和成本的平衡点。还有一个容易被忽略的是停止序列。如果你知道输出到某个标记就该结束了设置停止序列可以让模型提前停下不用生成完剩下的内容。5.3 蒸馏与微调长期方案如果你的业务场景固定、调用量大可以考虑用大模型的输出去训练一个小模型。这样线上全部走小模型成本能降一个数量级。具体做法是用大模型生成一批高质量的回答作为训练数据然后微调一个小模型来模仿。这个过程前期有投入但一旦跑通长期收益非常可观。当然这适合调用量足够大、场景足够稳定的情况。如果只是偶尔调用不值得折腾。6. 监控与迭代让节约成为持续动作省Token不是一次性的优化而是一个持续的过程。因为业务在变、模型在更新、用户行为也在变。今天有效的策略过两个月可能就不是最优了。6.1 建立Token消耗的监控第一步是把消耗看清楚。我习惯在每次调用时记录几个关键指标输入Token数、输出Token数、调用的模型、任务类型、耗时。这些数据积累起来就能看出钱花在哪里。有了数据之后做几个维度的分析哪些功能模块消耗最多哪些任务的输入输出比异常有没有明显的重复调用不同时间段的消耗模式是什么这些问题只有看了数据才能回答。凭感觉猜往往会猜错。6.2 设置预算与告警监控之后要有约束。给每个功能模块设一个Token预算超出就告警。这样能及时发现异常消耗避免月底看账单才发现问题。告警的阈值可以根据历史数据来定。比如某个模块平时每天消耗一万Token突然某天到了五万那就值得查一查。6.3 定期回顾与优化我一般每个月做一次回顾看看这个月的消耗结构对比上个月有没有变化有没有新的浪费点出现。常见的优化机会包括新上线的功能有没有做Token优化提示词有没有随着业务变化而变得冗余缓存命中率有没有下降有没有新的小模型可以替代大模型这个过程不需要很复杂花半个小时看看数据往往就能发现一两个可以改进的点。7. 常见问题与实操避坑这一节整理我在实际操作中踩过的坑和常见问题都是文档里不会写、但实际会遇到的东西。7.1 Token估算为什么总是不准很多人会发现自己按字数估算的Token和实际计费对不上。原因有几个中文和英文的Token比例不同不同模型的分词方式也不同。同一个词在不同模型里可能是不同的Token数。标点、空格、换行都算Token而且有时候比文字还占地方。特殊字符和表情符号的Token数往往比普通文字多。所以不要靠字数估算要用模型提供的Token计数工具。大多数API都提供了计数接口调用一下就知道准确数字。7.2 精简提示词后效果变差怎么办精简和效果之间需要平衡。如果精简后发现模型表现下降说明删掉了不该删的内容。我的做法是逐条删减每次只删一项观察效果。这样能精确定位哪些内容是必要的哪些是冗余的。不要一次性大改否则出了问题都不知道是哪里引起的。另外有些内容虽然看起来“没用”但可能对模型的输出风格有隐性影响。比如一句“请认真回答”可能不改变事实准确性但会让模型更谨慎。这类内容要不要保留取决于你的业务要求。7.3 缓存导致结果过时缓存用久了会遇到一个问题底层数据变了但缓存还是旧的。比如知识库更新了但缓存里还是老答案。解决办法是给缓存设置合理的过期时间或者在数据更新时主动清除相关缓存。过期时间的长短取决于数据的更新频率。更新频繁的就设短一点稳定的可以设长一点。7.4 多轮对话中信息丢失裁剪历史对话的时候最容易丢的是用户早期提到的关键约束。比如用户第一轮说了“我要北京的结果”后面几轮都没提裁剪时把第一轮丢了模型就不知道这个约束了。我的做法是把关键约束抽出来单独保存不放在对话历史里而是作为固定信息每次带上。这样既不会丢占的Token也少。7.5 常见问题速查表问题现象可能原因排查方向消耗突然增加某功能调用量上升或输入变长对比各模块Token消耗趋势估算与实际不符分词方式差异或特殊字符多用官方计数工具核对精简后效果下降删除了必要约束逐条回滚定位缓存结果过时过期时间太长或未主动清除检查缓存更新策略多轮对话丢信息裁剪策略太激进检查关键信息是否单独保存7.6 几个我常用的实操技巧把系统提示词里最稳定的部分放在最前面变化的部分放在后面。这样如果将来要用提示词缓存功能命中率会更高。对于格式要求能用示例就不用文字描述。一个简短的输入输出示例往往比一段说明更省Token也更有效。定期清理不再使用的提示词模板和缓存数据避免历史包袱。在开发环境把每次调用的Token数打日志养成看数据的习惯。很多浪费是看了数据才发现的。提示节约Token的核心不是“抠门”而是“精准”。把资源花在真正需要的地方去掉不必要的部分效果和成本可以兼得。8. 一个完整的优化实例前面讲的都是分块的方法这一节我把它们串起来用一个模拟场景走一遍完整流程。假设有一个客服问答系统用户提问系统从知识库检索相关内容然后让模型生成回答。优化前的做法是每次调用带上完整的系统提示词约300 Token、全部历史对话假设5轮约500 Token、检索到的全部5段资料约1500 Token用户当前问题约50 Token。输入合计约2350 Token。输出不限制平均约400 Token。单次总消耗约2750 Token。第一步精简系统提示词。把300 Token压到80 Token只保留角色和输出格式要求。省220 Token。第二步裁剪历史对话。最近两轮保留原文更早的做摘要。500 Token压到150 Token。省350 Token。第三步筛选检索资料。5段里只保留最相关的2段。1500 Token压到600 Token。省900 Token。第四步限制输出。设置max_tokens为200并在提示词里要求简洁回答。输出从400降到180。省220 Token。第五步加缓存。对高频问题做结果缓存假设命中率30%相当于整体再打七折。优化后单次消耗大约是输入8015060050880 Token输出180 Token合计1060 Token。相比原来的2750降了六成多。再算上缓存命中实际平均消耗更低。这个例子里没有用任何复杂技术就是前面讲的那些基本方法组合起来。关键是要系统地看整个调用链路每一环都问一句“这个真的需要吗”。9. 我个人的一些体会做Token优化这段时间最大的感受是大部分浪费不是技术问题是习惯问题。默认带上全部历史、默认用最大的模型、默认不限制输出——这些“默认”才是成本失控的真正原因。另一个体会是优化要有数据支撑。凭感觉觉得“这里应该能省”往往省不了多少还可能影响效果。真正有效的优化都是先看数据找到大头再针对性地处理。还有一点不要为了省而省。如果精简之后效果明显下降那省下来的钱还不够弥补体验损失。优化的目标是在效果可接受的前提下降低成本而不是把成本压到最低。最后分享一个小习惯我每次上线新功能之前都会先跑一批测试样本看看Token消耗的分布。如果发现某类请求的消耗异常高就先查清楚原因再上线。这个习惯帮我避免了好几次“上线后才发现账单爆炸”的情况。