問題:RAGが追いつかない
ナレッジベースは検索が高速でなければ役に立ちません。JieGouでRAGサポートをリリースした当初、パイプラインは動作していました — ドキュメントはチャンク分割され、エンベディングが生成され、プロンプトに注入されていました。しかし、パフォーマンスの数字は別の現実を示していました。
705件のドキュメントを持つナレッジベースで、関連するコンテキストの取得に約160秒かかっていました。つまり、ナレッジベースを使用するすべてのrecipe実行、すべてのworkflowステップ、すべてのagent会話が、LLMが生成を開始する前に数分の遅延を払わなければなりませんでした。
インタラクティブなユースケース — カスタマーサポート担当者がポリシーを調べる、営業担当者が会話中に製品スペックを取得する — 160秒は致命的です。
インフラの複雑さを増やすことなく、検索時間を1秒未満に短縮する必要がありました。
フェーズ1:Firestoreネイティブベクトル検索
元の検索アプローチは、Firestoreからすべてのエンベディングを読み込み、アプリケーションコードでコサイン類似度を計算し、top-kの結果を返すというものでした。シンプルで正確でしたが、ドキュメント数に対して線形にスケールしていました。
最初の最適化は、Firestore Vector Search(ScaNNインデキシングベース)を使って、類似度検索をFirestore自体に移すことでした。705個のエンベディングをすべてメモリに取り込んで距離を計算する代わりに、Firestoreにネイティブで最近傍検索を処理させます。
変更点
- 最適化前:すべてのエンベディングを取得 → Node.jsでコサイン類似度を計算 → ソート → top-kを取得
- 最適化後:
findNearest()による単一のFirestoreクエリ → top-kを直接返却
これにより、O(n)のデータ転送と計算が排除されました。Firestoreのベクトルインデックスは近似最近傍法を使用しており、わずかな再現率の低下と引き換えに、大規模コレクションでの大幅な速度向上を実現します。
結果
705件のドキュメントでのコールドクエリが約160秒から約10秒に低下。16倍の改善 — しかし、インタラクティブなワークフローにはまだ遅すぎました。
フェーズ2:フォールバック付きハイブリッド検索
すべてのクエリがベクトル検索から同等の恩恵を受けるわけではありません。ブルートフォースの方がベクトルインデックスクエリのオーバーヘッドより速い小規模なナレッジベースもあります。エンベディングに適さないドキュメント(テーブル、コードスニペット、構造化データ)もあります。
私たちはハイブリッド検索戦略を実装しました:
- まずベクトル検索を試行 — Firestoreベクトルインデックスが存在し、ナレッジベースにエンベディングがある場合、
findNearest()を使用 - ブルートフォースにフォールバック — ベクトル検索が失敗、利用不可、または結果が少なすぎる場合、エンベディングを読み込んでアプリケーションコードで類似度を計算
- マージと重複排除 — 両方のパスからの結果を結合し、ドキュメントIDで重複排除、類似度スコアで再ランキング
ハイブリッドアプローチにより、検索は決して失敗しません。Firestoreベクトルインデックスがまだ作成されていない場合(例:新しくプロビジョニングされた環境)、システムは元のブルートフォースパスに優雅にデグレードします。
usedVectorSearch フラグ
すべての検索操作は、トレースspanに usedVectorSearch ブール値を含むようになりました。これにより、どのクエリが高速パスを使用し、どれがフォールバックしているかを監視し、インデックス作成や再エンベディングが必要なナレッジベースを特定できます。
フェーズ3:ウォームクエリのRedisキャッシュ
最後の最適化はリピートクエリ — 短い時間窓内で同じナレッジベースに対して同じ質問をするケースをターゲットにしています。これは本番環境で常に発生します:
- 複数のworkflowステップが同じFAQナレッジベースにクエリ
- agent会話が毎ターン、コンテキストを再取得
- バッチ実行で50アイテムが同一の参照ドキュメントにクエリ
TTL 10分のドキュメント単位のRedisキャッシュを追加しました:
- 類似度検索を実行する前に、
(knowledgeBaseId, queryEmbeddingHash)をキーとしてRedisのキャッシュを確認 - キャッシュヒット時は即座に返却 — Firestoreクエリは一切不要
- キャッシュミス時はハイブリッド検索パイプラインを実行し、結果をキャッシュ
結果
| シナリオ | 最適化前 | 最適化後 |
|---|---|---|
| コールドクエリ、705件 | 約160秒 | 約10秒 |
| ウォームクエリ(Redisヒット) | 約160秒 | <1秒 |
| 小規模KB(<50件) | 約5秒 | 約2秒 |
| バッチ50件、同一KB | 合計約8,000秒 | 約10秒 + 49回 <1秒 |
バッチシナリオがキャッシュの最大の効果を発揮する場面です。最初のアイテムがコールドクエリのコストを負担し、残りの49アイテムはRedisにヒットしてミリ秒で返ります。
アーキテクチャ:外部依存ゼロ
重要な設計制約は追加インフラなしでした。多くのRAGプラットフォームでは、専用のベクトルデータベース — Pinecone、Weaviate、Qdrant、Milvus — のプロビジョニングと管理が必要です。それぞれが以下を追加します:
- デプロイと監視が必要なもう一つのサービス
- 管理が必要なもう一組の認証情報
- もう一つのベンダーの課金項目
- パイプラインにおけるもう一つの障害点
JieGouのアプローチは、すでに持っているインフラのみを使用します:
| コンポーネント | 用途 | 既存? |
|---|---|---|
| Firestore | ベクトルインデックス + ドキュメントストレージ | ✅ プライマリデータベース |
| Redis | クエリ結果キャッシュ | ✅ レート制限やセッションで使用中 |
| アプリケーションコード | ブルートフォースフォールバック | ✅ 既存のPodで稼働 |
Pinecone不要。Weaviate不要。プロビジョニング、セキュリティ保護、支払いが必要な新しいインフラは一切ありません。
ワークフローへの影響
より高速なrecipe実行
ナレッジベースを使用するすべてのrecipeで、ウォームクエリ時のコンテキスト取得が1秒未満になりました。リピートユースケースでは、生成前の「考え中…」のスピナーがなくなりました。
実用的なバッチ処理
同じナレッジベースに対して数百のアイテムを処理するバッチ実行が実用的になりました。最初のアイテムがキャッシュをウォームアップし、残りは高速に処理されます。
瞬時に感じるagent会話
会話型agentは毎ターン、ナレッジベースを再クエリします。Redisキャッシュにより、2ターン目からNターン目までのコンテキスト取得は、類似度検索を再実行する代わりにミリ秒で完了します。
観測可能な検索
usedVectorSearch トレースフラグにより、すべての実行でどの検索パスが使用されたかを正確に確認できます。ナレッジベースが一貫してブルートフォースにフォールバックしている場合、対応が必要なことがわかります。
今すぐお試しください
すでにJieGouのナレッジベースを使用している場合、これらの最適化はライブです — 設定変更は不要です。既存のナレッジベースは自動的にFirestoreベクトル検索とRedisキャッシュの恩恵を受けます。
まだナレッジベースを設定していない場合:
- JieGouコンソールで Knowledge Bases に移動
- ドキュメントをアップロードまたはURLからインポート
- ナレッジベースを任意のrecipeまたはworkflowにアタッチ
- 1秒未満で検索が完了するのをご確認ください
Firestoreネイティブベクトル検索、ハイブリッド検索、Redisキャッシュの組み合わせにより、AI自動化は遅延のペナルティなしに — そして追加インフラの管理なしに — 企業固有のコンテキストを取得できます。