假设你开了一家小面馆。后厨的水龙头哗哗流水,洗碗池里泡着上周的旧碗,洗菜水直接倒掉,营业执照你还每天背给客人听一遍。月底水费单出来,你傻眼了——每一滴水都是钱。你的 AI 应用也是这家面馆:用户每问一句话,程序都要把整段聊天记录、固定说明、各种客套话全部发给大模型,按字数计费。这个“字数”,业内叫 token。token 就是水,账单就是 API 费用。 这篇手记带你重新装修“后厨”:看懂水费单(计费原理)、关小水龙头(精简提示词)、倒掉洗碗水(裁剪历史)、循环用水(缓存复用)、改造管路(指令外置)、把账本写成摘要(历史压缩)。六招下来,同样的服务,水费能省一半以上。

岗位关联

对 LLM 应用开发者而言,掌握 Token 优化意味着用同样的预算服务更多用户、支撑更长对话,是 API 成本管理的基本功。

目录
  1. 可视化演示
  2. Token 计费原理
  3. Prompt 精简
  4. 上下文裁剪
  5. 缓存复用
  6. System Prompt 外置
  7. 历史对话压缩
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

Token 计费原理

拿到水费单,先看两栏:用了多少吨水、每吨多少钱。你的 API 账单长得一模一样——“输入 token 数 × 输入单价 + 输出 token 数 × 输出单价”。把模型想象成一座水流湍急的厨房:你传给它多少文本,它就要读多少字;它回复你多少字,这些“熟食”同样按量收费。所以在省钱之前,先学会读账单。

token 是模型处理文本的基本单位,你可以把它理解为“字块”:英文一个单词拆成 1 到 2 个 token,中文一个汉字大约折合 1 到 2 个 token。模型按 token 收费,就像自来水公司按吨收费。不同模型价格不同,如同不同城市水价不同;输出通常比输入贵,如同加工过的熟食比生食材贵。

一次请求的成本由三要素决定:调用次数、输入 token 量、输出 token 量。多轮对话之所以烧钱,是因为每轮都把历史全部重发一遍,输入量随轮数线性膨胀——这是账单里最大的水龙头。

看懂账单后你会发现:输出单价贵但难压缩,真正可控的是输入 token 量。于是后面三个方向浮出水面——减少输入量(精简、裁剪)、降低单价(缓存)、把固定内容放对位置(System 外置)。

C=N×(Tin×Pin+Tout×Pout)\displaystyle C = N \times (T_{in} \times P_{in} + T_{out} \times P_{out})
总成本 = 调用次数 ×(输入 token 数 × 输入单价 + 输出 token 数 × 输出单价),看懂它才知道钱花在哪。
  1. 调用次数 $N$应用每发起一次模型请求就算一次调用,所有用户在一个周期内触发请求的总次数累加为 N。
    NN
  2. 输入 Token 量 $T_{in}$每次请求发送给模型的全部文本,包括系统指令、历史对话和用户当前消息,分词后得到的小块总数。
    TinT_{in}
  3. 单价 $P_{in}$ 与 $P_{out}$服务商对每千 token 收取的价格,输入和输出往往不是同一档价位。
    Pin,PoutP_{in}, P_{out}
  4. 总成本 $C$把单次请求的输入费用与输出费用相加,再乘以调用次数,就得到一个周期的总支出。
    C=N×(Tin×Pin+Tout×Pout)C = N \times (T_{in} \times P_{in} + T_{out} \times P_{out})

Prompt 精简

你给顾客端面,半碗汤半碗面,顾客嫌水多。很多 prompt 也这样:客套话、重复强调、空泛形容词占了大半。比如“请用非常友好并且耐心的语气帮我解释一下这串错误信息”——“非常友好”“耐心”说了两遍“请好好说话”,删掉之后意思完全不变。这不是功能问题,是“注水”问题。

精简 prompt 不是删功能,是删除“说了等于没说”的部分。指令要具体:告诉模型“提取订单号、金额、时间”比“给我要点”高效得多。示例只挑最必要的一两个,别贴整篇样例。每删一段废话,输入 token 就少一段;每加一个必须保留的业务约束,模型就少犯一个错。

<!—— 注意:这段按约 120 字调整 ——>

精简的效果可以用新旧 token 的比值衡量。假设原始 prompt 占 $T_{old}$ 个 token,精简后是 $T_{new}$,两者的差占总量的比例就是精简率。

面条分量不变,汤少一半,既省钱又落胃。精简后的 prompt 输入更小、模型读得更快,省下的不只是钱,还有响应时间。

S=1−TnewTold\displaystyle S = 1 - \frac{T_{new}}{T_{old}}
精简率 S 越接近 1,说明删得越狠。例如从 500 token 减到 250 token,S = 0.5,即省下 50% 的输入开销。
  1. 原始 Token 数 $T_{old}$精简前整个 prompt 占用的 token 量,是省钱的基准线。
    ToldT_{old}
  2. 精简后 Token 数 $T_{new}$删除冗余、保留必要语义之后的新 prompt token 量。
    TnewT_{new}
  3. 精简率 $S$新旧 token 的比值越接近 1,说明省得越多;接近 0 则几乎没省。
    S=1−TnewToldS = 1 - \frac{T_{new}}{T_{old}}

上下文裁剪

后厨水池泡着上周的碗,你做饭前还得先换水。许多多轮对话应用就是这样:每次请求都把从第一天开始的全部聊天记录发给模型,聊到第 20 轮时,前 19 轮的“泡水碗”全在账单里躺着。

滑动窗口方案很简单:只保留最近 $w$ 轮消息,窗口外的旧消息不再发送给模型。注意,裁剪发生在“发送给模型”这一步,本地数据库仍然存着全部历史——用户回看没问题,模型只是“看不见”旧消息。这是最容易上手、收益最直接的优化之一。

代价同样明显:被裁掉的消息可能含有订单号、用户偏好等关键信息。所以实践中通常搭配关键信息摘取或摘要压缩(见后文“历史压缩”),让裁剪后的内容仍然有“记忆”。

水池永远只泡今天要洗的碗,水费立刻降下来。但明天要用的大料,记得先抄在小本本上——这正是下一节要讲的“缓存”和最后的“摘要”要给旧水找的新出路。

ΔC=(r−w)×m×Pin\displaystyle \Delta C = (r - w) \times m \times P_{in}
省下的钱 =(总轮数 − 保留轮数)× 每轮消息 token 数 × 输入单价。窗口越小,省得越多,但丢失风险也越大。
  1. 总轮数 $r$从对话开始到现在累计的用户与助手往来消息轮数。
    rr
  2. 窗口轮数 $w$滑动窗口决定保留最近多少轮,窗口之外的旧消息不再发送。
    ww
  3. 每轮消息量 $m$平均每轮用户消息和助手回复加起来的 token 数。
    mm
  4. 省下成本 $\Delta C$被裁掉的 $(r - w)$ 轮历史原本会每轮反复计费,裁剪后这些输入费用全部省下。
    ΔC=(r−w)×m×Pin\Delta C = (r - w) \times m \times P_{in}

缓存复用

洗菜水别倒,存起来冲厕所。大模型平台也提供了类似的“循环利用”:prompt caching。如果你这次请求的前缀和上一次一模一样,服务商直接把这段前缀的价格降到一折。对多轮对话、批量任务来说,固定的 system 指令和模板就是那锅反复回用的高汤。

命中条件很简单:前缀完全一致,且缓存未过期。多轮对话每轮都带着相同的 system prompt,批量任务每份文档共用同一套指令模板,这些场景命中率极高;而每次随机拼接、到处加随机数的 prompt 基本无法命中。

缓存不改变“输入都计费”的事实,只是把命中部分的价格降低。对长上下文场景,前缀动辄几千 token,哪怕打一折也能省下可观的成本。

同一锅高汤,几十道菜共用,味道不减,柴火钱大减。而要让高汤更容易被“认出来”,就得把固定内容稳定地放在前缀位置——这就是 System Prompt 外置要做的事。

Cprompt=Tmiss×P+Thit×0.1P\displaystyle C_{prompt} = T_{miss} \times P + T_{hit} \times 0.1P
一次带缓存的请求,输入成本 = 未命中部分按全价 + 命中部分按一折。命中部分占比越高,越划算。
  1. 未命中部分 $T_{miss}$请求里与缓存前缀不同的新增文本,只能按原价支付。
    TmissT_{miss}
  2. 命中部分 $T_{hit}$与上次请求完全一致的前缀,平台把这段价格降到全价的一折。
    ThitT_{hit}
  3. 折扣系数 $0.1$主流平台缓存命中输入价约为原价的 10%,不同产品略有浮动。
    0.1P0.1P
  4. 综合成本 $C_{prompt}$把未命中和命中两部分的费用相加,就是一次请求的输入总花销。
    Cprompt=Tmiss×P+Thit×0.1PC_{prompt} = T_{miss} \times P + T_{hit} \times 0.1P

System Prompt 外置

小面馆的营业执照本来就挂在墙上,但有人每次报菜名都先把执照念一遍——这就是把 system prompt(系统固定指令)复制进每一条用户消息的做法。指令一遍遍重复,token 一遍遍计费。

正确的做法:把固定指令放进独立的 system 字段,由应用统一管理。好处有三:第一,不用在每轮用户输入里手工拼接,省去重复劳动;第二,指令格式统一,不容易被用户消息搅乱;第三,固定前缀稳定不变,正好让上一节讲的缓存容易命中。

需要澄清的是:外置不等于免费。多数平台的 system 字段仍然计入输入 token。它的真正价值是把“不规则的开销”变成“规则的可复用前缀”——水管工改造管路,不是为了不喝水,而是为了让水流更可控、可循环。

管路改造完成,固定背景挂在墙上,每月省下的是重复念执照的口水,以及让高汤更容易被打折。接下来最后一招,对付的是已经泡在水里的旧账本。

ΔC=n×Tsys×Pin\displaystyle \Delta C = n \times T_{sys} \times P_{in}
省下的成本 = 请求次数 × system 指令 token 数 × 输入单价。若原来把 system 内容逐条复制进用户消息,外置后这部分重复拼接的开销就消失了。
  1. 请求轮数 $n$应用累计发出的 API 请求次数,轮数越多,重复拼接的浪费越大。
    nn
  2. 固定指令规模 $T_{sys}$system prompt 文本折算出的 token 数,原来靠手工拼进每一条 user 消息。
    TsysT_{sys}
  3. 输入单价 $P_{in}$每个 token 的输入价格,乘以重复次数就是流失的水费。
    PinP_{in}
  4. 省下成本 $\Delta C$外置后每轮少一次重复拼接对应的开销,同时固定前缀让缓存命中率更高。
    ΔC=n×Tsys×Pin\Delta C = n \times T_{sys} \times P_{in}

历史对话压缩

店主的小本本记了三个月流水账,找一条信息要翻半小时。于是每周写一行周记:“本周大扫除,耗水两吨,客人三十位。”省纸又省眼。历史对话压缩正是如此:用 LLM 把旧对话总结成摘要,让摘要代替原文进入请求。

具体做法:设定压缩阈值,比如超过 6 轮后,把最旧的一部分交给 LLM 生成一段摘要,保留关键信息——订单号、用户偏好、临时约定——丢弃无关细节。这份摘要后续每轮携带,替代原来的几十上百条消息。必要时还可以多级压缩:先压成一轮摘要,再在摘要之上做更高层总结。

成本和收益要一起算。摘要本身有一次性生成费用,但通常远小于原文在后续每轮重复发送的累计费用。只有净节省为正,压缩才值得做。

账本越记越薄,但每一条“待办、偏好、承诺”都浓缩在摘要里。信息还在,只是更轻了。六招全部到位,你的小面馆水费单,该换一张笑脸了。

ΔC=(Told−Tsum)×Pin−Cgen\displaystyle \Delta C = (T_{old} - T_{sum}) \times P_{in} - C_{gen}
净节省 =(原文 token − 摘要 token)× 输入单价 − 生成摘要的成本。原文越大、后续轮次越多,压缩越划算。
  1. 原文 Token 量 $T_{old}$被压缩的早期对话原始 token 总量,是账单上的最大负担。
    ToldT_{old}
  2. 摘要 Token 量 $T_{sum}$LLM 生成的摘要所占 token 数,远小于原文。
    TsumT_{sum}
  3. 生成成本 $C_{gen}$调用一次 LLM 做摘要所支付的费用,包括输入原文和输出摘要两部分。
    CgenC_{gen}
  4. 净节省 $\Delta C$每轮携带摘要替代原文省下的输入费用,减去一次性生成摘要的开销。
    ΔC=(Told−Tsum)×Pin−Cgen\Delta C = (T_{old} - T_{sum}) \times P_{in} - C_{gen}

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 演示

python50 行
"""对话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()
目的:一个小型模拟器,直观对比“每轮全量发历史”和“缓存 + 摘要优化”两条路线的累计 token 消耗。
  1. cn = sum(1 for ch in text if '\u4e00' <= ch <= '\u9fff')用 Unicode 范围数出汉字个数,作为 token 估算基础。
  2. history = "".join(user_msg(j) for j in range(1, i))原始方案把之前所有轮次的消息拼成一条长文本。
  3. orig_cost += tokens(SYSTEM + history + cur_user + cur_reply)每轮都带着全部历史计费,越往后越贵。
  4. if summary:有摘要时用摘要替代全部历史,prompt 体积骤减。
  5. prompt = SYSTEM + summary + cur_user优化后请求只包含固定指令、摘要和当前问题。
  6. cache_part = tokens(SYSTEM) * 0.1system 命中了前缀缓存,只按一折计费。
  7. opt_cost += tokens(prompt) - tokens(SYSTEM) + cache_part先把 system 全价扣除,再补上折扣价。
  8. if i % 5 == 0:每 5 轮触发一次历史压缩,生成一份摘要并计入成本。
  9. summary = "(前%d轮摘要..." % i一份极简摘要取代几十轮原文,是压缩的核心动作。

常见误区

误区Token 是钱,那就把 prompt 删到极致,字越少越省钱,反正模型很聪明能猜。

正解过度精简会丢失必要背景,模型可能频繁反问“这个字段怎么处理”“请提供具体规则”,反而额外消耗输出 token。精简的目标不是最短,而是在语义完整的前提下删除冗余。比如把“请用友好语气解释一下这个错误,我看不懂”压成“解释此错误”,若上下文里没有错误信息,模型就得瞎猜。

为何常见:大家把“token=钱”理解成“必须极限压缩”,忽略了模型对指令质量的真实依赖。

误区所有请求都开启 prompt caching,成本自动打一折,闭眼省钱。

正解缓存要求请求前缀与之前完全一致且未过期。如果 system 频繁改动,或每轮 prompt 都随机拼接,就命中不了;一次性的独立请求更是毫无缓存意义。缓存是否划算,要看重复率,而不是看开关。

为何常见:把“前缀复用折扣”误当成“全局折扣”,忽略了缓存命中的前提条件。

误区滑动窗口就是把旧历史删掉,反正用户看不到,丢了也不影响功能。

正解旧历史里常有订单号、用户偏好、临时约定,直接删掉会丢关键信息。稳妥做法是先做关键信息抽取或摘要压缩,再裁剪;对压缩结果不放心时,可以只压缩更久以前的段落。

为何常见:直觉上“删掉就是省”,忽略了对话信息的可用性是产品底线。

误区把 system prompt 放到独立字段,平台就不收这笔 token 费了,等于白赚。

正解绝大多数平台的 system 字段仍然按输入 token 计费。外置真正的价值是避免把固定指令手工复制进每条消息,保证前缀稳定,从而让缓存命中率更高。它是“省重复工作 + 利于缓存”,不是“免费”。

为何常见:把“字段独立”误解为“费用独立”,忽略了计费模型的基本规则。

误区反正公司掏钱,省 token 是财务的事,和技术没关系,也不影响用户体验。

正解输入变短意味着请求 payload 变小、排队时间变短,响应更快;缓存命中还能降低首 token 延迟。省 token 常常和提升体验是一回事,而不是对立关系。

为何常见:只看账单数字,忽略了 token 量对延迟、稳定性和并发能力的直接影响。

面试题

Q1. Token 计费的基础模型是?

单选题 · easy

  • A.只按输出字数计费
  • B.输入和输出都计费← 正确答案
  • C.只按请求次数计费
  • D.只按历史轮数计费

答案:B。LLM 按 token 计价,输入和输出都会被收费,只是单价不同。选项 A、C、D 都只描述了单一维度,忽略了输入侧和输出侧的并行计费,故选 B。

Q2. 一个汉字大约相当于多少 token?

单选题 · easy

  • A.一个汉字一个 token
  • B.十到二十个 token
  • C.一到两个 token← 正确答案
  • D.零点一个 token

答案:C。token 是文本碎片,英文按词拆、中文按字拆,一个汉字通常折合 1 到 2 个 token。选项 C 最接近真实估值,其余选项要么低估要么高估。

Q3. Prompt 精简的核心原则是?

单选题 · mid

  • A.删除所有形容词状语
  • B.尽量改成最短英文
  • C.保留语义删除冗余← 正确答案
  • D.增加更多示例说明

答案:C。精简是为了让模型准确理解,而不是凑字数。C 同时兼顾成本和效果;A 会误删必要限定,B 英文不一定更短,D 增加示例反而更贵。

Q4. 滑动窗口裁剪时旧消息怎么处理最稳妥?

单选题 · mid

  • A.直接删除完全不管
  • B.用摘要保留关键信息← 正确答案
  • C.随机保留其中几条
  • D.只在回复中简单提及

答案:B。直接删会丢失订单号、偏好等关键上下文;随机保留缺乏保障;“提一句”并没有把信息放进输入。用摘要保留关键信息,既省钱又不丢重点。

Q5. Prompt 缓存命中后输入价格一般是?

单选题 · mid

  • A.原价的五折水平
  • B.原价的一折水平← 正确答案
  • C.原价的九折水平
  • D.完全免费不收费

答案:B。主流平台 prompt caching 命中后,输入 token 价格约为原价的 10%,即一折。它不是零成本,也远高于五折九折,选 B 最贴近事实。

Q6. 关于 System Prompt 外置,正确的是?

单选题 · hard

  • A.外置后指令不再计入输入费用
  • B.外置后模型效果不会下降
  • C.外置后便于统一管理并利于缓存← 正确答案
  • D.外置后请求响应速度必然变慢

答案:C。外置的真正价值是统一管理和让前缀稳定以命中缓存,C 正确。A 是常见误解,多数平台 system 仍计费;B、D 与事实不符,外置本身不影响效果和速度。

Q7. 历史对话压缩的主要代价是?

单选题 · easy

  • A.增加更多输出内容
  • B.丢失部分细粒度信息← 正确答案
  • C.让模型完全无法使用
  • D.请求响应一定变慢

答案:B。摘要替代原文一定会丢掉某些细节,比如具体时间、数字、措辞,所以关键信息要额外保留。它不是完全不可用,也不会必然变慢,故选 B。

Q8. 下面哪些属于 Token 优化手段?

多选题 · mid

  • A.Prompt 精简与压缩← 正确答案
  • B.上下文滑动窗口← 正确答案
  • C.缓存复用前缀← 正确答案
  • D.加大模型输出长度

答案:ABC。A、B、C 分别对应输入精简、裁剪和缓存复用,都是正文讲过的省钱手段。D 增加输出只会让账单更贵,属于反向操作。

Q9. 缓存复用生效需要满足哪两个条件?

多选题 · hard

  • A.请求前缀与此前完全一致← 正确答案
  • B.缓存内容尚未过期← 正确答案
  • C.请求必须来自同一位用户
  • D.每次都修改 System 指令

答案:AB。缓存命中要求前缀一致且未过期,A、B 正确。C 不对,不同用户共享相同前缀也能命中;D 会破坏前缀稳定性,反而导致缓存失效。

Q10. 哪些场景更适合用缓存复用?

多选题 · easy

  • A.多轮对话固定 System← 正确答案
  • B.一次性独立小请求
  • C.批量任务共享相同模板前缀← 正确答案
  • D.每轮 prompt 完全不同

答案:AC。A 和 C 都具备高重复前缀,缓存命中率高。B 请求只有一次,没有可复用的历史;D 前缀每次都变,缓存形同虚设。