由於大多數 LLM 模型都有 Token 數量的限制,因此我們在開發 Generative AI (GAI) 應用程式時,都會對 Token 的用量斤斤計較,因此我們需要一個可以計算 Token 數量的函式庫,而在 .NET 世界裡 SharpToken 套件不但可以對文字進行編碼(Tokenize)與解碼,還可以用來計算文字的 Token 數量。今天這篇文章我就來介紹這個好用的 NuGet 套件。
瞭解基本背景知識
我一開始看到 SharpToken 的時候,其實不太理解他的用法,因為透過 SharpToken 計算出來的 Token 數量,好像跟 OpenAI 的 Tokenizer 計算結果不太一樣,這讓我十分困惑。
我們先來說說目前 GPT 相關的 API 大致可區分兩大類:
-
Chat completions API
Chat completions API 是一種透過一系列的往返訊息對話當作輸入,並由模型產生回應訊息的一種 AI 完成模式,是新一代的對話式 AI 模型。
常見的模型包括:
- GPT-4
gpt-4
(上限 8,192 tokens)
gpt-4-32k
(上限 32,768 tokens)
- GPT-3.5
gpt-3.5-turbo
(上限 4,097 tokens)
gpt-3.5-turbo-16k
(上限 16,385 tokens)
-
Completions API (Legacy)
Completions API 的最後更新時間為 2023 年的 7 月,算是早期的 AI 模型,與 Chat completions API 有著截然不同的呼叫方式,這種呼叫方式並非提供一系列的對話,而是透過自由輸入的文字(freeform text)來進行提問(Prompt),市面上許多 Prompt engineering (提示工程) 的技巧,大多是針對 Completions API 為主。不過大多 Prompt engineering (提示工程) 的技巧,通常也適用在 Chat completions API 模式上。
常見的模型包括:
- GPT-3.5
text-davinci-003
(上限 4,097 tokens)
text-davinci-002
(上限 4,097 tokens)
關於 OpenAI 的完整模型清單可以參見 OpenAI API Models
安裝 SharpToken 套件 (NuGet)
-
透過 NuGet package manager 安裝:
Install-Package SharpToken
-
透過 .NET CLI 安裝:
dotnet add package SharpToken
套件網址 ▶ https://www.nuget.org/packages/SharpToken
使用方式
-
先引用命名空間
using SharpToken;
-
取得 Tokenizer 編碼器
// 透過編碼名稱取得 GptEncoding 編碼器物件
var encoding = GptEncoding.GetEncoding("cl100k_base");
// 透過模型名稱取得 GptEncoding 編碼器物件
var encoding = GptEncoding.GetEncodingForModel("gpt-4");
-
對文字進行編碼,將字串轉成 Token 型態 (List<int>
)
var encoded = encoding.Encode("Hello, world!"); // Output: [9906, 11, 1917, 0]
中文也都可以正常支援!
-
對 Token 進行解碼,將 Token 轉回字串
var decoded = encoding.Decode(encoded); // Output: "Hello, world!"
用法非常簡單對吧,就單純的「編碼」與「解碼」而已,使用方式就跟 Base64 一樣簡單!
解決疑惑之處
目前 SharpToken
支援以下編碼器:
r50k_base
p50k_base
p50k_edit
cl100k_base
老實說,SharpToken 官網並沒有特別說明這幾個編碼要在何時使用,範例也只有寫到 gpt-4
, gpt-3.5-turbo
而已,且這兩個模型剛好都是使用 Chat Completions API
,支援的 Encoding 為 cl100k_base
編碼器!
所以我一開始拿 cl100k_base
編碼器來對任意文字作編碼,轉成 Token 的形式後 (List<int>
),理論上直接看他產生幾個 int
元素,就知道有幾個 Token 才對,但我怎樣算都跟 OpenAI 的 Tokenizer 計算出來的 Token 數量不一樣,這讓我十分困惑。
舉個例子來說,我用 多奇數位創意有限公司
這段中文來進行編碼:
- SharpToken 透過
cl100k_base
編碼器編碼後,會產生 12 個 Tokens
- OpenAI 的 Tokenizer 則會產生 21 個 Tokens
這兩邊差異蠻大的!
經研究後發現,原來 OpenAI 的 Tokenizer 網頁所採用的編碼器,其實是 Completions API 的版本,也就是 p50k_base
這個編碼器,難怪我怎樣算都不太對!
想想其實也覺得合理,因為 ChatGPT 剛出來的時候就推出了 Tokenizer 網頁,之後推出了 ChatGPT 就沒有再推出新版的 Tokenizer 線上工具了。
另外,你可以發現 cl100k_base
編碼器編碼出來的 Token 數量少很多,這同時也意味著採用 cl100k_base
編碼器其實比較省錢,成本比較低!
我之前寫的翻譯工具,選用的模型是 text-davinci-003
,所以我把程式改寫一下,不要寫死 encodingName
,直接拿 modelName
來取得 encodingName
即可萬無一失,計算過程也就正確無誤了!
// cl100k_base
//var encodingName = SharpToken.Model.GetEncodingNameForModel("gpt-35-turbo");
//var encodingName = SharpToken.Model.GetEncodingNameForModel("gpt-4");
// p50k_base
var encodingName = SharpToken.Model.GetEncodingNameForModel("text-davinci-003");
// Get encoding by encoding name
var encoding = GptEncoding.GetEncoding(encodingName);
var str = "多奇數位創意有限公司";
var encoded = encoding.Encode(str);
var decoded = encoding.Decode(encoded);
// 取得編碼後的 Token 總數
var token_count = encoded.Count
相關連結
- dmitry-brazhenko/SharpToken: SharpToken is a C# library for tokenizing natural language text. It's based on the tiktoken Python library and designed to be fast and accurate.
- OpenAI API