在现代自然语言处理中,标记是一种重要的概念,因为它们是语言模型处理文本的基本单元。本教程将向您展示如何使用OpenAI开源的快速分词工具tiktoken来计算文本中的标记数。通过了解文本中有多少标记,您可以:
- 判断文本是否太长以至于超出模型处理的限制。
- 了解使用OpenAI API调用的成本,因为计费是按标记计算的。
1. 引言故事
假设您是一名程序员,正在为自己的聊天应用项目编写代码。您已经集成了一个强大的自然语言处理模型,但现在需要确定用户输入的文本有多少标记,以便确保不会超出模型的限制。在解决这个问题之前,您曾不止一次被意想不到的文本长度问题困扰。一天,您在互联网上发现了一个名为tiktoken的开源工具,它能够快速准确地计算文本中的标记数。这似乎是您解决问题的完美工具,因此您决定深入了解它并开始使用它来解决您的标记计数问题。
2. 安装tiktoken
首先,您需要安装tiktoken工具。您可以使用pip来安装它:
pip install --upgrade tiktoken
安装完成后,您就可以开始使用tiktoken来计算文本中的标记数了。
3. 导入tiktoken
在您的Python项目中,首先导入tiktoken库:
import tiktoken
4. 加载编码
接下来,您需要加载一个编码,以告诉tiktoken如何将文本转换为标记。不同的模型使用不同的编码。在本示例中,我们使用了“cl100k_base”编码,它适用于一些OpenAI模型,包括gpt-4和gpt-3.5-turbo。您可以这样加载编码:
encoding = tiktoken.get_encoding("cl100k_base")
5. 使用编码.encode()方法将文本转换为标记
现在,您可以使用编码对象的.encode()
方法将文本转换为标记。该方法将文本字符串转换为标记的整数列表。例如,如果我们有文本字符串"tiktoken is great!",您可以这样做:
tokens = encoding.encode("tiktoken is great!")
这将返回一个整数列表,代表文本中的标记。在这个示例中,返回的标记列表为[83, 1609, 5963, 374, 2294, 0]
。
要计算文本中的标记数,只需查看标记列表的长度:
num_tokens = len(tokens)
这将给您文本中的标记数,本例中为6个标记。
6. 使用编码.decode()方法将标记转换回文本
如果您需要将标记转换回文本,可以使用编码对象的.decode()
方法。例如,如果我们有标记列表[83, 1609, 5963, 374, 2294, 0]
,您可以这样做:
text = encoding.decode([83, 1609, 5963, 374, 2294, 0])
这将返回文本字符串"tiktoken is great!"。
请注意,虽然.decode()
方法可以应用于单个标记,但对于不在utf-8边界上的标记,它可能会导致信息丢失。对于单个标记,.decode_single_token_bytes()
方法可以安全地将单个整数标记转换为其表示的字节。
7. 比较不同编码
不同编码在分割单词、分组空格和处理非英文字符方面有所不同。使用上述方法,我们可以比较不同编码在几个示例字符串上的效果。以下是一个比较不同编码的函数示例:
def compare_encodings(example_string: str) -> None:
"""打印三种字符串编码的比较结果。"""
# 打印示例字符串
print(f'\n示例字符串: "{example_string}"')
# 对于每个编码,打印标记数、标记整数和标记字节
for encoding_name in ["r50k_base", "p50k_base", "cl100k_base"]:
encoding = tiktoken.get_encoding(encoding_name)
token_integers = encoding.encode(example_string)
num_tokens = len(token_integers)
token_bytes = [encoding.decode_single_token_bytes(token) for token in token_integers]
print()
print(f"{encoding_name}: {num_tokens} 个标记")
print(f"标记整数: {token_integers}")
print(f"标记字节: {token_bytes}")
compare_encodings("antidisestablishmentarianism")
8. 为聊天完成API调用计算标记数
对于像gpt-3.5-turbo和gpt-4这样的ChatGPT模型,它们使用标记方式与较早的完成模型相同,但由于它们基于消息格式,因此更难计算消息将使用多少标记。
以下是一个用于计算传递给gpt-3.5-turbo或gpt-4的消息标记数的示例函数。请注意,从消息中计算标记的方式可能会因模型而异。考虑到下面的函数中计算的标记数量是一个估计值,而不是一个永恒的保证。
def num_tokens_from_messages(messages, model="gpt-3.5-turbo-0613"):
"""返回消息列表使用的标记数。"""
try:
encoding
= tiktoken.get_encoding(model)
except Exception as e:
print(f"获取编码时发生错误:{e}")
return None
total_tokens = 0
for message in messages:
tokens = encoding.encode(message["content"])
num_tokens = len(tokens)
# 添加额外的标记以表示用户或系统角色
if message["role"] == "system":
num_tokens += 1
else:
num_tokens += 2 # 一个用于角色,一个用于分隔符
total_tokens += num_tokens
return total_tokens
# 示例消息列表
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me a joke."},
{"role": "assistant", "content": "Why did the chicken cross the road?"},
{"role": "user", "content": "I don't know, why did the chicken cross the road?"}
]
total_tokens = num_tokens_from_messages(messages, model="gpt-3.5-turbo-0613")
print(f"消息列表中的总标记数:{total_tokens}")
这个函数可以帮助您估算给定消息列表的标记数,以便控制文本长度和计费。请注意,不同模型的标记数限制可能会有所不同,因此在实际使用中请谨慎估算。