Chuyển đến nội dung chính
友田 陽大
Local LLMs: AI on your own PC
生成AI
RAG
Ollama
ローカルLLM
セルフホスト
型安全

自分のドキュメントに答えるAIをローカルで作る:プライベートRAG入門(データは外に出ない)

手元のPDF・メモ・社内資料に質問できるAIを、データを外部に一切出さずにローカルで作る方法(プライベートRAG)を、実際にRAGを本番運用するエンジニアが入門解説。RAGの仕組み、Ollamaの埋め込みAPIとコサイン類似度による最小実装、精度を上げるコツ、本番化への道筋までを、型安全なコードとともに紹介します。

Published
Reading time
9 min read
Author
友田 陽大
Chia sẻ

最初に結論を述べます。手元のPDF・メモ・社内資料に「質問したら答えてくれるAI」を、データを一切外部に出さずに、自分のPCの中だけで作れます。 この仕組みを RAG(検索拡張生成) と呼びます。ChatGPTに資料を貼り付けて聞く代わりに、ローカルLLMと組み合わせて完全にプライベートに実現する——それがプライベートRAGです。本記事は、RAGの仕組みを最短で理解し、Ollama だけで動く最小実装から、精度を上げるコツ、本番化への道筋までを、実際にRAGを本番運用しているエンジニアの視点で解説します。

本記事はローカルLLMの始め方ガイドの応用編です。Ollamaの基本はそちらを参照してください。


RAGとは?「カンペを渡して答えさせる」技術

LLMは賢いですが、あなたの手元の資料(社内規程・議事録・個人のメモ)は知りません。これを解決するのがRAGです。発想はシンプルで——質問に関連する文書を検索して見つけ、それを「根拠(カンペ)」としてLLMに一緒に渡し、その根拠に基づいて答えさせる

ファインチューニング(モデルを追加学習させる)と違い、RAGは知識をその場で注入します。資料が変わってもデータを差し替えるだけでよく、学習し直す必要がありません(この使い分けはRAG vs ファインチューニングで詳説)。

RAGの処理は、3段階です。

1. 準備(一度だけ): 手元の文書を「埋め込み(ベクトル)」に変換して保存する
   ↓
2. 検索: 質問を同じくベクトル化し、意味が近い文書を探す
   ↓
3. 生成: 見つけた文書を「根拠」として、質問と一緒にローカルLLMへ渡して答えさせる

この3段すべてを自分のPC内で動かせば、データは外部に一切出ません。これがプライベートRAGの最大の価値です。


最小実装:Ollama の埋め込みAPI + コサイン類似度

「ベクトルDBが必要そう」と身構えるかもしれませんが、少数の文書なら、Ollamaの埋め込みAPIとコサイン類似度だけで作れます。追加のデータベースも不要です。

ステップ1:文書を埋め込み(ベクトル化)する

「埋め込み」とは、文章を**意味を表す数値の配列(ベクトル)**に変換することです。意味が近い文章どうしは、ベクトルも近くなります。Ollama は埋め込み用のモデルを提供しており、ローカルで変換できます。

/** Ollamaのローカル埋め込みAPIで、テキストをベクトルに変換する。通信はlocalhostのみ=データは外に出ない。 */
async function embed(
  text: string,
  model = "nomic-embed-text",
  endpoint = "http://localhost:11434",
): Promise<readonly number[]> {
  const res = await fetch(`${endpoint}/api/embeddings`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ model, prompt: text }),
    signal: AbortSignal.timeout(30_000), // タイムアウトで止まらない(回復性)
  });
  if (!res.ok) throw new Error(`embed failed: ${res.status} ${res.statusText}`);
  const data = (await res.json()) as { embedding: readonly number[] };
  return data.embedding;
}

ステップ2:質問に近い文書を検索する(コサイン類似度)

ベクトルどうしの「近さ」は、コサイン類似度で測ります。これは外部ライブラリなしで書ける、副作用のない純粋関数です。

/** 2つのベクトルの近さ(-1〜1、1に近いほど類似)。純粋関数なので単体テストが容易。 */
function cosineSimilarity(a: readonly number[], b: readonly number[]): number {
  if (a.length !== b.length) throw new Error("vector length mismatch");
  let dot = 0;
  let normA = 0;
  let normB = 0;
  for (let i = 0; i < a.length; i++) {
    dot += a[i] * b[i];
    normA += a[i] * a[i];
    normB += b[i] * b[i];
  }
  const denom = Math.sqrt(normA) * Math.sqrt(normB);
  return denom === 0 ? 0 : dot / denom; // ゼロ除算を防ぐ(堅牢性)
}

interface Chunk {
  readonly text: string;
  readonly embedding: readonly number[];
}

/** 質問ベクトルに近い順に上位k件の文書を返す。検索ロジックは生成と分離(SRP)。 */
function retrieveTopK(
  queryEmbedding: readonly number[],
  chunks: readonly Chunk[],
  k: number,
): readonly Chunk[] {
  return chunks
    .map((c) => ({ chunk: c, score: cosineSimilarity(queryEmbedding, c.embedding) }))
    .sort((a, b) => b.score - a.score)
    .slice(0, k)
    .map((r) => r.chunk);
}

ステップ3:根拠と一緒にローカルLLMへ渡す

検索した文書を「根拠」としてプロンプトに埋め込み、ローカルLLM(始め方ガイドのストリーミングクライアント)に渡します。

function buildPrompt(question: string, context: readonly Chunk[]): string {
  const grounding = context.map((c, i) => `[${i + 1}] ${c.text}`).join("\n\n");
  // 「根拠にないことは答えない」と明示し、幻覚(でっち上げ)を抑える
  return [
    "以下の根拠だけに基づいて、質問に日本語で答えてください。",
    "根拠に答えがない場合は「資料からは分かりません」と答えてください。",
    "",
    `# 根拠\n${grounding}`,
    "",
    `# 質問\n${question}`,
  ].join("\n");
}

これで、手元の文書に基づいて答えるAIが、完全にローカルで完成します。文書の埋め込み・検索・生成のすべてが localhost で完結し、データは外に出ません。


精度を上げる3つのコツ

最小実装は動きますが、「思ったより的外れな答えが返る」こともあります。RAGの精度は、LLMの賢さではなく『検索の質』でほぼ決まります。すぐ効くコツを3つ。

  1. チャンク化(文書の分割)を整える——長い文書は、意味のまとまり(見出し・段落)で分割します。粗すぎると根拠がぼやけ、細かすぎると文脈が失われます。隣接チャンクを少し重ねる(オーバーラップ)と安定します。
  2. 固有名詞はキーワード検索で補う——ベクトル検索は「意味の近さ」は得意ですが、型番・固有名詞・略語の完全一致が苦手です。キーワード検索(全文検索)と併用する「ハイブリッド検索」にすると、精度が大きく上がります。
  3. 根拠を提示させる——回答に「どの文書を根拠にしたか」(上の例の[1][2])を含めさせると、誤りに気づけ、信頼性が上がります。

この「検索の質」を本番品質まで突き詰めると、ハイブリッド検索・リランク・評価といった設計が効いてきます。詳しくは本番RAGの落とし穴と精度改善を参照してください。私が手がけた音声接客AIでは、まさにこの検索の質を作り込むことで「専門商材の誤答を構造的に排除」しました。


本番化への道筋:文書が増えたら、業務で使うなら

最小実装は「少数の文書を、自分が使う」段階に最適です。そこから先は、規模と用途で進化させます。

段階やること
文書が数百〜数千を超えるメモリ上の総当たりから、ベクトルDB(pgvector等)へ。検索が高速・スケーラブルに
複数人・部門で使うアクセス制御を検索層に組み込む(他人の文書が混ざらないよう構造的に分離)
業務の意思決定に使う精度を測る評価の仕組みを用意し、改善を回す

特に業務利用では、アクセス制御(他人・他部門の文書が検索結果に混ざらない)が必須です。これは「あとから」では危険で、最初から検索条件に組み込む設計が要ります(本番RAGの落とし穴参照)。個人で試す最小実装から、社内全体で使う本番RAGまでは地続きですが、本番には本番の作り込みが必要です。


よくある質問(FAQ)

Q. プライベートRAGとは何ですか?

手元の文書(PDF・メモ・社内資料)に質問できるAIを、データを外部に出さずに作る仕組みです。質問に関連する文書を検索し、それを根拠としてローカルLLMに渡して答えさせるRAG(検索拡張生成)を、すべて自分のPC内で完結させます。機密情報を外部のAIに入力したくない場合に最適です。

Q. データは本当に外部に出ませんか?

文書の埋め込み・検索・生成のすべてをローカル(Ollama等)で動かせば、データは外部に送信されません。通信はlocalhostで完結します。これがプライベートRAGの最大の価値で、機密情報・個人情報・未公開資料を安心して扱えます。

Q. ベクトルデータベースは必要ですか?

少数の文書なら不要です。Ollamaの埋め込みAPIとコサイン類似度(外部ライブラリなしで書ける純粋関数)だけで作れます。文書が数百〜数千を超えて検索が遅くなってきたら、pgvectorのようなベクトルDBへ移行すると、高速でスケーラブルになります。

Q. RAGとファインチューニング、どちらを使うべきですか?

手元の資料に基づいて答えてほしいだけなら、まずRAGです。RAGは知識をその場で注入するため、資料が変わってもデータを差し替えるだけで済みます。ファインチューニング(追加学習)は文体や振る舞いを変えたいときの選択肢で、知識の更新には不向きです。詳しくは「RAG vs ファインチューニング」の記事を参照してください。

Q. 答えが的外れになります。どうすれば精度が上がりますか?

RAGの精度は「検索の質」でほぼ決まります。LLMを賢いモデルに変える前に、(1)文書のチャンク化を整える、(2)固有名詞に弱いベクトル検索をキーワード検索と併用する(ハイブリッド検索)、(3)根拠を提示させる、を試してください。それでも不十分なら、リランクや評価の仕組みといった本番RAGの設計が必要です。


まとめ:ローカルで完結する「自分専用AI」

手元の資料に答えるAIをプライベートに作るために、押さえるべきは次の通りです。

  1. RAGは『関連文書を検索し、根拠としてLLMに渡して答えさせる』技術——ローカルで完結すればデータは外に出ない。
  2. 仕組みは3段——埋め込み→検索→生成。すべて自分のPC内で動かせる。
  3. 最小実装はOllamaの埋め込みAPI+コサイン類似度だけ——少数の文書ならDBも不要。
  4. 精度の鍵は『検索の質』——チャンク化・ハイブリッド検索・根拠提示で上げる。
  5. 本番化の道筋がある——ベクトルDB・アクセス制御・評価へと段階的に発展できる。

「社内の資料に答えるAIを、データを外に出さずに業務へ導入したい」——個人で試す最小実装から、アクセス制御と精度評価を備えた本番の社内RAGまで、私は実務で構築しています。お気軽にご相談ください。

友田

友田 陽大

Người phát triển sản phẩm đoạt Giải thưởng Bộ trưởng (METI). Với TypeScript + Python + AWS, tôi một mình triển khai trọn gói SaaS, chuyển đổi số công nghiệp và AI tạo sinh (RAG) sẵn sàng cho production — từ phân tích yêu cầu đến hạ tầng và vận hành.

I can take on the implementation from this article as an engagement

Self-hosting infrastructure for open-weight LLMs — build, production operations, and cost optimization

I've run Qwen3-8B-AWQ and 4-bit quantized Llama 3 in production on vLLM, operated as a reproducible inference stack on spot GPUs (Tesla T4) with Terraform. Quantization choice, VRAM and throughput sizing, swappable models behind a provider abstraction, and resumption after forced preemption — I design and implement inference infrastructure that stays up.

Nhận cả dự án trọn gói lẫn vai trò cố vấn kỹ thuật. Hãy bắt đầu bằng buổi tư vấn miễn phí 30 phút.

最短ルート:カレンダーから直接予約

相談内容が固まっている方は、フォーム送信よりその場で日程を確定する方がスムーズです。下記から空き時間をお選びください。

  • 30分のオンライン無料相談
  • Google Meet / Zoom / Microsoft Teams
  • NDA 商談前締結可・無理な営業はいたしません
無料相談の空き枠を予約する

Cũng đáng đọc