Ubuntu上のOllama＋Open WebUIで構築したローカルLLMでRAG（前編）

## はじめに

今流行りのローカルLLMを作ったので、その作成方法を公開します。
採用するのは簡単にできそうなOllama＋Open WebUIで、Dockerコンテナ上に立てます。
環境構築から始めてパラメータチューニングの方法まで解説します。

前編は構築編として、初期設定からRAGができるようになるところまでを解説していきます。
[後編](https://qiita.com/minnsou/items/9b9a0c9dc01dcaac7108)はコード解説編として、RAG周りのコードを読んでどのような処理をしているのかを解説していきます。

ハードウェア構成
・CPUはIntel(R) Core(TM) i5-8400
・GPUはGeForce GTX 1050
・メモリはDDR4 32GB

ソフトウェア構成
・OSはUbuntu Server 24.04.02 LTS
・Dockerを使ってその上にOllamaとOpen WebUIを構築

GPUがあるのでDockerでもGPUが使えるようにセットアップしていきます。
正直機械学習を行うには低スペックなPCですが、構築方法やパラメータ解説自体は参考になるかなと思います。

完成図は以下です。

![abs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/5b95849f-0367-466d-8b38-652461289cd5.png)


## OSインストール

ここは省略します。
今回は機械学習でよく使われている（と個人的に思っている）[Ubuntu Server 24.04.02 LTS](https://jp.ubuntu.com/download)
をインストールしました。
詳細は他の記事にいくらでも転がっていると思うので省略します。
Ubuntuが起動し、SSHログインできるようになった状態からスタートします。

## Dockerインストール

ここからDockerを使えるようにするための準備をしていきます。

Dockerの[公式ドキュメントのPrerequisites](https://docs.docker.com/engine/containers/resource_constraints/#gpu)に従って
GPUドライバインストール、nvidia-container-toolkitのインストールの順番でいきます。

### GPUドライバインストール

GPUドライバのインストールは魔境なのですが、[nvidiaの人の記事](https://medium.com/nvidiajapan/nvidia-docker-って今どうなってるの-20-09-版-558fae883f44)を参照して[cuda-toolkit](https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=24.04&target_type=deb_local)経由でGPUドライバを入れます。[^1]

[^1]:Dockerのドキュメントのリンクになっていた[NVIDIAの公式サイト](https://www.nvidia.com/en-us/drivers/)ではうまくGPUドライバがインストールできませんでした

写真のように自分の構成に合わせて出てきたスクリプトを入れます。

![cudatoolkit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/f7f6ad97-9ffc-43fa-ad2f-184fccee9a2e.png)

```
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-ubuntu2404.pin
sudo mv cuda-ubuntu2404.pin /etc/apt/preferences.d/cuda-repository-pin-600
wget https://developer.download.nvidia.com/compute/cuda/12.8.1/local_installers/cuda-repo-ubuntu2404-12-8-local_12.8.1-570.124.06-1_amd64.deb
sudo dpkg -i cuda-repo-ubuntu2404-12-8-local_12.8.1-570.124.06-1_amd64.deb
sudo cp /var/cuda-repo-ubuntu2404-12-8-local/cuda-*-keyring.gpg /usr/share/keyrings/
sudo apt-get update
sudo apt-get -y install cuda-toolkit-12-8
sudo apt-get -y install cuda-drivers
```

一度再起動し、これで`nvidia-smi`コマンドが打てるようになっていればOKです。

![nvidia-smi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/34fafc6e-6922-48d8-9b1d-417e9357149d.png)


### nvidia-container-toolkitのインストール

[NVIDIAの公式サイト](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html)に従って、nvidia-container-toolkitをインストールしていきます。これは公式ドキュメントのPrerequisitesに書いてある通りです。

```
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
  && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
```

両方インストールできたら改めてDockerをインストールします。
[Dockerの公式ドキュメントのインストールガイド](https://docs.docker.com/engine/install/ubuntu/#installation-methods)に従ってインストールします。

```
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```

これでDockerインストールできたことを確認します。

```
sudo docker run hello-world
```

![docker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/1bc3dbda-c5dd-49fe-abf6-7a6aaab5c32e.png)

Hello from Docker!が表示されればDockerのインストールは問題ありません。
また、コンテナ上でもGPUがちゃんと認識できているか確認します。

```
sudo docker run -it --rm --gpus all ubuntu nvidia-smi
```

![docker_nvidia-smi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/fbe35ec1-38f7-485a-97e8-f04b40e36fb3.png)


うまくコンテナ上で問題なく`nvidia-smi`ができていればDockerのインストール完了です。

なお、これからはsudoコマンドを毎回打つのが面倒なので`docker`ユーザグループを作り、そこにtestユーザを追加しておきます。詳細は[公式ドキュメント](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user)を参照してください。Ubuntu Serverなら以下のコマンドでOKです。

```
sudo usermod -aG docker $USER
logout
```

一度ログアウトし、再ログインすれば`sudo`なしでも`docker`コマンドが使えるようになっています。

![sudodocker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/f60dc0b5-c549-4dd5-a23e-ce630bbe0e7f.png)

## Ollama+Open WebUIの起動

[Open WebUIの公式ドキュメント](https://docs.openwebui.com/#open-webui-bundled-with-ollama)を参照してコンテナを起動します。

```
docker run -d -p 3000:8080 --gpus=all -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:ollama
```

ついでにバージョン管理のために[watchtower]()を入れます。
1日（86400秒）に1回Updateの確認をし、自動でコンテナイメージのアップデートをしてくれるようにします。

```
docker run -d --name watchtower --restart unless-stopped -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --interval 86400 open-webui
```

自動でアップデートされるのが嫌な方はこの手順は飛ばすでもOKです。
[Open WebUIの公式ドキュメント](https://docs.openwebui.com/#updating-open-webui)に手動アップデートの方法も書かれているので参照にしてください。

ちなみにイメージが更新されると以下のようにログに表示されます。
![スクリーンショット 2025-04-02 18.19.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/50c30a14-4c91-4c34-b9f4-d097a45be8d0.png)


http://IPアドレス:3000
にアクセスを実施し、Open WebUIの画面が出てくればOKです。

GUIで管理者アカウントを作り、ログインしてください。

![スクリーンショット 2025-03-24 20.51.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/5802b64b-aacb-43c2-a0ba-4991c70723a1.png)


## Ollamaのセットアップ＆テスト

好きなLLMを[一覧](https://ollama.com/search?c=tools)から選んでダウンロードします。
パラメータ数が少なめのllama3.2:1bとパラメータ数が多めのqwqをひとまずダウンロードしておきます。

![llama.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/80fa42ba-bbaf-4052-9c5c-6406d1d0bd73.png)

![qwq.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/fb4d716a-02e6-47eb-a8d4-ae7b651e205b.png)


```
docker container exec open-webui ollama pull qwq
docker container exec open-webui ollama pull llama3.2:1b
```

Open WebUIの画面で右上で好きなモデルを選択できるようになっているかと思います。

それぞれ会話をしてみます。

![select.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/b988530f-0d45-475d-bf05-2ccdd5c2aedb.png)


パラメータ数が少ないllama3.2:1bはちょっと日本語が怪しそうですが、無事に回答は返って来ました。[^2]

[^2]:[公式ドキュメント](https://ollama.com/library/llama3.2)のSupported Languagesに日本語が入っていないので、しょうがないところはあると思います。

次はqwqに「こんにちは」と投げかけてみましょう。

![qwq.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/d319024b-259f-4c0a-af01-24592c602921.png)

ちょっとはまともそうな会話になりそうです。


それぞれのGPU利用状況を見てみましょう。

![nvidia_1b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/eb902506-17cb-4db6-b8b4-57b7644e233f.png)

こちらは画像下側でOllamaのプロセスがGPUメモリを1500MiB使っていることが確認できます。

qwqを実行した時は、ここのプロセスが表示されません。
コンテナのログを見てみましょう。

```
docker container logs open-webui
```

qwqはパラメータ数が32bであり、合計で19.7GBのメモリが必要というログが出ています。

![qwq_log.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/f34e4809-1a6b-4526-848d-e7b977d4c112.png)

必要なメモリが多すぎるため、GPUメモリに乗らなかったようです。
その分は普通のメモリに表れています。

こちらがqwqを実行する**直前**の`free`の状況です。

![free_bf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/8c9c8510-bc7b-4eec-be96-cbe5ba7980ea.png)

こちらがqwqを実行した**直後**の`free`の状況です。
![free_af.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/e467ff83-fb27-4971-97d0-d26b352bbe42.png)

**usedが増えて**おり、必要なメモリ数を確保していることがわかります。

## RAGのテスト

ここからはOpen WebUIではデフォルトで使えるRAGを試していきます。

まずはRAGのために使用する架空のデータを生成します。
ネットに出ているものはすでに学習されている可能性があるので、今回は新たに生成した架空の人物の紹介文を使っていきます。

以下のプロンプトでデータを生成します。

```
架空の人物である男女４人の紹介を行ってください。
氏名、部署名、役職、部署での業務、趣味は必ず含めてください。
文字数は各人500文字程度としてください。
```

結果が出力されました。

![アストラ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/ac9ac56f-d63f-477f-a7ef-0e995481f2d9.png)

全文は長いので折りたたんで記載しておきます。

<details><summary>林小夏（リン・ショウハ）</summary>

部署：AI研究開発部
役職：シニアAIエンジニア
業務内容：
主に自然言語処理（NLP）を活用した会話型AIの開発を担当。医療診断支援システムのアルゴリズム設計や、製造業向けの予測メンテナンスAIのテスト工程をリード。チーム内の若手エンジニアのメンタリングも行い、週1回の技術勉強会を主催しています。近年は医療機関との共同研究プロジェクトを推進し、倫理的なAIの活用方法についても研究中です。
趣味：
週末は古本屋巡りを楽しみ、特に1950年代のSF小説に造詣が深い。自宅で3Dプリンタで小型ロボットを自作する「工作マニア」でもあり、昨年はアマゾン川の熱帯雨林調査チームに協力し、野生動物の生体情報収集用ドローンを製作。また、月1回は陶芸教室に通い、制作した作品はすべて地元の子供病院に寄付しています。
</details>

<details><summary>陳立（チェン・リ）</summary>

部署：グローバルマーケティング部
役職：地域担当マネージャー
業務内容：
東南アジア市場における新製品のプロモーション戦略を統括。現地企業との提携交渉や、SNSを活用したコンテンツマーケティングを指揮。特に、タイ・ベトナム市場向けのローカルタレント起用キャンペーンで売上150%増を達成。最近ではメタバースを活用したバーチャル展示会の企画を推進し、VR空間での商談システムの構築を進める。
趣味：
中国伝統楽器の二胡を演奏する「隠れ芸人」であり、休日はオンラインでクラシック音楽の配信をしています。また、自宅のガレージを改造した「家庭用自動車整備工房」で、1965年式のイギリス製ヴィンテージカーのレストアに没頭。車検証はなくとも、公道走行可能な状態を目指しています。
</details>


<details><summary>佐藤美咲（サトウ・ミサキ）</summary>

部署：サステナビリティ推進室
役職：SDGsプロジェクトリーダー
業務内容：
企業のカーボンフットプリント算定システムの構築と、再生可能エネルギー活用のコンサルティングを担当。特に、食品廃棄物をバイオガスに転換する技術の実証実験を主導。社内では環境経営の意識向上を目的に、従業員向けの「エコポイント制度」を考案し、参加率75%を達成。現在は海洋プラスチック問題に取り組むNGOと協力し、AIで廃棄物の種別分類を行うシステムの開発中です。
趣味：
週末は山梨県の果樹園でボランティアとしてリンゴの収穫作業を手伝い、収益の一部を自然保護団体に寄付。また、自宅の屋上を「垂直ガーデン」に改造し、都市農業の実験を継続中。最近では、家庭菜園で収穫した野菜を使った「サステナブル料理」のレシピ動画をYouTubeで配信し、サブスクリプション数1万人を超えました。
</details>


<details><summary>中村翔太（ナカムラ・ショウタ）</summary>

部署：プロダクトデザイン部
役職：UX/UIデザインチーム リード
業務内容：
金融機関向けのデジタルバンキングアプリのユーザーインターフェース設計を担当。特に、視覚障害者向けの音声ガイド機能の開発で業界初の認定を獲得。最近ではメタバース空間での仮想店舗のUIデザインを手がけ、バーチャル空間での購買行動の分析データを活用したデザイン改善を推進中。週2回は外部のUX設計のワークショップを開催し、業界の標準化に貢献しています。
趣味：
週末は自転車で郊外の廃墟を探索する「廃墟アート」を撮影し、写真展を開催。SNSでは「廃墟から生まれる未来のデザイン」と題した連載コラムで人気を集めています。また、自宅の地下室を改造した「暗室」で銀塩フィルム写真の現像作業をこなし、作品は現代美術館の企画展でも展示されました。
</details>



それぞれ`rin.txt`、`chen.txt`、`misaki.txt`、`shota.txt`という名前で保存し、これを使います。

Open WebUIではチャット画面の「＋」ボタンよりドキュメントを選択し、そのファイルについて質問をする機能があります。
しかし、会社等でローカルLLMを構築する際は、固有の知識をLLMに前もって入れておき、好きな時に参照させるといったことがやりたいと思います。
Open WebUIではその機能がすでに実装されており、それを**ナレッジベース**と呼びます。
GUIでは「ワークスペース」→「ナレッジベース」になります。

![knowledge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/e3baf715-25ef-4db5-a254-4a77a6ed53bd.png)

実際に作ってみましょう。
右上の「＋」を押すと「Create a knowledge base」が表示されるので「What are you working on?」には名前を、「What are you trying to achieve?」には説明を記載します。

![create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/1b16df72-031e-4099-b200-20382be6d67a.png)

ナレッジベースができたので、ファイルを添付します。

![add_file.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/92e6778f-29f3-45eb-920b-cb018c6da324.png)

４人分を添付すれば今回作ったナレッジベースは完成です。なお、できたものは「コレクション」と呼ばれます。
コレクション内の一つのファイルをクリックしてみましょう。`shota.txt`で表示されているように**改行は消えている**ところが確認できるかと思います。

![スクリーンショット 2025-03-24 0.55.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/8530bc83-6e91-4066-8fa7-c0b1e5a26406.png)

後編ではこのファイル添付でどのようなスクリプトを動いているかを解説しますが、今回は深入りしません。

それではこのナレッジを使ってRAGを実際にやっていこうと思います。

このナレッジベースに格納した情報を使うには、プロンプトに「#」を入れ、対応するナレッジを選択するだけです。

![スクリーンショット 2025-04-08 18.15.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/2e375f5f-be62-43f7-b95e-edf3c15c85c1.png)

「COLLECTION」に表示されている「人物紹介」を選択し、チェンについて聞いてみたいと思います。

![スクリーンショット 2025-04-08 18.16.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/206dbe35-c89e-4d56-9749-2d93f90e677a.png)

質問文を入れて、メッセージを送信してみます。

![スクリーンショット 2025-04-08 18.14.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/72bcfa82-26ba-4e17-85c9-aa6b7d543bd7.png)


うまく回答してくれましたね。

またPDFを添付した時の状態を見ていきます。
今回は具体例としてIMAP4 rev1が書かれている[RFC2060のPDF版](https://www.rfc-editor.org/rfc/pdfrfc/rfc2060.txt.pdf)を与えてみたいと思います。

ファイル名（rfc2060.txt.pdf）を選択して、中身を見てみましょう。

![スクリーンショット 2025-03-22 9.20.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/6888777c-0c53-4c62-946c-4f591d2c6b67.png)

ぱっと見では目次に使われている...が見づらいですね。
ヘッダーやフッターが何度も表示されていることもわかると思います。

検索のためにも**不要な部分（重複するヘッダー、フッター部分、目次など）は取り除くこと*が大事です。

## 終わりに

今回はUbuntuにDockerを使ったOllama＋Open WebUI環境を構築し、RAGをするところまで実施しました。[後編](https://qiita.com/minnsou/items/9b9a0c9dc01dcaac7108)はコードを読んでどのように動いているか解説していきたいと思います。