The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何使用 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

相關連結

留言評論