はじめに
Crystalのアドベントカレンダーのネタがないので、最近Crystalで作ったツールの紹介をしています。ChatGPTをコマンドラインから使うツールの chatgpt-cliを自分用に作っているのですが、消費したトークン数が表示できないという問題がありました。その問題自体は今も解決できていないのですが、Crystalから GTP-2
のトークン数を表示するという課題はtiktoken-crの作成である程度解決したので記事にします。
背景
今の社会を象徴するAIサービス「ChatGPT」を使ったことがない人はいないと思います。
このChatGPTで重要なのが「トークン」という概念です。ChatGPTは、入力された文章をトークンに分割して、それぞれのトークンに数値を割り当てます。
図:tokenizer で文章をトークンに分割したところ
そうすることでAIは入力と出力を処理することができます。ChatGPTが受け付けることができるトークンの数は決まっています。無料版の GPT-3.5-turboでは、最大4096トークンまで。GPT-4 では 8192トークンまで受け付けることができます。
だから、ChatGPTを利用してプログラムを生成するようなケースではこのトークン数の制限をにらめっこして、すべての処理が8192トークンに収まるようにしなければなりません。
文章とトークンの変換にはいくつかのライブラリがあります。BlingFireや、tokenizer、tiktokenです。このうち、BlingFireはC++で実装されていますが、残りの2つはRustで実装されているため、Crystalから呼び出すのが難しい状況がありました。
BlingFireのバインディングを作ってみた
僕はCrystalから利用できるTokenizerがどうしても欲しかったのでいくつか作ってみました。まず最初にBlingFireのバインディングを作りました。
Tiktokenのバインディングを作ってみた
さて、問題は残りの2つです。どうすればRustを呼び出せるのかわかりませんでした。
そんなときに次のフォーラムを見ました。
CrystalからRustを呼ぶときは、まずRustのライブラリからC言語と互換性のある共有ライブラリを出力して、それをCrystalから呼べばいいということでした。
そこで、まずはtiktokenをRustのライブラリとして利用できるようにした tiktoken のC APIを作成することにしました。Rustについてはほとんど何も知らなかったのですが、ChatGPTに質問&依頼しまくって、tiktoken-rs の C APIを作りました。
さらにこのC APIをRustから呼べるようにした、tiktoken-cr を作成しました。
最後に
Rustのライブラリは増加し続けており、RubyやCrystalといった言語では、Rustのライブラリの資産をどのように活用するべきかということが課題となっています。Rubyでは、magnus というライブラリが開発されています。これはRustとCrystalの型の変換を容易にします。
一方でCrystalからRustを呼び出すことは簡単でなく、一度 C API に落とし込む必要があります。WASMを出力して、WASMランタイムを呼び出せばよいという議論もありますが、この場合も C API を利用する必要があるでしょう。
C言語の「関数呼び出し」を機械語でどのように表現するかルールを定めたものをABIと呼びます。今後はそういった領域も勉強してみたいと思いました。
今回紹介したリポジトリは、あまりテストされていませんので、不具合が残っている可能性はあります。そういったものをプルリクエストで指摘して頂けると嬉しいです。
よいCrystalライフを。この記事は以上です。