Python MCPサーバーにRAG機能を追加する

MCP

はじめに

前回の記事では Python で MCP サーバーを作成し、Docker コンテナとして起動する手順を紹介しました。
今回はそのサーバーに Weaviate を使った RAG (Retrieval-Augmented Generation) 機能を追加します。
ローカルのドキュメントをベクトル化してインデックスし、MCP ツールを通じて自然言語で検索できるようにします。

プロジェクト構成

プロジェクトの構成は以下のようになります。

python-mcp-handson
├── Dockerfile
├── LICENSE
├── README.md
├── docker-compose.yml
├── docs
│   ├── overview.md
│   └── rag.md
├── pyproject.toml
├── src
│   ├── index_docs.py
│   └── main.py
└── uv.lock

リポジトリ

今回はソースコードが長くなるため、GitHub リポジトリにコードをアップロードしています。
コードの詳細はリポジトリを参照してください。

ポイントの説明

RAG について

RAG (Retrieval-Augmented Generation) は、外部の知識ベースやドキュメントから情報を検索し、その情報を元にテキスト生成を行う手法です。
この手法を使うことで、モデルがトレーニングデータに含まれていない最新の情報や、特定のドキュメントに基づいた回答を生成できるようになります。

ツール

今回追加するツールは以下の 2 つです。

ツール名説明
search_docs自然言語クエリでドキュメントをセマンティック検索する
list_indexed_sourcesインデックス済みのドキュメント一覧を返す

Weaviate の設定

Weaviate は Docker で起動します。今回は埋め込みモデルとして OpenAI の text-embedding-3-small を使用するので、モジュールは text2vec-openai を使用しています。

weaviate:
  image: cr.weaviate.io/semitechnologies/weaviate:1.28.4
  environment:
    DEFAULT_VECTORIZER_MODULE: "text2vec-openai"
    ENABLE_MODULES: "text2vec-openai"
    OPENAI_APIKEY: ${OPENAI_API_KEY}
  healthcheck:
    test: ["CMD", "wget", "--spider", "http://localhost:8080/v1/.well-known/ready"]
    interval: 10s
    retries: 5

ドキュメントのインデックス処理

index_docs.pydocs/ ディレクトリ以下のドキュメントを読み込み、チャンク分割して Weaviate にインデックスします。
チャンク分割では 1000 文字単位を基本としつつ、200 文字のオーバーラップを持たせています。
また、段落(\n\n)や文末(. / )を優先して分割するため、文脈が途切れにくくなっています。

CHUNK_SIZE = 1000
CHUNK_OVERLAP = 200

def chunk_text(text: str, ...) -> list[str]:
    # 段落 or 文の区切りで切る(可能なら)
    last_newline = chunk.rfind("\n\n")
    if last_newline > chunk_size // 2:
        end = start + last_newline + 2
    ...

ドキュメントをインデックスする処理は Docker Compose の profile を使って通常起動とは分離しています。必要なときだけ以下のコマンドで実行できます。

docker compose --profile index run --rm indexer

動作確認

今回も Visual Studio Code の GitHub Copilot Chat を使って動作確認を行います。

質問例:

ドキュメントからチャンクについての情報を取得してください。

Input:

{
  "query": "チャンク",
  "limit": 5
}

Output:

{
  "result": [
    {
      "content": "# RAG (Retrieval-Augmented Generation) 機能\n\n## 概要\n\nRAG とは、大規模言語モデル (LLM) の回答精度を向上させるために、\n外部の知識ベースから関連情報を検索・取得し、プロンプトに含める手法です。\n\n## アーキテクチャ\n\n```\nユーザー質問\n\n\n[MCP Server] ── search_docs ──▶ [Weaviate]\n    │                                │\n    │         セマンティック検索結果    │\n    │◀────────────────────────────────┘\n\n\n関連ドキュメントを含む回答\n```\n\n## コンポーネント\n\n### Weaviate\n\n- オープンソースのベクトルデータベース\n- `text2vec-openai` モジュールで自動的に OpenAI Embeddings を生成\n- Docker で起動、データは名前付きボリュームに永続化\n\n### OpenAI Embeddings\n\n- モデル: `text-embedding-3-small`\n- ドキュメントのチャンクとクエリをベクトル化\n- コサイン類似度で近傍検索\n\n### チャンク分割\n\nドキュメントは 1000 文字単位に分割され、200 文字のオーバーラップを持ちます。\n段落や文の区切りを優先して分割するため、文脈が途切れにくくなっています。\n\n## 使い方\n\n### 1. インデックス作成\n\n```bash\n# docs/ ディレクトリにドキュメントを配置してからインデックスを作成\ndocker compose --profile index run --rm indexer\n```\n\n### 2. 検索\n\nMCP クライアント(Claude Desktop など)から `search_docs` ツールを呼び出します。\n\n```\nsearch_docs(query=\"RAGとは何ですか\", limit=5)\n```\n\n## 注意事項",
      "source": "rag.md",
      "chunk_index": 0,
      "score": 0.2338
    },
    {
      "content": "ントを配置してからインデックスを作成\ndocker compose --profile index run --rm indexer\n```\n\n### 2. 検索\n\nMCP クライアント(Claude Desktop など)から `search_docs` ツールを呼び出します。\n\n```\nsearch_docs(query=\"RAGとは何ですか\", limit=5)\n```\n\n## 注意事項\n\n- インデックスを再作成すると既存データは削除されます\n- OpenAI API の利用料金が発生します\n- `docs/` ディレクトリ内のファイルのみインデックスされます(`.md`, `.txt`, `.rst`, `.html`)",
      "source": "rag.md",
      "chunk_index": 1,
      "score": 0.2028
    },
    {
      "content": "# python-mcp-handson ドキュメント\n\n## 概要\n\n`python-mcp-handson` は MCP (Model Context Protocol) サーバーのハンズオンプロジェクトです。\n\nFastMCP フレームワークを使用して、AIエージェントから呼び出せるツールを提供します。\nWeaviate ベクトルデータベースと OpenAI API を組み合わせた RAG (Retrieval-Augmented Generation) 機能を搭載しています。\n\n## 提供ツール\n\n### greet\n\n指定した名前に挨拶を返します。\n\n- 引数: `name` (str) - 挨拶する相手の名前(デフォルト: \"World\"\n- 戻り値: `\"Hello, {name}!\"` 形式の文字列\n\n### search_docs\n\ndocs ディレクトリのドキュメントをセマンティック検索します。\n\n- 引数:\n  - `query` (str) - 自然言語の検索クエリ\n  - `limit` (int) - 返す件数(デフォルト: 5)\n- 戻り値: `content`, `source`, `chunk_index`, `score` を含む辞書のリスト\n\n### list_indexed_sources\n\nインデックス済みドキュメントのファイル一覧を返します。\n\n## セットアップ\n\n詳細は README.md を参照してください。\n",
      "source": "overview.md",
      "chunk_index": 0,
      "score": 0.1188
    }
  ]
}

スコアでソートされた結果が得られました。
チャンク分割の部分はまだまだ改善の余地がありそうです。

まとめ

今回は Python MCP サーバーに Weaviate を使った RAG 機能を追加してみました。
これでエージェントがローカルのドキュメントを検索して回答に活用できるようになりました。
MCP は用意しておくと日頃の業務をエージェントに委任する際に便利なので、今後もいろいろ試していこうと思います。

コメント

タイトルとURLをコピーしました