tiktoken 使用说明文档(词元计数库)

token 词元
tiktoken 词元计数工具


目录


1. 概述

tiktoken 是由 OpenAI 开发的一个快速、高效的开源分词器(tokenizer),专门用于处理 OpenAI 大语言模型的文本分词任务。它基于字节对编码(Byte Pair Encoding, BPE)算法实现,能够将文本字符串分割成模型可理解的标记(token)序列。作为 OpenAI 官方推出的分词工具,tiktoken 与 GPT-4、GPT-3.5-turbo、GPT-4o 等主流模型紧密配合,确保了分词结果与模型实际处理方式的一致性。

在使用 OpenAI API 进行开发时,准确计算和管理 token 数量至关重要。一方面,API 按照 token 数量计费,精确估算 token 消耗有助于成本控制;另一方面,每个模型都有最大上下文长度限制,超出限制的请求将被拒绝或截断。tiktoken 提供了一种在本地快速计算 token 数量的解决方案,无需发送请求到 API 服务器,既节省了网络开销,又避免了不必要的 API 调用费用。

与传统的分词器相比,tiktoken 具有显著的性能优势。根据官方测试数据,在处理 1GB 文本时,tiktoken 的速度比同类 Python 分词器快 3-5 倍。这得益于其核心算法使用 Rust 语言实现,并提供了对 Python 的原生绑定接口。对于需要处理大量文本或频繁进行分词操作的应用场景,tiktoken 的高效性能够带来可观的性能提升。

核心功能:

  • 将文本字符串编码为 token ID 序列
  • 将 token ID 序列解码还原为文本
  • 支持多种 OpenAI 模型的编码器
  • 提供精确的 token 数量计算

2. 历史背景与发展

2.1 分词器的重要性

在深入理解 tiktoken 之前,我们需要首先认识到分词器在大语言模型中的核心地位。大语言模型并不直接处理原始文本,而是通过分词器将文本转换为一系列数字标记(token)。每个 token 可以是一个完整的单词、一个子词(subword)、甚至是一个字符。分词器的设计直接影响模型的词汇覆盖率、处理效率以及最终的性能表现。

OpenAI 在早期模型(如 GPT-2)中使用的分词器虽然功能完备,但在处理大规模文本时效率有限。随着 GPT-3 及后续模型的推出,模型规模和应用场景不断扩大,对分词器性能的要求也随之提高。特别是在 API 服务层面,准确预估 token 数量对于用户费用计算和请求限制管理变得至关重要。

分词器演进历程:

阶段 模型 分词方案 特点
早期 GPT-2 BPE (50,257 tokens) 基础分词能力
中期 GPT-3 r50k_base 扩展词汇表
成熟 GPT-3.5/GPT-4 cl100k_base 优化效率
最新 GPT-4o o200k_base 大规模词汇表

2.2 tiktoken 的诞生

tiktoken 由 OpenAI 于 2022 年 12 月正式发布,作为 OpenAI Cookbook 系列教程的一部分首次向公众介绍。该项目的推出旨在解决开发者在使用 OpenAI API 时面临的 token 计算难题。在此之前,开发者要么通过发送实际请求来获取 token 数量(浪费资源),要么使用非官方的分词器(结果可能不准确)。

tiktoken 的设计目标是提供一个与 OpenAI 模型完全兼容的分词器,同时具备高性能和易用性。项目采用 Rust 语言编写核心算法,通过 Python 绑定提供接口,既保证了执行效率,又降低了使用门槛。自发布以来,tiktoken 已成为 OpenAI 生态系统中的基础设施组件,被广泛应用于聊天机器人、文本分析、成本估算等多种场景。

发布时间线:

2022年12月 ─────► tiktoken 首次发布
    │
    │   支持 GPT-3 系列模型
    │   提供 r50k_base 编码器
    │
2023年3月 ──────► 支持 GPT-3.5-turbo
    │
    │   添加 cl100k_base 编码器
    │   优化性能
    │
2023年中期 ─────► 支持 GPT-4
    │
    │   扩展 cl100k_base 支持
    │   改进文档和示例
    │
2024年5月 ──────► 支持 GPT-4o
    │
    │   引入 o200k_base 编码器
    │   词汇表扩展至 200K
    │
至今 ───────────► 持续维护更新

2.3 持续演进

随着 OpenAI 模型家族的不断扩展,tiktoken 也在持续更新以支持新的模型和编码方式。2023 年,随着 GPT-4 的发布,tiktoken 添加了对 cl100k_base 编码的支持;2024 年,为配合 GPT-4o 系列模型,又引入了 o200k_base 编码。截至当前,tiktoken 支持包括 GPT-4o、GPT-4、GPT-3.5-turbo、Codex 等在内的所有主流 OpenAI 模型,成为了开发者不可或缺的工具。

版本更新要点:

  1. 性能优化: 持续改进分词算法效率
  2. 模型支持: 及时跟进新模型发布
  3. 离线能力: 增强离线使用支持
  4. 跨平台: 改进各平台兼容性

3. 资源与链接

以下是 tiktoken 的官方资源链接,开发者可以通过这些渠道获取最新版本、查阅文档、报告问题或参与社区讨论:

资源类型 链接地址 说明
GitHub 仓库 https://github.com/openai/tiktoken 源代码、Issue 追踪、贡献指南
PyPI 包索引 https://pypi.org/project/tiktoken/ 安装包下载、版本历史
OpenAI Cookbook https://developers.openai.com/cookbook/examples/how_to_count_tokens_with_tiktoken 官方教程和示例
Tokenizer 工具 https://platform.openai.com/tokenizer 在线可视化分词工具

提示: 建议定期查看 GitHub 仓库的 Release 页面,以获取最新版本更新和变更日志。


4. 核心概念

4.1 Token 与分词

Token 是大语言模型处理文本的基本单位。在自然语言处理中,将文本分割成 token 的过程称为分词(tokenization)。一个 token 可以是:一个完整的英文单词(如 hello)、一个单词的一部分(如 ing)、一个标点符号(如 !)、或者多个字符的组合。在中文环境中,一个 token 可能对应一个或多个汉字,具体取决于分词器的训练方式。

Token 特征:

英文文本示例:
"tiktoken is great!"
    ↓ 分词
["tiktoken", " is", " great", "!"]
    ↓ 映射为 ID
[83, 1609, 5963, 0]

中文文本示例:
"人工智能"
    ↓ 分词  
["人", "工", "智能"]
    ↓ 映射为 ID
[xxxx, xxxx, xxxx]

理解 token 的概念对于有效使用 OpenAI API 至关重要。经验法则:

  • 英文: 1 token ≈ 4 字符 ≈ 0.75 单词
  • 中文: 1 token ≈ 1-2 汉字(取决于具体内容和编码器)

4.2 字节对编码(BPE)

字节对编码(Byte Pair Encoding, BPE)是 tiktoken 采用的核心分词算法。BPE 最初是一种数据压缩算法,由 Philip Gage 于 1994 年提出,后来被成功应用于自然语言处理领域。BPE 的工作原理是迭代地合并最频繁出现的字节对(或字符对),直到达到预设的词汇表大小。

BPE 算法核心步骤:

1. 初始化: 将文本分解为字符序列
2. 统计: 计算所有相邻字节对的出现频率
3. 合并: 将最高频的字节对合并为新符号
4. 迭代: 重复步骤 2-3 直到达到目标词汇表大小

在 tiktoken 的实现中,BPE 算法首先将文本转换为字节序列,然后根据预训练的合并规则将这些字节组合成 token。这种方法的优势在于:

  • 通用性: 能够处理任意 Unicode 字符
  • 效率: 保持合理的词汇表大小
  • 压缩: 常见词组被合并为单个 token

4.3 编码(Encoding)与解码(Decoding)

在 tiktoken 中,编码(encoding)是指将文本字符串转换为 token ID 序列的过程,而解码(decoding)则是其逆过程——将 token ID 序列还原为文本字符串。

┌─────────────┐      encode()      ┌─────────────┐
│ 文本字符串  │ ─────────────────► │ Token ID 列表│
│ "Hello!"    │                    │ [15496, 0]  │
└─────────────┘                    └─────────────┘
       ▲                                  │
       │                                  │
       └──────────── decode() ◄───────────┘

关键要点:

  • 每个 token 在词汇表中都有唯一的整数 ID
  • 编码结果是一个整数列表
  • 解码可以还原原始文本(信息无损)
  • 编码器的词汇表大小决定了 ID 的范围

5. 编码器类型与模型对应

tiktoken 支持多种编码器,每种编码器对应不同的模型系列。选择正确的编码器对于获得准确的 token 计算结果至关重要。

编码器名称 对应模型 词汇表大小 发布时间
o200k_base GPT-4o、GPT-4o-mini ~200,000 2024年5月
cl100k_base GPT-4、GPT-3.5-turbo、text-embedding-ada-002 100,000 2023年3月
p50k_base Codex 模型(代码生成) 50,257 2022年
r50k_base GPT-3(davinci、curie 等) 50,257 2020年

编码器选择建议:

# ✅ 推荐:通过模型名称自动获取编码器
encoding = tiktoken.encoding_for_model("gpt-4")

# ⚠️ 备选:手动指定编码器(仅在明确知道时使用)
encoding = tiktoken.get_encoding("cl100k_base")

重要: 使用 encoding_for_model() 函数可以确保选择与目标模型匹配的编码器,避免因手动指定错误导致的不一致问题。


6. 安装与配置

6.1 系统要求

要求项 说明
Python 版本 3.8 及以上
操作系统 Windows、macOS、Linux
依赖项 无特殊依赖(核心算法预编译)

6.2 安装方法

方法一:使用 pip 安装(推荐)

pip install tiktoken

方法二:使用 conda 安装

conda install -c conda-forge tiktoken

方法三:从源码安装(开发用)

git clone https://github.com/openai/tiktoken
cd tiktoken
pip install -e .

验证安装:

python -c "import tiktoken; print(tiktoken.__version__)"

6.3 离线使用配置

tiktoken 在首次使用新编码器时会从网络下载词汇表文件。对于离线环境,需要预先配置:

步骤 1:设置缓存目录

# Linux/macOS
export TIKTOKEN_CACHE_DIR="/path/to/cache/directory"

# Windows (PowerShell)
$env:TIKTOKEN_CACHE_DIR="C:\path\to\cache\directory"

步骤 2:预先下载词汇表

# 在有网络的环境中运行
import tiktoken

# 预下载常用编码器的词汇表
tiktoken.get_encoding("cl100k_base")
tiktoken.get_encoding("o200k_base")

步骤 3:验证离线可用

# 在离线环境中运行
import os
os.environ["TIKTOKEN_CACHE_DIR"] = "/path/to/cache/directory"
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
print(enc.encode("test"))  # 应正常工作

7. Python 使用方法详解

7.1 基本导入与初始化

import tiktoken

# 方式一:通过编码器名称获取
enc = tiktoken.get_encoding("cl100k_base")

# 方式二:通过模型名称自动获取对应编码器(推荐)
enc = tiktoken.encoding_for_model("gpt-4")

# 支持的模型名称示例
models = [
    "gpt-4o",
    "gpt-4o-mini", 
    "gpt-4",
    "gpt-4-turbo",
    "gpt-3.5-turbo",
    "text-embedding-ada-002"
]

for model in models:
    enc = tiktoken.encoding_for_model(model)
    print(f"{model}: {enc.name}")

7.2 文本编码(encode)

encode() 方法将文本字符串转换为 token ID 列表:

import tiktoken

# 初始化编码器
enc = tiktoken.encoding_for_model("gpt-4")

# 编码文本
text = "tiktoken is a great tool for tokenization!"
tokens = enc.encode(text)

print(f"原始文本: {text}")
print(f"Token IDs: {tokens}")
print(f"Token 数量: {len(tokens)}")

输出示例:

原始文本: tiktoken is a great tool for tokenization!
Token IDs: [83, 1609, 5963, 374, 264, 3404, 3376, 369, 7602, 0]
Token 数量: 10

encode() 方法参数:

参数 类型 说明
text str 要编码的文本字符串
allowed_special set 允许的特殊 token 集合
disallowed_special set 禁止的特殊 token 集合

7.3 Token 解码(decode)

decode() 方法将 token ID 列表还原为文本字符串:

import tiktoken

enc = tiktoken.encoding_for_model("gpt-4")

# 编码
text = "Hello, World!"
tokens = enc.encode(text)
print(f"Token IDs: {tokens}")

# 解码
decoded_text = enc.decode(tokens)
print(f"解码文本: {decoded_text}")

# 验证一致性
assert text == decoded_text, "解码结果与原文不一致"

输出示例:

Token IDs: [9906, 11, 4435, 0]
解码文本: Hello, World!

7.4 查看实际 Token 内容

使用 decode_tokens_bytes() 方法查看每个 token 的原始字节内容:

import tiktoken

enc = tiktoken.encoding_for_model("gpt-4")
text = "tiktoken is great!"
tokens = enc.encode(text)

# 查看每个 token 的字节内容
token_bytes = enc.decode_tokens_bytes(tokens)

print("Token 详情:")
for i, (token_id, token_bytes_repr) in enumerate(zip(tokens, token_bytes)):
    try:
        token_str = token_bytes_repr.decode('utf-8')
    except:
        token_str = str(token_bytes_repr)
    print(f"  [{i}] ID: {token_id:6d} → '{token_str}'")

输出示例:

Token 详情:
  [0] ID:     83 → 't'
  [1] ID:   1609 → 'ik'
  [2] ID:   5963 → 'token'
  [3] ID:    374 → ' is'
  [4] ID:   3404 → ' great'
  [5] ID:      0 → '!'

7.5 编码器属性

编码器对象提供多个属性用于获取元信息:

import tiktoken

enc = tiktoken.encoding_for_model("gpt-4")

print(f"编码器名称: {enc.name}")
print(f"词汇表大小: {enc.n_vocab}")
print(f"最大 Token ID: {enc.max_token_value}")

输出示例:

编码器名称: cl100k_base
词汇表大小: 100277
最大 Token ID: 100276

8. 实际应用示例

8.1 计算对话消息的 Token 数量

在使用 ChatGPT API 时,消息格式本身也会占用 token。以下函数展示了如何准确计算:

import tiktoken

def num_tokens_from_messages(messages, model="gpt-4"):
    """
    计算对话消息的 token 数量
    
    Args:
        messages: 消息列表,格式为 [{"role": "user", "content": "..."}]
        model: 模型名称
        
    Returns:
        int: token 总数
    """
    encoding = tiktoken.encoding_for_model(model)
    num_tokens = 0
    
    for message in messages:
        # 每条消息的固定开销(字段分隔符等)
        num_tokens += 4
        
        for key, value in message.items():
            num_tokens += len(encoding.encode(value))
            if key == "name":  # name 字段有额外开销
                num_tokens -= 1
    
    # 对话开始标记
    num_tokens += 2
    
    return num_tokens


# 使用示例
messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello, how are you?"},
    {"role": "assistant", "content": "I'm doing well, thank you for asking!"},
    {"role": "user", "content": "Can you help me with Python?"}
]

total_tokens = num_tokens_from_messages(messages, model="gpt-4")
print(f"对话总 token 数: {total_tokens}")

8.2 成本估算工具

创建一个简单的成本估算工具:

import tiktoken

def estimate_cost(
    text: str, 
    model: str = "gpt-4", 
    input_rate: float = 0.03,  # 美元/1K tokens
    output_rate: float = 0.06   # 美元/1K tokens
) -> dict:
    """
    估算文本处理的 API 成本
    
    Args:
        text: 要处理的文本
        model: 模型名称
        input_rate: 输入 token 每 1000 个的价格(美元)
        output_rate: 输出 token 每 1000 个的价格(美元)
        
    Returns:
        dict: 包含 token 数量和预估成本
    """
    encoding = tiktoken.encoding_for_model(model)
    tokens = encoding.encode(text)
    num_tokens = len(tokens)
    
    input_cost = (num_tokens / 1000) * input_rate
    
    return {
        "token_count": num_tokens,
        "input_cost_usd": round(input_cost, 6),
        "model": model,
        "encoding": encoding.name
    }


# 使用示例
long_text = """
人工智能(Artificial Intelligence,简称 AI)是计算机科学的一个分支,
致力于研究和开发能够模拟、延伸和扩展人类智能的理论、方法、技术及应用系统。
""" * 100

result = estimate_cost(long_text, model="gpt-4")
print(f"Token 数量: {result['token_count']}")
print(f"预估输入成本: ${result['input_cost_usd']}")
print(f"使用编码器: {result['encoding']}")

8.3 文本截断处理

按 token 数量安全截断文本:

import tiktoken

def truncate_text_by_tokens(
    text: str, 
    max_tokens: int, 
    model: str = "gpt-4",
    suffix: str = "..."
) -> str:
    """
    按 token 数量截断文本
    
    Args:
        text: 原始文本
        max_tokens: 最大 token 数量
        model: 模型名称
        suffix: 截断后添加的后缀
        
    Returns:
        str: 截断后的文本
    """
    encoding = tiktoken.encoding_for_model(model)
    tokens = encoding.encode(text)
    
    if len(tokens) <= max_tokens:
        return text
    
    # 预留后缀的 token 空间
    suffix_tokens = encoding.encode(suffix)
    truncated_tokens = tokens[:max_tokens - len(suffix_tokens)]
    
    result = encoding.decode(truncated_tokens) + suffix
    return result


# 使用示例
long_text = "This is a very long text. " * 1000
truncated = truncate_text_by_tokens(long_text, max_tokens=50)

encoding = tiktoken.encoding_for_model("gpt-4")
print(f"截断后 token 数: {len(encoding.encode(truncated))}")
print(f"截断后文本预览: {truncated[:100]}...")

8.4 中英文混合文本处理

处理中英文混合文本:

import tiktoken

def analyze_mixed_language_text(text: str, model: str = "gpt-4") -> dict:
    """
    分析中英文混合文本的分词情况
    
    Args:
        text: 要分析的文本
        model: 模型名称
        
    Returns:
        dict: 分析结果
    """
    enc = tiktoken.encoding_for_model(model)
    tokens = enc.encode(text)
    token_bytes = enc.decode_tokens_bytes(tokens)
    
    # 统计
    chinese_chars = sum(1 for c in text if '\u4e00' <= c <= '\u9fff')
    english_words = len([w for w in text.split() if w.isascii()])
    
    return {
        "text": text,
        "total_chars": len(text),
        "chinese_chars": chinese_chars,
        "english_words": english_words,
        "token_count": len(tokens),
        "tokens_detail": list(zip(tokens, token_bytes)),
        "chars_per_token": round(len(text) / len(tokens), 2)
    }


# 使用示例
chinese_text = "人工智能正在改变世界"
mixed_text = "OpenAI 的 GPT-4 模型非常强大,支持多种语言。"

print("=== 中文文本分析 ===")
result_cn = analyze_mixed_language_text(chinese_text)
print(f"文本: {result_cn['text']}")
print(f"Token 数: {result_cn['token_count']}")
print(f"字符/Token 比: {result_cn['chars_per_token']}")

print("\n=== 混合文本分析 ===")
result_mix = analyze_mixed_language_text(mixed_text)
print(f"文本: {result_mix['text']}")
print(f"Token 数: {result_mix['token_count']}")
print(f"中文字符: {result_mix['chinese_chars']}")
print(f"英文单词: {result_mix['english_words']}")
print(f"字符/Token 比: {result_mix['chars_per_token']}")

9. 局限性与注意事项

9.1 已知局限

局限类型 具体说明 缓解措施
编码器版本 新模型可能使用新编码器,旧版本可能不支持 定期更新 tiktoken 版本
特殊字符 某些罕见 Unicode 字符可能产生较多 token 使用 decode_tokens_bytes() 验证
消息格式 简单的 encode 无法计算消息格式开销 使用专门的计算函数(见 8.1 节)
流式输出 无法实时追踪流式响应的 token 只能事后计算

9.2 常见问题排查

问题 1: 编码结果与 API 返回不一致

可能原因:

  • 使用了错误的编码器
  • 消息格式有额外开销
  • 文本预处理方式不同

解决方案:

# 确保使用正确的编码器
enc = tiktoken.encoding_for_model("gpt-4")  # 使用目标模型名称

# 对于对话,使用专门的计算函数
# 参考 8.1 节的 num_tokens_from_messages 函数

问题 2: 离线环境无法加载编码器

解决方案:

# 方法 1: 设置环境变量
import os
os.environ["TIKTOKEN_CACHE_DIR"] = "/path/to/cachedir"

# 方法 2: 在线预先下载
import tiktoken
tiktoken.get_encoding("cl100k_base")  # 首次会下载并缓存

问题 3: 特殊 token 处理

# 允许特定特殊 token
enc.encode("Hello<|endoftext|>", allowed_special={"<|endoftext|>"})

# 禁止所有特殊 token(遇到时报错)
enc.encode("Hello<|endoftext|>", disallowed_special=())

10. 最佳实践建议

10.1 编码器选择

  1. 始终使用 encoding_for_model()
    • 自动匹配正确的编码器
    • 避免手动指定导致的错误
  2. 复用编码器实例
    • 编码器初始化有开销
    • 在循环中复用同一实例
# ✅ 推荐
enc = tiktoken.encoding_for_model("gpt-4")
for text in texts:
    tokens = enc.encode(text)

# ❌ 不推荐
for text in texts:
    enc = tiktoken.encoding_for_model("gpt-4")  # 每次重新初始化
    tokens = enc.encode(text)

10.2 性能优化

  1. 批量处理优化
    • 使用列表推导式提高效率
    • 避免在循环中频繁调用
# ✅ 高效
enc = tiktoken.encoding_for_model("gpt-4")
token_counts = [len(enc.encode(t)) for t in texts]

# ❌ 低效
token_counts = []
for t in texts:
    enc = tiktoken.encoding_for_model("gpt-4")
    token_counts.append(len(enc.encode(t)))
  1. 内存优化
    • 大文本分块处理
    • 及时释放不需要的变量

10.3 准确性保障

  1. 验证分词结果
    • 定期检查 decode 结果
    • 特别关注特殊字符
# 验证编码-解码一致性
text = "你的文本内容"
tokens = enc.encode(text)
decoded = enc.decode(tokens)
assert text == decoded, f"不一致: {text} vs {decoded}"
  1. 关注版本更新
    • 订阅 GitHub Release
    • 及时更新到新版本

10.4 生产环境建议

# 推荐:封装为可复用模块
class TokenCounter:
    """Token 计算工具类"""
    
    _instances = {}
    
    @classmethod
    def get_encoder(cls, model: str):
        """获取或创建编码器实例(单例模式)"""
        if model not in cls._instances:
            cls._instances[model] = tiktoken.encoding_for_model(model)
        return cls._instances[model]
    
    @classmethod
    def count_tokens(cls, text: str, model: str = "gpt-4") -> int:
        """计算文本 token 数量"""
        enc = cls.get_encoder(model)
        return len(enc.encode(text))
    
    @classmethod
    def count_messages_tokens(cls, messages: list, model: str = "gpt-4") -> int:
        """计算对话消息 token 数量"""
        # 使用 8.1 节的函数
        return num_tokens_from_messages(messages, model)

11. 参考资料

  1. OpenAI. (2022). tiktoken: a fast BPE tokeniser for use with OpenAI’s models. GitHub. https://github.com/openai/tiktoken
  2. OpenAI. (2022). How to count tokens with tiktoken. OpenAI Cookbook. https://developers.openai.com/cookbook/examples/how_to_count_tokens_with_tiktoken
  3. Gage, P. (1994). A New Algorithm for Data Compression. C Users Journal, 12(2), 23-38.
  4. Sennrich, R., Haddow, B., & Birch, A. (2016). Neural Machine Translation of Rare Words with Subword Units. Proceedings of the 54th Annual Meeting of the Association for Computational Linguistics.
  5. OpenAI. (2024). Tokenizer Tool. OpenAI Platform. https://platform.openai.com/tokenizer

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐