【第6回】RAG(検索拡張生成)基盤の構築とベクトルデータベースの連携:自社データでLLMを拡張する

ここまでの連載(第1回〜第5回)を通じて、OllamaやvLLMを活用し、AlmaLinux上でエンタープライズのトラフィックに耐えうる「ローカルLLM推論サーバー」のインフラ基盤を完成させました。これにより、データが外部に漏れないセキュアな生成AI環境を手に入れることができました。

しかし、稼働し始めたローカルLLMを業務に適用しようとすると、すぐに決定的な壁にぶつかります。それは「LLMは自社の社内規定や、学習データに含まれていない最新の情報を全く知らない」という事実です。

コウ君

リナックス先生、前回構築したvLLMサーバーで「当社の最新の経費精算ルールについて教えて」と質問したら、全く存在しない架空の社内ルールをもっともらしく回答してきました……。これがいわゆる「ハルシネーション(幻覚)」ってやつですか? 毎回追加で学習(ファインチューニング)させないとダメなんでしょうか。

リナックス先生

コウ君、その通り。それがハルシネーションです。しかし、社内文書が変わるたびに巨大なLLMを再学習(ファインチューニング)させるのは、計算コストと運用手間の観点から現実的ではありません。そこで現代のエンタープライズAIで絶対的なデファクトとなっているのが「RAG(Retrieval-Augmented Generation:検索拡張生成)」というアーキテクチャです。今回はインフラエンジニアの視点から、このRAGを支える「ベクトルデータベース」の構築とデータパイプラインの設計を行います。

本記事では、AlmaLinux 9環境において、Rust言語で書かれた超高速ベクトルデータベース「Qdrant」と、テキストをベクトル化する専用推論サーバー「TEI(Text Embeddings Inference)」をPodmanコンテナとしてデプロイし、既存のローカルLLMとセキュアに連携させるマイクロサービス・アーキテクチャの構築手法を徹底的に解説します。


1. エンタープライズAIにおけるRAGアーキテクチャの全体像

RAG(検索拡張生成)とは、ユーザーからの質問に対して、LLMが「自分の記憶(事前学習データ)」だけで答えるのではなく、「外部のデータベースから関連する社内文書を検索し、その文書をプロンプトに動的に埋め込んでからLLMに回答させる」技術です。

1.1. RAGを構成する4つのコンポーネント

アプリケーション開発者はRAGを「プロンプトエンジニアリングの一部」と捉えがちですが、私たちインフラエンジニアは、これを「高度に連携する4つのマイクロサービス」としてインフラ設計・運用する責任があります。

  1. アプリケーションサーバー(フロントエンド): ユーザーの質問を受け付け、後続のシステムをオーケストレーションするサーバー。
  2. Embedding(エンベディング)サーバー: テキスト(文章)を「数百次元の数値の配列(ベクトル)」に変換する専用のAIモデルサーバー。
  3. ベクトルデータベース(Vector DB): ベクトル化された社内ドキュメントを大量に保存し、ユーザーの質問ベクトルと「意味が近い(コサイン類似度が高い)」ドキュメントをミリ秒単位で高速検索するデータベース。
  4. テキスト生成LLMサーバー(vLLM / Ollama): 検索して得られたドキュメントを元に、最終的な自然言語の回答を生成するサーバー(第1回〜第5回で構築済み)。
コウ君

なるほど、LLM本体に無理やり覚えさせるのではなくて、横に「検索用のデータベース」を置いて、そこからカンペを渡すようなイメージですね!

リナックス先生

その通りです。つまり、インフラの観点から見ると、RAGの導入によって「システム全体のネットワーク通信経路」が劇的に複雑化します。一つのユーザーリクエストを処理するために、内部ネットワークでAPIコールが飛び交うため、コンテナ間のネットワークレイテンシ(遅延)と、新しく追加されるデータベースのストレージI/O要件を厳格に設計する必要があります。

2. Embedding(ベクトル化)専用推論サーバーの構築

RAGアーキテクチャを構築するにあたり、テキスト生成を行うLLM(例:Llama 3)とは別に、テキストをベクトル(数値の羅列)に変換するためのEmbedding(エンベディング)モデルをデプロイする必要があります。

Ollama等の内部機能を使ってベクトル化することも可能ですが、本番環境のトラフィックを想定した場合、テキスト生成用の重いLLMと、ベクトル化用の軽いモデルを同じプロセスで動かすのはリソース効率が極めて悪くなります。エンタープライズのインフラ設計では、ベクトル変換専用の推論サーバーを独立して立ち上げます。

2.1. Hugging Face TEI (Text Embeddings Inference) の採用

今回は、Hugging Faceが提供している高スループットなEmbedding専用コンテナ「TEI (Text Embeddings Inference)」を採用します。vLLMと同様にPagedAttentionライクなメモリ管理を行い、ベクトル変換を極限まで高速化(数ミリ秒)するRust製サーバーです。

AlmaLinux上でPodmanを用いて、オープンソースで高性能な日本語対応Embeddingモデル(例:intfloat/multilingual-e5-large)を稼働させるQuadletユニットを作成します。

cat << 'EOF' | sudo tee /etc/containers/systemd/tei.container
[Unit]
Description=Text Embeddings Inference Server
After=network-online.target

[Container]
Image=ghcr.io/huggingface/text-embeddings-inference:cpu-1.5
ContainerName=tei-server
# APIポート(デフォルト80)を8081にバインド
PublishPort=127.0.0.1:8081:80
Volume=/opt/ai-models:/data:rw
# 日本語に強い多言語モデルを指定
Exec=--model-id intfloat/multilingual-e5-large --port 80

[Install]
WantedBy=multi-user.target
EOF

⚠️ CPUかGPUか:Embeddingモデルのサイジング
テキスト生成LLM(数GB〜数十GB)に対し、Embeddingモデルは通常0.5GB〜2GB程度と非常に軽量です。そのため、高価なGPUのVRAMを消費させずとも、最新のCPU(AVX-512等対応)であれば十分に実用的な速度が出ます。インフラコスト最適化のため、上記の設定ではあえて cpu バージョンのコンテナイメージを指定し、推論サーバー本体(vLLM)のGPUリソースを阻害しない設計としています。

設定後、systemdのリロードと起動を行います。

sudo systemctl daemon-reload
sudo systemctl enable --now tei.service
sudo journalctl -u tei.service -f

3. ベクトルデータベース「Qdrant」の選定とインフラ要件

文章がベクトル(例:1024次元の浮動小数点数の配列)に変換されたら、それを保存・検索するためのデータベースが必要です。MySQLやPostgreSQLのような従来のリレーショナルデータベースは「キーワードの完全一致検索」には強いですが、ベクトルの「距離(コサイン類似度など)の近さを計算する検索(近似近傍探索)」にはアーキテクチャ上適していません(※pgvector等の拡張機能もありますが、大規模・高トラフィック環境では専用DBに劣ります)。

3.1. なぜ「Qdrant」を選ぶのか?

現在、Pinecone(フルマネージド)、Milvus(超大規模分散型)、Chroma(Python軽量型)など多数のベクトルデータベースが存在しますが、オンプレミスのLinuxインフラ環境(AlmaLinux等)にデプロイする上で最も推奨されるのが「Qdrant(クドラント)」です。

  • Rust言語による実装: メモリ安全性が高く、Javaベース(Elasticsearch等)のようなヒープメモリ管理(ガベージコレクションによる突然の一時停止)のオーバーヘッドがありません。
  • 極めて低いリソース消費: アイドル時のCPU・メモリ消費がほぼゼロであり、小規模なPoCから大規模クラスタまでシームレスにスケールします。
  • シングルバイナリ・コンテナ親和性: 依存関係が少なく、Podmanコンテナ単体で完結するため、AlmaLinux環境での運用保守が極めて容易です。

3.2. ベクトルデータベースのインフラ要件(メモリとディスクI/O)

コウ君

LLMを動かすにはGPUのVRAMが必要でしたけど、ベクトルデータベースを動かすにはどんなサーバーリソースが必要なんですか?

リナックス先生

とても重要なポイントです。ベクトルDBはGPUを全く必要としません。代わりに必要となるのが、潤沢なシステムメモリ(RAM)と高速なストレージI/O(NVMe SSD)です。

ベクトル検索は、数万〜数千万のデータポイント間の距離計算を瞬時に行うため、検索インデックス(グラフデータ)を常に物理メモリ(RAM)上に乗せておく必要があります。また、QdrantはOSの mmap(メモリマップトファイル)を利用して、メモリに乗り切らないデータをストレージに退避しながら動作するため、ストレージのランダムアクセス速度(IOPS)が検索レイテンシに直結します。エンタープライズのRAG基盤では、HDDや安価なSATA SSDの利用は厳禁です。

PR

4. AlmaLinuxでのQdrantデプロイとQuadlet設定

それでは、AlmaLinux環境にQdrantをデプロイします。データを永続化するためのディレクトリを作成し、PodmanネットワークとQuadletを用いてセキュアに構築します。

4.1. データ永続化ディレクトリの準備と権限設定

Qdrantコンテナがデータを書き込むホスト側のディレクトリを準備します。インフラエンジニアとしては、パーミッションとSELinuxコンテキストの管理が不可欠です。

# Qdrant用データディレクトリの作成
sudo mkdir -p /var/lib/qdrant
sudo mkdir -p /var/lib/qdrant/storage
sudo mkdir -p /var/lib/qdrant/snapshots

# Podman(ルートレスまたは標準コンテナ)向けに所有権を設定
# ※コンテナ内のqdrantユーザー(デフォルトはUID/GID 1000)に合わせて権限を付与
sudo chown -R 1000:1000 /var/lib/qdrant

# SELinuxがEnforcingの場合、コンテナからのマウント書き込みを許可するコンテキストを付与
sudo chcon -Rt svirt_sandbox_file_t /var/lib/qdrant

4.2. プライベートなPodmanネットワークの作成

vLLM、TEI、Qdrant、そして後日構築するアプリケーションコンテナが相互に通信するため、ホスト外部(物理NIC)には公開されないコンテナ間専用のネットワークセグメントを作成します。

# rag-net という名前のブリッジネットワークを作成
sudo podman network create rag-net

4.3. QdrantのQuadletユニット作成

Qdrantサーバーの起動定義を作成します。REST API用のポート(6333)と、gRPC通信用のポート(6334)を持っています。

cat << 'EOF' | sudo tee /etc/containers/systemd/qdrant.container
[Unit]
Description=Qdrant Vector Database
After=network-online.target

[Container]
Image=docker.io/qdrant/qdrant:latest
ContainerName=qdrant-server
# 作成したプライベートネットワークに参加
Network=rag-net
# 外部からのアクセスはローカルホストのみに制限(セキュリティ対策)
PublishPort=127.0.0.1:6333:6333
PublishPort=127.0.0.1:6334:6334
# ストレージとスナップショットの永続化マウント
Volume=/var/lib/qdrant/storage:/qdrant/storage:rw
Volume=/var/lib/qdrant/snapshots:/qdrant/snapshots:rw

# Qdrantのメモリ使用量上限の設定(OOMキラー回避のため)
# システムRAMの空き容量に応じて適切に設定する
Environment=QDRANT__STORAGE__RAM_LIMIT_GB=16

[Install]
WantedBy=multi-user.target
EOF

設定を反映させ、Qdrantを起動します。

sudo systemctl daemon-reload
sudo systemctl enable --now qdrant.service
sudo journalctl -u qdrant.service -f

別のターミナルで curl http://127.0.0.1:6333/ を実行し、Qdrantのバージョン情報がJSON形式で返ってくれば、ベクトルデータベースのインフラ構築は完了です。

5. HNSWアルゴリズムとインフラ視点のメモリチューニング

Qdrantが起動しましたが、インフラエンジニアとして「ベクトル検索がなぜ速いのか」、そして「どうすればリソース枯渇(OOM)を防げるのか」のメカニズムを理解しておく必要があります。Qdrantをはじめとする現代のベクトルDBは、「HNSW(Hierarchical Navigable Small World)」というアルゴリズムを採用しています。

5.1. HNSWインデックスの構造とメモリ消費

ベクトル検索において、入力された質問ベクトルと数百万のドキュメントベクトル全ての距離を一つ一つ計算(ブルートフォース検索)していては、どれだけ計算機があっても時間がかかりすぎます。
そこでHNSWは、データ同士を「スキップリスト」と「多層グラフネットワーク」のような階層構造であらかじめ結びつけてインデックス化しておき、検索時は近道(ショートカット)を辿って超高速に近似値を見つけ出します。

しかし、この「グラフ構造をメモリ上に展開する」プロセスこそが、ベクトルデータベースにおける最大のメモリ消費要因(RAM・イーター)となります。データサイエンティストが検索精度を上げようとしてグラフのエッジ数(接続数)を無闇に増やすと、インフラ側のシステムメモリが瞬時に枯渇し、サーバーがスワップ地獄に陥って死にます。

5.2. ペイロード(メタデータ)のオンディスク構成

コウ君

社内のPDFやWordファイルを大量に入れたら、すぐにメモリが足りなくなりそうです。データベース専用のサーバーを別途立てないと厳しいでしょうか?

リナックス先生

そこがインフラ設計の腕の見せ所です。Qdrantには、ベクトル(数値)とHNSWインデックスだけをメモリに置き、実際のテキスト本文(ペイロード)はディスク(NVMe SSD)に配置する on_disk オプションが存在します。これを活用することで、限られたメモリ容量でも数百万件のドキュメントをさばくことが可能になります。

コレクション(RDBにおけるテーブル)を作成する際、APIを通じて明示的にオンディスク構成とHNSWのパラメーター(m や ef_construct)をチューニングすることが、エンタープライズ運用における必須要件となります。開発サイドとインフラサイドが協力し、「検索精度・速度・メモリ消費」の3つのトレードオフを適切に調整する設計(キャパシティプランニング)が求められます。

⚠️ セキュリティの観点:マルチテナント設計
社内規定には「一般社員が閲覧できるドキュメント」と「経営層・人事部のみが閲覧できるドキュメント」が混在します。RAGを導入する際、ベクトルDBにすべて無差別に突っ込むと、一般社員からの質問に対してAIが経営機密を回答してしまうという最悪のセキュリティインシデントが発生します。Qdrantの「ペイロードフィルタリング機能」を活用し、アクセス権限に基づく検索制御をインフラレイヤーで担保する設計が不可欠です。

6. まとめと次回の予告

本記事「【第6回】RAG(検索拡張生成)基盤の構築とベクトルデータベースの連携」では、ローカルLLMに社内知識を付与するインフラストラクチャとして、以下のシステムを設計・構築しました。

  • RAGのインフラ全体像: LLM本体の再学習(ファインチューニング)を避け、外部DBと連携するマイクロサービス・アーキテクチャの優位性を理解した。
  • TEIコンテナのデプロイ: テキスト生成用のvLLMとは別に、CPUに最適化されたHugging Face TEIを用いて、高効率なEmbedding(ベクトル化)専用サーバーを立ち上げた。
  • ベクトルデータベース「Qdrant」の構築: Rust製の高速かつ軽量なQdrantをPodmanネットワーク内でセキュアに構築し、NVMe SSDへのデータ永続化設計(SELinux含む)を完了した。
  • HNSWとメモリチューニング: ベクトル検索の心臓部であるHNSWアルゴリズムにおけるメモリ消費の罠を理解し、オンディスク構成を活用したリソース最適化の手法を学んだ。

これで、AIシステムを構成する「LLM(脳)」「Embedding(翻訳機)」「Vector DB(記憶)」という全てのバックエンド・インフラコンポーネントがAlmaLinux上に揃いました。

しかし、これら複数のコンポーネントが連携して動き始めると、今度は「どのコンテナがGPUメモリを食いつぶしているのか?」「ユーザーのレスポンス遅延の原因はベクトルDBのI/Oか、それともvLLMの推論待ちか?」といった、システムのブラックボックス化というインフラ運用最大の課題に直面します。

そこで次回、【第7回】ローカルLLM環境の監視(Prometheus/Grafana)とセキュリティ設計では、今回までに構築したすべてのAIコンポーネントからメトリクスを収集し、GrafanaのダッシュボードでVRAM消費やRPS(リクエスト/秒)をリアルタイムに可視化する「エンタープライズ監視基盤の構築」について徹底解説します。ご期待ください!

▼ 【高度なAIデータ基盤を構築しよう】 ▼

超高速NVMe搭載でRAGに最適!
「高コスパおすすめVPS・専用サーバー」

VPSランキングを見る

次世代データパイプラインを担う技術者へ
「インフラエンジニア専門転職」

転職エージェントを見る

コメント