WSL2×Docker×Ollama×Qdrantで、まずRAGを動かしてみた

全4回シリーズ「ローカルLLMでつくる 業務で使える社内RAG構築記」第1回

「社内の技術資料をAIに読ませて、質問したら答えてくれるようにしたい」

そう言われたら、今なら「RAGを使えば実現できるのでは?」と考える方も多いのではないでしょうか。

RAG(Retrieval-Augmented Generation)は、簡単に言えば、「質問に関係する社内資料を検索して、その結果をLLMに渡して回答させる仕組み」のことです。

私たちの社内でも、組み込み製品の仕様書やマニュアル、過去の技術サポート履歴といった「社内に蓄積された知見」を活用したいという声があり、社内向けRAGチャットの構築に着手することになりました。

必要なライブラリやスクリプトを準備し、初期検証を行った際の第一印象は、

「思ってたより簡単に動くな」

というものでした。

当初は「あとはデータを投入すれば完成だ」と考えていましたが、本当の難所はまさにそこからでした。

本連載では、私たちがRAGシステムの実装・運用を通じて得た知見や課題解決のプロセスをご紹介します。業務でのRAG導入をご検討中の皆様にとって、実用的な参考となれば幸いです。

第1回となる今回は、導入のファーストステップである「とりあえず動作するRAG」の構築までをご紹介します。

まずは「質問に答える」ところまで作る

今回、RAGの実行環境は、別部署ですでにローカルLLMの検証で利用していたWindowsサーバー(ネイティブ動作のOllamaによるGPU推論環境)をお借りすることにしました。

また、将来的に大量の社内資料を扱うことを見越して、高速なベクトルデータベースである「Qdrant」を採用したいと考えていたことから、開発環境はWSL2上のUbuntu環境に構築することにしました。

構築するRAGの構成は、大まかに以下の通りです。

実行環境:WSL2 Ubuntu24.04LTS

以下のコンポーネントは、すべて Docker Compose を用いて一括で構築します。

Ollama:ローカルでLLMを実行する推論エンジン
Qdrant:資料を検索するためのベクトルデータベース
FastAPI:RAGのメインロジックを担当するバックエンド API
React:ユーザーが操作するチャット画面(フロントエンド)
Redis:会話セッションやコンテキスト情報の保持
(参考)埋め込みモデルについて

Ollamaでは、回答を生成するモデルとは別に、資料や質問を検索用の数値表現(ベクター)に変換する「埋め込み(Embedding)モデル」もあわせて利用しています。

処理フロー自体は、非常にシンプルです。

質問 → ベクトル化 → Qdrantで検索 → 検索結果をLLMへ → 回答


まずは余計な機能を入れ込まず、この最小限の構成で動かすことを目指します。

なお、上記構成における具体的な環境構築やインストールの詳細手順については、すでに多くの技術サイトで分かりやすく解説されています。また最近では、Claude Code などのAIエージェントを活用してスムーズに環境構築を行われる方も増えているかと思いますので、本稿での詳しい解説は省略させていただきます。

(※もしご要望が多いようでしたら、詳細な導入手順についても別記事などで公開を検討したいと思います)

以上の導入作業が完了すると、入力した質問に対して、AIがそれらしい回答を返してくれる様子が確認できるはずです。

ローカルLLMを選ぶ理由

本システムで扱うデータには、製品の内部仕様書や顧客問い合わせ対応の履歴など、厳重な管理が求められる社内情報が含まれます。

このようなセキュリティレベルの高い情報を、外部のパブリックなクラウドAIサービスへ送信することは、情報漏洩リスクの観点から容認できません。

そのため、モデルの実行および推論処理のすべてを社内インフラ上に閉じた環境で行う「ローカルLLM」構成を採用しました。データを社外に出さずに高度な処理を行える手法として、近年多くの企業で導入検討が進められています。

留意点:ローカルLLMの選定理由とトレードオフ
精度の観点: ローカルLLMを採用することで直接的にRAGの回答精度が向上するわけではありません。本構成の目的はあくまで機密データの外部送信リスクを遮断・回避することにあります。
処理速度の観点: 社内サーバーのハードウェアスペックに制限されるため、商用クラウドAIサービスと比較して推論(応答生成)に要する時間が長くなる点には留意が必要です。

運用環境へ手軽に移植できる Dockerを採用

ソフトウェア開発において頭を悩ませがちなのが、「開発環境や依存ライブラリのバージョン違い」によるトラブルです。「手元のPCでは問題なく動いていたのに、別のPCやサーバーに持っていくと動かない」といった問題は、RAGシステムの構築でも当然のように発生します。

また今回は、推論サーバー自体を他部署と共用する都合がありました。そのため、GPUリソースを直接活用するOllama(Windowsネイティブ動作)を除き、その他の主要コンポーネントはすべてWSL2上のDockerコンテナとして構築・動作させる構成を採用しました。

そして、開発を通してあらためて実感したDockerのもう一つの大きなメリットが、

「何度でも簡単にやり直せる(破壊と再生が容易)」

という点です。

試行錯誤の過程でコンテナ内の環境を汚してしまっても、コマンド一つでリセットしてクリーンな状態に復元できます。さらに、チームメンバー間でも全く同じ開発構成を瞬時に再現可能です。

今回のように「自社の業務に最適なRAG構成を検証しながら手探りで開発する」フェーズにおいて、Dockerによるアプローチは非常に強力なアドバンテージになると思います。

そして、RAGは動いた——しかし

環境構築自体はそれほど難しくないため、正しくセットアップさえできれば、LLMはすぐにそれらしい回答を返してくれるようになります。

画面上でAIが答えてくれる様子を見ると、「なんだ、あとは社内資料を大量に読み込ませればもう完成じゃないか?」と思えてきます。実際、私たちもこの時はそう確信していました。

しかし……本当のRAGシステム開発は、まさにここからが本番だったのです。

実際に蓄積された大量の社内資料を投入し、現場で使われるような質問を投げてみると、次のような問題が次々に顕在化してきました。

  • 質問と関係のない資料を参照してしまう
  • 質問に関連する資料までたどり着けずに「該当する情報がありません」と回答してしまう
  • 似た別の製品情報を取り違えてしまう
  • 回答に必要なキー情報が検索結果から漏れてしまう
  • 正しく資料を検索できても、LLMの回答がおかしい

「とりあえずRAGを動かすこと」と、「業務で本当に使えるRAGを作ること」は全く別の次元の課題であり、後者には継続的な検証と最適化が不可欠となります。

まとめ

今回は連載の第1回として、WSL2+Docker環境上でOllamaやQdrantを組み合わせ、「とりあえず動くRAG」を構築するまでのプロセスをご紹介しました。

「ライブラリを揃えてローカルLLMを動かす」というスタート地点までは、驚くほどスムーズに進みます。

しかし、実際に社内資料を読み込ませて業務で使おうとした瞬間に、「正しく検索できない」「回答精度が上がらない」というRAG特有の深い壁に突き当たることになります。

「動いた」という達成感の先に待ち受けていたのは、まさにこの「精度向上」に向けた泥臭い試行錯誤の連続でした。