- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 기존 RAG의 한계: 어떤 질문에서 실패하는가
- GraphRAG란? (Microsoft Research, 2024)
- 핵심 구조 이해하기
- 코드로 보는 GraphRAG
- Local Search vs Global Search: 언제 무엇을 쓸까
- 지식 그래프 직접 살펴보기
- GraphRAG vs 일반 RAG: 성능 비교
- 비용 현실: 솔직한 계산
- GraphRAG가 적합한 경우 vs 일반 RAG로 충분한 경우
- LightRAG: GraphRAG의 더 실용적인 대안
- 결론: GraphRAG는 도구이지 모든 것의 답이 아니다
기존 RAG의 한계: 어떤 질문에서 실패하는가
Vector DB 기반 RAG를 운영하다 보면 특정 유형의 질문에서 일관되게 실패하는 패턴을 발견합니다.
실패하는 질문들:
- "이 분기 보고서들에서 전반적인 리스크 요인을 요약해줘"
- "우리 제품 리뷰에서 반복적으로 등장하는 불만 패턴은?"
- "CEO가 바뀐 이후 회사 전략의 변화를 설명해줘"
- "A 제품과 B 제품의 공통된 결함 특성은?"
왜 실패할까요? 이 질문들의 공통점은 단일 청크로는 답할 수 없고, 전체 지식베이스를 횡단하는 이해가 필요하다는 것입니다.
일반 RAG의 작동 방식을 생각해보면:
- 질문을 임베딩
- 유사도로 가장 관련성 높은 청크 3-5개 검색
- 그 청크들로 답변 생성
"이 분기 보고서들의 전반적인 리스크 요인"을 물으면 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 작동 방식:
- 질문에서 관련 엔티티 찾기
- 해당 엔티티와 연결된 텍스트 청크, 관계, 커뮤니티 요약 수집
- LLM으로 최종 답변 생성
Global Search 작동 방식:
- 모든 커뮤니티 요약을 여러 "청크"로 나눔
- 각 청크에 대해 부분 답변 생성 (Map phase)
- 부분 답변들을 합쳐 최종 답변 생성 (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가 더 경제적입니다.