完全オフラインのローカルRAGを構築するハンズオン

🛠️ ハンズオン|完全オフライン構築ガイド

完全オフラインのローカルRAGを構築するハンズオン

Ollama・nomic-embed-text・Chroma・LangChainだけで、社外秘マニュアルにも個人ファイルにも安心して質問できる「データを一歩も外に出さないAI」を、実際に動くコードで作ります。

🦙 Ollama 🧬 埋め込みモデル 🗄️ Chroma 🔗 LangChain 🔒 情報漏えい対策
🧭

この記事で作るもの

会社の社外秘マニュアルや、自分しか見ない個人ファイルを、インターネットに一切送信せずにAIへ質問できる「完全オフラインのドキュメントQ&Aシステム」を、実際に動くコードで構築します。使うのはOllama・埋め込みモデル「nomic-embed-text」・ベクターデータベース「Chroma」・つなぎ役の「LangChain」の4点だけ。Ollamaの基本操作がまだの方はOllamaとは何かから、PC選びに迷っている方は最適なモデル選びとPCスペックを先に読むとスムーズです。Pythonの基本的な実行経験(pip installやスクリプトの実行ができる程度)があれば十分で、AI・機械学習の専門知識は必要ありません。

01

なぜ「完全オフライン」が最強の情報漏えい対策なのか

クラウドAIに社外秘を読ませるのが怖い理由と、ローカルRAGがその不安をゼロにする仕組み

🧠

そもそもRAGって何だ?

RAG(Retrieval-Augmented Generation:検索拡張生成)は、ひとことで言うと「優秀だけど社外の事情を何も知らない新入社員に、まず関連資料だけを手渡してから質問に答えてもらう」しくみです。AIモデル自体は社外秘プロジェクトの内容を学習していません。質問が来るたびに関連する資料の切れ端をデータベースから探し出し、それを参考資料として渡してから回答させます。AI自身の知識を増やすのではなく「答えるための資料」を毎回手渡す——だから検索(Retrieval)+拡張(Augmented)+生成(Generation)なのです。基礎をもう少し詳しく知りたい方はRAGとは何かも参考にしてください。

クラウドAIのリスクは漏えいそのものより「気づけないこと」にあります。多くのAPI利用規約では、入力した文章を一定期間保持し、不正利用の監視や品質改善に使う場合があると定められています。無料プランや一部のビジネスプランでは、入力データが学習データとして再利用される可能性も排除できません。社外秘マニュアルや顧客情報を質問文に含めた瞬間、それは契約上の秘密保持義務(NDA)違反や、個人情報保護法上の第三者提供に該当しかねません。しかも一度送信したデータを相手のサーバーから完全に消し去ったことを、利用者側が確認する手段はほとんどありません。ローカルRAGはこの「気づけないリスク」自体を構造的に消せる点が最大の価値です。

具体的には、就業規則や社内規定の問い合わせ対応、製品マニュアルの検索、契約書のひな形確認、研究ノートや議事録の振り返りなど、「答えは社内のどこかにあるはずだが、探すのに時間がかかる」という場面ほどローカルRAGの効果が大きく出ます。質問する側は身構えずに自然な日本語で聞けばよく、AIが該当箇所を探し出して根拠付きで答えてくれます。

📊 クラウドAI API利用 と 完全オフラインRAG の比較

比較項目☁ クラウドAI API利用🔒 完全オフラインRAG
データの外部送信 質問・資料の内容を毎回ネット経由で送信 ゼロ。データはPCの中から一歩も出ない
情報漏えいへの強さ
35
96
運用コストの形 質問量に応じて課金され続ける 電気代のみ。大規模化はGPU投資が中心
回答の汎用知識・最新性
90
55
社内規定・契約上の安心感
40
94

※スコアは一般的傾向の目安です。契約内容やモデルにより変わります。

💡

「完全オフライン」の定義

Ollama自体はPCの中で推論しますが、モデルの初回ダウンロードはインターネット接続を必要とします。本当に外部送信していないかを確かめる方法は、⑤章で実際に手を動かして確認します。

02

ローカルRAGの仕組み ─ 中身では何が起きているのか

質問してから回答が返るまで、PCの中で何が起きているのかを2枚の図で分解する

🧬

役割の違う2つのAIモデル

このシステムには性格の異なる2つのAIモデルが登場します。ひとつは「nomic-embed-text」——文章の意味を数字の並び(ベクトル)に変換するだけの専門モデルで、自分の言葉で会話したり回答を生成したりはしません。もうひとつは「qwen3:4b」——実際に質問に答える文章を生成する、いわゆるLLM本体です。検索を担当する係と、回答を考える係が分業している、と捉えると理解しやすくなります。

検索・索引役

nomic-embed-text

文章やドキュメントの「意味」を高次元の数値ベクトルに変換する専用モデル。対話はできないが、文章どうしの近さを測ることに特化している。

規模約137Mパラメータ
役割質問と資料の近さを測る
容量目安数百MB
回答生成役

qwen3:4b

検索で見つかった資料を読み、実際に答えの文章を組み立てるLLM本体。日本語の理解力に定評があり、4Bという軽量サイズでもノートPCで動かしやすい。

規模約40億(4B)パラメータ
役割資料を根拠に回答文を生成
容量目安約3〜5GB

まず最初に1回だけ、すべての資料を読み込んでデータベース化する「仕込み」の作業が走ります。

🗂️ フェーズ1:インデックス作成(最初に1回だけ)

読み込み docs内のtxt/pdf チャンク分割 500字+重複100字 ベクトル化 nomic-embed-text (AIモデルが働く) DB保存 Chroma(./db) ① 読み込み ② 分割 ③ ベクトル化 ④ 保存

データベースができてしまえば、あとは質問するたびに次の4ステップが一瞬で実行されます。

💬 フェーズ2:質問応答(質問するたびに毎回)

ベクトル化 nomic-embed-text (AIモデルが働く) 検索 Chromaから近い3件 プロンプト合成 資料+質問を結合 生成 qwen3:4b (AIモデルが働く)

ここで使った数字にも意味があります。チャンクを500字で切るのは、AIが一度に参照する文章量を「意味のまとまりを保てる程度」に保つためです。短すぎると文脈が途切れ、長すぎると無関係な情報が混ざって回答の精度が落ちます。100字の重複(オーバーラップ)を持たせるのは、文の境界でちょうど重要な一文が分断されてしまう事故を防ぐ工夫です。検索件数をk=3に絞っているのも同じ理由で、件数を増やすほど情報は増えますが、AIに無関係な文章まで読ませることになり、処理が遅くなったり回答がぼやけたりします。

ポイントは、ネットワーク通信が一切登場しないことです。ベクトル化も検索も生成も、すべて同じPCの中のプロセス間でデータがやり取りされるだけ。だから後述するように、Wi-Fiを切っても全く同じように動きます。

03

実装ハンズオン ─ 動くコードで構築する

ここから実際に手を動かします。フォルダを1つ作るところから、質問が返ってくるところまで

📁

準備するフォルダ構成

作業フォルダの中に docs という名前のフォルダを作り、読み込ませたい社外秘テキストファイル(例:secret_project.txt)を置きます。スクリプトは local_rag.py として同じ階層に保存します。最初は数ファイルの小さなテキストで試し、動作を確認してから対象を増やすのが安全です。

1

Ollamaにモデルを2つ入れる

埋め込み用とLLM用、それぞれ1回pullすれば準備完了

2

Pythonライブラリを導入する

LangChainとChroma関連を一括インストール

3

ドキュメントを読み込む

docsフォルダ内のテキストを自動で集める

4

分割してベクトル化・保存する

検索しやすい単位に切り、Chromaへ格納

5

検索とLLMを連結する

資料を渡しながら回答させるチェーンを作る

6

質問を実行する

自然文で聞くだけ。Wi-Fiを切っても結果は変わらない

まずはターミナルで、テキストをベクトル化する「埋め込みモデル」と、回答を生成する「LLM」の2つをダウンロードします。

# 事前準備:Ollamaにモデルを2つpullする
# ① 文章を数値化(ベクトル化)する軽量・高性能モデル
ollama pull nomic-embed-text

# ② 質問に回答するLLM(日本語に強い軽量モデルの例)
ollama pull qwen3:4b

続けて、RAGの組み立てに使うPythonライブラリを導入します。

# 必要なライブラリのインストール
# LangChain本体・Ollama連携・Chroma(ベクターDB)をまとめて導入
pip install langchain langchain-community langchain-chroma chromadb

ここからが本体のコードです。前半は「読み込み→分割→ベクトル化→保存」、つまりフェーズ1(インデックス作成)にあたる部分です。

# local_rag.py(前半)─ 読み込み・分割・ベクトル化・保存
import os
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.embeddings import OllamaEmbeddings
from langchain_chroma import Chroma

# ① docsフォルダ内のすべての.txtファイルを読み込む
loader = DirectoryLoader('./docs', glob="**/*.txt", loader_cls=TextLoader)
documents = loader.load()

# ② 長文を500字単位(100字重複)に分割──検索精度を上げる下準備
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)
texts = splitter.split_documents(documents)

# ③ Ollamaのnomic-embed-textでベクトル化
embeddings = OllamaEmbeddings(model="nomic-embed-text")

# ④ ./db フォルダにベクトルを保存──ここで完全オフラインのDBが完成する
vector_store = Chroma.from_documents(
    documents=texts,
    embedding=embeddings,
    persist_directory="./db"
)

後半は「検索→プロンプト合成→生成」、つまりフェーズ2(質問応答)にあたる部分です。前半のスクリプトに続けて書きます。

# local_rag.py(後半)─ 検索・LLM連結・質問実行
from langchain_community.llms import Ollama
from langchain.chains import RetrievalQA

# ① 質問に近いチャンクを3件だけ持ってくる検索役を用意
retriever = vector_store.as_retriever(search_kwargs={"k": 3})

# ② 回答生成用のローカルLLM(temperature=0で創作を抑え事実重視に)
llm = Ollama(model="qwen3:4b", temperature=0)

# ③ 検索とLLMを1本のチェーンに結合
qa_chain = RetrievalQA.from_chain_type(llm=llm, chain_type="stuff", retriever=retriever)

# ④ 実行──Wi-Fiを切っても同じ回答が返ってくる
query = "社外秘プロジェクト『X』のリリース時期と注意点は何ですか?"
response = qa_chain.run(query)
print(response)

temperature=0は、AIの「創作性」を最小限に抑える設定です。値が高いほど表現は豊かになりますが、社外秘マニュアルの内容確認のように正確性が最優先の場面では0に固定し、資料に書かれていないことを勝手に作文(ハルシネーション)させないようにします。またchain_type="stuff"は、検索で見つかった資料をそのまま1つのプロンプトに詰め込んで渡す、最もシンプルな合成方法です。資料の件数が多くなる場合は、いったん要約してから渡すmap_reduceなどの方式に切り替えることもできます。

実行すると、docsフォルダの中身を根拠にした回答が返ってきます。仕組みは②章の図解そのもので、①ベクトル化→②検索→③プロンプト合成→④生成、の4ステップがこの数行の裏側で動いています。同じ質問をWi-Fiを切った状態で試せば、次の⑤章で確認するとおり、結果が変わらないことも体感できます。

拡張のヒント

PDFやWordも読みたい場合は、pypdfdocx2txtなどのローダーを追加し、DirectoryLoaderのglobパターンを**/*.pdfなどに変えるだけで対応できます。読み込めるかどうかは1冊だけ先にテストするのが安全です(詳しくは④⑤章)。

04

大規模運用に必要なスペック(PDF300冊・3万ページ)

「社外秘マニュアル100枚×300冊」級になると、必要なPCスペックが一気に変わる

📐

まずは規模を数字にする

PDF100枚×300冊=合計3万ページ。1ページ1,000字とすると約3,000万字、500字ずつのチャンクに切ると6万〜10万個のベクトルデータが生まれます。これは個人のローカルRAGとしては「エンタープライズ一歩手前」の規模で、数十ファイル程度の検証用とは必要スペックが大きく異なります。最適なモデル選びの基礎は最適なモデル選びとPCスペックも参照してください。

判断基準①

メインメモリ(RAM)

ChromaなどのベクターDBは検索を爆速にするため、データをRAM上に展開する。10万件クラスのベクトル+元テキストを保持すると、DBだけで数GB〜10GB近くを消費する。

結論32GB以上が安全圏
注意16GBはフリーズ・スワップのリスク
判断基準②

ビデオメモリ(VRAM)

モデル自体の容量5〜10GBに加え、検索で見つかった長文をAIの頭(コンテキスト)に詰め込む処理で、追加2〜4GBのVRAMを消費する。

推奨モデルqwen3:7b〜14bクラス
結論12GB〜16GB以上が目安
判断基準③

CPU・コア数

300冊を最初にすべてベクトル化する「初期インポート」は、CPUとGPUをフル回転させる重い処理。低スペックだと丸1日以上かかることもある。

推奨i7/i9・Ryzen7/9等マルチコア
所要時間数時間〜半日(一度きり)

💻 PDF300冊(3万ページ)規模の推奨PCスペック

コンポーネント快適・プロ仕様(おすすめ)最低限(要妥協)
OSWindows 11 または macOS同左
GPU(VRAM)RTX 4070 Ti SUPER(16GB)RTX 4060 Ti(16GB)/RTX 4070(12GB)
Macの場合M3/M4 Pro/Max(メモリ48GB以上)M2/M3/M4(メモリ32GB)
メインメモリ32GB〜64GB16GB(かなりギリギリ)
ストレージNVMe SSD 1TB以上SSD 512GB以上

※読込速度がボトルネックになりやすいため、ストレージはNVMe SSDを推奨。

もう一つ覚えておきたいのは、300冊すべてを毎回ベクトル化し直す必要はないという点です。マニュアルが1冊追加・改訂されたときは、その差分ファイルだけを読み込んでvector_store.add_documents()のように追記すれば済みます。初回の重いインポートは一度だけ我慢すれば、その後の運用はずっと軽くなります。保存先の./dbフォルダ自体も、3万ページ規模では数GB〜十数GBに育つため、ストレージの空き容量と、後述するバックアップ先にも余裕を持たせておきましょう。

⚠️

推奨モデルも引き上げる

3万ページ規模では、本記事で使ったqwen3:4bのような軽量モデルだと文章のニュアンスを読み違え、誤った回答(ハルシネーション)をしやすくなります。qwen3:7bqwen3:14bクラスへの切り替えも検討してください(VRAMとの兼ね合いは上のカード参照)。

05

落とし穴と注意点 ─ 本当にオフラインか確認する

「オフラインだから安全」と思い込む前に、確かめておきたいこと

完全オフラインで動くことと、勝手に安全になることは別の話です。ここでは構築時によくある2つの落とし穴と、本当にオフラインかどうかの確認方法を見ていきます。

🚨 重要

紙をスキャンしただけの画像PDFは、文字情報を一切含んでいません。Pythonの標準的なローダーでは何も抽出できず、RAGはエラーも出さずに空っぽのデータベースのまま動いてしまいます。pypdfpdfplumberで実際にテキストが抽出できるかを、本番投入の前に必ず1冊だけテストしてください。文字が拾えなければ、事前にOCR(文字認識)処理が必要です。

⚠ 注意

Wi-Fiを切って動くことを確認しても、それだけでは終わりません。OllamaはOLLAMA_HOST=0.0.0.0のような設定で社内LANや外部に公開できてしまい、無認証のまま誰でもアクセスできる状態になり得ます。ポートを公開していないか、ファイアウォール設定とあわせて確認してください(詳細はローカルLLMセキュリティ完全ガイド、実例はローカルAIデータ流出防止)。

✅ オフライン確認チェックリスト

  • Wi-Fi/LANを切断した状態で同じ質問をしても回答が返るか確認した
  • 1冊だけ先にOCR・テキスト抽出テストを行い、文字が拾えるか確認した
  • OllamaのOLLAMA_HOST127.0.0.1のままで、0.0.0.0等に変更していない
  • dbフォルダや資料フォルダのアクセス権限が、必要な人だけに絞られている

./dbフォルダはこのシステムの「記憶」そのものです。誤って削除すれば再構築(=再度の重いベクトル化)が必要になるため、定期的なバックアップを忘れないでください。逆に、社外秘マニュアルの提供が終了した、あるいは内容が古くなった場合は、該当する元ファイルをdocsフォルダから削除し、データベースを再構築することで、AIが古い情報や不要になった機密情報を参照し続ける事態を防げます。

✅ 対策済み確認

上の4点を満たしていれば、最初の「完全オフライン・ドキュメントQ&Aシステム」としては安全に運用できる状態です。規模を広げる際は④章のスペックと、社内での利用ルール(AI利用ガイドライン雛形)も合わせて整えましょう。

06

まとめ・よくある質問

3つのポイントと、よくある質問

🔒

データは外に出さない

質問も資料も同じPCの中だけで処理

🧩

役割の違う2つのAI

索引役と回答役が分業している

📈

規模に応じて伸びる

数十ファイルはノートPCでも、数万ページはGPU/メモリ次第

まずは数ファイルの小さなテキストで通して動かし、Wi-Fi切断テストと1冊だけのPDF抽出テストをクリアしてから、本番の資料を増やしていくのが安全な進め方です。慣れてきたら④章を参考にモデルやスペックを引き上げ、社内で使うなら⑤章のチェックリストと利用ガイドラインを必ずセットで整えてください。

ここまでの内容を、よくある疑問の形でも振り返っておきます。

無料で使えますか?

はい。Ollama・LangChain・Chromaはすべてオープンソースで無料です。必要なのはPC本体の性能のみで、大規模化のためにGPUを新規購入する場合はその費用がかかります。

PDFの日本語がうまく拾えません

スキャンしただけの画像PDFが原因の可能性が高いです。⑤章で触れたとおり、pypdfpdfplumberでテキスト抽出ができるかを先に確認し、できなければOCR処理を挟んでください。

ChatGPTのAPIを使う場合と何が違いますか?

最大の違いはデータが外部に送信されるかどうかです。料金体系・リスクの違いはChatGPTより危険?ローカルAI「Ollama」の意外なセキュリティリスクで詳しく比較しています。

nomic-embed-textじゃないと駄目ですか?

いいえ。mxbai-embed-largebge-m3など他の埋め込みモデルもOllamaから利用できます。日本語文書が多い場合は、対応言語と精度のバランスを見て選んでください。

会社で導入する際の注意点は?

「クラウドに送れないデータ」を扱える利点がありますが、無秩序な導入はシャドーAIになります。AI利用ガイドライン雛形で運用ルールを定め、本記事の多層防御をセットで整えてください。

もっと簡単にGUIで使いたいのですが

コマンドライン操作に抵抗がある場合は、OllamaとOpen WebUI完全攻略を参照してください。ブラウザ画面からファイルをアップロードして質問できるようになります。

Macでも同じ手順で動きますか?

はい。OllamaはWindows・Mac・Linuxに対応しており、コマンドはほぼ共通です。Apple SiliconのMacはGPUとメモリを共有するUnified Memory構成のため、大規模運用時は④章のメモリ目安を参考にしてください。

複数人で共有して使うのは危険ですか?

同じPC内で家族や同僚と共有する程度であれば問題ありませんが、ネットワーク経由で複数人にOllamaを開放する場合は⑤章の注意点がそのまま当てはまります。認証の仕組みを別途用意してください。

古いマニュアルを消したら、AIの回答もすぐ反映されますか?

いいえ。⑤章で触れたとおり、元ファイルをdocsフォルダから削除しただけではデータベースの中身は変わりません。./dbフォルダの再構築(または該当データのみの削除)までがワンセットです。

📚 主な参考・一次情報

  • Ollama 公式ドキュメント(https://ollama.com/)── モデルライブラリ・コマンド仕様
  • LangChain 公式ドキュメント(https://python.langchain.com/)── DocumentLoader・TextSplitter・RetrievalQAの仕様
  • Chroma 公式サイト(https://www.trychroma.com/)── ベクターデータベースの仕様・永続化オプション
  • nomic-embed-text モデルカード(Ollamaライブラリ内で配布)── パラメータ数・推奨用途
  • 情報セキュリティ全般の基礎は、IPA(情報処理推進機構)の各種ガイドラインも合わせて参照すると理解が深まります。
基礎から読む

RAGとは何か|検索拡張生成のしくみを基礎から解説

本記事はこの「RAGとは」の実装編にあたります。概念をもう一度整理したい方はこちらから読むと理解が深まります。

まとめ・ハブ

AI×セキュリティ完全ガイド(まとめハブ)

Ollama・ローカルLLM・AIエージェントのセキュリティ関連記事を1ページに整理。次に読む記事を探すならここから。

コメント