GPT-tokenizer
gpt-tokenizer
是一个高度优化的 Token Byte Pair 编码器/解码器,适用于所有 OpenAI 的模型(包括 GPT-2、GPT-3、GPT-3.5、GPT-4 和 GPT-4o)。它是用 TypeScript 编写的,完全兼容所有现代 JavaScript 环境。
这个包是 OpenAI 的 tiktoken 的一个移植,并且在此基础上增加了一些新功能。
OpenAI 的 GPT 模型利用字节对编码来将文本转换为整数序列,然后将其输入到模型中。
截至 2023 年,这是 NPM 上功能最全的开源 GPT 分词器。它实现了一些独特的功能,如:
- 通过
encodeChat
函数轻松对聊天内容进行分词 - 支持所有当前的 OpenAI 模型(可用编码:
r50k_base
、p50k_base
、p50k_edit
、cl100k_base
和o200k_base
) - 编码器和解码器函数的生成器版本
- 能够解码数据的异步流(使用
decodeAsyncGenerator
和decodeGenerator
处理任何可迭代输入) - 没有全局缓存(无意外的内存泄漏,如原始 GPT-3-Encoder 实现那样)
- 包含一个高性能的
isWithinTokenLimit
函数,用于在不编码整个文本/聊天的情况下评估 token 限制 - 通过消除传递数组提高整体性能
- 类型安全(用 TypeScript 编写)
- 开箱即用的浏览器支持
特别感谢 @dmitry-brazhenko 的 SharpToken,其代码作为该移植的参考。
历史注释:这个包最初是 latitudegames/GPT-3-Encoder 的一个分支,但 2.0 版本是从头开始重写的。
安装
作为 NPM 包
npm install gpt-tokenizer
作为 UMD 模块
<script src="https://unpkg.com/gpt-tokenizer"></script>
<script>
// 这个包现在可以作为一个全局变量使用:
const { encode, decode } = GPTTokenizer_cl100k_base
</script>
如果你希望使用自定义编码,请获取相关的脚本。
- https://unpkg.com/gpt-tokenizer/dist/cl100k_base.js
- https://unpkg.com/gpt-tokenizer/dist/p50k_base.js
- https://unpkg.com/gpt-tokenizer/dist/p50k_edit.js
- https://unpkg.com/gpt-tokenizer/dist/r50k_base.js
- https://unpkg.com/gpt-tokenizer/dist/o200k_base.js
全局名称是连接形式:GPTTokenizer_${encoding}
。
有关更多信息,请参阅支持的模型及其编码部分。
操作平台
操作平台以一个易记的网址发布:https://gpt-tokenizer.dev/
您可以在浏览器中使用 Playground 测试这个包。
操作平台模拟官方的 OpenAI Tokenizer。
用法
import {
encode,
encodeChat,
decode,
isWithinTokenLimit,
encodeGenerator,
decodeGenerator,
decodeAsyncGenerator,
} from 'gpt-tokenizer'
// 注意:根据模型,从相应的文件导入,例如:
// import {...} from 'gpt-tokenizer/model/gpt-4o'
const text = 'Hello, world!'
const tokenLimit = 10
// 将文本编码为 tokens
const tokens = encode(text)
// 将 tokens 解码为文本
const decodedText = decode(tokens)
// 检查文本是否在 token 限制内
// 如果超过限制,则返回 false,否则返回实际的 token 数量(真值)
const withinTokenLimit = isWithinTokenLimit(text, tokenLimit)
// 示例如下:
const chat = [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'assistant', content: 'gpt-tokenizer is awesome.' },
] as const
// 将聊天内容编码为 tokens
const chatTokens = encodeChat(chat)
// 检查聊天内容是否在 token 限制内
const chatWithinTokenLimit = isWithinTokenLimit(chat, tokenLimit)
// 使用生成器对文本进行编码
for (const tokenChunk of encodeGenerator(text)) {
console.log(tokenChunk)
}
// 使用生成器对 tokens 进行解码
for (const textChunk of decodeGenerator(tokens)) {
console.log(textChunk)
}
// 使用异步生成器对 tokens 进行解码
// (假设 `asyncTokens` 是一个 AsyncIterableIterator<number>)
for await (const textChunk of decodeAsyncGenerator(asyncTokens)) {
console.log(textChunk)
}
默认情况下,从 gpt-tokenizer
导入时使用的是 cl100k_base
编码,适用于 gpt-3.5-turbo
和 gpt-4
。
要获取适用于不同模型的分词器,请直接导入,例如:
import {
encode,
decode,
isWithinTokenLimit,
} from 'gpt-tokenizer/model/text-davinci-003'
如果您使用的解析器不支持 package.json 的 exports
解析,则可能需要从相应的 cjs
或 esm
目录导入,例如:
import {
encode,
decode,
isWithinTokenLimit,
} from 'gpt-tokenizer/cjs/model/text-davinci-003'
支持的模型及其编码
聊天:
gpt-4-32k
(cl100k_base
)gpt-4-0314
(cl100k_base
)gpt-4-32k-0314
(cl100k_base
)gpt-3.5-turbo
(cl100k_base
)gpt-3.5-turbo-0301
(cl100k_base
)gpt-4o
(o200k_base
)
注意:如果您使用的是 gpt-3.5-*
或 gpt-4-*
且未找到所需的模型,请直接使用 cl100k_base
编码。
仅限文本:
text-davinci-003
(p50k_base
)text-davinci-002
(p50k_base
)text-davinci-001
(r50k_base
)text-curie-001
(r50k_base
)text-babbage-001
(r50k_base
)text-ada-001
(r50k_base
)davinci
(r50k_base
)curie
(r50k_base
)babbage
(r50k_base
)ada
(r50k_base
)
代码:
code-davinci-002
(p50k_base
)code-davinci-001
(p50k_base
)code-cushman-002
(p50k_base
)code-cushman-001
(p50k_base
)davinci-codex
(p50k_base
)cushman-codex
(p50k_base
)
编辑:
text-davinci-edit-001
(p50k_edit
)code-davinci-edit-001
(p50k_edit
)
嵌入:
text-embedding-ada-002
(cl100k_base
)
旧嵌入:
text-similarity-davinci-001
(r50k_base
)text-similarity-curie-001
(r50k_base
)text-similarity-babbage-001
(r50k_base
)text-similarity-ada-001
(r50k_base
)text-search-davinci-doc-001
(r50k_base
)text-search-curie-doc-001
(r50k_base
)text-search-babbage-doc-001
(r50k_base
)text-search-ada-doc-001
(r50k_base
)code-search-babbage-code-001
(r50k_base
)code-search-ada-code-001
(r50k_base
)
API
encode(text: string): number[]
将给定文本编码为一系列标记。需要将文本转换为GPT模型可以处理的标记格式时使用此方法。
示例:
import { encode } from 'gpt-tokenizer'
const text = 'Hello, world!'
const tokens = encode(text)
decode(tokens: number[]): string
将一系列标记解码回文本。当你想将GPT模型的输出标记转回为人类可读文本时使用此方法。
示例:
import { decode } from 'gpt-tokenizer'
const tokens = [18435, 198, 23132, 328]
const text = decode(tokens)
isWithinTokenLimit(text: string, tokenLimit: number): false | number
检查文本是否在标记限制内。如果超出限制,则返回false
,否则返回标记数。使用此方法可以快速检查给定文本是否在GPT模型施加的标记限制内,而不需要对整个文本进行编码。
示例:
import { isWithinTokenLimit } from 'gpt-tokenizer'
const text = 'Hello, world!'
const tokenLimit = 10
const withinTokenLimit = isWithinTokenLimit(text, tokenLimit)
encodeChat(chat: ChatMessage[], model?: ModelName): number[]
将给定聊天内容编码为一系列标记。
如果没有直接导入模型版本,或者初始化时没有提供model
,则必须在此提供以便正确地为特定模型标记化聊天内容。当需要将聊天内容转换为GPT模型可以处理的标记格式时使用此方法。
示例:
import { encodeChat } from 'gpt-tokenizer'
const chat = [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'assistant', content: 'gpt-tokenizer is awesome.' },
]
const tokens = encodeChat(chat)
encodeGenerator(text: string): Generator<number[], void, undefined>
使用生成器对给定文本进行编码,生成标记块。当你希望按块编码文本时使用此方法,这在处理大文本或流数据时尤其有用。
示例:
import { encodeGenerator } from 'gpt-tokenizer'
const text = 'Hello, world!'
const tokens = []
for (const tokenChunk of encodeGenerator(text)) {
tokens.push(...tokenChunk)
}
encodeChatGenerator(chat: Iterator<ChatMessage>, model?: ModelName): Generator<number[], void, undefined>
与encodeChat
相同,但使用生成器作为输出,并且可以使用任何迭代器作为输入chat
。
decodeGenerator(tokens: Iterable<number>): Generator<string, void, undefined>
使用生成器解码一系列标记,生成解码文本块。当你希望按块解码标记时使用此方法,这在处理大量输出或流数据时尤其有用。
示例:
import { decodeGenerator } from 'gpt-tokenizer'
const tokens = [18435, 198, 23132, 328]
let decodedText = ''
for (const textChunk of decodeGenerator(tokens)) {
decodedText += textChunk
}
decodeAsyncGenerator(tokens: AsyncIterable<number>): AsyncGenerator<string, void, undefined>
使用生成器异步解码一系列标记,生成解码文本块。当你希望在异步环境中按块解码标记时使用此方法,这在处理大量输出或流数据时特别有用。
示例:
import { decodeAsyncGenerator } from 'gpt-tokenizer'
async function processTokens(asyncTokensIterator) {
let decodedText = ''
for await (const textChunk of decodeAsyncGenerator(asyncTokensIterator)) {
decodedText += textChunk
}
}
特殊标记
GPT模型使用一些特殊标记。并非所有模型都支持所有这些标记。
自定义允许集
gpt-tokenizer
允许你在编码文本时指定自定义的允许特殊标记集。为此,将包含允许的特殊标记的Set
作为参数传递给encode
函数:
import {
EndOfPrompt,
EndOfText,
FimMiddle,
FimPrefix,
FimSuffix,
ImStart,
ImEnd,
ImSep,
encode,
} from 'gpt-tokenizer'
const inputText = `一些文本 ${EndOfPrompt}`
const allowedSpecialTokens = new Set([EndOfPrompt])
const encoded = encode(inputText, allowedSpecialTokens)
const expectedEncoded = [8538, 2991, 220, 100276]
expect(encoded).toBe(expectedEncoded)
自定义不允许集
同样,你可以在编码文本时指定自定义的不允许特殊标记集。将包含不允许特殊标记的Set
作为参数传递给encode
函数:
import { encode } from 'gpt-tokenizer'
const inputText = `一些文本`
const disallowedSpecial = new Set(['Some'])
// 抛出一个错误:
const encoded = encode(inputText, undefined, disallowedSpecial)
在此示例中,会抛出一个错误,因为输入文本包含了一个不允许的特殊标记。
测试与验证
gpt-tokenizer
包含在TestPlans.txt文件中的一组测试用例,以确保其与OpenAI的Python tiktoken
库的兼容性。这些测试用例验证了gpt-tokenizer
的功能和行为,为开发者提供了可靠的参考。
运行单元测试并验证测试用例有助于保持库与原始Python实现之间的一致性。
许可证
MIT
贡献
欢迎贡献!请提交一个拉取请求或问题来讨论你的错误报告,或使用讨论功能来提出想法或任何其他问题。
希望你在项目中发现gpt-tokenizer
的有用之处!