---
createdAt: 2025-09-10
updatedAt: 2025-09-10
title: RAG搭載ドキュメントアシスタントの構築（チャンク分割、埋め込み、検索）
description: RAG搭載ドキュメントアシスタントの構築（チャンク分割、埋め込み、検索）
keywords:
  - RAG
  - ドキュメント
  - アシスタント
  - チャンク分割
  - 埋め込み
  - 検索
slugs:
  - blog
  - rag-powered-documentation-assistant
---

# RAG搭載ドキュメントアシスタントの構築（チャンク分割、埋め込み、検索）

## 得られるもの

私はRAG搭載のドキュメントアシスタントを構築し、すぐに使えるボイラープレートとしてパッケージ化しました。

- すぐに使えるアプリケーション（Next.js + OpenAI API）付き
- 動作するRAGパイプライン（チャンク分割、埋め込み、コサイン類似度）を含む
- Reactで構築された完全なチャットボットUIを提供
- すべてのUIコンポーネントはTailwind CSSで完全に編集可能
- すべてのユーザークエリをログに記録し、欠落しているドキュメント、ユーザーの問題点、製品の機会を特定するのに役立てる

👉 [ライブデモ](https://intlayer.org/doc/why) 👉 [コードボイラープレート](https://github.com/aymericzip/smart_doc_RAG)

## はじめに

ドキュメントの中で迷子になり、答えを探して延々とスクロールしたことがあるなら、その苦痛はよくわかるでしょう。ドキュメントは役に立ちますが、静的であり、検索も使いづらいことが多いです。

そこで登場するのが**RAG（Retrieval-Augmented Generation、検索強化生成）**です。ユーザーにテキストを掘り下げさせる代わりに、**検索**（ドキュメントの適切な部分を見つける）と**生成**（LLMが自然に説明する）を組み合わせることができます。

この投稿では、私がどのようにしてRAG搭載のドキュメントチャットボットを構築したか、そしてそれがユーザーがより速く答えを見つけるのを助けるだけでなく、プロダクトチームがユーザーの課題を理解する新しい方法を提供するかを説明します。

## なぜドキュメントにRAGを使うのか？

RAGが人気のアプローチになったのには理由があります。それは、大規模言語モデルを実際に役立てる最も実用的な方法の一つだからです。

ドキュメントにおける利点は明確です：

- 即時回答：ユーザーは自然言語で質問し、関連する回答を得られます。
- より良いコンテキスト：モデルは最も関連性の高いドキュメントの部分だけを参照するため、幻覚（誤情報）が減ります。
- 人間らしい検索体験：Algolia + FAQ + チャットボットを一つにまとめたような感覚です。
- フィードバックループ：クエリを保存することで、ユーザーが本当に困っていることを明らかにします。

その最後のポイントは非常に重要です。RAGシステムは単に質問に答えるだけでなく、人々が何を尋ねているのかを教えてくれます。つまり：

- ドキュメントに不足している情報を発見できます。
- 新たな機能リクエストが浮かび上がってきます。
- 製品戦略を導くパターンを見つけることもできます。

ですから、RAGは単なるサポートツールではありません。**プロダクト発見エンジン**でもあるのです。

## RAGパイプラインの仕組み

![RAG Pipeline](https://github.com/aymericzip/intlayer/blob/main/docs/assets/rag_flow.svg)

大まかに言うと、私が使ったレシピは以下の通りです：

1.  **ドキュメントのチャンク分割** 大きなMarkdownファイルをチャンクに分割します。チャンク分割により、ドキュメントの関連部分だけをコンテキストとして提供できます。
2.  **埋め込みの生成** 各チャンクをOpenAIの埋め込みAPI（text-embedding-3-large）やベクターデータベース（Chroma、Qdrant、Pinecone）を使ってベクトルに変換します。
3.  **インデックス作成と保存** 埋め込みはシンプルなJSONファイルに保存されます（デモ用）が、本番環境ではベクターデータベースを使用することが多いでしょう。
4.  **検索（RAGのR）** ユーザーのクエリを埋め込み、コサイン類似度を計算し、最もマッチするチャンクを取得します。
5.  **拡張と生成（RAGのAG）** 取得したチャンクをChatGPTのプロンプトに注入し、モデルが実際のドキュメントの文脈を踏まえて回答します。
6.  **フィードバックのためのクエリのログ記録** すべてのユーザークエリを保存します。これは問題点の把握、ドキュメントの不足、新たな機会の発見に非常に役立ちます。

## ステップ1: ドキュメントの読み込み

最初のステップはシンプルでした：docs/フォルダ内のすべての.mdファイルをスキャンする方法が必要でした。Node.jsとglobを使って、各Markdownファイルの内容をメモリに取得しました。

これによりパイプラインは柔軟になります。Markdownの代わりに、データベースやCMS、さらにはAPIからドキュメントを取得することも可能です。

## ステップ 2: ドキュメントのチャンク分割

なぜチャンク分割をするのか？それは言語モデルには**コンテキストの制限**があるからです。ドキュメント全体を一度に与えることはできません。

そこで、テキストを扱いやすいチャンク（例：各500トークン）に分割し、重複部分（例：100トークン）を設けます。重複部分は連続性を保ち、チャンクの境界で意味が失われないようにします。

**例：**

- チャンク1 → 「…多くの人が忘れていた古い図書館。そのそびえ立つ棚は本でいっぱいだった…」
- チャンク2 → 「…棚はあらゆるジャンルの本で満たされており、それぞれが物語をささやいていた…」

重複部分により、両方のチャンクが共通のコンテキストを含むため、検索時の一貫性が保たれます。

このトレードオフ（チャンクサイズとオーバーラップのバランス）は、RAGの効率性にとって重要です：

- 小さすぎると → ノイズが増えます。
- 大きすぎると → コンテキストサイズが膨れ上がります。

## ステップ3：埋め込みの生成

ドキュメントをチャンクに分割したら、各チャンクを表す高次元ベクトルである**埋め込み**を生成します。

私はOpenAIのtext-embedding-3-largeモデルを使用しましたが、任意の最新の埋め込みモデルを使うことができます。

**埋め込みの例：**

```js
[
  -0.0002630692, -0.029749284, 0.010225477, -0.009224428, -0.0065269712,
  -0.002665544, 0.003214777, 0.04235309, -0.033162255, -0.00080789323,
  //...+1533 elements
];
```

各ベクトルはテキストの数学的な指紋であり、類似検索を可能にします。

## ステップ4：埋め込みのインデックス作成と保存

埋め込みを何度も再生成しないように、embeddings.jsonに保存しました。

本番環境では、以下のようなベクトルデータベースを使用することが一般的です：

- Chroma
- Qdrant
- Pinecone
- FAISS、Weaviate、Milvusなど

ベクトルDBはインデックス作成、スケーラビリティ、高速検索を処理します。しかし、私のプロトタイプではローカルのJSONで十分でした。

## ステップ5：コサイン類似度による検索

ユーザーが質問をしたとき：

1. クエリの埋め込みを生成する。
2. すべてのドキュメント埋め込みと**コサイン類似度**で比較する。
3. 最も類似度の高い上位N個のチャンクだけを保持する。

コサイン類似度は2つのベクトル間の角度を測定します。完全一致は**1.0**のスコアです。

この方法で、システムはクエリに最も近いドキュメントの部分を見つけます。

## ステップ6：拡張＋生成

ここで魔法が始まります。上位のチャンクを取り出し、それらをChatGPTの**システムプロンプト**に注入します。

それは、モデルがまるでそれらのチャンクが会話の一部であるかのように回答することを意味します。

結果：正確で、**ドキュメントに基づいた応答**。

## ステップ7：ユーザークエリのログ記録

これが隠れたスーパーパワーです。

ユーザーが尋ねたすべての質問が保存されます。時間が経つにつれて、以下のようなデータセットが構築されます：

- 最も頻繁に尋ねられる質問（FAQに最適）
- 未回答の質問（ドキュメントが不足しているか不明瞭）
- 質問に偽装された機能リクエスト（「Xと統合できますか？」など）
- 予期していなかった新たなユースケース

これにより、あなたのRAGアシスタントは**継続的なユーザーリサーチツール**に変わります。

## コストはどのくらいかかるのか？

RAGに対する一般的な反論の一つはコストですが、実際には驚くほど安価です：

- 約200件のドキュメントの埋め込み生成は約**5分**で、費用は**1〜2ユーロ**程度です。
- ドキュメント検索機能は100％無料です。
- クエリには「thinking」モードなしで gpt-4o-latest を使用しています。Intlayer では、月に約 **300 件のチャットクエリ** があり、OpenAI API の請求額はめったに **10ドル** を超えません。

その上に、ホスティングコストを含めることができます。

## 実装の詳細

スタック:

- モノレポ: pnpm ワークスペース
- ドキュメントパッケージ: Node.js / TypeScript / OpenAI API
- フロントエンド: Next.js / React / Tailwind CSS
- バックエンド: Node.js API ルート / OpenAI API

`@smart-doc/docs` パッケージはドキュメント処理を担当する TypeScript パッケージです。Markdown ファイルが追加または変更されると、このパッケージには各言語のドキュメントリストを再構築し、埋め込みを生成し、それらを `embeddings.json` ファイルに保存する `build` スクリプトが含まれています。

フロントエンドには、以下を提供する Next.js アプリケーションを使用しています:

- MarkdownをHTMLにレンダリングする機能
- 関連するドキュメントを検索するための検索バー
- ドキュメントに関する質問を行うためのチャットボットインターフェース

ドキュメント検索を実行するために、Next.jsアプリケーションにはAPIルートが含まれており、`@smart-doc/docs`パッケージの関数を呼び出してクエリに一致するドキュメントチャンクを取得します。これらのチャンクを使用して、ユーザーの検索に関連するドキュメントページのリストを返すことができます。

チャットボット機能については、同じ検索プロセスを踏みますが、取得したドキュメントチャンクをChatGPTに送信するプロンプトに追加で注入します。

以下はChatGPTに送信されるプロンプトの例です：

システムプロンプト：

```txt
あなたはIntlayerのドキュメントに関する質問に答えることができる有用なアシスタントです。

関連チャンク：

-----
docName: "getting-started"
docChunk: "1/3"
docUrl: "https://example.com/docs/ja/getting-started"
---

# はじめに

...

-----
docName: "another-doc"
docChunk: "1/5"
docUrl: "https://example.com/docs/ja/another-doc"
---

# 別のドキュメント

...
```

ユーザーのクエリ：

```txt
はじめにどうすればいいですか？
```

APIルートからのレスポンスはSSEを使ってストリーミングします。

前述の通り、"thinking"モードなしでgpt-4-turboを使用しています。応答は関連性が高く、レイテンシも低いです。
gpt-5も試しましたが、レイテンシが高すぎました（返信に最大15秒かかることもありました）。しかし将来的に再検討する予定です。

👉 [ここでデモを試す](https://intlayer.org/doc/why) 👉 [GitHubでコードテンプレートを確認](https://github.com/aymericzip/smart_doc_RAG)

## さらに進むために

このプロジェクトは最小限の実装です。しかし、以下のように多くの方法で拡張できます：

- MCPサーバー → ドキュメント検索機能をMCPサーバーに移行し、ドキュメントをあらゆるAIアシスタントに接続可能にする

- ベクターデータベース → 数百万のドキュメントチャンクにスケール可能
- LangChain / LlamaIndex → RAGパイプライン用の既製フレームワーク
- 分析ダッシュボード → ユーザーのクエリや問題点を可視化
- マルチソース検索 → ドキュメントだけでなく、データベースのエントリ、ブログ投稿、チケットなども取得可能
- 改良されたプロンプティング → 再ランキング、フィルタリング、ハイブリッド検索（キーワード＋セマンティック）

## 直面した制限事項

- チャンク分割と重複は経験則に基づく。適切なバランス（チャンクサイズ、重複率、取得チャンク数）は反復とテストが必要。
- ドキュメントが変更されても埋め込みは自動再生成されない。システムは、保存されているチャンク数と異なる場合にのみファイルの埋め込みをリセットする。
- このプロトタイプでは、埋め込みはJSONに保存されています。これはデモには適していますが、Gitを汚染します。本番環境では、データベースや専用のベクターストアの方が適しています。

## ドキュメントを超えて重要な理由

興味深いのは単なるチャットボットだけではありません。**フィードバックループ**です。

RAGを使うと、単に答えるだけではなく：

- ユーザーが何に混乱しているかを学びます。
- 彼らがどの機能を期待しているかを発見します。
- 実際のクエリに基づいて製品戦略を適応させます。

**例：**

新機能をリリースしてすぐに以下がわかると想像してください：

- 質問の50％が同じ不明瞭なセットアップ手順に関するもの
- ユーザーがまだサポートしていない統合を繰り返し求める
- 新しいユースケースを示す用語で検索される

それがユーザーから直接得られる**プロダクトインテリジェンス**です。

## 結論

RAGは、LLMを実用的にする最もシンプルで強力な方法の一つです。**検索（retrieval）＋生成（generation）**を組み合わせることで、静的なドキュメントを**スマートアシスタント**に変え、同時に継続的な製品インサイトの流れを得ることができます。

私にとって、このプロジェクトはRAGが単なる技術的なトリックではないことを示しました。RAGはドキュメントを以下のように変革する方法です：

- インタラクティブなサポートシステム
- フィードバックチャネル
- 製品戦略ツール

👉 [ここでデモを試す](https://intlayer.org/doc/why) 👉 [GitHubでコードテンプレートを確認する](https://github.com/aymericzip/smart_doc_RAG)

もしあなたもRAGを試しているなら、どのように使っているかぜひ教えてください。
