Skip to content

Split View: GraphRAG 완전 가이드: 지식 그래프가 RAG의 한계를 어떻게 넘는가

|

GraphRAG 완전 가이드: 지식 그래프가 RAG의 한계를 어떻게 넘는가

기존 RAG의 한계: 어떤 질문에서 실패하는가

Vector DB 기반 RAG를 운영하다 보면 특정 유형의 질문에서 일관되게 실패하는 패턴을 발견합니다.

실패하는 질문들:

  • "이 분기 보고서들에서 전반적인 리스크 요인을 요약해줘"
  • "우리 제품 리뷰에서 반복적으로 등장하는 불만 패턴은?"
  • "CEO가 바뀐 이후 회사 전략의 변화를 설명해줘"
  • "A 제품과 B 제품의 공통된 결함 특성은?"

왜 실패할까요? 이 질문들의 공통점은 단일 청크로는 답할 수 없고, 전체 지식베이스를 횡단하는 이해가 필요하다는 것입니다.

일반 RAG의 작동 방식을 생각해보면:

  1. 질문을 임베딩
  2. 유사도로 가장 관련성 높은 청크 3-5개 검색
  3. 그 청크들로 답변 생성

"이 분기 보고서들의 전반적인 리스크 요인"을 물으면 RAG는 특정 보고서의 한 섹션을 가져올 뿐, 전체를 가로지르는 패턴을 볼 수 없습니다. 이게 근본적인 한계입니다.


GraphRAG란? (Microsoft Research, 2024)

Microsoft Research에서 2024년 발표한 논문 "From Local to Global: A GraphRAG Approach to Query-Focused Summarization" (Edge et al., 2024)에서 소개된 방법론입니다.

핵심 아이디어는 간단합니다: 단순히 텍스트를 청크로 나누는 대신, 문서에서 엔티티와 관계를 추출해 지식 그래프를 만들고, 그 위에서 검색한다.

일반 RAG:
문서들 → 청크 분할 → 임베딩 → 벡터 DB → 유사도 검색 → 관련 청크

GraphRAG:
문서들 → 엔티티 추출 → 지식 그래프 구성 → 커뮤니티 탐지 →
        → 계층적 요약 생성 → 다단계 검색 (Local + Global)

핵심 구조 이해하기

1. 엔티티와 관계 추출

GraphRAG는 LLM을 사용해 문서에서 엔티티(사람, 조직, 장소, 개념)와 그 관계를 추출합니다.

입력 텍스트:
"삼성전자는 2024년 갤럭시 S25를 출시하여 애플 아이폰 16과 직접 경쟁합니다.
갤럭시 S25는 퀄컴 스냅드래곤 8 Elite 칩을 탑재했습니다."

추출되는 엔티티:
- 삼성전자 (조직)
- 갤럭시 S25 (제품)
- 애플 (조직)
- 아이폰 16 (제품)
- 퀄컴 (조직)
- 스냅드래곤 8 Elite (제품/기술)

추출되는 관계:
- 삼성전자 --[출시]--> 갤럭시 S25
- 갤럭시 S25 --[경쟁]--> 아이폰 16
- 갤럭시 S25 --[탑재]--> 스냅드래곤 8 Elite
- 퀄컴 --[제조]--> 스냅드래곤 8 Elite

2. 커뮤니티 탐지 (Community Detection)

엔티티 그래프에서 Leiden 알고리즘 등을 사용해 서로 밀접하게 연결된 엔티티 그룹(커뮤니티)을 찾습니다.

예: 스마트폰 시장 커뮤니티, 반도체 커뮤니티, 소프트웨어 생태계 커뮤니티

3. 계층적 요약

각 커뮤니티에 대해 여러 수준의 요약을 생성합니다:

Level 0 (최세밀): 개별 엔티티/관계 요약
Level 1: 소규모 커뮤니티 요약
Level 2: 중규모 커뮤니티 요약 (일반적으로 이걸 많이 사용)
Level 3 (최포괄): 전체 주제 요약

코드로 보는 GraphRAG

Microsoft의 공식 graphrag 라이브러리를 사용합니다.

# 설치
pip install graphrag

# 프로젝트 초기화
mkdir my-graphrag-project
graphrag init --root ./my-graphrag-project

초기화하면 settings.yaml이 생성됩니다. 핵심 설정:

# settings.yaml 주요 설정
llm:
  api_key: ${GRAPHRAG_API_KEY}
  type: openai_chat
  model: gpt-4o-mini  # 인덱싱용 (비용 절감 위해 mini 사용)
  model_supports_json: true

embeddings:
  llm:
    model: text-embedding-3-small  # 임베딩용

input:
  type: file
  file_type: text
  base_dir: "input"  # 문서를 여기에 넣기

chunks:
  size: 1200
  overlap: 100
# 인덱싱 (지식 그래프 구축)
# graphrag index --root ./my-graphrag-project
# 이 명령이 내부적으로 하는 일:
# 1. 문서 청킹
# 2. 엔티티 및 관계 추출 (LLM 호출)
# 3. 그래프 구성
# 4. 커뮤니티 탐지
# 5. 각 커뮤니티에 대한 요약 생성 (LLM 호출)

# Python API로 쿼리
import asyncio
from graphrag.query.api import local_search, global_search

# Local Search: 특정 엔티티/관계 중심 질문
async def search_local(query: str):
    result = await local_search(
        config_dir="./my-graphrag-project",
        data_dir="./my-graphrag-project/output",
        root_dir="./my-graphrag-project",
        community_level=2,
        response_type="multiple paragraphs",
        query=query,
    )
    return result.response

# Global Search: 전체 지식베이스 합성이 필요한 질문
async def search_global(query: str):
    result = await global_search(
        config_dir="./my-graphrag-project",
        data_dir="./my-graphrag-project/output",
        root_dir="./my-graphrag-project",
        community_level=2,
        response_type="multiple paragraphs",
        query=query,
    )
    return result.response

# 사용 예시
local_result = asyncio.run(search_local(
    "삼성전자와 TSMC의 관계는 어떻게 되나요?"
))

global_result = asyncio.run(search_global(
    "이 문서들에서 반도체 산업의 주요 트렌드는 무엇인가요?"
))

Local Search vs Global Search: 언제 무엇을 쓸까

GraphRAG의 두 검색 모드를 이해하는 게 핵심입니다.

쿼리 유형최적 모드예시
특정 엔티티에 대한 질문Local Search"김철수의 역할은?"
두 엔티티의 관계Local Search"삼성과 TSMC의 관계는?"
전체 트렌드 파악Global Search"이 문서들의 주요 주제는?"
전반적인 패턴 분석Global Search"업계 전체의 리스크 요인은?"
시간에 따른 변화Local/Global 모두 활용"지난 5년간 전략 변화는?"

Local Search 작동 방식:

  1. 질문에서 관련 엔티티 찾기
  2. 해당 엔티티와 연결된 텍스트 청크, 관계, 커뮤니티 요약 수집
  3. LLM으로 최종 답변 생성

Global Search 작동 방식:

  1. 모든 커뮤니티 요약을 여러 "청크"로 나눔
  2. 각 청크에 대해 부분 답변 생성 (Map phase)
  3. 부분 답변들을 합쳐 최종 답변 생성 (Reduce phase)

지식 그래프 직접 살펴보기

GraphRAG가 생성한 그래프를 시각화하면 통찰을 얻을 수 있습니다.

import pandas as pd
import networkx as nx

# GraphRAG 출력 파일에서 엔티티와 관계 로드
entities_df = pd.read_parquet("./output/entities.parquet")
relationships_df = pd.read_parquet("./output/relationships.parquet")

print(f"총 엔티티 수: {len(entities_df)}")
print(f"총 관계 수: {len(relationships_df)}")

# NetworkX 그래프 구성
G = nx.DiGraph()

for _, entity in entities_df.iterrows():
    G.add_node(entity["title"], type=entity["type"])

for _, rel in relationships_df.iterrows():
    G.add_edge(
        rel["source"],
        rel["target"],
        weight=rel["weight"],
        description=rel["description"]
    )

# 가장 연결이 많은 엔티티 (허브 찾기)
top_hubs = sorted(G.degree(), key=lambda x: x[1], reverse=True)[:10]
print("가장 중요한 엔티티 Top 10:")
for entity, degree in top_hubs:
    print(f"  {entity}: {degree}개 연결")

GraphRAG vs 일반 RAG: 성능 비교

Microsoft의 원논문 결과 (HotPotQA, MuSiQue 데이터셋):

글로벌 질문 (전체 요약 필요):
- 일반 RAG:    포괄성 40%, 다양성 57%
- GraphRAG:    포괄성 72%, 다양성 62%
  → 포괄성 80% 향상!

로컬 질문 (특정 사실):
- 일반 RAG:    정확도 ~65%
- GraphRAG:    정확도 ~70%
  → 약간 개선

속도:
- 일반 RAG:    0.5-2- GraphRAG:    3-10 (커뮤니티 요약 합산 때문)

결론: 전역 질문에서는 GraphRAG가 압도적으로 좋지만, 특정 사실 검색에서는 일반 RAG와 비슷하거나 느립니다.


비용 현실: 솔직한 계산

GraphRAG의 가장 큰 단점은 인덱싱 비용입니다.

# GraphRAG 인덱싱 비용 추정
# 가정: 1,000개 문서, 각 1,000 토큰

num_documents = 1000
tokens_per_doc = 1000
total_tokens = num_documents * tokens_per_doc  # 1M 토큰

# 인덱싱 단계별 LLM 호출 횟수 추정
entity_extraction_calls = total_tokens / 1200  # 청크당 1번
# 각 추출 호출: ~800 토큰 입력 + ~400 토큰 출력

community_summary_calls = 200  # 커뮤니티 수 × 레벨
# 각 요약 호출: ~2000 토큰 입력 + ~500 토큰 출력

# GPT-4o-mini 기준 비용 ($0.15 / 1M input, $0.60 / 1M output)
entity_input_cost = (entity_extraction_calls * 800 / 1_000_000) * 0.15
entity_output_cost = (entity_extraction_calls * 400 / 1_000_000) * 0.60
community_cost = (community_summary_calls * 2500 / 1_000_000) * 0.40

total_indexing_cost = entity_input_cost + entity_output_cost + community_cost
print(f"추정 인덱싱 비용: ${total_indexing_cost:.2f}")
# 1,000개 문서: 약 $1-5 (GPT-4o-mini 사용 시)
# 10,000개 문서: 약 $10-50
# 100,000개 문서: 약 $100-500

# 쿼리 비용 (Global Search)
# Global search는 커뮤니티 요약 전체를 LLM에 보내므로 쿼리당 비용이 높음
# 커뮤니티가 200개, 각 요약 500토큰이면 쿼리당 ~100K 토큰 처리
global_query_cost = (100_000 / 1_000_000) * 2.50  # GPT-4o 기준
print(f"Global search 쿼리당 비용: ${global_query_cost:.3f}")  # $0.25/쿼리

이 비용이 받아들일 만한지 판단하려면:

  • 초기 인덱싱: 문서가 자주 변경되지 않는다면 일회성 비용
  • 쿼리 비용: Global search는 RAG보다 10-100배 비쌀 수 있음

GraphRAG가 적합한 경우 vs 일반 RAG로 충분한 경우

GraphRAG가 가치 있는 경우:

  • 수백~수천 개 문서에 걸친 패턴/트렌드 분석
  • 재무 보고서, 특허, 법률 문서 분석
  • 지식베이스가 거의 변경되지 않는 경우 (인덱싱 비용 일회성)
  • "이 회사에 대해 뭘 알고 있어?"처럼 광범위한 질문이 많은 경우

일반 RAG가 충분한 경우:

  • 특정 사실 검색 ("이 계약서의 만료일은?")
  • 빠른 응답이 필요한 실시간 서비스
  • 문서가 자주 업데이트되는 경우 (재인덱싱 비용)
  • 소규모 지식베이스 (< 100개 문서)
  • 비용 예산이 타이트한 경우

LightRAG: GraphRAG의 더 실용적인 대안

Microsoft의 GraphRAG가 너무 복잡하거나 비싸다면 LightRAG를 고려해보세요.

# pip install lightrag-hku
from lightrag import LightRAG, QueryParam
from lightrag.llm import gpt_4o_mini_complete

rag = LightRAG(
    working_dir="./lightrag-storage",
    llm_model_func=gpt_4o_mini_complete,
)

# 문서 추가
with open("document.txt", "r") as f:
    rag.insert(f.read())

# 쿼리 (naive, local, global, hybrid 4가지 모드)
result = rag.query(
    "주요 트렌드는 무엇인가요?",
    param=QueryParam(mode="global")  # hybrid 모드도 효과적
)

LightRAG는 구현이 더 간단하고 비용도 저렴하며, 소규모-중간 규모 지식베이스에서 충분한 성능을 냅니다.


결론: GraphRAG는 도구이지 모든 것의 답이 아니다

GraphRAG는 강력하지만 모든 상황에 적합하지는 않습니다.

핵심 정리:

  • 전역 질문(global queries)에서 일반 RAG를 크게 능가
  • 인덱싱 비용이 높으므로 지식베이스가 안정적일 때 적합
  • 쿼리 비용도 일반 RAG보다 높음
  • 간단히 시작하려면 Microsoft의 graphrag 또는 LightRAG 라이브러리 활용

투자 대비 효과를 생각하세요. "문서에서 전체적인 패턴을 이해해야 한다"는 명확한 요구사항이 있을 때 GraphRAG를 도입하고, 특정 사실 검색이 주 용도라면 잘 튜닝된 일반 RAG가 더 경제적입니다.

GraphRAG Complete Guide: How Knowledge Graphs Overcome RAG Limitations

Where Standard RAG Fails

After running vector-search RAG in production, you'll notice it fails consistently on certain question types.

Questions that break standard RAG:

  • "Summarize the overall risk factors across this quarter's reports"
  • "What complaint patterns appear repeatedly in our product reviews?"
  • "How has the company's strategy changed since the CEO transition?"
  • "What are the common failure characteristics between Product A and Product B?"

Why does it fail? These questions share a common property: no single chunk can answer them — you need a cross-document understanding of the entire knowledge base.

Standard RAG's mechanics:

  1. Embed the question
  2. Find the 3-5 most similar chunks by cosine similarity
  3. Generate an answer from those chunks

When you ask "what are the overall risk factors across these reports?" RAG retrieves a section from one report — it can't see patterns that span all the documents. That's the fundamental limitation.


What Is GraphRAG? (Microsoft Research, 2024)

Microsoft Research published "From Local to Global: A GraphRAG Approach to Query-Focused Summarization" (Edge et al., 2024) introducing this methodology.

The core idea is straightforward: instead of just splitting documents into chunks, extract entities and relationships to build a knowledge graph, then retrieve from that graph.

Standard RAG:
Documents -> Chunk -> Embed -> Vector DB -> Similarity Search -> Relevant Chunks

GraphRAG:
Documents -> Entity Extraction -> Knowledge Graph -> Community Detection ->
          -> Hierarchical Summaries -> Multi-level Retrieval (Local + Global)

Understanding the Core Structure

1. Entity and Relationship Extraction

GraphRAG uses an LLM to extract entities (people, organizations, places, concepts) and their relationships from documents.

Input text:
"Samsung launched the Galaxy S25 in 2024, competing directly with Apple's
iPhone 16. The Galaxy S25 is powered by the Qualcomm Snapdragon 8 Elite chip."

Extracted entities:
- Samsung (organization)
- Galaxy S25 (product)
- Apple (organization)
- iPhone 16 (product)
- Qualcomm (organization)
- Snapdragon 8 Elite (product/technology)

Extracted relationships:
- Samsung --[launched]--> Galaxy S25
- Galaxy S25 --[competes with]--> iPhone 16
- Galaxy S25 --[powered by]--> Snapdragon 8 Elite
- Qualcomm --[manufactures]--> Snapdragon 8 Elite

2. Community Detection

Using algorithms like Leiden on the entity graph, GraphRAG finds clusters of closely connected entities (communities).

Examples: smartphone market community, semiconductor community, software ecosystem community.

3. Hierarchical Summaries

Summaries are generated for each community at multiple granularity levels:

Level 0 (most detailed): individual entity/relationship summaries
Level 1: small community summaries
Level 2: mid-scale community summaries (most commonly used)
Level 3 (most comprehensive): global topic summaries

GraphRAG in Code

Using Microsoft's official graphrag library:

# Install
pip install graphrag

# Initialize project
mkdir my-graphrag-project
graphrag init --root ./my-graphrag-project

The generated settings.yaml key configuration:

# Key settings in settings.yaml
llm:
  api_key: ${GRAPHRAG_API_KEY}
  type: openai_chat
  model: gpt-4o-mini  # for indexing (mini to reduce cost)
  model_supports_json: true

embeddings:
  llm:
    model: text-embedding-3-small

input:
  type: file
  file_type: text
  base_dir: "input"  # put your documents here

chunks:
  size: 1200
  overlap: 100
# Indexing (building the knowledge graph)
# graphrag index --root ./my-graphrag-project
# What this does internally:
# 1. Chunk documents
# 2. Extract entities and relationships (LLM calls)
# 3. Build the graph
# 4. Run community detection
# 5. Generate summaries for each community (LLM calls)

# Querying via Python API
import asyncio
from graphrag.query.api import local_search, global_search

# Local Search: entity/relationship-focused questions
async def search_local(query: str):
    result = await local_search(
        config_dir="./my-graphrag-project",
        data_dir="./my-graphrag-project/output",
        root_dir="./my-graphrag-project",
        community_level=2,
        response_type="multiple paragraphs",
        query=query,
    )
    return result.response

# Global Search: questions requiring synthesis across the full knowledge base
async def search_global(query: str):
    result = await global_search(
        config_dir="./my-graphrag-project",
        data_dir="./my-graphrag-project/output",
        root_dir="./my-graphrag-project",
        community_level=2,
        response_type="multiple paragraphs",
        query=query,
    )
    return result.response

# Usage
local_result = asyncio.run(search_local(
    "What is the relationship between Samsung and TSMC?"
))

global_result = asyncio.run(search_global(
    "What are the main trends in the semiconductor industry across these documents?"
))

Local vs Global Search: When to Use Which

Understanding the two query modes is the key to using GraphRAG effectively.

Query TypeBest ModeExample
Question about a specific entityLocal Search"What is John Kim's role?"
Relationship between two entitiesLocal Search"What's the Samsung-TSMC relationship?"
Overall trend identificationGlobal Search"What are the main themes in these docs?"
Cross-document pattern analysisGlobal Search"What are the industry-wide risk factors?"
Changes over timeBoth"How did strategy evolve over 5 years?"

Local Search internally:

  1. Find relevant entities from the query
  2. Collect text chunks, relationships, and community summaries connected to those entities
  3. Generate final answer with LLM

Global Search internally:

  1. Split all community summaries into "batches"
  2. Generate partial answers for each batch (Map phase)
  3. Merge partial answers into final answer (Reduce phase)

Exploring the Knowledge Graph Directly

Visualizing GraphRAG's generated graph reveals insights about your data.

import pandas as pd
import networkx as nx

# Load entities and relationships from GraphRAG output
entities_df = pd.read_parquet("./output/entities.parquet")
relationships_df = pd.read_parquet("./output/relationships.parquet")

print(f"Total entities: {len(entities_df)}")
print(f"Total relationships: {len(relationships_df)}")

# Build NetworkX graph
G = nx.DiGraph()

for _, entity in entities_df.iterrows():
    G.add_node(entity["title"], type=entity["type"])

for _, rel in relationships_df.iterrows():
    G.add_edge(
        rel["source"],
        rel["target"],
        weight=rel["weight"],
        description=rel["description"]
    )

# Find hub entities (most connected)
top_hubs = sorted(G.degree(), key=lambda x: x[1], reverse=True)[:10]
print("Top 10 most connected entities:")
for entity, degree in top_hubs:
    print(f"  {entity}: {degree} connections")

GraphRAG vs Standard RAG: Performance Comparison

From Microsoft's original paper (HotPotQA, MuSiQue datasets):

Global queries (requiring whole-document synthesis):
- Standard RAG:  comprehensiveness 40%, diversity 57%
- GraphRAG:      comprehensiveness 72%, diversity 62%
  -> 80% improvement in comprehensiveness!

Local queries (specific fact retrieval):
- Standard RAG:  accuracy ~65%
- GraphRAG:      accuracy ~70%
  -> Modest improvement

Latency:
- Standard RAG:  0.5-2 seconds
- GraphRAG:      3-10 seconds (due to community summary aggregation)

Conclusion: GraphRAG dominates on global queries, but is comparable to or slower than standard RAG for specific fact retrieval.


Cost Reality: Honest Numbers

GraphRAG's biggest drawback is indexing cost.

# GraphRAG indexing cost estimate
# Assumptions: 1,000 documents, 1,000 tokens each

num_documents = 1000
tokens_per_doc = 1000
total_tokens = num_documents * tokens_per_doc  # 1M tokens

# Estimated LLM calls during indexing
entity_extraction_calls = total_tokens / 1200  # 1 call per chunk
# Each call: ~800 input tokens + ~400 output tokens

community_summary_calls = 200  # number of communities x levels
# Each call: ~2000 input tokens + ~500 output tokens

# Cost using GPT-4o-mini ($0.15/1M input, $0.60/1M output)
entity_input_cost = (entity_extraction_calls * 800 / 1_000_000) * 0.15
entity_output_cost = (entity_extraction_calls * 400 / 1_000_000) * 0.60
community_cost = (community_summary_calls * 2500 / 1_000_000) * 0.40

total_indexing_cost = entity_input_cost + entity_output_cost + community_cost
print(f"Estimated indexing cost: ${total_indexing_cost:.2f}")
# 1,000 documents: approx $1-5 (using GPT-4o-mini)
# 10,000 documents: approx $10-50
# 100,000 documents: approx $100-500

# Query cost (Global Search)
# Global search processes all community summaries for each query
# 200 communities x 500 tokens each = ~100K tokens processed per query
global_query_cost = (100_000 / 1_000_000) * 2.50  # GPT-4o pricing
print(f"Global search cost per query: ${global_query_cost:.3f}")  # $0.25/query

Is this acceptable? Depends on your situation:

  • Initial indexing: one-time cost if your documents don't change often
  • Query cost: Global search can be 10-100x more expensive per query than standard RAG

GraphRAG vs Standard RAG: When to Use Which

GraphRAG is worth it when:

  • Analyzing patterns/trends across hundreds to thousands of documents
  • Financial reports, patents, legal document analysis
  • Knowledge base is relatively static (indexing cost amortizes)
  • Broad exploratory questions are common ("what do we know about this company?")

Standard RAG is sufficient when:

  • Specific fact retrieval ("what's the expiration date on this contract?")
  • Real-time services requiring fast response
  • Frequently updated documents (re-indexing cost)
  • Small knowledge base (under ~100 documents)
  • Tight cost budget

LightRAG: A More Practical Alternative

If Microsoft's GraphRAG feels too complex or expensive, consider LightRAG.

# pip install lightrag-hku
from lightrag import LightRAG, QueryParam
from lightrag.llm import gpt_4o_mini_complete

rag = LightRAG(
    working_dir="./lightrag-storage",
    llm_model_func=gpt_4o_mini_complete,
)

# Insert documents
with open("document.txt", "r") as f:
    rag.insert(f.read())

# Query (4 modes: naive, local, global, hybrid)
result = rag.query(
    "What are the main trends?",
    param=QueryParam(mode="global")  # hybrid mode is also effective
)

LightRAG is simpler to implement, cheaper to run, and delivers sufficient performance for small to medium knowledge bases.


Conclusion: GraphRAG Is a Tool, Not a Silver Bullet

GraphRAG is powerful, but it's not the right choice for every situation.

Summary:

  • Significantly outperforms standard RAG on global queries
  • High indexing cost means it's best when the knowledge base is stable
  • Query cost is also higher than standard RAG
  • To get started quickly: use Microsoft's graphrag library or LightRAG

Think about ROI. Adopt GraphRAG when you have a clear requirement like "we need to understand patterns across this corpus." For specific fact retrieval, a well-tuned standard RAG pipeline is more cost-effective.