mcpField
G
graphrag-patterns

graphrag-patterns

github.com/latestaiagentsデータ・データベース6207 回インストール28 週間前に更新
リポジトリ

graphrag-patterns について

graphrag-patternsは、検索拡張生成でエンティティ関係やマルチホップ推論を扱う開発者向けに、GraphRAGの設計パターンを紹介するスキルです。グラフ検索、ベクトルとの併用、テキストからCypherへの変換を扱います。

主な機能

  1. 01GraphRAGとベクトルRAGの比較
  2. 02エンティティ抽出とナレッジグラフ構築
  3. 03グラフ拡張検索の紹介
  4. 04自然言語からCypherへの変換
  5. 05ベクトルとグラフのハイブリッド検索
  6. 06Microsoft GraphRAGのコミュニティ要約

活用シーン

  1. 01マルチホップ質問に適した検索方式の選択
  2. 02文書からエンティティと関係を抽出
  3. 03既存のNeo4jグラフをクエリ
  4. 04意味的類似性とグラフトラバーサルの併用

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/latestaiagents/agent-skills --skill graphrag-patterns

インストール後、Claude Code で/graphrag-patternsを入力して読み込まれたか確認します。

詳細

GraphRAG のパターン

ナレッジグラフと RAG を組み合わせ、つながりのあるデータを対象とした複雑な推論を実現します。

GraphRAG と Vector RAG の使い分け

ユースケースVector RAGGraphRAG
シンプルな Q&A✅過剰
事実の検索✅✅
複数ホップの推論❌✅
「X は Y とどのような関係にありますか?」❌✅
エンティティ間の関係❌✅
コンプライアンス/監査証跡❌✅
テーマの要約❌✅

コアアーキテクチャ

┌─────────────────────────────────────────────────────────────┐
│                      User Query                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Query Analyzer                            │
│         (Determine: vector, graph, or hybrid?)               │
└─────────────────────────────────────────────────────────────┘
                    │                    │
          ┌────────┴────────┐  ┌────────┴────────┐
          ▼                 ▼  ▼                 ▼
┌─────────────────┐  ┌─────────────────┐
│  Vector Search  │  │  Graph Traverse │
│  (Semantic)     │  │  (Structured)   │
└─────────────────┘  └─────────────────┘
          │                    │
          └────────┬──────────┘
                   ▼
┌─────────────────────────────────────────────────────────────┐
│                  Context Fusion                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    LLM Generation                            │
└─────────────────────────────────────────────────────────────┘

パターン 1:エンティティ抽出 → ナレッジグラフ

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from neo4j import GraphDatabase

# Step 1: Extract entities and relationships from documents
EXTRACTION_PROMPT = """Extract entities and relationships from this text.

Text: {text}

Return JSON format:
{{
  "entities": [
    {{"name": "...", "type": "Person|Organization|Concept|Event|Location"}}
  ],
  "relationships": [
    {{"source": "...", "target": "...", "type": "..."}}
  ]
}}
"""

async def extract_knowledge(text: str, llm: ChatOpenAI) -> dict:
    """Extract entities and relationships from text."""
    prompt = ChatPromptTemplate.from_template(EXTRACTION_PROMPT)
    chain = prompt | llm
    result = await chain.ainvoke({"text": text})
    return json.loads(result.content)


# Step 2: Store in Neo4j
class KnowledgeGraph:
    def __init__(self, uri: str, user: str, password: str):
        self.driver = GraphDatabase.driver(uri, auth=(user, password))

    def add_entity(self, name: str, entity_type: str, properties: dict = None):
        with self.driver.session() as session:
            session.run(
                f"""
                MERGE (e:{entity_type} {{name: $name}})
                SET e += $properties
                """,
                name=name,
                properties=properties or {}
            )

    def add_relationship(self, source: str, target: str, rel_type: str):
        with self.driver.session() as session:
            session.run(
                """
                MATCH (a {name: $source})
                MATCH (b {name: $target})
                MERGE (a)-[r:""" + rel_type + """]->(b)
                """,
                source=source,
                target=target
            )

パターン 2:グラフで強化した検索

from llama_index.core import PropertyGraphIndex
from llama_index.graph_stores.neo4j import Neo4jPropertyGraphStore

def create_property_graph_index(documents):
    """Create a property graph index with LlamaIndex."""

    # Connect to Neo4j
    graph_store = Neo4jPropertyGraphStore(
        username="neo4j",
        password="password",
        url="bolt://localhost:7687",
    )

    # Build index - automatically extracts entities/relationships
    index = PropertyGraphIndex.from_documents(
        documents,
        property_graph_store=graph_store,
        show_progress=True,
    )

    return index


def query_with_graph(index, query: str):
    """Query using both vector and graph retrieval."""

    # Create retriever that uses both paths
    retriever = index.as_retriever(
        include_text=True,  # Include original text chunks
        similarity_top_k=5,
    )

    # Get results
    nodes = retriever.retrieve(query)
    return nodes

パターン 3:グラフに直接クエリするための Text-to-Cypher

from langchain_community.graphs import Neo4jGraph
from langchain.chains import GraphCypherQAChain

def create_text_to_cypher_chain():
    """Create a chain that converts natural language to Cypher queries."""

    # Connect to Neo4j
    graph = Neo4jGraph(
        url="bolt://localhost:7687",
        username="neo4j",
        password="password"
    )

    # Print schema for debugging
    print(graph.schema)

    # Create chain
    chain = GraphCypherQAChain.from_llm(
        llm=ChatOpenAI(model="gpt-4", temperature=0),
        graph=graph,
        verbose=True,
        validate_cypher=True,  # Validate before executing
        return_intermediate_steps=True
    )

    return chain


# Usage
chain = create_text_to_cypher_chain()
result = chain.invoke({
    "query": "What companies has John Smith worked for?"
})
# Generated Cypher: MATCH (p:Person {name: 'John Smith'})-[:WORKED_AT]->(c:Company) RETURN c.name

パターン 4:ベクトル検索とグラフ検索のハイブリッド

class HybridGraphRAG:
    """Combine vector similarity with graph traversal."""

    def __init__(self, vector_store, graph_store):
        self.vector_store = vector_store
        self.graph_store = graph_store

    def retrieve(self, query: str, top_k: int = 5) -> list[dict]:
        # 1. Vector search for relevant chunks
        vector_results = self.vector_store.similarity_search(query, k=top_k)

        # 2. Extract entities from query
        query_entities = self._extract_entities(query)

        # 3. Graph traversal from those entities
        graph_context = []
        for entity in query_entities:
            # Get 1-hop neighbors
            neighbors = self.graph_store.query(f"""
                MATCH (e {{name: '{entity}'}})-[r]-(n)
                RETURN e.name, type(r), n.name, n.description
                LIMIT 10
            """)
            graph_context.extend(neighbors)

        # 4. Combine results
        combined = {
            "vector_chunks": [r.page_content for r in vector_results],
            "graph_context": graph_context,
            "entities": query_entities
        }

        return combined

    def _extract_entities(self, text: str) -> list[str]:
        # Use NER or LLM to extract entities
        # Simplified version:
        prompt = f"Extract entity names from: {text}"
        # ... LLM call
        return entities

パターン 5:Microsoft GraphRAG(コミュニティ検出)

# Microsoft's GraphRAG approach uses community detection
# for global summarization queries

from graphrag.index import run_indexing
from graphrag.query import LocalSearch, GlobalSearch

# Index documents (creates communities)
await run_indexing(
    input_dir="./documents",
    output_dir="./index",
    config={
        "llm": {"model": "gpt-4"},
        "embeddings": {"model": "text-embedding-3-small"},
        "chunks": {"size": 300, "overlap": 100},
        "community_detection": {
            "algorithm": "leiden",
            "resolution": 1.0
        }
    }
)

# Local search (specific entity questions)
local = LocalSearch(index_dir="./index")
result = local.search("What is Company X's main product?")

# Global search (summarization across communities)
global_search = GlobalSearch(index_dir="./index")
result = global_search.search("What are the main themes in these documents?")

パターンの使い分け

パターン使用する場面
エンティティ抽出 → KGゼロから構築する場合、カスタムスキーマを使う場合
Property Graph インデックス手早くセットアップしたい場合、LlamaIndex エコシステムを利用する場合
Text-to-Cypher既存のグラフがある場合、複雑なクエリを使う場合
ベクトル検索とグラフ検索のハイブリッドセマンティックな類似性と構造の両方が必要な場合
Microsoft GraphRAG大規模なコーパスがある場合、要約クエリを使う場合

ベストプラクティス

  1. スキーマを定義する - 重要なエンティティと関係を把握します
  2. シンプルに始める - 2~3 種類のエンティティから始め、必要に応じて拡張します
  3. Cypher を検証する - 生成されたクエリは、実行前に必ず検証します
  4. グラフクエリをキャッシュする - グラフのトラバーサルはコストがかかる場合があります
  5. ベクトル検索と組み合わせる - グラフだけではセマンティックな類似性を捉えられません
  6. 複数ホップのクエリをテストする - 2~3 ホップのクエリが許容できるパフォーマンスで動作することを確認します

よくある落とし穴

  • 過剰な抽出:エンティティが多すぎると、グラフにノイズが生じます
  • 関係の欠落:つながりのないエンティティは役に立ちません
  • スキーマのずれ:エンティティの種類に一貫性がないと、クエリが機能しなくなります
  • フォールバックがない:エンティティが見つからない場合、グラフのみでは機能しません

ツールとリソース

  • Neo4j:本番環境向けのグラフデータベース
  • LlamaIndex PropertyGraphIndex:簡単に使える Python 連携
  • Microsoft GraphRAG:コミュニティベースのアプローチ
  • Amazon Neptune:マネージド型グラフデータベース
  • LangChain GraphCypherQAChain:Text-to-Cypher チェーン

コメント