3月のとある火曜日朝、あるCEOが投げかけた質問は、本来なら30秒で答えが出るはずだった:これまで100万ドルを下回る責任上限に合意したことはあるか?

答えは確かに存在した。文書化され、署名され、ファイリングされ、ずっと共有ドライブに保存されていた。それを探し出すのに3日かかり、見つからなかったせいで4万ドルの損失を被った。

どの組織にも「その火曜日」は存在する。知識は実在し、生き続け、100種類のフォーマットで100万ものファイルに散在し、キャビネットに最も近かった人が整理したままになっている。組織は、そこにいる誰よりも多くのことを知っている。難しいのは、それを引き出すことだ。

キーワード検索が失敗する、具体的で修正可能な理由

最初に思いつく修正策は、すべての単語をインデックス化して検索することだ。「liability cap」と入力すれば、「liability」と「cap」を含むすべての文書が返ってくる。しかしこれは失敗する。しかも、その失敗の仕方が重要なので、正確に名指しする価値がある。なぜなら、それぞれの失敗が本当の修正策が何をすべきかを指し示すからだ。

契約書には「liability cap」とは書かれていない。「limitation of liability」と書かれている。2つのフレーズ、1つの意味、共通のキーワードはゼロ。検索は何も返さず、その文書は存在しないと結論づけてしまう。検索バーは「そんな契約はない」と「違う言葉でファイリングされている」との違いを区別できない。

単語の一致は意味の一致ではない。 従業員ハンドブックとサプライヤー契約書で「termination」を検索すると、解雇、契約満了、ソフトウェアライセンスの終了に関する段落などが返ってくるが、並び順は単語の出現頻度以外に意味を持たない。

人が尋ねるのは質問であってキーワードではない。誰も検索語で考えていない。「100万ドルを下回る責任上限に合意したことはあるか?」と考える。キーワードエンジンは、これが質問であることすら理解せず、ましてやどの単語が重要かも知らない。

実際にギャップを埋めるもの

修正策は、単語の比較をやめて意味の比較を始めることだ。そのためには、テキストを「距離を測れる何か」に変換する必要がある。

埋め込みモデルは文章を読み、数値のリスト(数百個程度)を返し、その文章を「距離=意味の類似度」を表す空間に配置する。有給休暇に関する文章は互いに近くに配置され、責任上限に関する文章はまったく別の場所に配置される。モデルは文字の共通性ではなく、言語の実際の使われ方に基づいて配置する。

python
from sentence_transformers import SentenceTransformer

model = SentenceTransformer("all-MiniLM-L6-v2")

texts = [
    "4.2 Annual Leave\nFull-time employees accrue fifteen (15) days...",
    "Remote Work Policy > Schedule\nUp to three (3) days per week...",
    "Appendix B\nLodging: $180 per night, booked via travel portal.",
]
vectors = model.encode(texts)
print(vectors.shape)  # (3, 384): three texts, one map, 384 coordinates each

Enter fullscreen mode Exit fullscreen mode

ここからが面白い部分だ。「従業員は初年度に何日の有給休暇を取得できるか?」という質問を同じ空間に埋め込むと、年次休暇に関する文章の近くに配置される。その文章には「vacation」という単語は一度も登場しない。キーワード検索が落ちていた隙間は、まさにこのステップで閉じられる。2つの表現が同じ意味を持つからであり、モデルが注意を払っていた唯一のポイントだからだ。

そのモデルは80MBだ。ノートPC上でGPUやAPIキーなしで動作する。これは思った以上に重要だ。企業向けAIで最初に問われる深刻な質問は「どのモデルが最高か」ではなく、「私のデータはどこへ行くことを許されるか」だからだ。ローカルで動作するモデルは、その質問に「どこにも行かない」と答える。

誰も警告してくれない部分

チュートリアルが省略しているのはこれだ。埋め込みを行う前に、まずテキストを取り出さなければならないが、アーカイブは抵抗してくる。

PDFは文書ではない。文字の形を生み出す一連の描画命令であり、テキストを要求しても拒否される場合がある。スプレッドシートは仮装したデータベースだ。文字列に平坦化すると、何を指しているのかわからない数字の列が得られる。1994年のスキャンされた契約書にはテキストレイヤーが一切なく、紙の写真しかない。素朴なパイプラインは空文字列を返して次のファイルに進み、結果としてアーカイブで最も重要な文書が不可視化される。

そして、テキストを抽出したら、それを断片に分割しなければならない。500文字で素朴に切ると、文の途中で単語が分断され、「during thei」から始まる何も答えられないチャンクが生まれる。文書の本来の区切りで切り、見出しを保持すれば、同じ文章が司書が「ファイリングされた」と認識できるものになる。

これらはどれも「面白いAI」の部分ではない。しかし、面白いAIの部分が機能するかどうかをすべて決定する。

詳細版を読みたい場合
私はこれをゼロから構築する方法について本を書いた。架空の240人規模の製造業者が、フォルダー内の単一PDFから、章ごとに実用的な検索システムを構築する過程を追っている。印刷されたコード行はすべて、印刷前に実際に実行された。

第1章は無料で、コード不要で問題全体を説明している:https://leanpub.com/learn2rag