假设你开了一家小面馆。后厨的水龙头哗哗流水,洗碗池里泡着上周的旧碗,洗菜水直接倒掉,营业执照你还每天背给客人听一遍。月底水费单出来,你傻眼了——每一滴水都是钱。你的 AI 应用也是这家面馆:用户每问一句话,程序都要把整段聊天记录、固定说明、各种客套话全部发给大模型,按字数计费。这个“字数”,业内叫 token。token 就是水,账单就是 API 费用。 这篇手记带你重新装修“后厨”:看懂水费单(计费原理)、关小水龙头(精简提示词)、倒掉洗碗水(裁剪历史)、循环用水(缓存复用)、改造管路(指令外置)、把账本写成摘要(历史压缩)。六招下来,同样的服务,水费能省一半以上。
对 LLM 应用开发者而言,掌握 Token 优化意味着用同样的预算服务更多用户、支撑更长对话,是 API 成本管理的基本功。
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
Token 计费原理
拿到水费单,先看两栏:用了多少吨水、每吨多少钱。你的 API 账单长得一模一样——“输入 token 数 × 输入单价 + 输出 token 数 × 输出单价”。把模型想象成一座水流湍急的厨房:你传给它多少文本,它就要读多少字;它回复你多少字,这些“熟食”同样按量收费。所以在省钱之前,先学会读账单。
token 是模型处理文本的基本单位,你可以把它理解为“字块”:英文一个单词拆成 1 到 2 个 token,中文一个汉字大约折合 1 到 2 个 token。模型按 token 收费,就像自来水公司按吨收费。不同模型价格不同,如同不同城市水价不同;输出通常比输入贵,如同加工过的熟食比生食材贵。
一次请求的成本由三要素决定:调用次数、输入 token 量、输出 token 量。多轮对话之所以烧钱,是因为每轮都把历史全部重发一遍,输入量随轮数线性膨胀——这是账单里最大的水龙头。
看懂账单后你会发现:输出单价贵但难压缩,真正可控的是输入 token 量。于是后面三个方向浮出水面——减少输入量(精简、裁剪)、降低单价(缓存)、把固定内容放对位置(System 外置)。
- 调用次数 $N$应用每发起一次模型请求就算一次调用,所有用户在一个周期内触发请求的总次数累加为 N。
- 输入 Token 量 $T_{in}$每次请求发送给模型的全部文本,包括系统指令、历史对话和用户当前消息,分词后得到的小块总数。
- 单价 $P_{in}$ 与 $P_{out}$服务商对每千 token 收取的价格,输入和输出往往不是同一档价位。
- 总成本 $C$把单次请求的输入费用与输出费用相加,再乘以调用次数,就得到一个周期的总支出。
Prompt 精简
你给顾客端面,半碗汤半碗面,顾客嫌水多。很多 prompt 也这样:客套话、重复强调、空泛形容词占了大半。比如“请用非常友好并且耐心的语气帮我解释一下这串错误信息”——“非常友好”“耐心”说了两遍“请好好说话”,删掉之后意思完全不变。这不是功能问题,是“注水”问题。
精简 prompt 不是删功能,是删除“说了等于没说”的部分。指令要具体:告诉模型“提取订单号、金额、时间”比“给我要点”高效得多。示例只挑最必要的一两个,别贴整篇样例。每删一段废话,输入 token 就少一段;每加一个必须保留的业务约束,模型就少犯一个错。
<!—— 注意:这段按约 120 字调整 ——>
精简的效果可以用新旧 token 的比值衡量。假设原始 prompt 占 $T_{old}$ 个 token,精简后是 $T_{new}$,两者的差占总量的比例就是精简率。
面条分量不变,汤少一半,既省钱又落胃。精简后的 prompt 输入更小、模型读得更快,省下的不只是钱,还有响应时间。
- 原始 Token 数 $T_{old}$精简前整个 prompt 占用的 token 量,是省钱的基准线。
- 精简后 Token 数 $T_{new}$删除冗余、保留必要语义之后的新 prompt token 量。
- 精简率 $S$新旧 token 的比值越接近 1,说明省得越多;接近 0 则几乎没省。
上下文裁剪
后厨水池泡着上周的碗,你做饭前还得先换水。许多多轮对话应用就是这样:每次请求都把从第一天开始的全部聊天记录发给模型,聊到第 20 轮时,前 19 轮的“泡水碗”全在账单里躺着。
滑动窗口方案很简单:只保留最近 $w$ 轮消息,窗口外的旧消息不再发送给模型。注意,裁剪发生在“发送给模型”这一步,本地数据库仍然存着全部历史——用户回看没问题,模型只是“看不见”旧消息。这是最容易上手、收益最直接的优化之一。
代价同样明显:被裁掉的消息可能含有订单号、用户偏好等关键信息。所以实践中通常搭配关键信息摘取或摘要压缩(见后文“历史压缩”),让裁剪后的内容仍然有“记忆”。
水池永远只泡今天要洗的碗,水费立刻降下来。但明天要用的大料,记得先抄在小本本上——这正是下一节要讲的“缓存”和最后的“摘要”要给旧水找的新出路。
- 总轮数 $r$从对话开始到现在累计的用户与助手往来消息轮数。
- 窗口轮数 $w$滑动窗口决定保留最近多少轮,窗口之外的旧消息不再发送。
- 每轮消息量 $m$平均每轮用户消息和助手回复加起来的 token 数。
- 省下成本 $\Delta C$被裁掉的 $(r - w)$ 轮历史原本会每轮反复计费,裁剪后这些输入费用全部省下。
缓存复用
洗菜水别倒,存起来冲厕所。大模型平台也提供了类似的“循环利用”:prompt caching。如果你这次请求的前缀和上一次一模一样,服务商直接把这段前缀的价格降到一折。对多轮对话、批量任务来说,固定的 system 指令和模板就是那锅反复回用的高汤。
命中条件很简单:前缀完全一致,且缓存未过期。多轮对话每轮都带着相同的 system prompt,批量任务每份文档共用同一套指令模板,这些场景命中率极高;而每次随机拼接、到处加随机数的 prompt 基本无法命中。
缓存不改变“输入都计费”的事实,只是把命中部分的价格降低。对长上下文场景,前缀动辄几千 token,哪怕打一折也能省下可观的成本。
同一锅高汤,几十道菜共用,味道不减,柴火钱大减。而要让高汤更容易被“认出来”,就得把固定内容稳定地放在前缀位置——这就是 System Prompt 外置要做的事。
- 未命中部分 $T_{miss}$请求里与缓存前缀不同的新增文本,只能按原价支付。
- 命中部分 $T_{hit}$与上次请求完全一致的前缀,平台把这段价格降到全价的一折。
- 折扣系数 $0.1$主流平台缓存命中输入价约为原价的 10%,不同产品略有浮动。
- 综合成本 $C_{prompt}$把未命中和命中两部分的费用相加,就是一次请求的输入总花销。
System Prompt 外置
小面馆的营业执照本来就挂在墙上,但有人每次报菜名都先把执照念一遍——这就是把 system prompt(系统固定指令)复制进每一条用户消息的做法。指令一遍遍重复,token 一遍遍计费。
正确的做法:把固定指令放进独立的 system 字段,由应用统一管理。好处有三:第一,不用在每轮用户输入里手工拼接,省去重复劳动;第二,指令格式统一,不容易被用户消息搅乱;第三,固定前缀稳定不变,正好让上一节讲的缓存容易命中。
需要澄清的是:外置不等于免费。多数平台的 system 字段仍然计入输入 token。它的真正价值是把“不规则的开销”变成“规则的可复用前缀”——水管工改造管路,不是为了不喝水,而是为了让水流更可控、可循环。
管路改造完成,固定背景挂在墙上,每月省下的是重复念执照的口水,以及让高汤更容易被打折。接下来最后一招,对付的是已经泡在水里的旧账本。
- 请求轮数 $n$应用累计发出的 API 请求次数,轮数越多,重复拼接的浪费越大。
- 固定指令规模 $T_{sys}$system prompt 文本折算出的 token 数,原来靠手工拼进每一条 user 消息。
- 输入单价 $P_{in}$每个 token 的输入价格,乘以重复次数就是流失的水费。
- 省下成本 $\Delta C$外置后每轮少一次重复拼接对应的开销,同时固定前缀让缓存命中率更高。
历史对话压缩
店主的小本本记了三个月流水账,找一条信息要翻半小时。于是每周写一行周记:“本周大扫除,耗水两吨,客人三十位。”省纸又省眼。历史对话压缩正是如此:用 LLM 把旧对话总结成摘要,让摘要代替原文进入请求。
具体做法:设定压缩阈值,比如超过 6 轮后,把最旧的一部分交给 LLM 生成一段摘要,保留关键信息——订单号、用户偏好、临时约定——丢弃无关细节。这份摘要后续每轮携带,替代原来的几十上百条消息。必要时还可以多级压缩:先压成一轮摘要,再在摘要之上做更高层总结。
成本和收益要一起算。摘要本身有一次性生成费用,但通常远小于原文在后续每轮重复发送的累计费用。只有净节省为正,压缩才值得做。
账本越记越薄,但每一条“待办、偏好、承诺”都浓缩在摘要里。信息还在,只是更轻了。六招全部到位,你的小面馆水费单,该换一张笑脸了。
- 原文 Token 量 $T_{old}$被压缩的早期对话原始 token 总量,是账单上的最大负担。
- 摘要 Token 量 $T_{sum}$LLM 生成的摘要所占 token 数,远小于原文。
- 生成成本 $C_{gen}$调用一次 LLM 做摘要所支付的费用,包括输入原文和输出摘要两部分。
- 净节省 $\Delta C$每轮携带摘要替代原文省下的输入费用,减去一次性生成摘要的开销。
AI 应用场景
电商售后客服机器人
阶段:应用部署与运营优化
解决的问题:客服机器人多轮对话时,每轮都把完整历史发给模型,用户聊到 20 轮时单次输入 token 高达几千,成本随对话长度失控。通过 System Prompt 外置 + 滑动窗口 + 历史摘要压缩,单轮输入成本可降 60% 以上。
具体案例:某电商售后机器人日均 1 万会话、平均 15 轮。优化前日均消耗约 8000 万 token,优化后降至约 2600 万 token,月度 API 费用下降近 70%,平均响应时间从 3.2 秒降到 1.8 秒——预算省了,体验反而好了。
批量文档处理管线
阶段:数据准备与批处理
解决的问题:数百份文档做摘要或信息抽取时,公共指令和模板前缀每次都重复计费。利用 prompt caching 让相同前缀命中,批量任务的输入成本大幅压缩;再配合模板精简,双重省钱。
具体案例:法律合同审查工具每天处理 5000 份合同,固定审查规则约 800 token 放在前缀位置,缓存命中率 90% 以上,输入成本理论上只剩“新增部分全价 + 命中部分一折”,整体成本下降约七成。
多租户 SaaS 助手
阶段:架构设计与成本预算
解决的问题:多租户共享同一套 system 指令和工具定义,如果每个租户各写各的,前缀千奇百怪,缓存完全失效。把公共背景统一放到 system 字段并固定顺序,所有租户共用同一条缓存前缀。
具体案例:一个面向中小商家的经营助手平台,统一指令模板后,缓存命中率稳定在 85%,加上历史压缩,月度账单比之前降了一半,支撑了更多免费试用用户。
Python 演示
"""对话Token成本模拟器: 对比原始方案与优化方案的累计消耗""" SYSTEM = "你是客服助手, 回答简洁, 态度友好." def tokens(text): """极简估算: 汉字一字约1 token, 英文按词数估算""" cn = sum(1 for ch in text if '\u4e00' <= ch <= '\u9fff') en = len(text.split()) return cn + int(en * 1.3) def user_msg(i): return "用户: 我的订单什么时候发货?" def reply_msg(i): return "客服: 您的订单已在运输中, 请耐心等待." def main(): rounds = 10 orig_cost = 0 opt_cost = 0 summary = "" for i in range(1, rounds + 1): cur_user = user_msg(i) cur_reply = reply_msg(i) # 原始方案: system + 全部历史 + 当前消息 + 回复 history = "".join(user_msg(j) for j in range(1, i)) orig_cost += tokens(SYSTEM + history + cur_user + cur_reply) # 优化方案: system前缀缓存打1折 + 摘要替代历史 if summary: prompt = SYSTEM + summary + cur_user else: prompt = SYSTEM + cur_user cache_part = tokens(SYSTEM) * 0.1 opt_cost += tokens(prompt) - tokens(SYSTEM) + cache_part opt_cost += tokens(cur_reply) # 每5轮生成一份对话摘要 if i % 5 == 0: summary = "(前%d轮摘要: 用户询问订单, 客服统一回复运输中.)" % i opt_cost += tokens(summary) print("原始方案累计消耗: %d token" % orig_cost) print("优化方案累计消耗: %d token" % round(opt_cost)) print("节省比例: %.1f%%" % ((1 - opt_cost / orig_cost) * 100)) if __name__ == "__main__": main()
cn = sum(1 for ch in text if '\u4e00' <= ch <= '\u9fff')用 Unicode 范围数出汉字个数,作为 token 估算基础。history = "".join(user_msg(j) for j in range(1, i))原始方案把之前所有轮次的消息拼成一条长文本。orig_cost += tokens(SYSTEM + history + cur_user + cur_reply)每轮都带着全部历史计费,越往后越贵。if summary:有摘要时用摘要替代全部历史,prompt 体积骤减。prompt = SYSTEM + summary + cur_user优化后请求只包含固定指令、摘要和当前问题。cache_part = tokens(SYSTEM) * 0.1system 命中了前缀缓存,只按一折计费。opt_cost += tokens(prompt) - tokens(SYSTEM) + cache_part先把 system 全价扣除,再补上折扣价。if i % 5 == 0:每 5 轮触发一次历史压缩,生成一份摘要并计入成本。summary = "(前%d轮摘要..." % i一份极简摘要取代几十轮原文,是压缩的核心动作。
常见误区
误区Token 是钱,那就把 prompt 删到极致,字越少越省钱,反正模型很聪明能猜。
正解过度精简会丢失必要背景,模型可能频繁反问“这个字段怎么处理”“请提供具体规则”,反而额外消耗输出 token。精简的目标不是最短,而是在语义完整的前提下删除冗余。比如把“请用友好语气解释一下这个错误,我看不懂”压成“解释此错误”,若上下文里没有错误信息,模型就得瞎猜。
为何常见:大家把“token=钱”理解成“必须极限压缩”,忽略了模型对指令质量的真实依赖。
误区所有请求都开启 prompt caching,成本自动打一折,闭眼省钱。
正解缓存要求请求前缀与之前完全一致且未过期。如果 system 频繁改动,或每轮 prompt 都随机拼接,就命中不了;一次性的独立请求更是毫无缓存意义。缓存是否划算,要看重复率,而不是看开关。
为何常见:把“前缀复用折扣”误当成“全局折扣”,忽略了缓存命中的前提条件。
误区滑动窗口就是把旧历史删掉,反正用户看不到,丢了也不影响功能。
正解旧历史里常有订单号、用户偏好、临时约定,直接删掉会丢关键信息。稳妥做法是先做关键信息抽取或摘要压缩,再裁剪;对压缩结果不放心时,可以只压缩更久以前的段落。
为何常见:直觉上“删掉就是省”,忽略了对话信息的可用性是产品底线。
误区把 system prompt 放到独立字段,平台就不收这笔 token 费了,等于白赚。
正解绝大多数平台的 system 字段仍然按输入 token 计费。外置真正的价值是避免把固定指令手工复制进每条消息,保证前缀稳定,从而让缓存命中率更高。它是“省重复工作 + 利于缓存”,不是“免费”。
为何常见:把“字段独立”误解为“费用独立”,忽略了计费模型的基本规则。
误区反正公司掏钱,省 token 是财务的事,和技术没关系,也不影响用户体验。
正解输入变短意味着请求 payload 变小、排队时间变短,响应更快;缓存命中还能降低首 token 延迟。省 token 常常和提升体验是一回事,而不是对立关系。
为何常见:只看账单数字,忽略了 token 量对延迟、稳定性和并发能力的直接影响。
面试题
Q1. Token 计费的基础模型是?
- A.只按输出字数计费
- B.输入和输出都计费← 正确答案
- C.只按请求次数计费
- D.只按历史轮数计费
答案:B。LLM 按 token 计价,输入和输出都会被收费,只是单价不同。选项 A、C、D 都只描述了单一维度,忽略了输入侧和输出侧的并行计费,故选 B。
Q2. 一个汉字大约相当于多少 token?
- A.一个汉字一个 token
- B.十到二十个 token
- C.一到两个 token← 正确答案
- D.零点一个 token
答案:C。token 是文本碎片,英文按词拆、中文按字拆,一个汉字通常折合 1 到 2 个 token。选项 C 最接近真实估值,其余选项要么低估要么高估。
Q3. Prompt 精简的核心原则是?
- A.删除所有形容词状语
- B.尽量改成最短英文
- C.保留语义删除冗余← 正确答案
- D.增加更多示例说明
答案:C。精简是为了让模型准确理解,而不是凑字数。C 同时兼顾成本和效果;A 会误删必要限定,B 英文不一定更短,D 增加示例反而更贵。
Q4. 滑动窗口裁剪时旧消息怎么处理最稳妥?
- A.直接删除完全不管
- B.用摘要保留关键信息← 正确答案
- C.随机保留其中几条
- D.只在回复中简单提及
答案:B。直接删会丢失订单号、偏好等关键上下文;随机保留缺乏保障;“提一句”并没有把信息放进输入。用摘要保留关键信息,既省钱又不丢重点。
Q5. Prompt 缓存命中后输入价格一般是?
- A.原价的五折水平
- B.原价的一折水平← 正确答案
- C.原价的九折水平
- D.完全免费不收费
答案:B。主流平台 prompt caching 命中后,输入 token 价格约为原价的 10%,即一折。它不是零成本,也远高于五折九折,选 B 最贴近事实。
Q6. 关于 System Prompt 外置,正确的是?
- A.外置后指令不再计入输入费用
- B.外置后模型效果不会下降
- C.外置后便于统一管理并利于缓存← 正确答案
- D.外置后请求响应速度必然变慢
答案:C。外置的真正价值是统一管理和让前缀稳定以命中缓存,C 正确。A 是常见误解,多数平台 system 仍计费;B、D 与事实不符,外置本身不影响效果和速度。
Q7. 历史对话压缩的主要代价是?
- A.增加更多输出内容
- B.丢失部分细粒度信息← 正确答案
- C.让模型完全无法使用
- D.请求响应一定变慢
答案:B。摘要替代原文一定会丢掉某些细节,比如具体时间、数字、措辞,所以关键信息要额外保留。它不是完全不可用,也不会必然变慢,故选 B。
Q8. 下面哪些属于 Token 优化手段?
- A.Prompt 精简与压缩← 正确答案
- B.上下文滑动窗口← 正确答案
- C.缓存复用前缀← 正确答案
- D.加大模型输出长度
答案:ABC。A、B、C 分别对应输入精简、裁剪和缓存复用,都是正文讲过的省钱手段。D 增加输出只会让账单更贵,属于反向操作。
Q9. 缓存复用生效需要满足哪两个条件?
- A.请求前缀与此前完全一致← 正确答案
- B.缓存内容尚未过期← 正确答案
- C.请求必须来自同一位用户
- D.每次都修改 System 指令
答案:AB。缓存命中要求前缀一致且未过期,A、B 正确。C 不对,不同用户共享相同前缀也能命中;D 会破坏前缀稳定性,反而导致缓存失效。
Q10. 哪些场景更适合用缓存复用?
- A.多轮对话固定 System← 正确答案
- B.一次性独立小请求
- C.批量任务共享相同模板前缀← 正确答案
- D.每轮 prompt 完全不同
答案:AC。A 和 C 都具备高重复前缀,缓存命中率高。B 请求只有一次,没有可复用的历史;D 前缀每次都变,缓存形同虚设。