多くのチームは、依然として同じ方法で最初の検索パイプラインを構築しています。固定のトークン制限(例えば512など)を設定し、ドキュメントを均一なブロックに分割して、それらのブロックをベクトルデータベースに投入するのです。小規模なデータセットで単純な質問を扱う場合は、これで魔法のように機能します。しかし、本番環境では破綻します。
条項が文章の途中で切断されると、法的契約書は意味のない断片へとバラバラになります。単一のチャンクが3つの無関係な関数を飲み込んでしまうと、APIドキュメントはノイズだらけの「スープ」と化します。セグメント間にオーバーラップがないと、カスタマーサポートのチケットは文脈を完全に失います。その結果は予測通りです。レイテンシの増大、リコールの低下、そして生成器がハルシネーションを起こさざるを得なくなる回答です。
私たちは検索レイヤーを解体し、再構築しました。その結果、リコールは78%から95%へと跳ね上がり、レイテンシは62%削減され、週末のハックではなく、真のインフラとして機能するパイプラインへと進化しました。以下に、実際に効果があった手法を紹介します。
スマート・チャンキング:トークンよりも構造を重視
最初の間違いは、すべてのドキュメントが同じ言語で書かれていると思い込むことです。512トークンのチャンクが意味をなすのは物語的な散文だけで、それ以外ではほとんど役に立ちません。私たちは、ソースの構造を尊重する戦略へと移行しました。
法的文書には、再帰的チャンキング(recursive chunking)を使用します。このアルゴリズムは、まずセクションや条項といった高レベルの境界で分割を試みます。セクションがまだ長すぎる場合は、サブセクション、段落、そして文の順に探していきます。これにより、条項の論理的な入れ子構造が維持されます。競業避止義務契約はそのままの形で保たれ、定義事項が免責条項に混ざり込むこともありません。
APIドキュメントには、構造を意識したチャンキング(structure-aware chunking)が求められます。関数のシグネチャ、パラメータテーブル、およびリクエスト例は、セットであるべきです。固定のトークン数で分割すると、パラメータが1つのチャンクに、例が別のチャンクに残ってしまうことがよくあります。代わりに、ドキュメントオブジェクト単位でチャンク化します。1つのチャンクに、完全なエンドポイントまたは単一の関数を収めます。これにより、リトリーバーは質問に実際に答えることができる、自己完結したリファレンスを返すことが可能になります。
サポートチケットには、セマンティック・チャンキング(semantic chunking)が自然に適合します。トークンの境界で切るのではなく、トピックが切り替わる箇所を検出します。ログインの苦情から始まり、請求に関する質問へと転換するチケットは、2つの首尾一貫した断片に分割されます。各断片が必要なメタデータを保持するため、モデルはユーザーが実際にどの問題を気にしているのかを推測する必要がなくなります。
社内Wikiはより複雑です。散文、テーブル、図解、埋め込まれたスレッドが混在しています。これらには、エージェンティック・チャンキング(agentic chunking)を使用します。小型言語モデルが先読みを行い、テーマ的に完結したユニットがどこで終わるかを判断します。取り込み時のコストは多少上がりますが、新しいページ形式ごとにルールを手動で調整するという、人間による煩雑な作業を排除できます。
ハイブリッド検索:あらゆるケースをカバーする
ベクトル検索は、曖昧な意味を捉えることに長けています。「アップロードが遅い」と尋ねれば、レイテンシや帯域幅に関する段落を喜んで返してくれます。しかし、完全一致の扱いに弱いことで有名です。開発者がエラーコード ERR_CONNECTION_REFUSED を検索した場合、高密度な埋め込み(dense embeddings)は、それを単なる一般的なノイズとして扱ってしまうことがよくあります。
古典的なキーワードアルゴリズムであるBM25は、その逆を行います。正確な文字列や希少な用語を確実に捉えますが、意味的なニュアンスを見落とします。「契約への署名」に関するクエリでは、「契約の実行(executing the contract)」というタグが付いたコンテンツがヒットしない可能性があります。
