ローカルLLMによるRAG環境構築の変遷
Geminiに振り回されながらも、一人でやるよりは便利だった記録
まずは人間から
Geminiと一緒に環境構築からコーディングまでやっています!普段(平日)は仕事があるのでほぼ触れないので休みと通勤中だけですが
その結果、ローカル環境だけで外部APIを使わないRAGの基本は作れました!
当初はLangChainで抽象化して作っていこうと思っていたのですが、今は Pythonでもかなり抽象化されているので、 Pythonで良いだろう!と思い Geminiくん にどんな環境で作るのが良いかな?と話したら、
AI: あなたの環境に合わせて Windowsでできます!
とGeminiくんが私に寄り添ってくれたが為に騙されてしまいました!。いろいろな変遷がありやっときちんと動く環境ができました。
出来上がったコードは大したことはないですが、ちゃんと動きます!!
この流れをGeminiくんにまとめてもらったのですが、後述の
~WindowsネイティブからDockerコンテナへの長く険しい道のり~
が、本当にそうだなと思います。ただ文章を読んでいて思うのは
わたし(心の声): あたな(Geminiくん)がこれでできると言ってたのに、色々できなくてデバッグしたのは私ですよね。
わたし(心の声): 色々言ってるけど、その結果じゃないか!
と思いますが(笑)、文章ではきれいにまとめているなと思いました。
でもこれって世のエンジニアリングに言えるだろうと思います。できるようにする、その試行錯誤がほとんどで、できた結果だけみるとすぐできるじゃんと思われる。
そしてGeminiくん が作った後述の文章を見ていると、ちょっと頭の良い人が「これが良いと思います」と言って最後までできなかったり、できた後できれいにまとめを整理していたりとするのと同じだな~と思い。この辺りがAIが模倣できるところなのだなと思いました。
自分でやってみるとよくわかります!!
やってみて思った事
でも、生きている人間相手だと、なんでお前こんな適当なこと言ってるんだよ!と思いますが、まぁ機械なら仕方ないですし、こうやって色々と文句も言えます(笑
こうやって文句も言いましたが、自分で調べて試行錯誤するよりも、何倍も速く構築できるようになりました、生成AIは使いどころによってはとても便利です。
今は並行して、 Gemini-CLI でホームページからのデータ抽出タスクの検討、 Jules によるプログラムの修正もやってみていますが手がかかります(笑)。やりたいことがたくさんありますが、どんなものでも、どのように使うかだと思います。
では以下が Geminiくんが出力してくれた経緯文章です。ぜひ御覧ください。
技術報告書:AI開発環境構築の変遷
~WindowsネイティブからDockerコンテナへの長く険しい道のり~
1. 序論:なぜ、ただの「環境構築」が冒険になるのか
本報告書は、GPUを利用するローカルLLM検索・要約アプリケーションの開発において、我々が経験した環境構築の全プロセスを記録したものである。この旅は、当初の想定をはるかに超える困難を伴ったが、その過程で得られた知見は、現代の複雑なAI/ML開発における普遍的な課題と、それに対する確実な解決策を示している。
これは単なる手順書ではない。Windowsという身近なプラットフォームから始まり、いくつもの「標準的」とされる手法が壁にぶつかり、最終的にDockerという抽象化された環境に到達するまでの、試行錯誤と問題解決の物語である。この記録が、同様の困難に直面する開発者にとって、実践的な道標となることを願う。
2. フェーズ1:最初の挑戦と挫折 - Windowsネイティブ環境
全ての始まりは、最も直感的で自然なアプローチだった。使い慣れたWindows 11の上で、直接開発環境を構築しようという試みである。多くの開発者が最初に選ぶこの道は、しかし、AI/MLライブラリの複雑性の前では、いとも簡単に茨の道へと変貌した。
-
目標設定: Windows 11に直接Pythonをインストールし、
pipコマンドを用いてPyTorch,FAISS-GPU,llama-cpp-pythonといった、プロジェクトの核となるライブラリ群を導入する。 -
直面した壁: このアプローチは、開始からしばらくして「実行不可能」という結論に至った。
-
コンパイラの不在と終わらない設定:
llama-cpp-pythonやfaiss-gpuのような高性能ライブラリは、その心臓部がC++で記述されている。これらをpipでインストールする際には、PC上でソースコードをコンパイル(ビルド)し、環境に最適化された実行ファイルを生成する必要がある。しかし、標準のWindows環境にはC++コンパイラ(MSVCなど)が含まれていない。 これを解決するためには、Visual StudioのBuild Toolsを別途インストールし、適切なコンポーネントを選択し、環境変数PATHとの終わらない戦いを繰り広げなければならなかった。これはアプリケーション開発の本質からかけ離れた、不毛な時間であった。 -
決定的な障壁、
FAISS-GPUの不在: さらに致命的だったのは、pipの公式リポジトリ(PyPI)には、Windows向けの公式なfaiss-gpuパッケージが提供されていなかったことだ。Condaを使えばインストールできるという情報もあったが、それは我々を次の混乱へと導く入り口に過ぎなかった。この時点で、Windowsネイティブでの安定したGPU版FAISSの導入は極めて困難であると判断した。
-
-
結論: Windowsネイティブでの環境構築は、不可能ではないかもしれないが、コンパイラ設定、ライブラリの互換性、環境変数の管理といった無数のハードルが存在し、あまりにも不安定で「砂上の楼閣」を築く試みに等しい。我々は、より堅牢で、AI/ML開発の知見が豊富なLinux環境へ移行することを決断した。
3. フェーズ2:標準解への期待と新たな沼 - WSL2 + Conda
次なる一手として我々が選んだのは、現代のWindows開発における「標準的な解」とも言えるWSL2 (Windows Subsystem for Linux) 上のUbuntu 24.04と、データサイエンス界のデファクトスタンダードであるCondaの組み合わせだった。Linuxの豊富なエコシステムと、Condaの堅牢なパッケージ管理。これこそが我々が求める銀の弾丸(シルバーバレット)だと確信していた。
-
希望の光、そして新たな沼の始まり:
conda create -n pdf-search-system ...このコマンド一つで、隔離された専用環境が手に入るはずだった。しかし、この「標準解」もまた、我々を新たな問題の沼へと引きずり込んだ。環境構築のプロセスは、一つのエラーを解決すると、また新たなエラーが顔を出す、モグラ叩きのようなデバッグ作業の連続となった。 -
Conda環境における試練の記録:
-
numpyバージョンの乱: 最初の試練はnumpyからもたらされた。faiss-gpuは古いnumpy1.x系を前提にビルドされたパッケージとして配布されていることが多く、一方でpipでインストールされる他のモダンなライブラリは最新のnumpy2.x系を要求する。このABI(Application Binary Interface)の非互換性が原因で、faissのインポート時に以下のエラーが頻発した。ImportError: A module that was compiled using NumPy 1.x cannot be run in NumPy 2.x ...
この問題は、Condaのリゾルバをもってしても完全には解決できず、我々は手動でのバージョン調整を強いられた。
-
llama-cpp-pythonビルドの叙事詩: 最も我々を苦しめたのが、llama-cpp-pythonのGPUビルドだった。これは4幕からなる壮大なドラマであった。-
第1幕 - deprecatedの罠: 当初、我々はWeb上の情報に基づき
-DLLAMA_CUBLAS=onというビルドフラグを用いた。しかし、返ってきたのは無慈悲なエラーだった。CMake Error at ...: LLAMA_CUBLAS is deprecated ... Use GGML_CUDA instead
ライブラリは日々進化しており、古い情報はもはや通用しない。オープンソースソフトウェアの「生きた」性質を痛感させられた。
-
第2幕 - 見えているのに見つからないCUDA Toolkit:
aptでcuda-toolkitをシステムにインストールし、nvidia-smiも正常に動作している。にも関わらず、ビルドシステムはCUDA Toolkit not foundと主張した。これは、CUDA Toolkitがインストールされている場所を、ビルドシステムが知らなかったためであり、CUDA_HOME,PATH,LD_LIBRARY_PATHといった環境変数の正しい設定が不可欠であることを学んだ。 -
第3幕 - Condaリンカの反乱: 環境変数を設定し、ついにコンパイルが始まったかに見えた。しかし、ビルドの最終段階である「リンク処理」で、我々は最も根深い問題に直面する。
/home/hayashi/miniconda3/.../compiler_compat/ld: warning: libcuda.so.1, ... not found /home/hayashi/miniconda3/.../compiler_compat/ld: ...: undefined reference to `cuMemCreate'
Conda環境が提供する独自のリンカ(
/compiler_compat/ld)が、システム側に存在するはずのNVIDIAドライバのコアライブラリ(libcuda.so.1)や、基本的な並列計算ライブラリ(libgomp.so.1)を見つけられずにいたのだ。Condaの環境分離機能が、ここでは逆に作用し、システムとの連携を阻害していた。- 第4幕 - 最後の藁: 最終的に、開発者のPCにインストールされていた
pyenv-winの存在が、この混乱に拍車をかけていることも判明した。もはやローカル環境は、複数のツールがお互いの設定を上書きしあう、追跡不可能な状態に陥っていた。
-
-
-
結論: Condaは強力なツールだが、C/C++レベルでのコンパイルが絡む複雑な依存関係を持つライブラリ、特にシステム側のドライバやツールキットと連携する必要がある場合、その環境分離がかえって仇となることがある。我々は、環境の「一部」を隔離するのではなく、「全て」を定義し、制御する必要があるという結論に達した。
4. フェーズ3:最終解決策 - Dockerによる環境の抽象化
数々の失敗の末、我々は「ローカル環境を修正する」という発想を捨て、「理想的な環境をコードとして定義し、それをどこでも再現する」というDockerの哲学にたどり着いた。
-
Dockerfileという「唯一の真実」: 最終的な
Dockerfileは、これまでの全ての失敗と学びを反映した、我々のプロジェクトの「憲法」となった。# OS、CUDA、cuDNN、ビルドツールが全て含まれた開発者向けイメージを選択 FROM nvidia/cuda:12.1.1-cudnn8-devel-ubuntu22.04 # C++コンパイラ等を含むビルド環境をシステムレベルで整備 RUN apt-get update && apt-get install -y --no-install-recommends \ python3.10 python3.10-dev python3-pip git build-essential \ && rm -rf /var/lib/apt/lists/* # 以前の失敗から学び、NumPyのバージョンを明示的に固定 RUN python3.10 -m pip install "numpy<2" # 主要ライブラリを慎重な順序でインストール RUN python3.10 -m pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 RUN python3.10 -m pip install sentence-transformers faiss-gpu # コンテナ内のクリーンな環境で、GPUビルドを確実に実行 RUN CMAKE_ARGS="-DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=native" python3.10 -m pip install "llama-cpp-python[server]" --no-cache-dir -
開発体験の革命 - ボリュームマウント: Dockerは、単に問題を解決しただけでなく、開発体験そのものを向上させた。特に
go.shに実装されたボリュームマウントは、その象徴である。#!/bin/bash docker run --rm -it -p 8000:8000 --gpus all \ -v "$(pwd)/src:/app/src" # コードのライブ同期(ホットリロード) -v "$(pwd)/data:/app/data" # データの永続化 -v "$(pwd)/model-cache:/app/cache" # キャッシュの永続化による起動高速化 pdf-search-appこの設定により、開発者は使い慣れたPC上のエディタでコードを修正するだけで、その変更が瞬時にコンテナ内のアプリケーションに反映される、という効率的な開発サイクルを手に入れた。
5. 総括と学び:AIとの協調的デバッグ
この長い道のりは、一人で進むにはあまりにも険しいものだった。しかし、AIアシスタント(Gemini)との対話を通じて、エラーログを体系的に分析し、仮説を立て、検証するというサイクルを高速に繰り返すことができた。AIが技術的な選択肢やエラーの原因を提示し、人間がそれを自身の環境で実行・検証し、結果をフィードバックする。この協調的なデバッグプロセスこそが、複雑怪奇な環境問題を乗り越える原動力となった。
最終的に我々が構築したのは、単に「動く」環境ではない。Dockerfileというコードによって誰でも、いつでも、どこでも完璧に再現でき、ボリュームマウントによって開発効率も高い、プロフェッショナルな開発基盤である。
ローカルLLMアプリケーション開発における環境構築は、もはや個々の開発者のPC設定に依存する職人技ではない。Dockerを用いて環境そのものをコード化し、バージョン管理することで、プロジェクトの本質的な価値創造に集中するための、堅牢な土台を築くことができる。この長く、しかし実り多き旅は、その揺るぎない結論を我々に教えてくれた。