はじめに
こんにちは、DROBE の都筑です。
みなさん LLM 使っていますか。今回は LLM を利用して長文から構造化データを抽出する手法について記載します。
構造化データの抽出
LLM を利用して構造化データを抽出することを Extraction と呼びます。 Extraction は以下のようなユースケースが考えられます。
- テキスト情報から構造化したデータを抽出し DB にインサートする
- 外部 API を呼ぶために入力を解釈してパラメータを抽出する
Extraction は非常に有用ですが、元となるテキストの最大長は利用する LLM の最大 token 数に依存します。
LLM と長文の処理
長文を LLM で扱うユースケースとしては文章要約がアプリケーションとして想定されることが多く、いくつかの方法が考案されています。LangChain の公式ドキュメントを覗くと、以下の 3 つの手法が提案されていました。
Stuff
Map-Reduce
Refine
1 つめの Staff とは単純に全入力を LLM に突っ込むという手法です。2023年9月現在、最も手軽に使える OpenAI の gpt3.5-turbo では最大 16k token が使えるのでそれで充分であれば特に難しいことを考える必要はありません。また anthropic 社の Claude2 など 100k token に対応しているモデルも登場しており、近い将来 token の事を気にする必要はなくなりそうです。
2 つめの Map-Reduce は、入力をチャンクに分割しそれぞれに対して要約、最後に全ての要約を入力として一つの要約に纏めるというものです。Map-Reduce という名前でピンとくる方もいると思いますが、この手法は処理を並列化できて後述の Refine に比べて高速に動かすことが出来るという利点があります。
3 つめの Refine は、入力をチャンクに分割し、順番に要約をしていくのですが、最初のチャンクの要約を次のチャンクの要約時に入力として一緒に与えてあげるということをします。この手法では直前のチャンクの要約結果を待たないと次のチャンクの要約を行えないので処理を並列化することが出来ずに遅くなりますが、Map-Reduce に比べて内容をより正確に要約できるとのことです。
長文データから構造化データを抽出する手法
DROBE では長文のデータからタグを抽出して DB に保存する、というタスクを行おうとしていますが、LangChain の思想を参考にして以下のようなデータパイプラインを設計しました。
以下が大まかなステップです。
- 文章をチャンクに分割する
- 分割された文章からタグを抽出する
- 抽出されたタグをマージしユニークな配列にする
最初のステップとして長文のデータをチャンクに分割していますが、これにより token 数がすくない LLM でも情報の抽出が可能になります。チャンクへの分割は一見簡単なように見えて難解なトピックです。一般的には以下のような挙動が期待されます。
- 文章の意味が失われないように分割を行う
- 分割されたチャンクを指定したサイズを超えるまで結合していく
- チャンクが指定サイズに達したら、次のチャンクを作る
この処理は、日本語の場合はなかなか難しい問題です。普通に実装する難易度が高いと考え、今回は Text Split は gpt3.5 にやらせることにしました。精度の必要なタグの抽出は gpt4 にやらせ、分割はより多くの token を扱える gpt3.5 で行うといった工夫です。
ちなみに、LangChain では TextSplitter というクラスが用意されています。
実装を覗いてみると、正規表現などを使った Splitter の他に、 all-mpnet-base-v2
model を利用した splitter も準備されていました。
英語であれば LangChain が準備してくれている Splitter を使ってみると良さそうに思いました。
おわりに
長文のデータから構造化データを取得する方法を紹介しました。LLM の進化によりこういった手法などはいずれ必要なくなると考えていますが、現時点ではまだまだ扱える token サイズに制限があるためにこういったやりかたを考える必要があります。同じように困っている方の参考になれば幸いです。