はじめに
Microsoft GraphRAG は、LLM を使って文書コーパスから 知識グラフを自動構築 し、グラフベースの RAG(Retrieval-Augmented Generation)を実現するオープンソースフレームワークです。
従来のチャンクベース RAG(ベクトル検索 + LLM 生成)は「この論文でタンパク質 X の結合親和性はいくつか?」のようなローカルクエリには有効ですが、「この300論文全体の主要研究テーマは何か?」 のようなグローバルクエリには対応できません。GraphRAG は文書間の関係性をグラフ化し、コミュニティ要約 機能でこの問題を解決します。
本記事では、科学文献コーパスを対象に GraphRAG で知識グラフを構築・活用する手順を解説します。
GraphRAG vs 通常の RAG
| 特徴 | 通常の RAG | GraphRAG |
|---|---|---|
| インデックス | ベクトル埋め込み(チャンク単位) | 知識グラフ + コミュニティ要約 |
| ローカルクエリ | ✅ 得意 | ✅ 対応 |
| グローバルクエリ | ❌ 苦手 | ✅ 得意 |
| 関係性の発見 | ❌ | ✅ エンティティ間の関係を可視化 |
| コスト | 低 | 中〜高(グラフ構築に LLM 使用) |
科学文献検索における GraphRAG の利点
科学文献の調査では、通常の RAG では困難な以下のタスクが頻繁に発生します。GraphRAG はこれらに対して構造的な解決策を提供します。
1. 分野横断的な研究動向の俯瞰
通常の RAG は「クエリに類似したチャンク」を返すだけなので、数百本の論文を横断して「主要な研究テーマは何か」「どのテーマが成長しているか」を答えることができません。GraphRAG は Leiden アルゴリズム でエンティティのコミュニティ(クラスタ)を検出し、各コミュニティの LLM 要約を保持しているため、グローバルクエリ(コーパス全体に関する質問)に対して構造化された回答を生成できます。
例: 「タンパク質構造予測分野の主要な研究テーマを5つ挙げ、最新動向を説明してください」
2. エンティティ間の暗黙的な関係の発見
科学文献では「手法 A は疾患 X に適用され、手法 B は疾患 Y に適用されたが、疾患 X と Y は同じパスウェイに関連している」といった 間接的な関連 が研究仮説の着想につながります。通常のベクトル検索では、手法 A と手法 B が異なる論文に登場する場合に両者の関係を見つけられません。GraphRAG はエンティティ間のエッジ(関係性)を明示的に保持するため、共通の隣接ノードを持つ未接続ペア(潜在的な関連)を検出でき、仮説生成に活用できます(Step 7 ユースケース 3 参照)。
3. 系統的文献レビューの効率化
系統的レビュー(Systematic Review)では「網羅性」と「構造化」が求められます。通常の RAG はクエリに最も類似したチャンクしか返さないため、網羅的な俯瞰には向きません。GraphRAG のコミュニティ階層は MECE(漏れなくダブりなく)に近い構造でコーパスを分割するため、テーマの抜け漏れを防ぎつつ体系的に整理 できます。グローバルクエリとローカルクエリを組み合わせることで、「全体傾向 → 各テーマの深掘り」を段階的に実行できます。
4. 用語の正規化と統合
科学論文では同一概念が複数の表記で登場します(例: "AlphaFold2", "AF2", "AlphaFold v2")。通常のベクトル検索では表記揺れにより検索漏れが発生しますが、GraphRAG の LLM ベースのエンティティ抽出は文脈を理解して同一エンティティとして統合します。これにより、表記揺れに左右されない横断的な知識発見 が可能になります。
📝 本シリーズの他の記事もあわせてご覧ください:
前提条件
環境構築
# Python 3.10 以上
pip install graphrag
# Azure OpenAI を使用する場合
pip install graphrag[azure]
Azure OpenAI リソース
GraphRAG は知識グラフ構築時に大量の LLM 呼び出しを行うため、Azure OpenAI Service の GPT-4o エンドポイントが必要です。
# 環境変数の設定
export GRAPHRAG_API_KEY="<your-azure-openai-key>"
export GRAPHRAG_LLM_MODEL="gpt-4o"
export GRAPHRAG_EMBEDDING_MODEL="text-embedding-3-large"
Step 1 — プロジェクトの初期化
ディレクトリ構造の作成
mkdir -p science-graphrag/input
cd science-graphrag
# GraphRAG プロジェクトの初期化
graphrag init --root .
生成される構成ファイル:
science-graphrag/
├── settings.yaml # GraphRAG 設定
├── .env # API キー(gitignore 推奨)
├── input/ # 入力文書(テキストファイル)
├── output/ # 生成された知識グラフ
└── prompts/ # カスタムプロンプト(オプション)
設定ファイルの編集
# settings.yaml
llm:
api_key: ${GRAPHRAG_API_KEY}
type: azure_openai_chat
model: gpt-4o
api_base: https://<your-resource>.openai.azure.com/
api_version: "2024-06-01"
deployment_name: gpt-4o
embeddings:
llm:
api_key: ${GRAPHRAG_API_KEY}
type: azure_openai_embedding
model: text-embedding-3-large
api_base: https://<your-resource>.openai.azure.com/
api_version: "2024-06-01"
deployment_name: text-embedding-3-large
chunks:
size: 1200
overlap: 100
entity_extraction:
max_gleanings: 1
community_reports:
max_length: 2000
Step 2 — 科学文献の準備
PubMed からの論文取得例
import requests
import os
from pathlib import Path
INPUT_DIR = Path("input")
INPUT_DIR.mkdir(exist_ok=True)
def fetch_pubmed_abstracts(query: str, max_results: int = 50) -> list[dict]:
"""PubMed から論文アブストラクトを取得"""
# 検索
search_url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi"
search_params = {
"db": "pubmed",
"term": query,
"retmax": max_results,
"retmode": "json",
"sort": "relevance",
}
search_resp = requests.get(search_url, params=search_params)
pmids = search_resp.json()["esearchresult"]["idlist"]
# アブストラクト取得
fetch_url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi"
fetch_params = {
"db": "pubmed",
"id": ",".join(pmids),
"retmode": "xml",
"rettype": "abstract",
}
fetch_resp = requests.get(fetch_url, params=fetch_params)
return fetch_resp.text, pmids
# 例: タンパク質構造予測に関する最新論文
xml_data, pmids = fetch_pubmed_abstracts(
"protein structure prediction deep learning 2024",
max_results=100,
)
# XML をパースして個別テキストファイルに変換
import xml.etree.ElementTree as ET
root = ET.fromstring(xml_data)
for i, article in enumerate(root.findall(".//PubmedArticle")):
title_elem = article.find(".//ArticleTitle")
abstract_elem = article.find(".//AbstractText")
pmid_elem = article.find(".//PMID")
if title_elem is not None and abstract_elem is not None:
title = title_elem.text or ""
abstract = abstract_elem.text or ""
pmid = pmid_elem.text if pmid_elem is not None else str(i)
content = f"Title: {title}\n\nAbstract: {abstract}\n\nPMID: {pmid}"
filepath = INPUT_DIR / f"pubmed_{pmid}.txt"
filepath.write_text(content)
print(f"{len(list(INPUT_DIR.glob('*.txt')))} 件の論文を保存しました")
ローカル PDF 論文の変換(MarkItDown)
論文 PDF の変換には Microsoft 製 OSS の MarkItDown を使用します。pdftotext などの従来ツールと異なり、見出し・表・リンクなどの文書構造を Markdown として保持できるため、GraphRAG のエンティティ抽出精度が向上します。
# インストール
pip install 'markitdown[all]'
from markitdown import MarkItDown
from pathlib import Path
def convert_pdf_to_markdown(pdf_path: str, output_dir: str = "input") -> str:
"""PDF を MarkItDown で Markdown 変換し GraphRAG 入力に配置"""
md = MarkItDown()
result = md.convert(pdf_path)
out_path = Path(output_dir) / (Path(pdf_path).stem + ".txt")
out_path.write_text(result.text_content)
return str(out_path)
# 使用例
# convert_pdf_to_markdown("papers/alphafold2.pdf")
Tip: スキャン PDF や図中テキストも抽出したい場合は、Azure Document Intelligence 連携が利用できます。
markitdown paper.pdf \ -d -e "https://<your-resource>.cognitiveservices.azure.com/"また
pip install markitdown-ocrで LLM Vision ベースの OCR プラグインも使用可能です。
Step 3 — 知識グラフの構築(インデクシング)
# グラフ構築の実行
graphrag index --root .
このコマンドにより以下の処理が自動実行されます。
- チャンキング: 文書をチャンクに分割
- エンティティ抽出: LLM がテキストからエンティティ(タンパク質名、手法名、研究機関等)を抽出
- 関係性抽出: エンティティ間の関係を特定
- コミュニティ検出: Leiden アルゴリズムでエンティティのクラスタ(コミュニティ)を検出
- コミュニティ要約: 各コミュニティの要約を LLM で生成
- 埋め込み生成: テキストチャンクとエンティティの埋め込みベクトルを生成
出力ファイル
output/
├── create_final_nodes.parquet # エンティティノード
├── create_final_edges.parquet # エッジ(関係性)
├── create_final_communities.parquet # コミュニティ
├── create_final_community_reports.parquet # コミュニティ要約
├── create_final_text_units.parquet # テキストチャンク
└── create_final_documents.parquet # 元文書
所要時間の目安: 100論文(アブストラクトのみ)で GPT-4o 使用時、約10〜30分。フルテキスト論文は数時間かかる場合があります。
Step 4 — クエリの実行
GraphRAG は2種類のクエリモードを提供します。
グローバルクエリ(コーパス全体の傾向分析)
graphrag query --root . --method global \
--query "タンパク質構造予測分野の主要な研究テーマと最新動向をまとめてください"
Python API の場合:
import asyncio
from graphrag.query.cli import run_global_search
async def global_query(question: str):
"""グローバルクエリでコーパス全体の傾向を分析"""
result = await run_global_search(
root_dir=".",
query=question,
community_level=2,
)
print(result.response)
print(f"\nソース数: {len(result.context_data)}")
return result
result = asyncio.run(global_query(
"この論文コーパスにおける主要な研究テーマを5つ挙げ、それぞれの最新動向を説明してください"
))
ローカルクエリ(特定のエンティティに関する質問)
graphrag query --root . --method local \
--query "AlphaFold2 と ESMFold の精度と速度の違いは何ですか?"
async def local_query(question: str):
"""ローカルクエリで特定の概念について詳細に分析"""
result = await run_local_search(
root_dir=".",
query=question,
)
print(result.response)
return result
result = asyncio.run(local_query(
"RFdiffusion と ProteinMPNN はどのように連携して使われていますか?"
))
Step 5 — 知識グラフの可視化
NetworkX + Matplotlib による可視化
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
# Parquet ファイルの読み込み
nodes_df = pd.read_parquet("output/create_final_nodes.parquet")
edges_df = pd.read_parquet("output/create_final_edges.parquet")
# NetworkX グラフの構築
G = nx.Graph()
for _, row in nodes_df.iterrows():
G.add_node(row["title"], type=row.get("type", "unknown"))
for _, row in edges_df.iterrows():
G.add_edge(row["source"], row["target"], weight=row.get("weight", 1))
print(f"ノード数: {G.number_of_nodes()}")
print(f"エッジ数: {G.number_of_edges()}")
# 次数中心性で重要なエンティティを特定
centrality = nx.degree_centrality(G)
top_entities = sorted(centrality.items(), key=lambda x: x[1], reverse=True)[:20]
print("\n=== 重要エンティティ TOP 20 ===")
for entity, score in top_entities:
print(f" {entity}: {score:.4f}")
# 可視化
plt.figure(figsize=(16, 12))
# 上位ノードのサブグラフを表示
top_nodes = [e[0] for e in top_entities]
subgraph = G.subgraph(
set(top_nodes) | {n for e in top_nodes for n in G.neighbors(e)}
)
pos = nx.spring_layout(subgraph, k=2, iterations=50, seed=42)
# ノードサイズを次数に比例
node_sizes = [centrality.get(n, 0) * 5000 + 100 for n in subgraph.nodes()]
nx.draw_networkx(
subgraph, pos,
node_size=node_sizes,
node_color="lightblue",
edge_color="gray",
alpha=0.8,
font_size=8,
with_labels=True,
)
plt.title("科学文献ナレッジグラフ(上位エンティティ)", fontsize=14)
plt.axis("off")
plt.tight_layout()
plt.savefig("graphrag_knowledge_graph.png", dpi=150, bbox_inches="tight")
plt.show()
コミュニティ構造の分析
# コミュニティレポートの読み込み
communities_df = pd.read_parquet("output/create_final_community_reports.parquet")
print(f"コミュニティ数: {len(communities_df)}")
print("\n=== コミュニティ要約 ===")
for _, row in communities_df.head(5).iterrows():
print(f"\n--- Community {row['community']} ---")
print(f"タイトル: {row['title']}")
print(f"要約: {row['summary'][:200]}...")
Step 6 — LazyGraphRAG(研究段階の低コスト版)
LazyGraphRAG は、Microsoft Research が提案したグラフ構築コストを大幅に削減するアプローチです。全文のエンティティ抽出を行わず、NLP による名詞句抽出と共起グラフのみでインデクシングし、クエリ時にオンデマンドで LLM を使用します[4]。
⚠️ 注意: LazyGraphRAG のコードは2026年4月現在 OSS として公開されていません。GraphRAG リポジトリ(v3.x)のクエリモードは Global / Local / DRIFT / Basic の4種です。LazyGraphRAG の技術は Microsoft Discovery に統合されており、利用する場合は Microsoft Discovery 経由となります。
| 比較項目 | GraphRAG(フル) | LazyGraphRAG(研究提案) |
|---|---|---|
| インデクシングコスト | 高(全文 LLM 処理) | ベクトル RAG と同等(フルの0.1%) |
| クエリ品質 | 最高 | 高(フルの Global Search を上回る*) |
| インデクシング時間 | 数時間 | 数分 |
| 公開状況 | ✅ OSS(graphrag パッケージ) | ❌ 未公開(Microsoft Discovery に統合) |
*relevance test budget = 500 時、AP ニュース 5,590記事でのベンチマーク結果
Step 7 — 応用ユースケース
ユースケース 1: 系統的文献レビュー(Systematic Review)
# 1. 文献収集(PubMed + arXiv)
# 2. GraphRAG でインデクシング
# 3. グローバルクエリで主要テーマを特定
# 4. ローカルクエリで各テーマの詳細を調査
review_queries = [
"この分野の主要な研究テーマを5つ挙げてください",
"各テーマの代表的な手法とその性能を比較してください",
"未解決の課題と今後の研究方向性を分析してください",
"日本の研究グループの貢献はどのようなものがありますか?",
]
for query in review_queries:
result = asyncio.run(global_query(query))
print(f"\n{'='*60}")
ユースケース 2: 競合技術マッピング
# 特定の技術領域の競合状況を分析
result = asyncio.run(local_query(
"AlphaFold2、ESMFold、OpenFold、RoseTTAFold の4手法について、"
"精度、速度、必要リソース、ライセンスの観点で比較してください"
))
ユースケース 3: 仮説生成(Hypothesis Generation)
知識グラフの構造から、未探索の関係性を発見し、新たな研究仮説を生成できます。
# 間接的な関連を持つエンティティペアを検出
# (直接エッジはないが共通の隣接ノードを多く持つペア)
for u, v in nx.non_edges(G):
common = len(list(nx.common_neighbors(G, u, v)))
if common >= 3:
print(f"潜在的関連: {u} ↔ {v} (共通ノード: {common})")
Azure テンプレートでの一括デプロイ
GraphRAG の Azure テンプレートを使うと、Azure AI Search + Cosmos DB + Azure OpenAI を組み合わせたプロダクション環境を一括構築できます。
# Azure テンプレートのクローン
git clone https://github.com/Azure-Samples/graphrag-accelerator.git
cd graphrag-accelerator
# Azure リソースの作成
azd up
デプロイされるリソース:
- Azure OpenAI: GPT-4o + text-embedding-3-large
- Azure AI Search: ベクトルインデックス
- Azure Cosmos DB: グラフデータの永続化
- Azure Blob Storage: 入力文書と出力データ
- Azure Container Apps: GraphRAG API サーバー
コスト目安
| 処理 | 文書量 | GPT-4o トークン(概算) | コスト目安 |
|---|---|---|---|
| インデクシング | 50論文(アブストラクト) | 約500K入力, 200K出力 | ~$5 |
| インデクシング | 100論文(フルテキスト) | 約5M入力, 2M出力 | ~$50 |
| グローバルクエリ | 1回 | 約100K入力, 5K出力 | ~$0.5 |
| ローカルクエリ | 1回 | 約20K入力, 2K出力 | ~$0.1 |
コスト最適化: インデクシングコストを抑えたい場合は、まずアブストラクトのみで試行するか、DRIFT Search(Local + Global のハイブリッド)を活用してください。LazyGraphRAG の技術は Microsoft Discovery で利用可能です。
注意事項
- LLM コスト: グラフ構築には大量の LLM 呼び出しが必要です。大規模コーパスでは事前にコストを見積もってください
-
エンティティ抽出の品質: プロンプトのカスタマイズで抽出精度を向上できます(
prompts/ディレクトリ) - 日本語対応: GraphRAG はマルチ言語対応ですが、日本語の科学用語の抽出精度は英語より低下する場合があります
- データの機密性: Azure OpenAI を使用する場合、データは Microsoft のデータ保護方針に基づいて処理されます
まとめ
本記事では、GraphRAG を使った科学文献ナレッジグラフの構築と活用の手順を紹介しました。
- 環境構築 — graphrag パッケージ + Azure OpenAI
- 文献準備 — PubMed API / PDF 変換でテキストファイルを用意
- インデクシング — LLM でエンティティ・関係性を抽出しグラフ構築
- クエリ — グローバル(全体傾向)+ ローカル(特定概念)の2モード
- 可視化 — NetworkX でナレッジグラフを描画
- 応用 — 系統的文献レビュー、競合分析、仮説生成
GraphRAG は Microsoft Discovery の Knowledge Engine の基盤技術としても採用されており、科学文献の横断的な知識発見に特に有効なツールです。
📝 本シリーズの他の記事もあわせてご覧ください:
References
[1] From Local to Global: A Graph RAG Approach to Query-Focused Summarization - Microsoft Research, 2024
[2] microsoft/graphrag (GitHub) - Microsoft Research, 2024
[3] GraphRAG Accelerator (Azure Template) - Azure Samples, 2024
[4] LazyGraphRAG: Setting a new satisficing standard for RAG quality at ultra low cost - Microsoft Research, 2024
[5] Transforming R&D with Agentic AI — Introducing Microsoft Discovery - Microsoft, 2025
[6] microsoft/markitdown (GitHub) - Microsoft, 2025