想象你是一家智能积木玩具厂的仓库调度员。厂里的机器臂笨得很,它不认识“今天天气不错”这句话,只认积木编号:1743、321、86……所以每次接到客户订单,你得先把整句话翻译成一张“积木编号清单”,机器臂才能开工。这个翻译动作,就是大模型里的“分词”(tokenization)。 为了让装配更快,厂里的设计师们发明了一套“标准积木规格表”:把经常拼在一起的小积木预先粘成一块大积木,比如把 h、e、l、l、o 五个小粒粘成一块现成的“hello“。反复粘合成千上万次,最终沉淀出一只装满了十万多块精选积木的大箱子——这只箱子就是 GPT-4 的 cl100k_base 词表。负责按规格表快速拆单、准确报数的那个”智能拆单员”,就是我们今天的主角:Tiktoken 库。 这篇文章会带你走进这座积木厂:先看为什么要分词,再看 BPE 算法怎么反复粘合字节对,接着了解字节级设计的巧思、正则预分词这把“剪刀”、词表的完整训练流程,最后认识 cl100k_base 词表和 Tiktoken 库,并学会用它估算 API 成本。
对 LLM 应用开发者和数据工程师来说,理解 Tiktoken 与 BPE 是硬通货:它能让你精确预估 API 账单、优化 prompt 长度、设计高效的 RAG 与数据清洗管道。读完这篇,你将不再把 token 当黑盒,而是能亲手算出每一句话的“积木件数”。
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
分词与词表
想象你是智能积木玩具厂的仓库调度员。机器臂不认“今天天气不错”,只认积木编号:1743、321、86……每接到客户订单,你得先把句子翻译成一张“积木编号清单”。这个翻译动作,在 AI 世界叫分词(tokenization),而清单上的每一项,就是一个 token。
在 GPT 这类大模型眼里,根本不存在“字符”这个概念,它只吃整数 ID。所有 token 的集合叫作词表(vocabulary),词表有多大,模型就能认多少种积木件。GPT-4 的词表有十万多件,而 Tiktoken 正是官方配发的“拆单工具”。一个 token 可能是整个单词(hello)、半个单词(hell)、一个标点,甚至一个空格——拆得越合理,模型理解得越省力。
开发者最关心的实操问题是“这句话会消耗多少 token”。经验上,英文大约每 4 个字符折合 1 个 token,中文则约 1 个字接近 1 个 token。这个数字直接决定 API 账单,所以拆单前先粗算一下很有必要。
就像调度员扫一眼订单页数就能猜出大概用多少积木件,工程师看一眼 prompt 字数也能估出 token 消耗。当然,真正的精确数,还要交给 Tiktoken 这个专业拆单员来算——这正是后面几节要讲的事。
- 分子 L_chars$L_{\text{chars}}$ 是文本的字符个数,英文字母、数字、空格都算一个字符
- 分母常量 4英文语料的经验统计值,平均约 4 个字符对应 1 个 token
- 向上取整符号$\left\lceil \cdot \right\rceil$ 表示结果不是整数就进一位,比如 9 个字符算出 2.25,实际按 3 个 token 计
BPE合并算法
积木厂仓库最初只有 256 种最基础的“小方粒”。设计师发现,每次装配 “hello“ 都要先找 h、e、l、l、o 五粒,太慢了。于是他们守在流水线边统计:哪两粒最常被拼在一起?l 和 l 总黏着,先粘成 ”ll“;h 和 e 也常出现,粘成 ”he“。粘完再统计,ll 和 o 又常一起,粘成 ”llo“。几次之后,仓库里多了一块现成的 ”hello” 大件。
这套“反复粘合最常见相邻对”的思路,就是 BPE(Byte Pair Encoding,字节对编码)算法,GPT 系列分词的核心。BPE 属于子词分词法:它不把单词当不可分割的整体,也不把文本拆到只剩字母,而是从最小元素出发,自底向上合成高频子词。常见词如 “the“ 很快变成整件,生僻词如 ”loww“ 则可拆成 ”low” + "w",永远不会因为词表里没有而失败。
训练时每轮只做两件事:统计当前所有相邻对的出现频率,把频率最高的一对合并成新符号并加入词表。反复迭代几万次,满屏字母的文本会被逐渐覆盖上“单词级大件”,模型的输入序列也随之变短。
设计师每粘合一粒大积木,流水线上的装配动作就少一步;BPE 每合并一次,模型处理这段文本的 token 数就少一个。语料里高频出现的词,最终都会变成“整装件”。
- 频率统计 f(a,b)$f(a,b)$ 表示相邻对 $(a,b)$ 在所有训练文本里共同出现的总次数,$\mathcal{D}$ 是全部训练片段
- 计数函数 count$\mathrm{count}(ab, w)$ 计算片段 $w$ 内部出现相邻对 $ab$ 的次数,再对所有片段求和
- 挑选最大值 argmax$\arg\max_{p,q} f(p,q)$ 表示从所有候选相邻对里找出频率最高的一对
- 词表更新 V$V^{(k+1)}$ 是第 $k+1$ 轮的词表,等于上一轮词表并上新符号 $\{ab\}$,词表每轮多一项
字节级BPE
仓库现在接到世界各地的订单:阿拉伯文、日文,还有夹杂 🚀 的表情包。如果每种语言的每个字符都做成一种小方粒,仓库会爆炸。设计师一狠心:干脆把最底层规格统一成 256 种“标准微粒”(字节),任何文字都能拆成这些微粒的排列。仓库从此不怕生僻字。
这些“标准微粒”就是 UTF-8 编码后的字节。英文 a 占 1 字节,中文“你”占 3 字节,emoji 占 4 字节。BPE 不再作用在字符上,而是作用在这串字节上。初始词表就是 256 个字节(取值 0~255),之后合并出的每个新符号,本质是若干字节的组合。
为什么非要字节级?因为 Unicode 字符有上百万个,字符级词表再大也会遇到 OOV(out-of-vocabulary,词表外词)。字节级词表从 256 出发,理论上任何 UTF-8 文本都能被拆解,永远不会出现“这个词没见过”。这个设计同时解决了多语言与未知词两大难题,也保证了 decode 可以无损还原原文。
有了 256 种标准微粒,设计师的世界清净了——不管客户用什么语言下订单,原料都能拆到最底层,再按统计规律重新聚合成“大件”。这就是字节级 BPE 让 GPT 系列“通吃”全球语言的根本原因。
- 文本映射为字节序列$s \mapsto [b_1, b_2, \dots, b_m]$ 表示一个字符或多个字符被编码成一串字节,比如“你”变成 3 个字节
- 字节取值范围$b_i \in \{0, 1, \dots, 255\}$ 说明每个字节只有 256 种取值,这就是“256 种标准微粒”的由来
- 序列长度 m$m$ 随文本内容变化,英文短、中文更长,因为不同字符占 1~4 个字节不等
正则预分词
设计师没敢直接对整段话做统计——那会乱套。“hello world“ 里如果 h 和 e 隔着空格也能硬粘,产线会疯掉。发货部老师傅给出建议:先用一把剪刀按语言习惯把句子剪开。这把剪刀碰到单词、数字、标点、空格的结合处就下刀,剪出的每个片段都是”可独立装配的单元”。
这把剪刀就是正则预分词(pre-tokenization)。GPT-2 训练词表时采用的规则效果大致是:连续字母归成一段,标点单独成段,空格保留成片段前缀。比如 “hello world!“ 会被切成 [”hello”, " world", “!“]。注意第二个片段前面带着空格,这是刻意保留的——模型需要知道 ”world” 是在句首还是句中。
预分词最大的价值是把 BPE 的搜索空间大大缩小。BPE 只在每个片段内部寻找可合并的相邻对,跨片段永不合并。空格、标点的边界信息因此被完整保留,数字也常常整段留下。这让大模型对代码、编号、URL 的切分质量明显提升,GPT-4 的分词器延续了同样的思路。
先剪后粘,节奏清晰。就像仓库师傅先把大件订单按“包装盒”分开,再在盒子里做积木优化——既不跨盒混装,也不漏掉任何零件。预分词就是 BPE 正式开工前的“分盒工序”。
- 预分词映射 R(s)$\mathcal{R}(s)$ 是正则规则作用在文本上的结果,输出一个片段集合
- 无损拼接条件$s = \mathrm{concat}(s_1, \dots, s_k)$ 是所有片段首尾相连后必须等于原文,保证拆分不增不减
词表训练流程
现在把设计师的完整工作流程摆上台面:先收集海量历史订单——网页、书籍、代码,这叫语料;然后用剪刀预分词;接着从 256 个字节出发,一轮轮统计、合并;直到词表达到目标规模,比如 10 万件。整个过程几乎自动化,不需要人为干预。
具体来说,训练 BPE 词表只需五步:准备语料 → 正则预分词 → 初始化字节级词表 → 循环执行合并(每轮加一项)→ 收敛输出词表。每一步都非常机械。OpenAI 当年就是用类似流程,在超大语料上跑出了 cl100k_base 词表。训练好的结果包含两部分:词表里的符号串,以及每个符号的 rank(合并顺序优先级,越小表示越靠近底层字节)。
词表大小和合并次数是同一个硬币的两面:基础表 256 项,每合并一次词表多一项,因此总的合并次数 M 恰好等于最终词表大小减 256。cl100k_base 的容量 100,256,就来自约 10 万次合并。
这批“规格表”一旦定型,就变成所有产线共享的资产。仓库不再每次重新发明积木,而是直接拿着规格表拆单。理解了训练流程,你就知道词表不是天上掉下来的,而是海量语料里“长”出来的。
- 最终词表大小$|V_{\text{final}}|$ 是训练结束后词表里符号的总个数,比如 cl100k_base 的 100,256
- 基础字节表$|V_{\text{base}}|$ 恒为 256,对应 256 种 UTF-8 字节微粒
- 合并次数 M$M$ 就是训练过程中执行的“粘合”总次数,也是词表净增长量
cl100k_base词表
经过千锤百炼,GPT-4 工厂选定了一款“豪华积木箱”,型号 cl100k_base。cl 是 class(系列)的缩写,100k 指约 10 万容量。GPT-4、GPT-3.5-turbo 的 API 都配发这款箱子。它的总容量是 100,256:256 个基础字节,加上约 10 万个由 BPE 合并而来的子词与整词。
除了普通 token,箱子里还有一批“管理件”——特殊 token。比如 <|endoftext|> 标记文本结束,<|fim_prefix|>、<|fim_middle|>、<|fim_suffix|> 用来支撑代码补全的填充式任务(FIM,Fill-In-the-Middle)。它们和普通 token 一样占用编号,encode 时被单独识别,不会和普通字符混淆。
为什么 GPT-4 选 10 万容量而不是 5 万?词表越大,单个 token 携带的信息越多,模型处理同样文本要走的步数越少,但最后一层 softmax 的计算负担也越大。10 万是在“表达力”与“算力成本”之间折中的结果。实际效果是:英文常见词大多一整个 token,中文按字节合并出常用字词,少见内容退化为多字节组合。
这款积木箱就是 GPT-4 系列仓库的标准配置。作为开发者,你不必自己训练词表,直接用官方成品即可;理解它的内部构造,才能在估算 token 时心中有数,也知道那些带尖括号的“管理件”是干什么用的。
- 词表符号 V$V_{\text{cl100k}}$ 表示 cl100k_base 这套词表(积木箱)的全部符号集合
- 容量 100256$100{,}256$ 是词表总项数,即 256 个基础字节 + 约 100,000 次合并新增的符号
- 模型含义任何输入文本最终都会被映射成这 100,256 个编号中的若干个,不会越界
Tiktoken库
现在请出真正的“智能拆单员”——Tiktoken,OpenAI 开源的快速分词库。它自带 cl100k_base 等词表的规格书(rank 表),给定一段文本,能瞬间输出 token ID 列表;反过来给 ID 列表,也能一字不差还原文本。装上它,你就拥有了和 OpenAI API 完全一致的分词口径。
工程上它做了三件事:一是预编译正则,把文本切成片段;二是在每个片段内部查 BPE 合并表,按 rank 从底层到高层贪心匹配出 token;三是维护一张“符号串 → rank”的字典,rank 越小表示它越是基础的字节或越早合并的基元。算法主体用 Rust 实现,速度远快于纯 Python 的 BPE 实现。
使用极其简单:tiktoken.get_encoding("cl100k_base") 拿到编码器,enc.encode(text) 返回 id 列表,enc.decode(ids) 还原原文。要处理特殊 token 就用 encode_with_special_tokens。对 GPT-4 系列模型,还可以用 encoding_for_model("gpt-4") 自动匹配词表。开发者几乎不需要关心底层细节。
这位拆单员最大的美德是“可靠”:拆得再碎,装回去一个零件不少。无论是提交给 API 的 prompt,还是接收到的补全结果,都能精确换算成 token 数,让账单清清楚楚。
- 编码函数 encode$\mathrm{encode}(s)$ 把文本 $s$ 变成一串 token ID,即“拆单员”把句子拆成积木编号
- 解码函数 decode$\mathrm{decode}(\cdot)$ 把 token ID 序列拼回字符串,即按编号把积木原样装回
- 恒等式还原等式表示对任意合法文本,两者复合后等于原文,说明分词可逆、信息零丢失
成本优化
作为厂里调度员,每次接单先让拆单员算件数,因为财务部是按件收钱的。API 的费用公式简单粗暴:token 总数除以 1000,向上取整,再乘单价。一句话 prompt 可能只要 20 个 token,一份长文档摘要却可能吃掉 4000 个 token。
实践中有两个常用经验:英文 1 token ≈ 4 字符 ≈ 0.75 个单词;中文 1 个汉字约 0.6~1.5 个 token,保守估算按 1~2 个算。但经验只是预判,真正开发时必须用 Tiktoken 精确统计——prompt 模板、历史消息、function 定义都会占用上下文,漏算任何一项都会让成本评估失真。
控制成本的核心手段包括:精简 prompt、用摘要代替长文本、设置最大响应 token、对用户输入限流。在 RAG(检索增强生成)场景里,检索回来的文档块要按 token 预算动态截断,给“生成答案”留足空间;批处理任务则先统计全部样本的 token 分布,再决定分几批跑、要不要压缩。
拆单员的账本,就是产品盈亏的晴雨表。会估 token,你就能在功能上线前算出成本红线,而不是等账单来了才拍大腿。
- 总 token 数 n_tokens$n_{\text{tokens}}$ 是一次请求的完整 token 总数,包含 prompt 与模型生成的回答
- 千 token 取整$\left\lceil \frac{n_{\text{tokens}}}{1000} \right\rceil$ 把 token 数折算成“千 token”单位,不足一千按一千算
- 单价 P$P$ 是模型每 1000 个 token 的美元价格,不同模型差别很大
- 费用 cost$\text{cost}$ 就是这次请求的美元成本,向上取整的惩罚让短请求也要付“起步价”
AI 应用场景
API 成本预估与配额管理
阶段:推理部署
解决的问题:开发 LLM 应用时无法预测用户输入长度,账单容易失控。传统做法是等月底看账单再补救,而用 Tiktoken 可以在每次 API 调用前精确统计 prompt 的 token 数,乘上单价做实时预算;也能对单用户每日累计 token 设上限,超限自动降级。
具体案例:某客服机器人项目上线前,用 Tiktoken 跑历史 10 万条真实用户问题,得出平均每条 86 个 token、P99 为 240 个 token,据此把单次调用的 token 上限设为 600,成本下降约 35%。
RAG 长文本上下文适配
阶段:数据预处理与检索
解决的问题:RAG 检索回的文档可能超过模型上下文窗口(如 8k 或 128k 限制)。按字符截断容易切断语义,而用 Tiktoken 对每个文档块计算 token 数,可按预算精确拼接 prompt,超限部分降级为摘要或丢弃。
具体案例:企业知识库问答场景中,文档块长短不一。工程师用 Tiktoken 批量分词后按 token 分布分桶存储,检索阶段动态调整条数与长度,把最终 prompt 稳定压在 3,000 token 以内,回答质量提升且不再报上下文超限错误。
微调语料的质量评估与清洗
阶段:数据质量分析
解决的问题:模型微调语料里混着大量重复、超长、噪音文本。直接看字符数不够直观,用 Tiktoken 计算每条样本的 token 数,结合重复度做过滤——token 数超过阈值的样本往往是未清洗的整页网页;近似重复的文本也可按 token 分布去重。
具体案例:数据工程师处理 500 万条 SFT 语料时,先用 Tiktoken 统计 token 分布,发现 12% 的样本超过 4,096 token,进一步排查出是爬虫抓取的整页 HTML。清洗后有效语料 token 总量下降 20%,训练效率明显提升。
Python 演示
import refrom collections import Counter def apply_merge(symbols, pair): """把列表里所有等于 pair 的相邻两项合并成一项""" out, i = [], 0 while i < len(symbols): if i < len(symbols) - 1 and (symbols[i], symbols[i + 1]) == pair: out.append(symbols[i] + symbols[i + 1]) i += 2 else: out.append(symbols[i]) i += 1 return out def train_bpe(corpus, num_merges=10): """用正则预分词 + BPE 合并,返回合并规则与词表""" pieces = re.findall(r'\w+|\s+', corpus) # 预分词: 单词与空白分开 word_freq = Counter(pieces) # 统计每个片段出现次数 word_splits = {w: list(w) for w in word_freq} # 每个片段先拆成最细字符 merges = [] for _ in range(num_merges): pair_freq = Counter() for w, freq in word_freq.items(): parts = word_splits[w] for i in range(len(parts) - 1): pair_freq[(parts[i], parts[i + 1])] += freq if not pair_freq: break best = max(pair_freq, key=pair_freq.get) # 找到最高频相邻对 merges.append(best) for w in word_splits: word_splits[w] = apply_merge(word_splits[w], best) vocab = sorted({s for parts in word_splits.values() for s in parts}) return merges, vocab def estimate_tokens(text, chars_per_token=4): """按 4 字符一个 token 向上取整估算""" return (len(text) + chars_per_token - 1) // chars_per_token if __name__ == '__main__': corpus = ('low ' * 200 + 'hello world ' * 200).strip() merges, vocab = train_bpe(corpus, num_merges=8) print('前 8 次合并:', merges) print('最终词表示例:', vocab[:20]) sample = 'hello world low low' print(f'估算 token 数: {estimate_tokens(sample)}')
pieces = re.findall(r'\w+|\s+', corpus)用正则预分词,把连续单词与空白切成独立片段,对应正文的“剪刀”word_freq = Counter(pieces)统计每个片段出现次数,后续给相邻对计数加权word_splits = {w: list(w) for w in word_freq}把每个片段拆成最细字符列表,这就是“256 基础件”的雏形pair_freq[(parts[i], parts[i + 1])] += freq给相邻对计数,关键是用片段频次加权best = max(pair_freq, key=pair_freq.get)每轮挑出最高频字节对,它就是本轮的“胶水”word_splits[w] = apply_merge(word_splits[w], best)把所有片段里出现的这对字节全部粘合成新符号vocab = sorted({s for parts in word_splits.values() for s in parts})汇总所有符号得到最终词表
常见误区
误区我以为分词就是把句子按空格切成单词,token 数量约等于单词数量。写 prompt 时数了下有 20 个词,就觉得只要 20 个 token。
正解BPE 会把常见单词合成一个 token,把不常见单词拆成子词,空格还常常被保留成“ world“这样的带前缀 token。比如 ”hello world“ 在 cl100k_base 里可能是 2 个 token,而 ”supercalifragilistic“ 会被拆成好几个。就像积木箱里既有”你好“整件,也有”我“和”你”小件,不能按空格数猜件数。
为何常见:人习惯按空格分词思考,而子词分词是数据驱动的最优拆法,二者天然不同。
误区我觉得既然文本被拆成了碎片再转成数字,信息一定有损,decode 可能还原不出原文,尤其是生僻字或表情符号。
正解字节级 BPE 保证了 decode(encode(s)) == s 恒成立。UTF-8 字节是“标准微粒”,任何文本拆到字节层都能原样拼回。就像积木拆成零件,只要编号齐全,一定能装回原来的模型。这也是 OpenAI 敢按 token 计费的信任基础。
为何常见:很多旧分词器确实有损或存在未登录词,用户把历史经验套到了字节级 BPE 上。
误区BPE 是从英文语料训练出来的,遇到中文、日文、阿拉伯文肯定会乱套,生成的 token 没意义。
正解字节级 BPE 的底座是 256 个 UTF-8 字节,英文、中文、emoji 在底层都是字节的组合。中文常用字经过合并后会形成独立 token,生僻字则退化为多个字节 token,但永远不会失败。GPT-4 的中文能力就建立在 cl100k_base 对中文的字节级覆盖之上。
为何常见:人们看到词表里大量英文子词,就误以为分词器不懂别的语言,没意识到字节层已经统一了所有文字。
误区我拿 `len(text) // 4` 算 token 数,觉得这就是 API 账单上的数字,从没怀疑过。
正解4 字符一 token 只是英文经验的粗略平均值。中文大约一字一 token,数字串、代码、空格密集的文本偏差很大。精确 token 数必须用 Tiktoken 的 encode 实测,经验公式只适合快速粗估。就像按字数猜运费,猜得再准也不如称重器。
为何常见:官方文档给出过 4 字符的近似值,初学者容易把“近似”当成“精确”。
面试题
Q1. Tiktoken 使用的核心分词算法是什么?
- A.WordPiece 算法
- B.BPE 字节对编码← 正确答案
- C.SentencePiece 算法
- D.按空格直接切分
答案:B。Tiktoken 正是 OpenAI 对 BPE 的高效工程实现。WordPiece 是 BERT 系常用的,SentencePiece 是 T5/LLaMA 系常用的,而直接按空格切分会丢失子词信息。用积木比喻,Tiktoken 拿的就是 BPE 规格表来拆单。
Q2. cl100k_base 词表的容量大约是?
- A.大约 5 万个
- B.约 10 万个← 正确答案
- C.仅有 256 个
- D.超过 100 万个
答案:B。cl100k_base 的精确容量是 100,256,其中 256 是基础字节表,剩下约 10 万来自 BPE 合并。5 万是许多早期模型的规模,256 只是字节基础表,100 万则远高于实际。记住"100k"这个系列名即可。
Q3. BPE 训练时,每一轮合并操作的依据是什么?
- A.随机选一对相邻字节
- B.出现频率最高的相邻字节对← 正确答案
- C.词典中排序最靠前的词
- D.长度最短的字节对
答案:B。BPE 每轮统计所有相邻对的频率,选最高的那对合并进词表。随机、按排序或按长度都不符合 BPE 的贪心统计本质。就像积木设计师只关心“哪两粒最常被拼在一起”,而不是哪粒最短。
Q4. 使用字节级 BPE 而不是字符级 BPE 的好处有哪些?
- A.可以处理任意语言的文本← 正确答案
- B.避免遇到未知词的情况← 正确答案
- C.词表一定会变得更小
- D.保证解码阶段无损还原← 正确答案
答案:ABD。字节级以 256 个 UTF-8 字节为底座,任何语言、任何符号都能编码,天然消灭 OOV,且 decode 可无损还原。但词表大小由合并次数决定,与是否字节级无关,所以 C 错。这就像统一了 256 种标准微粒后,仓库从不怕生僻原料。
Q5. GPT-2 分词流程中,预分词(pre-tokenize)的主要作用是什么?
- A.按 BPE 合并规则直接切分文本
- B.先用正则把文本切成片段再做 BPE← 正确答案
- C.把文本编码成 UTF-8 字节序列
- D.把 token id 映射回字符串
答案:B。预分词是 BPE 之前的一道工序,用正则按空格、标点、字母数字边界切分,让 BPE 只在片段内部合并。直接按 BPE 切是编码阶段的事,UTF-8 编码是另一层,id 映射回字符串是 decode。就像装箱前先分盒,再在盒内做优化。
Q6. 一段英文文本大约每多少个字符对应 1 个 token?
- A.大约 1 个字符
- B.大约 4 个字符← 正确答案
- C.大约 10 个字符
- D.大约 64 个字符
答案:B。经验统计表明,英文里 1 个 token 平均对应约 4 个字符,或者说 0.75 个英文单词。1 个字符一 token 过于碎片化,10 个和 64 个又明显高估了单词的信息密度。这个系数常用于 prompt 的快速成本粗估。
Q7. 关于特殊 token(如 <|endoftext|>),下列说法正确的是?
- A.它们同样占用词表中的编号← 正确答案
- B.普通文本中永远不可能出现
- C.用于标记文本开始或结束等边界← 正确答案
- D.解码时会被直接忽略丢弃
答案:AC。特殊 token 与普通 token 共享编号空间,A 对;它们承担边界标记作用,C 对。B 太绝对,编码器只是优先识别它们;D 错,decode 时它们依然会还原成对应字符串。就像积木箱里的“管理件”,平时不参与拼装,但管着箱子的起止标记。
Q8. 某 API 按每 1000 token 收费 0.002 美元,一次请求消耗 4,200 token,费用是多少?
- A.0.008 美元
- B.0.010 美元← 正确答案
- C.0.012 美元
- D.0.016 美元
答案:B。4,200 token 除以 1000 得 4.2,向上取整为 5,再乘 0.002 得 0.010 美元。这正是成本公式 $\lceil n/1000 \rceil \times P$ 的运用。选 A 的忘了向上取整,选 C、D 则是把 4.2 直接乘或错算。
Q9. 关于 Tiktoken 中 encode 与 decode 的关系,正确的是?
- A.解码可能会丢失标点符号
- B.任意合法文本都能无损还原← 正确答案
- C.编码仅接受英文输入
- D.解码输出的是词向量表示
答案:B。字节级 BPE 使 decode(encode(s)) == s 恒成立,标点、空格、emoji 都能还原,B 对。A 会丢失信息所以错;C 忽略多语言支持;D 混淆了 token id 与 embedding——解码输出的是字符串,不是向量。拆得再碎也能原样装回,这正是 Tiktoken 可靠之处。
Q10. 关于 token 数估算与成本控制,正确的说法有?
- A.英文约四字符对应一个 token← 正确答案
- B.中文约一个字对应一个 token← 正确答案
- C.经验估算可以完全替代精确计算
- D.prompt 越长消耗 token 越多← 正确答案
答案:ABD。A 和 B 都是行业公认的经验系数,D 是 API 计费的基本逻辑,三者都对。C 错,经验估算只能用于粗估,开发环境必须用 Tiktoken 精确统计,否则 prompt 模板、历史消息等隐性消耗会让账单失控。