coredot.today
Graph RAG with Milvus: 벡터 검색에 지식 그래프를 더하면 AI가 '관계'를 추론한다
블로그로 돌아가기
Graph RAGMilvus지식 그래프벡터 데이터베이스멀티홉 추론RAG트리플렛

Graph RAG with Milvus: 벡터 검색에 지식 그래프를 더하면 AI가 '관계'를 추론한다

'오일러의 스승의 아들이 뭘 했지?' — 단순 벡터 검색은 이 질문에 답하지 못한다. 엔티티 사이의 관계를 추적해야 하기 때문이다. Milvus 벡터 DB 위에 지식 그래프를 결합한 Graph RAG가 멀티홉 추론 문제를 어떻게 해결하는지, 역사적 맥락부터 핵심 구현, 2026년 생태계까지 종합 특집으로 풀어본다.

코어닷투데이2026-04-0563

들어가며: "오일러의 스승의 아들은 뭘 했지?"

이런 질문을 AI에게 던져보자.

"What contribution did the son of Euler's teacher make?"

단순해 보이지만, 이 질문에 답하려면 AI가 세 단계의 관계를 추적해야 한다:

Step 1
오일러(Euler)의 스승은 누구인가? → 요한 베르누이(Johann Bernoulli)
Step 2
요한 베르누이의 아들은 누구인가? → 다니엘 베르누이(Daniel Bernoulli)
Step 3
다니엘 베르누이는 무엇을 했는가? → 유체역학, 확률론, 베르누이 원리

일반적인 RAG 시스템에 이 질문을 던지면 어떻게 될까? 벡터 검색은 질문과 가장 유사한 문서 청크를 가져온다. "오일러"와 "스승"이 언급된 문단, "베르누이 가문"에 대한 문단은 찾을 수 있다. 하지만 "다니엘 베르누이의 업적"이 담긴 문단은? 원래 질문과의 벡터 유사도가 낮아서 검색되지 않는다.

결과는 이렇다:

Naive RAG의 답변
"검색된 문맥에 오일러 스승의 아들에 대한 정보가 충분하지 않습니다."
Graph RAG의 답변
"오일러의 스승인 요한 베르누이의 아들, 다니엘 베르누이는 유체역학, 확률론, 통계학에 주요한 기여를 했습니다. 그는 유체 흐름의 행동을 설명하는 베르누이 원리로 가장 유명하며, 이는 공기역학 이해의 근본이 됩니다."

같은 데이터, 같은 질문인데 답이 완전히 다르다. Graph RAG가 할 수 있고 Naive RAG가 할 수 없는 것 — 그것은 엔티티 사이의 관계를 추적하는 멀티홉 추론이다.

이 글에서는 Milvus 벡터 데이터베이스를 활용한 Graph RAG의 구현을 중심으로, 이 기술이 왜 필요한지, 어떻게 작동하는지, 그리고 2026년 현재 어디까지 왔는지를 종합적으로 다룬다.

📎 이 글은 Milvus 공식 부트캠프의 Graph RAG with Milvus 노트북을 기반으로 작성되었다.


1. 지식 그래프의 역사: 컴퓨터에게 '관계'를 가르치다

지식 그래프의 역사와 발전 — 노드와 엣지로 연결된 지식의 네트워크

시맨틱 웹의 꿈 (2001~2012)

지식 그래프의 뿌리는 멀리 있다. 2001년, 팀 버너스리(Tim Berners-Lee)는 "The Semantic Web"이라는 사이언티픽 아메리칸 기고에서 "기계가 이해할 수 있는 웹"을 제안했다. 웹 페이지가 단순한 텍스트가 아니라, 구조화된 데이터로 연결되어 기계가 추론할 수 있는 세계 — 그것이 시맨틱 웹의 비전이었다.

이 비전을 실현하기 위한 기술들이 차례로 등장했다:

연도기술의미
2001RDF (Resource Description Framework)모든 지식을 (주어, 술어, 목적어) 트리플렛으로 표현
2004OWL (Web Ontology Language)개념 간의 계층과 제약 조건을 정의
2007DBpedia위키피디아에서 구조화된 데이터를 추출한 최초의 대규모 지식 베이스
2008Freebase커뮤니티 기반 지식 베이스 (후에 Google이 인수)

하지만 시맨틱 웹은 너무 학술적이었다. 일반 웹 개발자가 RDF와 SPARQL(W3C, 2008년 표준화)을 배워서 웹사이트를 만들기에는 진입 장벽이 높았고, 채택률은 낮았다. 한편 2007년에는 Neo4j가 프로퍼티 그래프(Property Graph) 모델을 대중화하며, 학술적인 RDF 트리플보다 개발자 친화적인 방식으로 그래프 데이터를 다루는 길을 열었다.

Google Knowledge Graph의 등장 (2012)

2012년 5월, 구글이 Knowledge Graph를 공개하며 게임이 바뀌었다. "검색 결과를 넘어, 사물(things)을 이해하라"라는 슬로건 아래, 구글은 5억 개 이상의 엔티티와 35억 개의 관계를 담은 거대한 지식 그래프를 구축했다.

"레오나르도 다빈치"를 검색하면 단순히 관련 웹페이지 목록이 아니라, 생년월일, 직업, 대표작, 관련 인물이 패널로 정리되어 나타났다. 이것이 지식 그래프의 대중화 순간이었다.

키워드 검색 Knowledge Graph (2012) 엔티티 이해

그 뒤를 이어 주요 지식 그래프들이 잇따라 등장했다:

  • Wikidata (2012.10) — Denny Vrandečić와 Markus Krötzsch가 설계한 위키미디어 재단의 다국어 지식 베이스, 현재 1억+ 항목. 사실상의 오픈 지식 그래프 표준이 되었다
  • YAGO (2013) — 막스 플랑크 연구소의 학술 지식 그래프
  • Microsoft Academic Graph (2015) — 학술 논문 관계 그래프
  • Amazon Product Graph (2018) — 상품 간 관계와 속성

트리플렛: 지식 그래프의 원자 단위

모든 지식 그래프의 기본 구성 요소는 트리플렛(Triplet)이다. (주어, 술어, 목적어) — 이 세 요소로 세상의 모든 관계를 표현한다.

베르누이 가문과 오일러의 관계를 보여주는 지식 그래프 트리플렛 — 가족, 스승-제자 관계의 시각화

베르누이 가문을 예로 들어보자:

🔗 베르누이 가문 트리플렛
Jakob Bernoulli 의 동생은 Johann Bernoulli
Johann Bernoulli 의 아들은 Daniel Bernoulli
Daniel Bernoulli 로 유명한 베르누이 원리
Leonhard Euler 의 스승은 Johann Bernoulli
베르누이 원리 의 기초가 되는 공기역학의 이해

이 트리플렛들을 이으면 그래프가 된다. 노드(node)는 엔티티, 엣지(edge)는 관계다. 그래프 위에서 경로를 따라가면 "오일러 → 요한 베르누이 → 다니엘 베르누이 → 베르누이 원리"라는 추론 체인이 자연스럽게 만들어진다.

바로 이것이 멀티홉 추론의 핵심이다.


2. RAG의 한계: 왜 벡터 검색만으로는 부족한가

RAG의 기본 원리

RAG(Retrieval-Augmented Generation)는 Facebook AI Research(FAIR)의 Patrick Lewis 등이 2020년 발표한 논문 "Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks"(NeurIPS 2020)에서 제안된 이후, LLM의 환각(hallucination)을 줄이는 표준적인 기법이 되었다. 사전 학습된 seq2seq 모델(BART)에 Dense Passage Retriever(DPR)를 결합하여, 생성 시점에 위키피디아 인덱스에서 관련 문서를 검색하는 방식이었다.

기본 원리는 단순하다:

질문 벡터 검색 관련 문서 Top-K LLM 답변 생성

"벡터 검색"이란 질문을 임베딩 벡터로 변환한 뒤, 문서 벡터와의 코사인 유사도가 높은 상위 K개를 가져오는 것이다. "재택근무 정책이 뭐야?"라는 질문에는 잘 작동한다 — 관련 문서에 "재택근무"와 "정책"이라는 의미가 직접 담겨 있기 때문이다.

멀티홉 질문에서의 구조적 실패

하지만 멀티홉 질문은 다르다. 다시 원래의 질문으로 돌아가자:

"오일러의 스승의 아들은 뭘 했지?"

이 질문의 벡터와 가장 유사한 문서 청크는 무엇일까?

  1. "오일러는 바젤에서 태어나 요한 베르누이의 학생이었다..." — ✅ 검색됨 (오일러, 스승 언급)
  2. "요한 베르누이는 미적분학 발전의 주요 인물이었다..." — ✅ 검색됨 (요한 베르누이 직접 언급)
  3. "다니엘 베르누이는 유체역학에 주요한 기여를 했다..." — ❌ 검색 안 됨!

세 번째 문서가 바로 정답의 핵심인데, 왜 검색이 안 될까? 질문에는 "다니엘 베르누이"도, "유체역학"도, "베르누이 원리"도 언급되지 않기 때문이다. 벡터 유사도가 낮다.

멀티홉 추론에서 끊어진 정보의 연결 — AI가 중간 관계를 추적하지 못하는 문제

멀티홉 QA 벤치마크(HotpotQA, MuSiQue, 2WikiMultiHopQA)에서 일반 RAG의 정확도가 급락하는 이유도 여기에 있다. 심지어 관련 청크를 찾아오더라도, Liu et al.(2023)이 밝힌 "Lost in the Middle" 문제 — LLM이 컨텍스트 윈도우의 중간에 있는 정보를 놓치는 현상 — 로 인해 정답을 놓칠 수 있다.

이것이 벡터 검색의 구조적 한계다:

1
직접 유사도만 측정
벡터 검색은 질문과 문서 사이의 직접적인 의미 유사도만 본다. "A→B→C"라는 간접 관계가 있을 때 A와 C의 유사도는 낮을 수 있다.
2
청크 간 연결 없음
각 문서 청크는 독립적으로 저장되고 검색된다. 청크 A와 청크 B가 같은 엔티티를 공유한다는 정보는 사라진다.
3
로컬 검색의 태생적 한계
Top-K 검색은 질문 주변의 좁은 영역만 탐색한다. 관계 체인을 따라 멀리 떨어진 정보에는 접근할 수 없다.

숫자로 보는 실패

Milvus 노트북의 실제 실험 결과를 보자:

방식검색된 문서답변
Naive RAG① 오일러-베르누이 관계 문서 ② 요한 베르누이 업적 문서"정보 부족으로 답변 불가"
Graph RAG① 오일러-베르누이 관계 문서 ② 다니엘 베르누이 업적 문서"다니엘 베르누이는 유체역학, 확률론에 기여. 베르누이 원리로 유명"

Naive RAG는 "요한 베르누이 업적 문서"를 가져왔다. 질문과 유사도는 높지만, 아들인 다니엘 베르누이의 업적이 담긴 문서는 아니다. Graph RAG는 엔티티 관계를 추적하여 정확히 "다니엘 베르누이 업적 문서"를 찾아냈다.


3. Graph RAG의 등장: 그래프가 RAG를 만났을 때

Microsoft GraphRAG (2024)

2024년 4월, Microsoft Research의 Darren Edge 등이 발표한 "From Local to Global: A Graph RAG Approach to Query-Focused Summarization"는 Graph RAG 분야를 폭발적으로 성장시킨 기점이 되었다.

핵심 아이디어: 문서에서 엔티티와 관계를 추출하여 지식 그래프를 구축하고, Leiden 알고리즘으로 커뮤니티(클러스터)를 탐지한 뒤, 각 커뮤니티의 요약을 생성한다. 질문에 따라 로컬 검색(특정 엔티티 주변)과 글로벌 검색(커뮤니티 요약 기반)을 사용한다.

자세한 내용은 GraphRAG 완전 가이드를 참고하라.

그 뒤의 진화

GraphRAG 이후 여러 변형이 등장했다:

시스템발표핵심 차별점비용 효율
MS GraphRAG2024.04커뮤니티 탐지 + 계층적 요약낮음 (인덱싱 비용 高)
LightRAG2024.10커뮤니티 제거, 듀얼 레벨 검색높음 (토큰 6000배 절감)
PathRAG2025경로 기반 프루닝높음
Milvus Graph RAG2024벡터 DB + 인접 행렬 확장매우 높음 (경량)

이 글의 주인공인 Milvus Graph RAG는 기존 접근법들과 결이 다르다. 대규모 그래프 구축이나 커뮤니티 탐지 대신, 벡터 데이터베이스 위에서 인접 행렬 연산으로 서브그래프를 확장하는 경량 접근법이다. 작지만 강력하다.


4. Milvus: 벡터 검색의 강자

Milvus란 무엇인가

Milvus는 Zilliz(2017년 Xie Chao가 설립)가 개발한 오픈소스 벡터 데이터베이스다. 2019년 10월 첫 공개, 2020년 Linux Foundation AI & Data Foundation에 합류, 2022년 클라우드 네이티브 분산 아키텍처인 Milvus 2.0 출시를 거쳐 GitHub 스타 30,000개를 돌파하며 Pinecone, Weaviate, Qdrant와 함께 벡터 DB 분야의 선두 그룹을 형성하고 있다.

핵심 특징:

  • 대규모 벡터 검색: 수십억 개의 벡터를 밀리초 단위로 검색
  • 다양한 인덱스: IVF_FLAT, HNSW, DiskANN 등
  • 하이브리드 검색: 벡터 검색 + 스칼라 필터링
  • Milvus Lite: 로컬 파일 기반 경량 모드 (이 노트북에서 사용)
  • Zilliz Cloud: 완전 관리형 클라우드 서비스

왜 Milvus 위에 Graph RAG를 구축하는가

기존 Graph RAG 시스템(MS GraphRAG, LightRAG)은 자체 그래프 저장소를 사용하거나 Neo4j 같은 그래프 DB에 의존한다. Milvus 접근법은 다른 철학을 취한다:

💡
핵심 통찰
그래프 DB 없이, 벡터 DB만으로 그래프 추론이 가능하다. 엔티티와 관계를 각각 벡터 컬렉션에 저장하고, 인접 행렬로 연결 정보를 관리하면 된다.

이 접근법의 장점은 명확하다:

  • 인프라 단순화: 별도의 그래프 DB가 필요 없음
  • 벡터 검색의 장점 유지: 의미 기반 유사도 검색 그대로 활용
  • 수학적 우아함: 행렬 곱으로 N-degree 이웃을 한 번에 계산

5. 실전 구현: 3개의 컬렉션 설계

이제 Milvus Graph RAG의 구현을 살펴보자. 전체 아키텍처는 의외로 간결하다.

5.1 데이터 준비: 트리플렛 추출

먼저, 문서에서 트리플렛을 추출한다. 실제 프로덕션에서는 NER(Named Entity Recognition) 모델이나 LLM을 사용하지만, 핵심 원리를 이해하기 위해 사전 정의된 데이터를 사용한다.

hljs language-python
nano_dataset = [
    {
        "passage": "Jakob Bernoulli (1654–1705): Jakob was one of the earliest members...",
        "triplets": [
            ["Jakob Bernoulli", "made significant contributions to", "calculus"],
            ["Jakob Bernoulli", "was the older brother of", "Johann Bernoulli"],
            # ...
        ],
    },
    # ... 총 4개의 문서, 22개의 트리플렛
]

각 트리플렛에서 엔티티(주어/목적어)와 관계(주어 + 술어 + 목적어를 합친 문장)를 추출한다:

hljs language-python
entities = []    # ["Jakob Bernoulli", "calculus", "Johann Bernoulli", ...]
relations = []   # ["Jakob Bernoulli made significant contributions to calculus", ...]
passages = []    # [원본 문서 텍스트, ...]

그리고 두 가지 핵심 매핑을 구축한다:

entityid_2_relationids 엔티티 → 관련 관계들
relationid_2_passageids 관계 → 출처 문서들

이 매핑이 나중에 서브그래프 확장최종 문서 역추적의 핵심이 된다.

5.2 3개의 Milvus 컬렉션

데이터를 3개의 벡터 컬렉션에 나누어 저장한다:

Milvus 벡터 DB 3개의 컬렉션으로 구성
🔵 Entity Collection 엔티티 이름의 임베딩 벡터 "Jakob Bernoulli", "Euler", ...
🟠 Relation Collection 관계 문장의 임베딩 벡터 "Euler was a student of Johann..."
🟢 Passage Collection 원본 문서의 임베딩 벡터 전체 문단 텍스트

각 컬렉션에 데이터를 삽입하는 코드:

hljs language-python
from pymilvus import MilvusClient
from langchain_openai import OpenAIEmbeddings

milvus_client = MilvusClient(uri="./milvus.db")  # Milvus Lite
embedding_model = OpenAIEmbeddings(model="text-embedding-3-small")

# 엔티티, 관계, 문서를 각각 임베딩하여 저장
milvus_insert(collection_name="entity_collection", text_list=entities)
milvus_insert(collection_name="relation_collection", text_list=relations)
milvus_insert(collection_name="passage_collection", text_list=passages)

왜 3개로 나누는가? 이것이 이 접근법의 핵심 설계 결정이다:

  • Entity Collection: 질문에서 추출한 엔티티(NER)를 빠르게 찾기 위해
  • Relation Collection: 질문 전체와 의미적으로 유사한 관계를 찾기 위해
  • Passage Collection: Naive RAG 비교용 + 보조 검색

엔티티와 관계를 분리하여 검색하고, 나중에 병합하는 것이 핵심이다. 이것을 다중 경로 검색(Multi-way Retrieval)이라 부른다.


6. 다중 경로 검색: 두 갈래 길로 답을 찾다

두 갈래 경로로 보물을 찾는 탐험가 — 엔티티 경로와 관계 경로를 동시에 탐색

이 방법의 핵심 아이디어: 하나의 질문을 두 가지 다른 경로로 검색한다.

경로 1: 엔티티 검색 (Entity Retrieval)

질문에서 엔티티를 추출(NER)하고, 엔티티 컬렉션에서 유사한 엔티티를 찾는다.

hljs language-python
query = "What contribution did the son of Euler's teacher make?"
query_ner_list = ["Euler"]  # NER로 추출

# "Euler"의 임베딩으로 Entity Collection 검색
entity_search_res = milvus_client.search(
    collection_name="entity_collection",
    data=query_ner_embeddings,
    limit=3,  # Top-3 엔티티
)

이 경로는 명시적으로 언급된 엔티티를 잡아낸다.

경로 2: 관계 검색 (Relation Retrieval)

질문 전체를 Relation Collection에서 검색하여, 의미적으로 유사한 관계를 찾는다.

hljs language-python
# 질문 전체의 임베딩으로 Relation Collection 검색
query_embedding = embedding_model.embed_query(query)
relation_search_res = milvus_client.search(
    collection_name="relation_collection",
    data=[query_embedding],
    limit=3,  # Top-3 관계
)

이 경로는 질문과 의미적으로 관련된 관계를 잡아낸다.

왜 두 경로가 필요한가

엔티티 경로관계 경로
검색 대상엔티티 이름관계 문장 전체
잡아내는 것명시적으로 언급된 개체의미적으로 관련된 관계
강점정확한 엔티티 매칭넓은 의미 커버리지
약점NER 정확도에 의존관련 없는 관계 포함 가능
비유GPS로 정확한 주소 찾기주변 탐색으로 관련 장소 발견

두 경로를 합치면 정확성과 포괄성을 모두 확보할 수 있다. 마치 지도에서 정확한 주소(엔티티)와 주변 탐색(관계)을 동시에 하는 것과 같다.


7. 인접 행렬로 서브그래프 확장: 수학의 우아함

돋보기로 그래프의 이웃 노드들이 펼쳐지는 서브그래프 확장 과정

검색으로 시작점을 찾았다면, 이제 그 주변을 확장해야 한다. "Euler"를 찾았으니, Euler와 연결된 "Johann Bernoulli"를, 그리고 Johann과 연결된 "Daniel Bernoulli"를 찾아야 한다.

이것을 서브그래프 확장(Subgraph Expansion)이라 하며, 이 노트북은 인접 행렬(Adjacency Matrix)을 사용한 매우 우아한 방법을 제시한다.

7.1 인접 행렬 구축

엔티티와 관계 사이의 연결을 행렬로 표현한다:

Aij={1엔티티 i가 관계 j에 등장0그 외A_{ij} = \begin{cases} 1 & \text{엔티티 } i \text{가 관계 } j \text{에 등장} \\ 0 & \text{그 외} \end{cases}

hljs language-python
import numpy as np
from scipy.sparse import csr_matrix

# 엔티티-관계 인접 행렬 (엔티티 수 × 관계 수)
entity_relation_adj = np.zeros((len(entities), len(relations)))
for entity_id, entity in enumerate(entities):
    entity_relation_adj[entity_id, entityid_2_relationids[entity_id]] = 1

# 희소 행렬로 변환 (효율적 연산)
entity_relation_adj = csr_matrix(entity_relation_adj)

행렬 A의 크기는 (엔티티 수 × 관계 수)다. 값이 1이면 "이 엔티티가 이 관계에 참여한다"는 뜻이다.

7.2 행렬 곱으로 이웃 찾기

여기서 수학의 마법이 시작된다.

엔티티-엔티티 1-degree 인접 행렬:

E1=AATE_1 = A \cdot A^T

행렬 AA와 그 전치행렬 ATA^T의 곱은 "같은 관계에 참여하는 엔티티 쌍"을 찾아낸다. E1[i][j]>0E_1[i][j] > 0이면 엔티티 iijj가 적어도 하나의 관계를 공유한다는 뜻이다.

관계-관계 1-degree 인접 행렬:

R1=ATAR_1 = A^T \cdot A

마찬가지로, 같은 엔티티를 공유하는 관계 쌍을 찾는다.

hljs language-python
# 1-degree 인접 행렬
entity_adj_1_degree = entity_relation_adj @ entity_relation_adj.T
relation_adj_1_degree = entity_relation_adj.T @ entity_relation_adj

7.3 N-degree 확장

2-degree 이웃이 필요하면? 행렬을 한 번 더 곱하면 된다:

E2=E1E1E_2 = E_1 \cdot E_1

이렇게 하면 "친구의 친구"까지 도달할 수 있다. 대부분의 경우 1~2 degree면 충분하다.

hljs language-python
target_degree = 1  # 대부분 1이면 충분

# target degree 인접 행렬 계산
entity_adj_target = entity_adj_1_degree
for _ in range(target_degree - 1):
    entity_adj_target = entity_adj_target * entity_adj_1_degree

# 엔티티에서 도달 가능한 관계 찾기
entity_relation_adj_target = entity_adj_target @ entity_relation_adj

7.4 확장 결과 병합

검색된 엔티티와 관계 각각에서 서브그래프를 확장한 뒤, 두 결과를 합집합(Union)으로 병합한다:

hljs language-python
# 관계 경로에서 확장
expanded_from_relation = set()
for hit_id in filtered_hit_relation_ids:
    expanded_from_relation.update(
        relation_adj_target[hit_id].nonzero()[1].tolist()
    )

# 엔티티 경로에서 확장
expanded_from_entity = set()
for hit_id in filtered_hit_entity_ids:
    expanded_from_entity.update(
        entity_relation_adj_target[hit_id].nonzero()[1].tolist()
    )

# 합집합으로 후보 관계 구성
candidate_ids = list(expanded_from_relation | expanded_from_entity)
엔티티 검색 결과 서브그래프 확장
+
관계 검색 결과 서브그래프 확장
↓ 합집합
후보 관계 집합 LLM 리랭킹

왜 인접 행렬인가

이 접근법이 우아한 이유는 계산 효율성에 있다:

  • scipy 희소 행렬(CSR): 대부분의 값이 0인 그래프에서 메모리와 연산 효율 극대화
  • 행렬 곱 한 번: N-degree 이웃을 재귀 탐색 없이 한 번의 행렬 곱으로 계산
  • 확장 가능: 엔티티 수가 수만 개여도 희소 행렬 곱은 밀리초 단위

그래프 DB의 BFS/DFS 탐색과 비교하면, 행렬 연산은 배치 처리에 최적화되어 있어 벡터 DB 환경에 자연스럽게 통합된다.


8. LLM 리랭킹: 후보를 골라내는 AI

서브그래프 확장으로 후보 관계를 모았다면, 이제 진짜 관련 있는 것만 골라야 한다. 여기서 LLM의 추론 능력이 등장한다.

Chain-of-Thought 리랭킹

LLM에게 후보 관계 목록과 질문을 함께 주고, 사고 과정(thought process)과 함께 가장 유용한 관계 3개를 선택하도록 한다.

ONE-SHOT EXAMPLE
질문 제3차 십자군 원정의 지도자의 어머니는 언제 태어났는가?
사고 과정 제3차 십자군 지도자 → 리처드 사자심왕. 그의 어머니 → 엘레노어. 엘레노어의 출생 → 1122년.
선택된 관계 [11] Richard the Lionheart led the Third Crusade
[7] Eleanor was the mother of Richard
[1] Eleanor was born in 1122

이 One-Shot 예제를 바탕으로, 실제 질문에 대해서도 같은 패턴으로 추론한다:

hljs language-python
def rerank_relations(query, candidate_texts, candidate_ids):
    # Chain-of-Thought 프롬프트
    rerank_prompts = ChatPromptTemplate.from_messages([
        HumanMessage(one_shot_input),    # One-shot 예제 입력
        AIMessage(one_shot_output),       # One-shot 예제 출력
        HumanMessagePromptTemplate(...)   # 실제 질문 + 후보 관계
    ])

    # JSON 형식으로 응답 강제
    rerank_chain = (
        rerank_prompts
        | llm.bind(response_format={"type": "json_object"})
        | JsonOutputParser()
    )

    result = rerank_chain.invoke({
        "question": query,
        "relation_des_str": relation_descriptions
    })
    return result["useful_relationships"]

리랭킹의 핵심 설계 결정

설계 요소선택이유
Few-shot 수One-shot (1개)토큰 효율 + 충분한 형식 안내
추론 방식Chain-of-Thought멀티홉 추론 경로를 명시적으로 추적
출력 형식JSON파싱 안정성 (json_object 모드)
선택 수3개정밀도-재현율 균형

왜 벡터 유사도로 리랭킹하지 않는가

벡터 유사도는 "의미적 가까움"을 측정하지만, 추론 체인의 유용성은 측정하지 못한다. "Euler was born in Basel"은 질문과 벡터 유사도가 높을 수 있지만, 답에 필요한 관계가 아니다. LLM은 추론 경로를 따라 정말 필요한 관계를 판별할 수 있다.


9. 전체 파이프라인: 한눈에 보기

지금까지의 모든 단계를 하나의 파이프라인으로 정리하자:

Offline
데이터 준비: 문서에서 트리플렛 추출 → 엔티티, 관계, 문서를 각각 벡터화하여 3개 Milvus 컬렉션에 저장 → 인접 행렬 구축
Step 1
다중 경로 검색: 질문에서 NER로 엔티티 추출 → Entity Collection + Relation Collection 각각 Top-K 검색
Step 2
서브그래프 확장: 인접 행렬 곱으로 검색된 엔티티/관계의 N-degree 이웃 탐색 → 후보 관계 합집합 구성
Step 3
LLM 리랭킹: Chain-of-Thought로 후보 관계 중 가장 유용한 3개 선택
Step 4
답변 생성: 선택된 관계 → 출처 문서 역추적 → LLM에 전달하여 최종 답변 생성

최종 답변 생성

리랭킹된 관계에서 원본 문서를 역추적한다:

hljs language-python
final_passages = []
for relation_id in rerank_relation_ids:
    for passage_id in relationid_2_passageids[relation_id]:
        if passage_id not in final_passage_ids:
            final_passages.append(passages[passage_id])

# Top-2 문서로 최종 답변 생성
answer = rag_chain.invoke({
    "question": query,
    "context": "\n".join(final_passages[:2])
})

10. 결과 비교: 극적인 차이

Naive RAG vs Graph RAG — 실패와 성공의 극적인 대비

같은 질문, 같은 데이터. 결과는 완전히 다르다.

Naive RAG

❌ Naive RAG — 검색된 문서
문서 1: "Leonhard Euler (1707–1783) was one of the greatest mathematicians of all time, and his relationship with the Bernoulli family was significant. Euler was born in Basel and was a student of Johann Bernoulli..."

문서 2: "Johann Bernoulli (1667–1748): Johann, Jakob's younger brother, was also a major figure in the development of calculus..."

Naive RAG가 가져온 두 문서는 오일러와 요한 베르누이에 대한 것이다. 질문의 핵심인 "아들(다니엘 베르누이)의 업적"이 없다.

답변: "검색된 문맥에서 오일러 스승의 아들이 한 기여에 대한 정보를 찾을 수 없습니다."

Graph RAG

✅ Graph RAG — 검색된 문서
문서 1: "Leonhard Euler (1707–1783) was one of the greatest mathematicians... was a student of Johann Bernoulli..."

문서 2: "Daniel Bernoulli (1700–1782): The son of Johann Bernoulli, Daniel made major contributions to fluid dynamics, probability, and statistics. He is most famous for Bernoulli's principle..."

Graph RAG는 "Euler → Johann Bernoulli" 관계를 찾고, 서브그래프를 확장하여 "Johann Bernoulli → Daniel Bernoulli"를 거쳐, 다니엘 베르누이의 업적 문서를 정확히 가져왔다.

답변: "오일러의 스승인 요한 베르누이의 아들, 다니엘 베르누이는 유체역학, 확률론, 통계학에 주요한 기여를 했습니다. 그는 유체 흐름의 행동을 설명하는 베르누이 원리로 가장 유명하며, 이는 공기역학 이해의 근본이 됩니다."

차이의 원인

검색 성공의 핵심 요인
관계 추적 능력
Graph RAG
관계 추적 능력
Naive
직접 유사도 검색
Graph RAG
직접 유사도 검색
Naive

Naive RAG는 직접 유사도 검색에서는 Graph RAG와 비슷하지만, 관계 추적이 전혀 안 된다. 멀티홉 질문에서의 성패가 여기서 갈린다.


11. 2026년 Graph RAG 생태계 지도

2026년 현재, Graph RAG 생태계는 빠르게 성숙하고 있다. 각 접근법의 특성을 이해하고 상황에 맞게 선택하는 것이 중요하다.

주요 시스템 비교

MS GraphRAGLightRAGPathRAGMilvus Graph RAG
출시2024.042024.1020252024
그래프 구축LLM 추출 + Leiden 클러스터링LLM 추출 + 키-값LLM 추출 + 경로 프루닝트리플렛 + 인접 행렬
검색 방식로컬/글로벌 이중저수준/고수준 듀얼 레벨최단 경로 탐색다중 경로 + LLM 리랭킹
별도 그래프 DB필요불필요불필요불필요
인덱싱 비용매우 높음낮음중간낮음
멀티홉 추론강함중간강함강함
글로벌 질문매우 강함중간약함약함
증분 업데이트어려움쉬움중간쉬움
적합한 규모대규모중소규모중규모중소규모

어떤 걸 써야 할까?

🏢
MS GraphRAG
"5000건의 고객 불만에서 반복 패턴을 찾아줘" — 글로벌 요약이 필요할 때. 비용을 감당할 수 있는 엔터프라이즈 환경.
🚀
LightRAG
"GraphRAG의 장점을 원하지만 비용은 1/100로" — 비용 민감한 스타트업. 증분 업데이트가 잦은 환경.
🔗
Milvus Graph RAG
"이미 Milvus를 쓰고 있고, 멀티홉 추론만 추가하고 싶다" — 기존 벡터 DB 인프라에 그래프를 얹고 싶을 때. 최소 비용으로 최대 효과.

주목할 연구들

이 표에 담기지 않은 중요한 연구들도 있다:

  • HippoRAG (Gutierrez et al., NeurIPS 2024) — 인간의 해마(hippocampus) 기억 인덱싱에서 영감을 받아, 지식 그래프를 인공 해마 인덱스로 사용하는 검색 프레임워크. Personalized PageRank으로 KG 위를 탐색하며, 인접 행렬 기반 검색 패턴의 이론적 근거를 제공한다.
  • Think-on-Graph (Sun et al., 2024) — LLM 에이전트가 지식 그래프 위를 인터랙티브하게 탐색하며 추론하는 방식. 검색이 아닌 탐색(exploration)으로 멀티홉 문제를 해결한다.
  • KG-RAG (Varma & Gaur, 2023) — 의료 분야의 SPOKE 지식 그래프와 RAG를 결합하여 의료 QA 성능을 향상시킨 사례. 도메인 특화 KG의 가치를 입증했다.

2026년의 트렌드

1. 하이브리드 접근법의 부상

단일 방법론에 의존하기보다, 상황에 따라 Naive RAG, Graph RAG, Agentic RAG를 결합하는 하이브리드 파이프라인이 주류가 되고 있다. 질문 유형을 분류(단순 사실 vs 멀티홉 vs 글로벌)한 뒤, 적합한 검색 전략을 선택하는 라우터 패턴이 보편화되었다.

2. 자동 트리플렛 추출의 성숙

LLM 기반 트리플렛 추출의 품질이 크게 향상되었다. GPT-4o, Claude 등의 모델이 긴 문서에서도 안정적으로 엔티티와 관계를 추출하며, 특히 도메인 특화 파인튜닝된 소형 모델(7B~13B)이 비용 효율적인 대안으로 떠올랐다.

3. 벡터 DB와 그래프 DB의 융합

Milvus를 포함한 주요 벡터 DB들이 그래프 구조를 네이티브로 지원하기 시작했다. 반대 방향에서는 Neo4j가 LangChain과의 통합으로 벡터 검색을 지원하고, Amazon Neptune Analytics가 그래프+벡터 하이브리드 쿼리를 도입했다. 별도의 인접 행렬을 관리하는 대신, 벡터 검색과 그래프 탐색을 하나의 쿼리로 실행하는 방향으로 양쪽 모두 수렴하고 있다.


12. 실전 적용 시나리오

Graph RAG는 엔티티 간 관계가 핵심인 도메인에서 빛난다.

기업 지식 관리

질문
"작년에 A 부서가 진행한 프로젝트 중, B 고객이 관여한 건에서 발생한 이슈는?"
Graph RAG 추론 경로
A 부서 → 프로젝트 X, Y, Z → B 고객 참여 프로젝트 Y → 이슈 #123, #456

부서, 프로젝트, 고객, 이슈 — 네 종류의 엔티티를 관계로 연결해야 답할 수 있다. Naive RAG로는 불가능하다.

의료 분야

환자의 증상(A) → 가능한 질병(B) → 권장 검사(C) → 약물 상호작용(D). 의료 지식은 본질적으로 멀티홉 관계의 체인이다. Graph RAG를 활용한 의료 QA 시스템은 진단 보조에서 특히 유망하다.

법률 분석

법 조항(A) → 판례(B) → 인용된 다른 판례(C) → 관련 법 조항(D). 법률 문서 분석에서 "이 조항과 관련된 모든 판례의 최종 결론은?"이라는 질문은 전형적인 멀티홉 문제다.

금융 리스크 분석

기업 A → 공급 계약 → 기업 B → 대출 관계 → 은행 C. 공급망 리스크의 연쇄 전파를 추적하는 데 Graph RAG가 강력하다. 2025년 이후 금융 규제(Basel III+)에서도 이런 연결 분석이 요구되고 있다.


마무리: 벡터 검색의 다음 단계

📌
핵심 3줄 요약
1. Naive RAG는 엔티티 간 관계를 추적하지 못해 멀티홉 질문에 실패한다.
2. Milvus Graph RAG는 벡터 DB 위에 인접 행렬 기반 서브그래프 확장 + LLM 리랭킹을 결합하여, 별도 그래프 DB 없이 관계 추론을 실현한다.
3. 2026년 현재, 단일 RAG 방법론이 아닌 하이브리드 접근법이 주류이며, 질문 유형에 따라 적합한 검색 전략을 선택하는 것이 핵심이다.

"오일러의 스승의 아들은 뭘 했지?"라는 질문은 단순해 보이지만, AI에게는 깊은 도전이다. 단어의 유사도가 아니라 엔티티 사이의 관계를 추적해야 하기 때문이다.

Graph RAG는 이 도전에 대한 우아한 답이다. 그리고 Milvus 접근법은 그 답을 가장 가볍고 실용적인 방식으로 구현할 수 있음을 보여준다.

벡터 검색이 "의미"를 이해하게 해주었다면, Graph RAG는 "관계"를 이해하게 해준다. 다음 단계는 무엇일까? 아마도 "맥락"과 "의도"까지 이해하는 AI 검색 — Agentic RAG가 그 답이 될지도 모른다.


참고 자료

  • Graph RAG with Milvus — Milvus Bootcamp — 이 글의 기반이 된 공식 노트북
  • Lewis et al. (2020). Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks. NeurIPS 2020.
  • Edge et al. (2024). From Local to Global: A Graph RAG Approach to Query-Focused Summarization. Microsoft Research.
  • Guo et al. (2024). LightRAG: Simple and Fast Retrieval-Augmented Generation. arXiv:2410.05779.
  • Singhal et al. (2012). Introducing the Knowledge Graph. Google Official Blog.
  • Gutierrez et al. (2024). HippoRAG: Neurobiologically Inspired Long-Term Memory for Large Language Models. NeurIPS 2024.
  • Sun et al. (2024). Think-on-Graph: Deep and Responsible Reasoning of Large Language Model on Knowledge Graph. ICLR 2024.
  • Liu et al. (2023). Lost in the Middle: How Language Models Use Long Contexts. arXiv:2307.03172.
  • Milvus Documentationhttps://milvus.io/docs

관련 글