はじめに
前回の記事では、GraphRAGの概念とAzure OpenAI Service / Ollamaでの設定方法を解説しました。
本記事では、実際にarXiv論文をGraphRAGでインデックス化し、ナレッジグラフを構築して質問応答を行うハンズオン実験の結果を共有します。
本記事のポイント
- ローカルOllamaを使用した現実的な構成での実験
- 複数モデルのベンチマーク比較と最適なモデル選定
- Local Search / Global Search の実用性評価
- 小型モデル使用時の限界と対策
目次
実験概要
目的
AI for Science関連のarXiv論文を使って、GraphRAGの実用性を検証する。
実験条件
| 項目 | 値 |
|---|---|
| 対象論文 | arXiv「AI for Science」関連論文 |
| 論文数 | 1本(検証用に絞り込み) |
| LLM | Ollama(ローカル実行) |
| 環境 | WSL2 + Windows(GPU: RTX 4090想定) |
| GraphRAG | v2.7.0 |
ワークフロー
環境構築
ディレクトリ構成
experiment/
├── papers/ # arXiv PDFファイル
├── markdown/ # docling変換後のMarkdown
├── markdown_single/ # 1論文のみ(検証用)
└── graphrag/
├── settings.yaml # GraphRAG設定
├── output/ # 出力ファイル
├── cache/ # キャッシュ
└── logs/ # ログ
Pythonパッケージ
# 仮想環境作成
python -m venv .venv
source .venv/bin/activate
# 必要パッケージ
pip install graphrag==2.7.0
pip install docling
Ollamaモデル
# チャットモデル(最終的に採用したもの)
ollama pull smollm2:1.7b
# 埋め込みモデル
ollama pull nomic-embed-text
論文の取得と変換
arXivからPDFをダウンロード
import arxiv
# AI for Science関連の論文を検索
search = arxiv.Search(
query="AI for Science",
max_results=15,
sort_by=arxiv.SortCriterion.SubmittedDate
)
for result in search.results():
result.download_pdf(dirpath="papers/")
doclingでMarkdownに変換
from docling.document_converter import DocumentConverter
converter = DocumentConverter()
for pdf_path in Path("papers/").glob("*.pdf"):
result = converter.convert(str(pdf_path))
markdown = result.document.export_to_markdown()
output_path = Path("markdown/") / f"{pdf_path.stem}.md"
output_path.write_text(markdown)
doclingの変換には論文1本あたり1〜2分かかります。15本で約20分。
モデル選定の試行錯誤
選定方針
ローカルOllamaを使用するため、現実的な時間で動作することを最優先にモデルを選定しました。
| 優先度 | 観点 | 説明 |
|---|---|---|
| 1 | 処理時間 | 数時間以内にインデックス構築を完了できること |
| 2 | 安定性 | タイムアウトやエラーなく最後まで実行できること |
| 3 | 品質 | 回答の正確性(トレードオフとして許容) |
テストしたモデル
| モデル | サイズ | 結果 | 処理速度 | 問題点 |
|---|---|---|---|---|
| qwen2.5:7b | 4.7GB | ❌ | 40-50秒/chunk | 一部チャンクで600秒超タイムアウト |
| qwen2.5:3b | 1.9GB | ❌ | 約10分/chunk | 非常に遅い |
| qwen2.5:1.5b | 986MB | ❌ | 可変 | 300秒タイムアウト発生 |
| gpt-oss:20b | 13.8GB | △ | 約5.5分/chunk | 安定だが遅すぎる |
| smollm2:1.7b | 1.0GB | ✅ | 40秒〜1分/chunk | 一部重いチャンクあり |
最終採用
# smollm2:1.7b を採用
# 理由: 最も高速かつ安定、ただし英語特化
models:
default_chat_model:
model: smollm2:1.7b
request_timeout: 2400 # 40分
max_retries: 20
default_embedding_model:
model: nomic-embed-text
smollm2:1.7bは英語特化モデルです。日本語のクエリには対応していません。
インデックス構築
最終設定(settings.yaml)
models:
default_chat_model:
type: chat
model_provider: ollama
model: smollm2:1.7b
api_base: http://192.168.224.1:11434 # WSLからWindowsのOllamaに接続
api_key: "ollama" # ダミー値(必須)
concurrent_requests: 1
async_mode: threaded
retry_strategy: exponential_backoff
max_retries: 20
request_timeout: 2400 # 40分
default_embedding_model:
type: embedding
model_provider: ollama
model: nomic-embed-text
api_base: http://192.168.224.1:11434
api_key: "ollama"
request_timeout: 300
input:
storage:
type: file
base_dir: "../markdown_single"
file_type: text
file_pattern: ".*.md"
chunks:
size: 400 # 小さめで安定性向上
overlap: 50
実行コマンド
cd experiment/graphrag
source ../../.venv/bin/activate
# バックグラウンドで実行(長時間かかるため)
nohup python -m graphrag index --root . > logs/indexing-engine.log 2>&1 &
処理時間
| ステップ | 所要時間 |
|---|---|
| load_input_documents | <1秒 |
| create_base_text_units | <1秒 |
| extract_graph (28チャンク) | 約1時間20分 |
| create_communities | <1秒 |
| community_reports | 約25秒 |
| generate_text_embeddings | 約4秒 |
| 合計 | 約1時間20分 |
特定のチャンクで35分以上かかる場合があります。タイムアウトは余裕を持って設定しましょう。
出力ファイル
output/
├── communities.parquet (11KB)
├── community_reports.parquet (36KB)
├── documents.parquet (34KB)
├── entities.parquet (20KB) # 48エンティティ
├── relationships.parquet (12KB)
├── text_units.parquet (48KB) # 28チャンク
└── lancedb/ # ベクトルDB
クエリテスト
Local Search(エンティティベース検索)
graphrag query --root . --method local \
--query "What is ARIA framework and how does it work for AI for Science?"
結果: ✅ 正確な回答
The ARIA (Automated Research Intelligence Assistant) framework is a novel, human-in-the-loop architecture designed to facilitate data-driven scientific research through automated analysis...
論文の内容に基づいた詳細な説明が生成されました。
Global Search(コミュニティベース検索)
graphrag query --root . --method global \
--query "What are the main themes and contributions of this paper?"
結果: ❌ ハルシネーション
The paper explores a complex web of relationships between journalists, environmentalists, and extremist groups...
論文と全く関係ない内容が返ってきました。
小型モデルの限界
問題の原因
コミュニティレポートの内容を確認したところ、完全なハルシネーションが発生していました。
import pandas as pd
df = pd.read_parquet('output/community_reports.parquet')
print(df[['community', 'title', 'summary']])
community 0: "The DURKE BATAGLANI Community"
→ 論文に存在しない架空のエンティティ
community 1: "Aurelia and Firuzabad"
→ 人質交渉という無関係なテーマ
機能別の動作状況
| 機能 | smollm2:1.7bでの動作 | 推奨対策 |
|---|---|---|
| extract_graph | ✅ 正常 | - |
| Local Search | ✅ 正常 | - |
| community_reports | ❌ ハルシネーション | より大きなモデル(7B以上)を使用 |
| Global Search | ❌ ハルシネーション | より大きなモデル(7B以上)を使用 |
結論
- Local Searchは実用可能: エンティティ抽出と関係性に基づく検索は正常動作
- Global Searchは要改善: コミュニティレポート生成には7B以上のモデルを推奨
- トレードオフ: 処理時間を優先した結果、品質面で妥協が必要だった
ベストプラクティス
Ollama + GraphRAG の設定Tips
| 項目 | 推奨値 | 理由 |
|---|---|---|
| request_timeout | 2400秒(40分) | 特定チャンクが非常に重い |
| max_retries | 20以上 | 重いチャンクでのリトライ対応 |
| api_key | "ollama" | ダミー値必須(GraphRAG 2.7.0) |
| chunks.size | 400 | 小さいほど処理が安定 |
| concurrent_requests | 1 | Ollamaはシングルリクエスト推奨 |
モデル選択ガイド
| 用途 | 推奨モデル | 理由 |
|---|---|---|
| 高速処理(Local Searchのみ) | smollm2:1.7b | 最速、安定 |
| 全機能(Global Search含む) | qwen2.5:7b以上 | 品質確保 |
| 埋め込み | nomic-embed-text | 軽量、高速 |
トラブルシューティング
| 症状 | 原因 | 対策 |
|---|---|---|
| 600秒でタイムアウト | チャンクが重い | request_timeout を 2400秒に |
| auth_type: none エラー | GraphRAG 2.7.0非サポート | api_key: "ollama" を設定 |
| Global Searchがおかしい | 小型モデルの限界 | 7B以上のモデルを使用 |
| 処理が進まない | WSL↔Windows通信 | api_base のIP確認 |
本番運用の考慮事項
本実験はローカルOllamaでの検証でしたが、本番運用を見据えた場合、以下の点を考慮する必要があります。
LLMプロバイダーの選択
| 選択肢 | メリット | デメリット | 推奨ケース |
|---|---|---|---|
| Azure OpenAI Service | 高品質、安定、SLA保証 | コスト(トークン課金) | エンタープライズ、品質重視 |
| OpenAI API | 高品質、最新モデル | コスト、レート制限 | PoC、中規模 |
| Ollama(ローカル) | 無料、データ外部送信なし | GPU必要、品質にばらつき | 機密データ、コスト重視 |
| Azure AI Foundry | Microsoftエコシステム統合 | 学習コスト | Azure環境利用者 |
機密データを扱う場合は、外部APIへのデータ送信リスクを考慮し、Ollamaまたはプライベートクラウドでの運用を検討してください。
コスト試算(Azure OpenAI Service)
論文1本(約40KB)のインデックス構築を想定:
| 項目 | トークン数(推定) | 単価(GPT-4o) | コスト |
|---|---|---|---|
| extract_graph(28チャンク) | 約500K tokens | $2.50/1M input | 約$1.25 |
| community_reports(2件) | 約50K tokens | $10.00/1M output | 約$0.50 |
| 埋め込み(48エンティティ) | 約20K tokens | $0.13/1M | 約$0.003 |
| 合計(1論文) | - | - | 約$1.75 |
100論文の場合: 約$175(約26,000円)
GPT-4o-miniを使用すれば約1/10のコストに。
スケーラビリティ
| 論文数 | Ollamaローカル | Azure OpenAI |
|---|---|---|
| 1〜10本 | ✅ 実用的(数時間) | ✅ 高速(数分) |
| 10〜100本 | ⚠️ 数日かかる | ✅ 数時間 |
| 100本以上 | ❌ 非現実的 | ✅ 並列処理で対応 |
品質担保
| 観点 | 対策 |
|---|---|
| ハルシネーション防止 | GPT-4クラス以上のモデルを使用 |
| 多言語対応 | 日本語論文には日本語対応モデル(GPT-4o推奨) |
| エンティティ抽出精度 | ドメイン特化のプロンプトカスタマイズ |
| 結果の検証 | 抽出されたエンティティ・関係性の目視確認 |
セキュリティ・コンプライアンス
| 要件 | Azure OpenAI | Ollama |
|---|---|---|
| データの外部送信 | あり(Azure内) | なし |
| GDPR対応 | ✅ | ✅(データがローカル) |
| 医療・金融規制 | ✅(リージョン選択で対応) | ✅ |
| 監査ログ | ✅ | 要自前実装 |
推奨構成
検証・PoC向け
コスト: 無料(GPU電気代のみ)
品質: Local Searchのみ実用的
本番運用向け
コスト: 従量課金($2〜/論文)
品質: Global Search含め高品質
運用時のチェックリスト
- LLMプロバイダーの選定(コスト vs 品質 vs セキュリティ)
- インデックス更新頻度の決定(差分更新 or 全再構築)
- エラーハンドリング・リトライ戦略
- 監視・アラート設定(処理時間、エラー率)
- バックアップ・リカバリ計画
- コスト上限アラート(Azure Cost Management)
まとめ
実験結果
| 項目 | 結果 |
|---|---|
| インデックス構築 | ✅ 成功(約1時間20分) |
| Local Search | ✅ 正常動作 |
| Global Search | ⚠️ ハルシネーション(モデル限界) |
学んだこと
- 小型モデルでもLocal Searchは動く: エンティティ抽出・関係性抽出は1.7Bモデルでも機能
- コミュニティレポートには大きなモデルが必要: Global Searchを使うなら7B以上
- タイムアウトは余裕を持って: 600秒でも不足、2400秒推奨
- チャンクサイズは小さめに: 400が安定性と品質のバランス良好
次のステップ
- 7B以上のモデルでGlobal Search品質を検証
- 複数論文での大規模インデックス構築
- LazyGraphRAGとの比較実験
参考文献
[1] Microsoft GraphRAG - GitHub
[2] GraphRAG Documentation
[3] docling - GitHub
[4] Ollama
[5] SmolLM2 - Hugging Face
シリーズ記事
- #1 AI for Scienceとは?
- #2 Microsoft GraphRAG による知識データベースの構築
- #3 GraphRAGで論文を読む:arXiv論文でのハンズオン実験(本記事)