如何使用 SharpToken 計算不同 OpenAI 模型在送出提示詞時的 Token 數量

由於大多數 LLM 模型都有 Token 數量的限制,因此我們在開發 Generative AI (GAI) 應用程式時,都會對 Token 的用量斤斤計較,因此我們需要一個可以計算 Token 數量的函式庫,而在 .NET 世界裡 SharpToken 套件不但可以對文字進行編碼(Tokenize)與解碼,還可以用來計算文字的 Token 數量。今天這篇文章我就來介紹這個好用的 NuGet 套件。

generative-ai

瞭解基本背景知識

我一開始看到 SharpToken 的時候,其實不太理解他的用法,因為透過 SharpToken 計算出來的 Token 數量,好像跟 OpenAI 的 Tokenizer 計算結果不太一樣,這讓我十分困惑。

我們先來說說目前 GPT 相關的 API 大致可區分兩大類:

  1. 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)
  2. 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

使用方式

  1. 先引用命名空間

    using SharpToken;
    
  2. 取得 Tokenizer 編碼器

    // 透過編碼名稱取得 GptEncoding 編碼器物件
    var encoding = GptEncoding.GetEncoding("cl100k_base");
    
    // 透過模型名稱取得 GptEncoding 編碼器物件
    var encoding = GptEncoding.GetEncodingForModel("gpt-4");
    
  3. 對文字進行編碼,將字串轉成 Token 型態 (List<int>)

    var encoded = encoding.Encode("Hello, world!"); // Output: [9906, 11, 1917, 0]
    

    中文也都可以正常支援!

  4. 對 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

相關連結

留言評論