在模型能力拼得难分伯仲之后,AI 圈子里正在出现一个新的衡量维度:Token 效率。过去我们习惯用“效果好不好”来评价一个模型,现在更多团队开始追问“达到同样的效果,到底花了多少 Token”。这篇文章会围绕 Token 效率这个新考核方向展开,讲清楚它的概念、计算方式、影响因素,以及在实际项目中如何通过 Prompt 优化、上下文管理和模型选择来提升 Token 使用效率。
1. 背景与核心概念
1.1 为什么 Token 效率会成为 AI 考核的新指标
过去一两年,大语言模型(LLM)的发展重心几乎都放在“能力”上:谁能写更长的代码,谁能做更难的数学推理,谁能在复杂对话中不跑偏。这些指标当然重要,但当主流模型的能力差距逐渐缩小时,另一个问题就浮出水面:大家完成同样一个任务,消耗的 Token 数量可能相差好几倍。
举例来说,同一个“从一段客户反馈中提取投诉类别”的任务:
- 模型 A 可能用 800 Token 完成,输出结果干净利落。
- 模型 B 可能用 1800 Token 完成,中间多绕了几段推理、重复了几次结论。
在单次调用场景下,1000 Token 的差距似乎不大。但如果你的业务每天调用几万次甚至几十万次,这个差距会直接反映在 API 账单上。更关键的是,Token 消耗还直接影响响应速度。Token 越多,模型生成时间越长,用户的等待时间就越长。
所以,Token 效率本质上是一个综合指标,它同时牵动着成本、性能和用户体验。这也是为什么越来越多人开始把它当作评估 AI 应用的重要分母——效果是分子,Token 消耗是分母,分子不变的情况下,分母越小,整体效率越高。
1.2 什么是 Token 和 Token 效率
Token 是大语言模型处理文本时的最小单位。它既不是一个完整的单词,也不是一个字符,而是模型分词器(Tokenizer)切分出来的片段。英文中一个单词通常是一个 Token,但长单词可能被拆成多个;中文里一个汉字可能对应一个或多个 Token,具体取决于分词器的规则。
Token 效率,简单说就是:完成一个任务所需的 Token 数量与任务产出质量之间的比值。
用公式表达就是:
Token 效率 = 任务产出质量 / 消耗 Token 总量不过在实际项目中,这个公式很难精确量化,因为我们很难给“产出质量”打一个绝对分数。所以工程上更常用的评估方式是控制变量对比:固定同一个任务,固定同一个模型,分别用不同的 Prompt 策略或不同的调用方式执行,然后对比 Token 消耗和输出质量。谁用更少的 Token 达到相同或更好的效果,谁的 Token 效率就更高。
1.3 Token 效率与模型能力的区别
这里需要区分一个容易混淆的概念:Token 效率不等于模型能力。
- 模型能力衡量的是模型“能不能做到”,比如能不能正确回答一道数学题。
- Token 效率衡量的是模型“做到这件事花了多少代价”,比如回答这道数学题用了多少个 Token。
一个能力很强的模型可能 Token 效率并不高,因为它习惯把推理过程完整展开,输出很长;而一个能力稍弱的模型反而可能用更短的路径给出正确结果。当然,在实际工程中,我们希望找到能力与效率的平衡点,而不是单纯追求某一项。
从团队管理和产品考核的角度看,Token 效率作为考核指标还有一个好处:它比“回答质量”更容易量化。质量需要人工评估或复杂的自动化评测,而 Token 消耗在每次 API 调用的响应里都有明确数字。这就让 AI 应用的成本控制和性能优化有了可量化的抓手。
2. Token 消耗的构成与计量方式
2.1 一次 API 调用的 Token 构成
要优化 Token 效率,首先得搞清楚一次模型调用中 Token 消耗在哪里。以 OpenAI 兼容接口为例,一次调用的 Token 消耗主要由三部分组成:
- 输入 Token(Input Tokens):包括 System Prompt、用户消息、历史对话、工具定义、参考文档等。
- 输出 Token(Output Tokens):模型生成的回答内容。
- 缓存 Token(Cached Tokens):部分平台支持 Prompt 缓存,命中的 Token 价格更低,但仍会计入消耗。
在多数平台的 Usage 字段中,你能看到类似这样的返回:
{ "usage": { "prompt_tokens": 856, "completion_tokens": 132, "total_tokens": 988 } }prompt_tokens是输入侧消耗。completion_tokens是输出侧消耗。total_tokens是两者之和。
部分平台还会拆出prompt_tokens_details这样的嵌套字段,里面包含cached_tokens,用来告诉你这次调用命中多少缓存。这个字段对成本优化很有参考价值,因为缓存命中的部分通常价格更低、速度更快。
2.2 不同模型和平台的 Token 计算差异
Token 的具体切分规则由每个模型的分词器决定,不同厂商、不同系列模型之间并不完全相同。
以常见的两种模型为例:
- OpenAI 的 GPT 系列使用 tiktoken 库进行分词。一段英文文本中,平均一个英文单词约等于 1.3 个 Token;中文文本平均一个字约等于 0.6 到 2 个 Token,视具体分词结果而定。
- Anthropic 的 Claude 系列使用自己的分词器,规则与 OpenAI 不同。同样一段文本,在 Claude 中消耗的 Token 数和在 GPT 中可能不同。
此外,DeepSeek、Qwen、Llama 等模型也各有各的分词方式。这就意味着,同一个 Prompt 放在不同模型上运行,Token 消耗可能有明显差异。做技术选型时,不能只看模型单价,还要把“同样任务下谁的 Token 消耗更少”纳入考量。
一个实用的做法是:在项目初期,准备一批有代表性的业务文本,分别用候选模型的分词器做 Token 统计,算出平均 Token 消耗。这样就能得到相对客观的对比数据,而不是凭感觉选模型。
2.3 如何实际查看 Token 消耗
在开发调试阶段,最直接的方式是从 API 响应中读取 usage 字段。下面是一个使用 OpenAI Python SDK 的示例:
from openai import OpenAI client = OpenAI( api_key="your-api-key", base_url="your-api-base-url" # 如果使用兼容接口,可配置自定义地址 ) response = client.chat.completions.create( model="your-model-name", messages=[ {"role": "system", "content": "你是一个简洁的 AI 助手,回答尽量简短。"}, {"role": "user", "content": "用一句话解释什么是数据库索引。"} ] ) print(response.choices[0].message.content) print(response.usage)运行后,你会在控制台看到类似这样的输出:
数据库索引是一种用于加快数据检索速度的数据结构,类似于书籍的目录。 CompletionUsage(completion_tokens=34, prompt_tokens=68, total_tokens=102)这里的输出 Token 只有 34 个,输入 Token 68 个,总消耗 102 个 Token。如果发现回答里存在大量冗余内容,就可以通过调整 Prompt 或后处理来降低输出 Token。
3. 影响 Token 效率的关键因素
3.1 系统提示词(System Prompt)的权重
在很多 AI 应用中,System Prompt 是输入 Token 消耗的大头。尤其是当我们把大量角色设定、格式要求、例子、负面约束全部塞进 System Prompt 时,每次调用都会重复消耗这些 Token。
比如下面这个系统提示词:
你是一位经验丰富的客服质检专家,拥有超过 10 年的呼叫中心质检经验。 你擅长识别客服人员的服务态度问题、业务能力问题和合规风险问题。 请在分析时注意以下事项: 1. 不要编造对话中不存在的内容; 2. 不要过度解读客服人员的语气; 3. 如果对话内容不完整,请明确说明; 4. 输出格式必须是 JSON,包含字段:case_type、risk_level、suggestion; 5. ...这段内容可能就有 200 到 300 Token。如果每个请求都携带它,那这部分 Token 就是固定成本。对于低频调用来说影响不大,但当调用量上来之后,这部分固定成本会被放大。
优化思路有几个方向:
- 精简角色设定,去掉不必要的修饰语。
- 把“负面约束”转化为正面指令。
- 把固定不变的提示词移到 System 层,而不是每条用户消息里重复。
- 对可变的业务规则,考虑在调用前用代码拼接,而不是都塞进 Prompt。
3.2 历史对话与上下文窗口的管理
在多轮对话场景中,历史消息会随着轮次增加不断累积。如果每次调用都把完整历史发送给模型,输入 Token 会线性增长。假设每轮用户消息和助手回复平均消耗 200 Token,10 轮之后历史对话就是 2000 Token。如果再夹带工具调用结果或检索到的文档片段,这个数字还会更大。
常见的上下文管理策略有以下几种:
- 滑动窗口:只保留最近 N 轮对话,更早的对话直接丢弃。
- 摘要压缩:每过几轮,用模型对前面的对话生成摘要,后续调用用摘要代替完整历史。
- 关键信息提取:只保留对话中与当前任务相关的实体、结论和待办事项,忽略寒暄内容。
- 消息裁剪:对超长消息进行截断处理,只保留开头和结尾部分。
这些策略需要根据业务场景灵活组合。比如客服机器人适合“摘要 + 最近几轮原文”的方案,而代码生成助手可能更适合保留完整的代码修改历史。
3.3 输出长度与生成参数的影响
输出 Token(completion_tokens)往往比输入 Token 更“值钱”,因为生成是逐 Token 进行的,速度更慢,成本占比也更高。影响输出 Token 数量的因素主要有:
- max_tokens / max_completion_tokens:这个参数直接限制输出上限。如果设置过大,模型可能把回答写得很长;设置过小又会截断答案。
- temperature:温度参数影响随机性。温度较高时,模型可能生成更多探索性内容,导致输出变长;温度较低时,输出更集中、更短。
- top_p:核采样参数,与 temperature 类似,也会间接影响输出长度。
- 模型自身的表达习惯:有些模型倾向于把推理过程完整写出来,有些则更简洁。这和模型训练方式有关,很难通过参数完全改变。
工程上的建议是:先用默认参数跑一批真实请求,观察输出 Token 的分布。如果大部分请求的输出 Token 远低于上限,说明 max_tokens 设置过大;如果频繁触达上限,说明任务本身需要更长的输出空间,需要拆分或优化任务描述。
3.4 Prompt 编写方式的效率差异
同样的任务,Prompt 写得好不好,Token 消耗可能差出好几倍。来看一组对比。
低效版本:
请帮我分析下面这段用户反馈,告诉我这个用户遇到了什么问题,然后根据你的分析结果,给出一些改进建议。注意,你要仔细阅读用户反馈中的每一个细节,不要遗漏任何信息。如果用户提到了多个问题,请全部列出来,并分别给出建议。用户在下面的引号中给出了他的反馈: “我昨天在你们平台下单买了一个手机壳,今天收到货发现颜色发错了,我明明选的是深蓝色,结果寄来的是黑色。而且包装盒也有点破损。我想退货,但是客服一直联系不上,在线客服排队排了 20 分钟都没人理我。非常不满意。”这个提示词为了强调“仔细阅读”“不要遗漏”,加入了大量冗余表达,光是引导语可能就占了 100 多 Token。
高效版本:
分析用户反馈,输出 JSON,字段:issue_list(问题列表)、improvement_suggestions(对应建议)。 用户反馈: “我昨天在你们平台下单买了一个手机壳,今天收到货发现颜色发错了,我明明选的是深蓝色,结果寄来的是黑色。而且包装盒也有点破损。我想退货,但是客服一直联系不上,在线客服排队排了 20 分钟都没人理我。非常不满意。”高效版本直接用指令明确任务、指定输出格式、给出用户反馈,没有多余的话。它消耗的输入 Token 少了,同时因为格式约束明确,输出 Token 也更可控。
这个对比揭示了一个核心原则:Prompt 中的每一个词都在消耗 Token,要确保每个词都有存在的理由。
4. 提升 Token 效率的实战方法
4.1 建立 Token 消耗基线
优化 Token 效率的第一步,不是凭感觉改 Prompt,而是先建立基线数据。建议在项目中增加一个简单的日志模块,记录每次调用的 Token 消耗情况。
下面是一个轻量级的记录方案:
import json import time from datetime import datetime class TokenUsageLogger: def __init__(self, log_file="token_usage.jsonl"): self.log_file = log_file def log_call(self, scenario: str, model: str, prompt_tokens: int, completion_tokens: int, total_tokens: int, latency: float): record = { "timestamp": datetime.now().isoformat(), "scenario": scenario, "model": model, "prompt_tokens": prompt_tokens, "completion_tokens": completion_tokens, "total_tokens": total_tokens, "latency_ms": round(latency * 1000, 2) } with open(self.log_file, "a", encoding="utf-8") as f: f.write(json.dumps(record, ensure_ascii=False) + "\n") logger = TokenUsageLogger() # 在调用模型时记录 start = time.time() response = client.chat.completions.create( model="your-model-name", messages=[...] ) latency = time.time() - start usage = response.usage logger.log_call( scenario="customer_feedback_analysis", model="your-model-name", prompt_tokens=usage.prompt_tokens, completion_tokens=usage.completion_tokens, total_tokens=usage.total_tokens, latency=latency )通过这种方式,你可以按场景统计 Token 消耗,然后针对消耗最高的场景做专项优化。很多团队忽视了这一步,直接凭感觉改 Prompt,结果优化后效果反而变差,却不知道问题出在哪里。
4.2 Prompt 精简四步法
这里给出一个可以直接套用的 Prompt 精简流程,分四步执行。
第一步:去冗余
把 Prompt 中所有的问候语、铺垫句、重复强调删除。例如:
- “请注意听好了”——删除。
- “这是一个非常重要的任务”——删除。
- “请仔细阅读以下内容”——删除。
第二步:改否定为肯定
把“不要输出无关内容”改成“只输出结果”;把“不要编造事实”改成“基于给定材料回答”。否定指令往往会让模型先产生一个“不应该做什么”的表征,然后才转回正向生成,这个过程中可能产生多余 Token,也更容易让模型在边界附近徘徊。
第三步:指定输出格式
利用 JSON、Markdown 列表、表格等结构化格式,约束输出内容。模型只要遵循格式,输出 Token 通常会更紧凑。
请将以下会议纪要整理为 JSON 格式,包含字段: - date:会议日期 - attendees:参与者列表 - decisions:决策事项列表 - action_items:待办事项列表,每项含 owner 和 deadline 会议原文: ...第四步:压缩上下文
将参考文档、历史对话等长内容进行预压缩,只保留与当前任务相关的部分。比如用检索方式只取三个最相关的段落,而不是把整份文档发给模型。
4.3 合理利用 Prompt 缓存
现在不少模型平台支持 Prompt 缓存(Prompt Caching),系统会自动识别重复的输入前缀。如果你的应用有固定的 System Prompt,且前缀部分保持不变,缓存命中后可以显著降低输入成本和延迟。
具体效果不同平台实现不同,但通用的设计建议是:
- 把不变内容放在消息的前面,比如系统提示词、通用指令。
- 把可变内容放在消息的后面,比如用户具体问题、动态数据。
- 不要频繁改动 Prompt 前缀,否则缓存命中率会下降。
以下面的消息结构为例:
System: [固定的角色与任务指令 + 通用工具说明] User: [动态的用户问题 + 具体数据]这样每次调用时,System 部分保持相同,平台有机会命中缓存;User 部分变化不影响前缀缓存。
4.4 在业务层做 Token 效率优化
除了 Prompt 本身的优化,业务层的设计也能大幅影响 Token 消耗。
策略一:任务路由
不是所有请求都需要调用大模型。简单任务可以走规则匹配或小模型,只有复杂任务才调用大模型。举个例子,一个智能客服系统可以先判断用户问题的类型:
- 查订单状态:直接调订单系统接口返回结果,不用模型。
- 查退换货政策:从 FAQ 库中检索固定答案。
- 投诉安抚与复杂问题:调用大模型生成个性化回复。
这种方式减少的不仅是 Token 消耗,还有延迟和故障概率。
策略二:输出后处理
当模型输出过长时,可以在业务代码中做二次裁剪。比如要求模型输出 JSON,但你只需要其中两个字段,那可以在代码中只提取需要的字段,而不是把整个 JSON 都返回给前端。
策略三:错峰与批量
如果业务允许非实时响应,可以把一些任务集中批量处理,避免在高并发时段进行大量模型调用。这在成本控制上也有帮助,因为部分平台对高并发请求没有额外优惠,但合理的流量规划能让计费更平滑。
5. 常见问题与排查思路
5.1 Token 消耗突增
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 单次调用 Token 突增 | Prompt 中拼接了超长文本或完整历史 | 检查 messages 内容,确认是否发送了多余上下文 |
| 总消耗持续上涨 | 对话轮次累积,历史消息未裁剪 | 引入滑动窗口或摘要压缩 |
| 输出 Token 远超预期 | max_tokens 设置过大、模型偏好长输出 | 调低输出上限,使用更明确的格式指令 |
| 相同任务消耗波动大 | Prompt 前缀经常变化,缓存命中率低 | 固定不变内容,把动态内容放在消息尾部 |
排查时可以先按场景维度聚合日志,找出 Token 消耗最高的几个场景,再针对每个场景做细致分析。
5.2 输出质量与 Token 效率的权衡
优化 Token 效率时最常遇到的坑是:为了省 Token,把 Prompt 压缩得过度,结果模型输出质量明显下降。比如把 System Prompt 从 500 Token 压缩到 100 Token,虽然输入成本确实降低了,但模型开始漏掉关键的输出字段,导致下游解析失败,反而增加了重试成本。
这里要区分“有效 Token”和“无效 Token”:
- 有效 Token:承载了任务目标、格式约束、关键信息。
- 无效 Token:重复强调、作用不大的修饰语、冗余的历史记录。
优化的目标是减少无效 Token,而不是把所有 Token 都当成负担。如果删掉某些指令后模型行为出现明显偏差,说明这部分 Token 是有效的,需要保留。
5.3 Token 计数不一致
开发过程中可能遇到这样的情况:本地用分词器统计的 Token 数和平台返回的 usage 不一致。这是因为不同平台可能在 Token 统计时包含了特殊标记、工具定义或其他元信息。解决方式是:以平台返回的 usage 字段为准,本地统计只作为预估参考。
5.4 长文本场景中的截断问题
当输入内容超过模型上下文窗口时,常见的做法是截断,但简单的“从头截断”或“从尾截断”很可能会丢失关键信息。更合理的做法是:
- 按段落切分文档。
- 用检索模型或关键词匹配选出与当前问题最相关的段落。
- 只把选中段落拼进上下文。
这种做法既控制了 Token 消耗,也不至于丢失重要信息。
6. 最佳实践与工程建议
6.1 建立 Token 成本看板
如果你的团队多人都在调用模型 API,建议在日志中心建立 Token 成本看板,按场景、用户、模型维度统计消耗。这样做的好处是:
- 早期发现异常消耗,避免月底账单超标。
- 为模型选型提供数据支撑。
- 让每个同学直观感受到自己改动 Prompt 带来的成本变化。
看板不需要很复杂,简单的表格或折线图就够用,关键是数据要完整、持续在记。
6.2 针对不同任务选用不同模型
没有必要所有任务都用最强的模型。一个合理的分层方案是:
- 简单的分类、抽取任务:使用小参数模型或高吞吐模型。
- 中等难度的总结、改写任务:使用中等规模模型。
- 复杂的推理、长文本生成任务:使用最强模型和更大的上下文配置。
很多平台提供了多个型号的模型,它们在 Token 价格上存在显著差异。结合任务路由策略,可以在不明显降低效果的前提下大幅缩减成本。
6.3 线上变更前先做 A/B 对比
当你准备优化 Prompt 时,不要直接全量上线。先准备 20 到 50 条覆盖典型场景的测试用例,用旧版和新版 Prompt 分别跑一遍,对比:
- 输出质量(人工评估或规则评估)。
- Token 消耗(输入、输出、总消耗)。
- 响应延迟。
只有新版本在质量和效率之间取得更优平衡时,才切到线上。如果难以判断质量好坏,可以优先关注是否影响了核心结果字段的完整率。
6.4 记录和复用高质量 Prompt 模板
团队协作中,Prompt 经常散落在各个代码文件、测试脚本和聊天记录里。建议把经过验证的高效 Prompt 沉淀为模板,统一管理。模板中可以包含占位符,业务侧动态填充内容。这样既能保证 Prompt 质量稳定,也方便后续统一调整和统计。
6.5 关注输出 Token 的下游成本
输出 Token 的消耗不仅体现在 API 计费上,还体现在下游解析、展示和存储成本上。如果一个 AI 应用的输出每次有 2000 Token,但前端只展示其中 200 Token 的内容,那多出的 1800 Token 就是纯浪费。在这种场景下,可以考虑要求模型先输出结构化结果,再由前端决定展示哪些部分。
6.6 定时复盘 Token 使用情况
建议每两周或每月做一次 Token 使用复盘,回答以下问题:
- 哪个场景消耗 Token 最多?是否符合业务价值预期?
- 有没有出现重复调用、无效调用?
- 有没有新的模型版本可以替换当前选型?
- Prompt 缓存的命中率是否在合理范围?
这个节奏能让 Token 效率优化成为一个持续改进的过程,而不是一次性动作。
7. 总结与学习路线
这篇内容围绕 Token 效率展开了几个层面的梳理:先解释了 Token 和 Token 效率的基本概念,讲清楚了它和模型能力的区别;然后分析了 Token 消耗的三个来源,也就是输入、输出和缓存;接着从 System Prompt、历史对话、输出参数和 Prompt 写法四个维度拆解了影响 Token 效率的关键因素;然后给出了建立消耗基线、Prompt 精简四步法、自定义缓存和业务层优化等实战方法;最后补充了常见的异常排查思路和工程侧的最佳实践。
这些方法并不难,真正需要的是在实际项目中养成记录和分析 Token 消耗的习惯。你可以从今天开始,在项目代码里加一行日志,记录每次调用的 usage 字段;也可以挑一个你日常使用频率最高的 Prompt,用本文的“精简四步法”重新改写一遍,对比一下优化前后的 Token 消耗。这些做法的门槛都很低,但累积起来,往往会带来超出预期的成本节省和性能提升。
如果后续想继续深入,可以从这几个方向入手:
- 学习不同模型的分词器原理,理解 Token 切分规则背后的逻辑。
- 研究更复杂的上下文管理方案,比如基于向量检索的动态上下文组装。
- 探索结构化输出和函数调用(Function Calling / Tool Use)如何进一步压缩输出 Token。
- 关注模型平台官方的计费文档和缓存策略说明,确保优化方向与平台规则一致。
Token 效率这个指标,在未来一段时间里会越来越重要。它不仅是成本问题,也是产品体验问题。掌握好这个维度,相当于多了一个优化 AI 应用的抓手,值得每个做 AI 工程的开发者认真对待。