Appearance
05. Token、Tokenizer 与上下文窗口
版本:
v1.2最后更新:
2026-07-09适用对象:准备把 LLM 应用从“会调用模型”推进到“能做成本、延迟、质量与上下文治理”的产品、研发、平台、算法与运维同学
很多 AI 系统的问题,表面上看像是:
- Prompt 写得不够好
- 检索结果不够准
- 模型太贵
- 延迟突然变慢
- 多轮历史越来越失控
但往下深挖,经常会发现根因和下面三个概念直接相关:
- token
- tokenizer
- context window
如果不真正理解它们,你很难稳定优化:
- 成本
- 延迟
- 上下文质量
- 模型路由
- 缓存收益
- 多轮状态治理
所以这一章不是“术语扫盲”,而是很多生产问题的共同底层。
1. 为什么这章在生产里特别重要
在 Demo 阶段,团队常常只关心:
- 模型能不能回答
- 结果看起来像不像对
但一旦进入生产,问题会变成:
- 一次请求到底要花多少钱
- 为什么同一个场景延迟忽高忽低
- 为什么多轮历史越积越贵
- 为什么结构化输出一上工具 schema 就突然爆 token
- 为什么换了模型,明明字数差不多,token 却变化很大
- 为什么明明上下文窗口很大,效果还是不稳定
这些问题的共同底层几乎都绕不开 token 和上下文预算。
一句话理解:
Token 是模型系统里的流量计、成本表和容量约束。
2. 什么是 Token
最实用的理解是:
- token 是模型处理输入和输出时使用的离散计量单位
它通常不是:
- 一个汉字
- 一个英文单词
- 一个字符
更准确地说,文本、代码、JSON、表格、URL、多模态描述内容进入模型前,会先被 tokenizer 切成 token 序列,再交给模型处理。
对工程系统来说,token 最重要的意义不在定义本身,而在于它直接决定:
- 输入成本
- 输出成本
- 上下文容量
- 实际延迟
- 是否会触发截断、裁剪或缓存策略
根据 OpenAI 当前 Token counting 官方文档,精确估算 token 的意义至少包括:
- 在请求发出前预估成本
- 判断是否会打满模型上下文窗口
- 为上下文裁剪和模型路由提供依据
3. 为什么不能按字符、字数或单词数理解 token
这是很多新手最容易犯的第一类错误。
同样长度的两段文本,token 数可能差很多,原因通常包括:
- 常见词会被编码成较少 token
- 罕见词可能被拆成多个子词
- 标点、空格、数字、URL、JSON、代码片段的切分方式不同
- 中英混排和特殊符号会放大差异
- 不同模型使用的 tokenizer 也可能不同
这也是为什么:
- 看起来差不多长的中文和英文,真实 token 成本未必接近
- 一段表格、SQL、JSON、Python 代码通常比自然语言更“烧 token”
- 工具 schema 看着不长,拼到请求里后可能明显增重
工程上真正该记住的是:
肉眼长度不是成本长度,token 长度才是成本长度。
4. 什么是 Tokenizer
Tokenizer 可以理解为:
- 把原始输入转换成模型可处理 token 序列的组件
它决定的不是“文本显示长什么样”,而是模型实际看到什么切分结果。
从 Hugging Face 当前 tokenizer 官方文档视角看,它不是一个边缘组件,而是模型输入预处理的核心部分。这一点很重要,因为它提醒我们:
- 文本送进模型前,已经先经过了一次结构变换
对工程系统来说,这意味着:
- 估算成本时必须关心 tokenizer
- 做 prompt 压缩时必须关心 tokenizer
- 做长上下文治理时必须关心 tokenizer
- 做跨模型迁移时必须重新验证 token 分布
5. 常见分词算法为什么值得知道
大多数团队不需要自己实现 tokenizer,但最好知道常见思路,例如:
- BPE
- WordPiece
- Unigram
知道这些算法的价值不是为了面试,而是为了理解:
- 为什么专有名词、缩写、代码和混合语言文本会被切得更碎
- 为什么同一段文本在不同模型上 token 数可能明显不同
- 为什么“稍微改写一下字符串形态”就可能改变真实成本
如果系统里存在下面内容,这种差异会被进一步放大:
- 大量代码
- 长文档
- 表格
- JSON
- URL
- 中英混排
- 工单号、订单号、设备号等长串标识
6. Tokenizer pipeline 不只是“切词”
很多 tokenizer 并不是“文本进来,直接切 token”这么简单,而是会经历多个阶段,例如:
- 规范化
- 预分词
- 子词切分
- 后处理
这也是为什么:
- 空格、大小写、标点、换行、特殊字符都可能影响结果
- 一样的内容换一种写法,token 数可能就变了
- 结构化文本和自然语言之间的 token 密度常常明显不同
对生产系统而言,这提醒我们:
- 不要把“看起来类似”当成“真实计费类似”
7. 什么是上下文窗口
上下文窗口可以理解为:
- 模型在一次请求中能够处理的总 token 容量
这里的“总容量”不是只算用户输入,而是通常要一起容纳:
- 系统规则
- 用户输入
- 检索证据
- 工具定义
- 历史消息
- 中间状态
- 模型输出
- 某些模型还包括 reasoning 相关 token
所以,上下文窗口不是“用户能输入多少字”,而是:
整条请求-响应回路可用的总预算
8. 上下文窗口里到底都装了什么
很多团队直到线上成本爆了才意识到,请求里真正烧 token 的远不止用户提问。
一个真实请求里常见的 token 消耗项包括:
instructions或系统规则- few-shot 示例
- 用户当前输入
- 历史消息
- 检索片段
- 工具描述和 schema
- 图片 / 文档等多模态输入的编码开销
- 模型输出
- reasoning token 或思考预算
在复杂 Agent 或 RAG 系统里,真正最重的部分常常不是用户一句话,而是:
- 被系统自己拼进去的上下文
这也是为什么很多成本治理最终会回到一句话:
先量系统自己拼了什么,再谈用户说了什么。
9. 为什么上下文窗口不是越大越好
更大的上下文窗口当然有价值,但它不是免费午餐。
9.1 成本误区
上下文窗口越大,不代表每次都会花满,但它很容易诱导团队:
- 什么都往里塞
一旦这样做,成本通常不是线性“有点变贵”,而是:
- 每个请求都被历史、证据、schema 和状态对象一起放大
9.2 延迟误区
输入 token 越多,通常意味着:
- 请求构建更慢
- 服务端处理更重
- 首 token 延迟和总延迟都可能上升
9.3 质量误区
长上下文并不自动等于高质量。
如果你把大量低价值、重复、过期或冲突信息一起塞进去,常见结果是:
- 关键证据被淹没
- 检索相关性下降
- 模型更容易引用旧信息
- 工具选择被上下文噪声干扰
真正成熟的心智模型不是:
- 窗口越大越强
而是:
窗口越大,越需要预算治理和信息分层。
10. 输入窗口、输出窗口和 reasoning 预算最好分开理解
很多团队说“这个模型有超长上下文”,但工程上真正有用的是把预算拆开看。
至少要分清:
- 输入 token 预算
- 输出 token 预算
- 某些推理模型的 reasoning token 预算
根据 OpenAI 当前 Reasoning best practices 官方文档,reasoning models 的内部思考过程会消耗上下文窗口,而且 reasoning token 计入输出 token 计费。官方当前建议是在复杂任务中为 reasoning 预留足够空间,甚至可按任务预留上万 token。
这意味着:
- 不是“用户只问一句话,所以输出预算可以随便小”
- 复杂任务里,如果不给 reasoning 留预算,模型可能在质量和完整性上退化
更实用的理解是:
你管理的不是一个窗口,而是多个争抢同一容量池的预算项。
11. 一个请求里真正会烧 token 的东西有哪些
如果你们开始做生产优化,建议把一次请求拆成下面这些类别分别统计:
- 基础规则 token
- few-shot token
- 用户输入 token
- 历史消息 token
- 检索证据 token
- 工具 schema token
- 多模态输入 token
- 模型可见输出 token
- reasoning token
这样做的价值很大,因为你能回答:
- 到底是产品需求在烧钱
- 还是工程拼接方式在烧钱
很多团队以为自己成本高是因为:
- 用户问题太长
结果拆账后才发现真相是:
- 历史消息太长
- 工具定义太宽
- 检索片段塞太多
- 思考预算没控住
12. 为什么精确 token counting 是工程刚需
OpenAI 当前 Token counting 指南非常明确地把 token counting 放在请求前治理里,而不是事后统计。
你应该在请求发出前就能回答:
- 这次预估会花多少 token
- 是否超出窗口
- 哪部分最重
- 是否需要裁剪历史或检索结果
- 是否应该换一个更便宜或更大窗口的模型
12.1 事前计数比事后记账更重要
事后记账只能告诉你:
- 钱已经花掉了
事前计数才真正帮助你:
- 防止超窗
- 做预算拦截
- 做模型路由
- 做上下文压缩
12.2 本地估算和服务端真实计费可能不完全相同
这点非常重要。
即便你用官方 tokenizer 或近似工具,也要知道:
- 最终计费仍以服务端实际处理为准
偏差可能来自:
- 模型 tokenizer 差异
- 请求结构差异
- 工具定义注入方式
- 多模态编码细节
- 推理 token 的额外消耗
所以更稳妥的做法是:
- 本地做请求前估算
- 服务端 usage 做最终核账
- 两者都留痕
13. Prompt caching 为什么已经不是“可选优化”
根据 OpenAI 当前 Prompt caching 官方文档,prompt caching 的本质不是“缓存整次回答”,而是:
- 让相同前缀输入在后续请求里复用已处理成本
这对生产系统是重要杠杆,因为很多请求都共享大段稳定前缀:
- 系统规则
- 长工具定义
- 大型知识模板
- 固定 few-shot
- 共享上下文前缀
13.1 OpenAI 当前的核心前提:前缀必须高度一致
OpenAI 当前文档强调的不是“语义差不多就行”,而是:
- 请求前缀要尽可能稳定、一致
也就是说,下面这些做法会显著影响命中率:
- 每轮都重排工具列表
- 每次都改系统提示词顺序
- few-shot 示例顺序随机
- 把可复用前缀和高频变化内容混在一起
13.2 Anthropic 也把 prompt caching 放到了显式产品能力层
Anthropic 当前文档同样提供 prompt caching 能力,核心思想一致:
- 可复用前缀值得被单独治理
这说明 prompt caching 已经不是某一家平台的偶然优化,而是:
- 长上下文时代的通用工程杠杆
13.3 Gemini 也有上下文缓存思路
Google Gemini 当前官方文档提供 context caching / prompt caching 相关能力,其工程价值同样在于:
- 把高复用、低变化、长前缀内容从重复计算里剥离出来
今天做多模型平台时,缓存治理已经应该进入默认设计,而不是上线后补救。
14. 哪些内容最适合做缓存
通常最适合缓存的是:
- 长期稳定系统规则
- 很少变化的工具 schema
- 固定 few-shot 示例
- 长期不变的模板化背景说明
- 重复使用的大段产品知识前缀
这些内容共同特点是:
- 长
- 稳定
- 多请求共享
它们既容易形成缓存收益,也最适合做版本化治理。
15. 哪些内容通常不适合做缓存
通常不适合直接依赖缓存收益的内容包括:
- 高频变化的用户输入
- 每次都不一样的检索片段
- 时效性强的工单、订单、日志
- 当前会话临时状态
- 高度个性化的短期上下文
这些内容的问题不是“绝对不能缓存”,而是:
- 你不能把成本优化预期建立在它们稳定命中上
16. 怎样提高缓存命中
如果你们已经开始做缓存治理,更实用的方法通常是:
- 把稳定前缀和变化内容分层
- 保持稳定前缀的顺序稳定
- 工具定义尽量版本化,不要每次动态拼不同字段
- 固定 few-shot 的排列和表述
- 不要把本轮临时状态插到稳定前缀中间
一句话总结:
缓存命中靠的不是“开关”,而是前缀工程。
17. 为什么工具 schema 会成为隐形成本黑洞
很多团队只有在接入大量工具后才意识到:
- 工具不是免费能力,它们会显著增加请求体积
工具 schema、描述、参数定义、枚举字段、使用说明都会进入模型可见上下文。
这会带来几个现实问题:
- 工具越多,请求前缀越重
- schema 越松,说明文字越长
- 多轮 Agent 每轮都带全量工具时,成本会被持续放大
更好的做法通常是:
- 只暴露本轮必要工具
- 缩短描述但保留判断边界
- 把大工具面拆成按任务动态收缩的能力集
18. 多轮对话里最容易失控的是历史上下文
很多团队一开始的做法很简单:
- 每轮把全部历史继续追加
短期能跑,长期几乎一定失控。
失控方式通常包括:
- 成本越来越高
- 延迟越来越高
- 旧信息影响新任务
- 历史里错误摘要被持续复用
- 关键新证据被挤到窗口后面
18.1 历史越长,不代表模型记得越好
真正的问题不是“历史多不多”,而是:
- 历史里有多少对当前任务仍然有价值的信息
18.2 摘要不是天然可靠的压缩手段
很多系统会做摘要压缩,但摘要如果不可追溯,就会出现:
- 错误事实被固化
- 重要边界条件被压没
- 原始证据无法回放
18.3 历史治理应该和任务类型绑定
客服问答、代码 copilot、审批 Agent、RAG 工作流,对历史保留策略不应该一样。
真正成熟的做法通常是:
- 针对不同任务单独定义历史保留、摘要和过期策略
19. RAG 系统里最容易浪费 token 的地方
RAG 的 token 浪费通常不是出在 embedding,而是出在:
- 检索召回过多
- chunk 太长
- 重复证据太多
- 排序不准
- 把整段原文机械拼进上下文
19.1 “召回越多越保险”通常是错觉
召回更多片段确实可能提高覆盖,但也常常导致:
- token 成本快速膨胀
- 上下文噪声增多
- 相关片段被稀释
19.2 真正值得优化的是证据密度
相比“多塞几段”,更有价值的往往是:
- 提高 chunk 质量
- 做重排
- 去重
- 保留高证据密度片段
- 控制单轮注入总预算
20. 长上下文不等于长记忆
这是最容易被误解的点之一。
上下文窗口大,表示:
- 一次请求里能容纳更多内容
它不自动表示:
- 模型对长期状态有真正稳定记忆
- 历史里所有关键信息都会被稳定利用
- 你不再需要显式状态管理
更准确地说:
- 长上下文解决的是“能放多少”
- 长记忆解决的是“该保留什么、如何稳定调用什么”
所以即便模型支持超长窗口,你仍然需要:
- 状态对象设计
- 历史裁剪策略
- 摘要与回放策略
- 检索与记忆分层
21. 多模态输入为什么更要谨慎做预算
一旦输入里包含:
- 图片
- 视频片段
- 音频转写
token 预算问题往往会更复杂。
原因不是“多模态一定更贵”,而是:
- 输入编码方式不同
- 同一素材可能被转换成大量模型可见表示
- 你更难通过肉眼直接判断真实成本
工程上更稳妥的做法是:
- 对多模态单独做预算规则
- 不要沿用纯文本任务的估算习惯
- 对图片、文档和转写链路分别统计成本
22. reasoning token 为什么是 2026 年必须单独讲的成本项
在推理模型上,很多团队只盯着:
- 最终给用户看到的输出 token
这在今天已经不够了。
根据 OpenAI 当前 Reasoning best practices 文档,reasoning token:
- 占用上下文窗口
- 按输出 token 计费
- 对复杂任务质量有直接影响
这带来几个工程结论:
22.1 复杂任务不能只给“用户可见回答”留预算
如果任务本身需要长推理链路,你必须预留:
- 思考空间
否则常见后果是:
- 答案变短但质量下降
- 工具规划不完整
- 复杂任务中途收缩
22.2 reasoning token 也是优化对象
优化 reasoning token 的常见方向不是“完全不要思考”,而是:
- 让任务边界更清楚
- 让证据更高质量
- 减少无意义循环
- 减少过度宽泛的工具面
22.3 任务级成本统计必须把 reasoning 纳入
否则你会误以为:
- 输出看起来不长,所以任务不贵
但真实计费可能已经被 reasoning 拉高。
23. 什么时候必须做 token counting
以下场景基本都建议做请求前 token counting:
- RAG 注入片段超过几个 chunk
- 多轮会话历史开始累积
- 使用大量工具或复杂 schema
- 使用长系统提示词或大量 few-shot
- 接入推理模型
- 存在模型路由、成本门禁或预算上限
- 使用多模态输入
如果系统已经进入生产,几乎可以认为:
token counting 不是可选项,而是标配。
24. 生产里建议单独监控这些 token 指标
如果你们已经在做观测,建议至少把下面这些指标拆开看:
- 每请求输入 token
- 每请求输出 token
- reasoning token
- 缓存命中量与缓存折扣收益
- 历史消息 token
- 检索注入 token
- 工具 schema token
- 多模态输入 token
- 超窗前裁剪次数
- 因预算不足触发的降级次数
这些指标的意义在于:
- 让你知道是哪个层在变重,而不是只有一个总账单
25. 一个实用的上下文预算思路
很多系统真正需要的不是“大窗口”,而是:
- 清晰预算
一个实用做法是把上下文预算按层拆开:
- 规则层预算
- 用户输入预算
- 历史层预算
- 检索层预算
- 工具层预算
- 输出层预算
- reasoning 预留预算
25.1 预算最好按“层”和“责任人”来分
这样你们才能回答:
- 是 Prompt 团队把规则做重了
- 是 RAG 团队把检索片段塞多了
- 还是 Agent 团队把工具面做宽了
25.2 长上下文不应该等于“全量回放”
上下文大,不等于什么都保留。
更稳妥的做法是:
- 只保留当前任务仍需要的信息
25.3 上下文预算要配套压缩和过期策略
预算不是“写在文档里就结束”,还要配套:
- 历史摘要
- 证据去重
- 过期淘汰
- 动态裁剪
- 路由降级
26. 成本、延迟和质量为什么经常一起被 token 驱动
很多团队喜欢把这三件事分开讨论:
- 成本优化
- 延迟优化
- 质量优化
但在 LLM 系统里,token 往往是三者交汇点。
26.1 成本维度
token 越多,通常成本越高。
26.2 延迟维度
token 越多,请求构建、服务端处理和结果生成通常越慢。
26.3 质量维度
token 并不是越少越好,过度压缩也会导致:
- 证据不足
- 输出不完整
- reasoning 不够
所以真正成熟的优化目标不是:
- 把 token 压到最低
而是:
在可接受质量下,让 token 分布合理。
27. 模型迁移时为什么一定要重测 token 分布
换模型时,很多团队只看:
- 单价
- 排行榜
- 能力评分
但如果忽略 tokenizer 和上下文差异,实际账单和延迟可能与你预期差很大。
迁移时至少要重测:
- 同类请求的输入 token 分布
- 输出 token 分布
- reasoning token 分布
- 工具 schema 开销
- 缓存命中收益变化
这类差异在下面场景尤其明显:
- 代码任务
- JSON 重任务
- 多工具 Agent
- 长 RAG 问答
28. 常见误区
28.1 只按字符估成本
这是最常见也最容易出大偏差的错误。
28.2 上下文越大越好
大窗口只会放大治理能力,不会替代治理能力。
28.3 只盯用户输入,不盯系统拼接内容
线上最重的部分,常常恰恰是系统自己拼进去的内容。
28.4 觉得缓存会自动解决一切
缓存收益依赖稳定前缀工程,不是“打开开关”就完事。
28.5 只优化输入,不优化输出
如果输出很长,或者 reasoning token 很重,单看输入优化是不够的。
28.6 把历史追加当成长记忆方案
这通常只会让成本和噪声一起膨胀。
28.7 觉得 token counting 只是财务问题
它同时影响:
- 成本
- 延迟
- 路由
- 上下文质量
- 降级策略
29. 建议和哪些专题一起看
30. 重点官方资源
- OpenAI Token counting
- OpenAI Prompt caching
- OpenAI Reasoning best practices
- OpenAI Latency optimization
- Anthropic Token counting
- Anthropic Prompt caching
- Anthropic Context windows
- Google Gemini Token counting
- Google Gemini Context caching
- Google Gemini Long context
- Hugging Face Tokenizer summary
31. 一句话总结
今天做 LLM 系统时,token 不只是计费单位,它同时还是:
上下文容量约束、缓存收益边界、延迟驱动因素和多轮治理的核心预算对象