본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 6장: GraphRAG — 그래프 기반 검색 증강 생성
2026년 3월 25일·AI / ML·

6장: GraphRAG — 그래프 기반 검색 증강 생성

Microsoft GraphRAG의 아키텍처, 커뮤니티 요약, 글로벌/로컬 검색 전략, Neo4j GraphRAG Python 라이브러리, 그리고 벡터+그래프+키워드 하이브리드 검색을 다룹니다.

16분985자7개 섹션
knowledge-graphaidata-engineering
공유
knowledge-graph6 / 10
12345678910
이전5장: LLM 기반 엔티티 추출과 관계 생성다음7장: 지식 그래프 임베딩

학습 목표

  • Microsoft GraphRAG의 아키텍처와 동작 원리를 이해합니다
  • **Community Summary(커뮤니티 요약)**의 생성 과정과 활용법을 파악합니다
  • **Global Search(글로벌 검색)**와 **Local Search(로컬 검색)**의 차이를 구분합니다
  • neo4j-graphrag-python 라이브러리의 사용법을 습득합니다
  • 벡터 + 그래프 + 키워드 하이브리드 검색을 구현합니다

GraphRAG란 무엇인가

1장에서 간략히 소개한 GraphRAG를 이번 장에서 본격적으로 다룹니다. GraphRAG는 지식 그래프의 구조적 정보를 RAG 파이프라인에 통합하여, 기존 벡터 전용 RAG의 한계를 극복하는 접근법입니다.

기존 RAG vs GraphRAG

핵심적인 차이를 정리하면 다음과 같습니다.

측면Vector RAGGraphRAG
검색 방식의미적 유사도만유사도 + 구조 + 키워드
다중 홉 질문약함그래프 순회로 해결
전역 질문매우 약함커뮤니티 요약으로 해결
설명 가능성낮음그래프 경로로 추적 가능
구축 비용낮음중간~높음

Microsoft GraphRAG 아키텍처

Microsoft Research가 공개한 GraphRAG는 두 단계로 구성됩니다: **인덱싱(Indexing)**과 쿼리(Query).

인덱싱 단계

각 단계의 역할은 다음과 같습니다.

  1. 텍스트 청킹: 문서를 적절한 크기로 분할합니다
  2. 엔티티/관계 추출: 5장에서 다룬 LLM 기반 추출을 수행합니다
  3. Knowledge Graph 구축: 추출된 엔티티와 관계로 그래프를 구성합니다
  4. 커뮤니티 감지: Leiden 알고리즘으로 밀접하게 연결된 노드 그룹을 식별합니다
  5. 커뮤니티 요약: 각 커뮤니티의 내용을 LLM으로 요약합니다

커뮤니티 요약의 핵심

커뮤니티 요약은 GraphRAG의 가장 혁신적인 부분입니다. 그래프를 커뮤니티(밀접하게 연결된 노드 그룹)로 분할하고, 각 커뮤니티의 내용을 자연어로 요약합니다.

이렇게 생성된 커뮤니티 요약은 "이 데이터셋의 주요 주제는 무엇인가?"와 같은 전역 질문에 답하는 데 활용됩니다. 개별 문서 청크만으로는 파악하기 어려운 전체적인 구조와 주제 분포를 이해할 수 있습니다.


글로벌 검색과 로컬 검색

GraphRAG는 질문의 유형에 따라 두 가지 검색 전략을 제공합니다.

Global Search (글로벌 검색)

전체 데이터셋에 대한 종합적인 이해가 필요한 질문에 사용합니다.

적합한 질문 예시:

  • "이 문서 컬렉션의 주요 주제는 무엇인가?"
  • "그래프 데이터베이스 생태계의 전체적인 구조는?"
  • "AI와 지식 그래프의 주요 연구 동향을 요약해 주세요"

동작 방식:

  1. 모든 커뮤니티 요약을 수집합니다
  2. 질문과 관련된 요약들을 선별합니다
  3. 선별된 요약들을 종합하여 답변을 생성합니다

Local Search (로컬 검색)

특정 엔티티나 관계에 대한 구체적인 질문에 사용합니다.

적합한 질문 예시:

  • "Neo4j의 벡터 인덱스는 어떻게 작동하는가?"
  • "GraphRAG에서 Leiden 알고리즘의 역할은?"
  • "Python으로 Neo4j에 연결하는 방법은?"

동작 방식:

  1. 질문에서 핵심 엔티티를 식별합니다
  2. 해당 엔티티와 연결된 그래프 이웃을 탐색합니다
  3. 관련 텍스트 청크를 벡터 검색으로 보완합니다
  4. 수집된 컨텍스트로 답변을 생성합니다
query_routing.py
python
from enum import Enum
 
class SearchMode(Enum):
    GLOBAL = "global"
    LOCAL = "local"
    HYBRID = "hybrid"
 
def route_query(question: str) -> SearchMode:
    """질문 유형에 따라 검색 모드를 결정합니다."""
    # 전역 키워드 감지
    global_indicators = ["전체", "요약", "주요 주제", "동향", "개요", "전반적"]
    if any(indicator in question for indicator in global_indicators):
        return SearchMode.GLOBAL
 
    # 구체적 엔티티 언급 감지
    # 실제로는 LLM이나 NER 모델을 사용하여 더 정교하게 판단
    specific_indicators = ["어떻게", "무엇", "왜", "구체적으로"]
    if any(indicator in question for indicator in specific_indicators):
        return SearchMode.LOCAL
 
    return SearchMode.HYBRID

neo4j-graphrag-python 라이브러리

neo4j-graphrag-python은 Neo4j에서 공식 제공하는 GraphRAG 구현 라이브러리입니다. 지식 그래프 구축부터 하이브리드 검색까지 GraphRAG의 전체 과정을 지원합니다.

설치

terminal
bash
pip install neo4j-graphrag

기본 사용법: 벡터 + 그래프 검색

neo4j_graphrag_basic.py
python
from neo4j import GraphDatabase
from neo4j_graphrag.retrievers import VectorCypherRetriever
from neo4j_graphrag.llm import OpenAILLM
from neo4j_graphrag.embeddings import OpenAIEmbeddings
from neo4j_graphrag.generation import GraphRAG
 
# Neo4j 연결
driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "password"))
 
# 임베딩 모델
embedder = OpenAIEmbeddings(model="text-embedding-3-small")
 
# 벡터 + Cypher 하이브리드 리트리버
retriever = VectorCypherRetriever(
    driver=driver,
    index_name="document_embeddings",
    retrieval_query="""
        // 벡터 검색으로 찾은 노드에서 그래프를 순회하여 추가 컨텍스트 수집
        MATCH (node)-[:COVERS]->(tech:Technology)
        OPTIONAL MATCH (tech)-[:DEPENDS_ON]->(dep:Technology)
        WITH node, score,
             collect(DISTINCT tech.name) AS technologies,
             collect(DISTINCT dep.name) AS dependencies
        RETURN node.title AS title,
               node.content AS content,
               score,
               technologies,
               dependencies
    """,
    embedder=embedder
)
 
# LLM
llm = OpenAILLM(model_name="gpt-4o")
 
# GraphRAG 파이프라인 생성
rag = GraphRAG(retriever=retriever, llm=llm)
 
# 질의
response = rag.search(query="Neo4j에서 벡터 인덱스를 사용하는 방법은?")
print(response.answer)

고급: KG Builder 파이프라인

neo4j-graphrag 라이브러리는 지식 그래프 구축도 지원합니다.

neo4j_graphrag_builder.py
python
from neo4j_graphrag.experimental.pipeline.kg_builder import SimpleKGPipeline
from neo4j_graphrag.llm import OpenAILLM
 
# 추출할 엔티티/관계 타입 정의
entities = ["Person", "Technology", "Concept", "Organization"]
relations = ["USES", "DEVELOPED_BY", "DEPENDS_ON", "IMPLEMENTS"]
 
# KG 구축 파이프라인
pipeline = SimpleKGPipeline(
    llm=OpenAILLM(model_name="gpt-4o"),
    driver=driver,
    entities=entities,
    relations=relations,
    on_error="IGNORE",  # 추출 오류 시 건너뛰기
)
 
# 텍스트에서 KG 구축
text = """
Neo4j는 프로퍼티 그래프 데이터베이스로, Cypher 쿼리 언어를 사용합니다.
GraphRAG는 Neo4j의 벡터 인덱스와 그래프 순회를 결합하여
검색 정확도를 향상시킵니다.
"""
 
result = await pipeline.run(text=text)
print(f"생성된 노드: {result.node_count}, 관계: {result.relationship_count}")
Tip

neo4j-graphrag-python은 활발하게 개발 중인 라이브러리입니다. 실험적(experimental) API는 변경될 수 있으므로, 프로덕션에서는 안정(stable) API를 우선 사용하고, 버전을 고정하여 관리하는 것을 권장합니다.


하이브리드 검색 구현

실전에서의 GraphRAG는 벡터 검색, 그래프 순회, 키워드 검색을 결합한 하이브리드 방식을 사용합니다.

세 가지 검색의 결합

hybrid_retrieval.py
python
from dataclasses import dataclass
 
@dataclass
class SearchResult:
    content: str
    score: float
    source: str  # "vector", "graph", "keyword"
    metadata: dict
 
class HybridRetriever:
    """벡터 + 그래프 + 키워드 하이브리드 검색을 수행합니다."""
 
    def __init__(self, driver, embedder):
        self.driver = driver
        self.embedder = embedder
 
    def vector_search(self, query: str, top_k: int = 5) -> list[SearchResult]:
        """벡터 유사도 기반 검색을 수행합니다."""
        embedding = self.embedder.embed_query(query)
        records, _, _ = self.driver.execute_query("""
            CALL db.index.vector.queryNodes("document_embeddings", $topK, $embedding)
            YIELD node, score
            RETURN node.title AS title, node.content AS content, score
        """, topK=top_k, embedding=embedding)
 
        return [
            SearchResult(
                content=r["content"], score=r["score"],
                source="vector", metadata={"title": r["title"]}
            ) for r in records
        ]
 
    def graph_search(self, entities: list[str], depth: int = 2) -> list[SearchResult]:
        """엔티티에서 출발하여 그래프를 순회합니다."""
        records, _, _ = self.driver.execute_query("""
            UNWIND $entities AS entityName
            MATCH (e {name: entityName})
            CALL apoc.path.subgraphAll(e, {maxLevel: $depth})
            YIELD nodes, relationships
            UNWIND nodes AS n
            WHERE n.content IS NOT NULL
            RETURN DISTINCT n.title AS title, n.content AS content,
                   1.0 / (1 + size(shortestPath((e)-[*]-(n)))) AS score
        """, entities=entities, depth=depth)
 
        return [
            SearchResult(
                content=r["content"], score=r["score"],
                source="graph", metadata={"title": r["title"]}
            ) for r in records
        ]
 
    def keyword_search(self, query: str, top_k: int = 5) -> list[SearchResult]:
        """전문 검색 인덱스를 활용한 키워드 검색을 수행합니다."""
        records, _, _ = self.driver.execute_query("""
            CALL db.index.fulltext.queryNodes("document_fulltext", $query)
            YIELD node, score
            RETURN node.title AS title, node.content AS content, score
            LIMIT $topK
        """, query=query, topK=top_k)
 
        return [
            SearchResult(
                content=r["content"], score=r["score"],
                source="keyword", metadata={"title": r["title"]}
            ) for r in records
        ]
 
    def hybrid_search(self, query: str, entities: list[str],
                      weights: dict = None) -> list[SearchResult]:
        """세 가지 검색을 결합합니다."""
        if weights is None:
            weights = {"vector": 0.4, "graph": 0.4, "keyword": 0.2}
 
        # 각 검색 수행
        vector_results = self.vector_search(query)
        graph_results = self.graph_search(entities) if entities else []
        keyword_results = self.keyword_search(query)
 
        # 가중치 적용
        all_results = {}
        for result in vector_results:
            key = result.metadata.get("title", result.content[:50])
            all_results[key] = result
            all_results[key].score *= weights["vector"]
 
        for result in graph_results:
            key = result.metadata.get("title", result.content[:50])
            if key in all_results:
                all_results[key].score += result.score * weights["graph"]
            else:
                result.score *= weights["graph"]
                all_results[key] = result
 
        for result in keyword_results:
            key = result.metadata.get("title", result.content[:50])
            if key in all_results:
                all_results[key].score += result.score * weights["keyword"]
            else:
                result.score *= weights["keyword"]
                all_results[key] = result
 
        # 점수 순 정렬
        sorted_results = sorted(all_results.values(), key=lambda r: r.score, reverse=True)
        return sorted_results

쿼리 라우팅 통합

graphrag_pipeline.py
python
class GraphRAGPipeline:
    """GraphRAG 전체 파이프라인입니다."""
 
    def __init__(self, retriever: HybridRetriever, llm):
        self.retriever = retriever
        self.llm = llm
 
    def answer(self, question: str) -> str:
        """질문에 대한 답변을 생성합니다."""
        # 1. 쿼리 라우팅
        mode = route_query(question)
 
        # 2. 검색
        if mode == SearchMode.GLOBAL:
            context = self._global_search(question)
        elif mode == SearchMode.LOCAL:
            entities = self._extract_entities(question)
            results = self.retriever.hybrid_search(question, entities)
            context = "\n\n".join([r.content for r in results[:5]])
        else:
            entities = self._extract_entities(question)
            results = self.retriever.hybrid_search(question, entities)
            context = "\n\n".join([r.content for r in results[:5]])
 
        # 3. LLM 응답 생성
        prompt = f"""다음 컨텍스트를 기반으로 질문에 답변하세요.
 
컨텍스트:
{context}
 
질문: {question}
 
답변:"""
        return self.llm.generate(prompt)
 
    def _extract_entities(self, question: str) -> list[str]:
        """질문에서 핵심 엔티티를 추출합니다."""
        # 실제 구현에서는 NER 모델이나 LLM을 사용
        # 여기서는 간략화
        return []
 
    def _global_search(self, question: str) -> str:
        """커뮤니티 요약을 활용한 글로벌 검색을 수행합니다."""
        records, _, _ = self.retriever.driver.execute_query("""
            MATCH (c:Community)
            RETURN c.summary AS summary, c.title AS title
        """)
        summaries = [f"[{r['title']}] {r['summary']}" for r in records]
        return "\n\n".join(summaries)

정리

이번 장에서는 GraphRAG의 이론과 구현을 상세히 살펴보았습니다.

  • Microsoft GraphRAG는 커뮤니티 요약을 통해 전역 질문에 답하는 혁신적 접근을 제시했습니다
  • 글로벌 검색은 전체 데이터셋에 대한 종합적 이해에, 로컬 검색은 구체적 질문에 적합합니다
  • neo4j-graphrag-python은 Neo4j 기반 GraphRAG의 공식 구현 라이브러리입니다
  • 실전에서는 벡터 + 그래프 + 키워드의 하이브리드 검색이 표준입니다
  • 쿼리 라우팅을 통해 질문 유형에 맞는 최적의 검색 전략을 선택합니다

다음 장 미리보기: 7장에서는 지식 그래프 임베딩을 다룹니다. TransE, Node2Vec, GraphSAGE 등 그래프의 구조를 벡터 공간에 인코딩하는 기법과, 링크 프레딕션 등의 활용 패턴을 살펴봅니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#knowledge-graph#ai#data-engineering

관련 글

AI / ML

7장: 지식 그래프 임베딩

TransE, DistMult, ComplEx 등 관계 예측 모델과 Node2Vec, GraphSAGE 등 노드 임베딩 기법, PyTorch Geometric을 활용한 구현까지 지식 그래프 임베딩의 핵심을 다룹니다.

2026년 3월 27일·17분
AI / ML

5장: LLM 기반 엔티티 추출과 관계 생성

비정형 텍스트에서 LLM을 활용하여 엔티티와 관계를 추출하고, JSON 파싱, 엔티티 해소, Neo4j 적재까지의 전체 파이프라인을 구축하는 방법을 다룹니다.

2026년 3월 23일·19분
AI / ML

8장: 지식 그래프 쿼리와 추론

Cypher 고급 쿼리 패턴, PageRank/커뮤니티 감지/중심성 등 그래프 알고리즘의 실전 활용, LLM과 그래프 추론의 결합, Text2Cypher 자연어 변환까지 다룹니다.

2026년 3월 29일·16분
이전 글5장: LLM 기반 엔티티 추출과 관계 생성
다음 글7장: 지식 그래프 임베딩

댓글

목차

약 16분 남음
  • 학습 목표
  • GraphRAG란 무엇인가
    • 기존 RAG vs GraphRAG
  • Microsoft GraphRAG 아키텍처
    • 인덱싱 단계
    • 커뮤니티 요약의 핵심
  • 글로벌 검색과 로컬 검색
    • Global Search (글로벌 검색)
    • Local Search (로컬 검색)
  • neo4j-graphrag-python 라이브러리
    • 설치
    • 기본 사용법: 벡터 + 그래프 검색
    • 고급: KG Builder 파이프라인
  • 하이브리드 검색 구현
    • 세 가지 검색의 결합
    • 쿼리 라우팅 통합
  • 정리