HomeEngineeringAI

Vector RAG의 한계와 Graph RAG

2026년 4월 25일15 min readavatarYejun Park
RAG
GraphRAG
LLM
AI
Knowledge Graph

Vector RAG가 multi-hop 관계 질의에서 왜 한계를 갖는지 분석하고, Graph RAG의 동작 원리와 구체적인 구현 예시를 다룹니다.

문서나 코드처럼 관계 구조가 중요한 데이터에서는 단순 Vector RAG만으로 연결 관계를 안정적으로 추적하기 어렵다. Vector RAG의 구조적 한계를 정리하고, 이를 보완하는 Graph RAG의 동작 원리와 구체적인 구현 예시를 다룬다.


Vector RAG의 한계

1. 관계/경로를 직접 보존·탐색하기 어려움

각 chunk는 독립적으로 임베딩되므로 retrieval 단계에서 chunk 간 관계나 경로를 명시적으로 보존·탐색하기 어렵다.

relation-heavy problem: 데이터 자체보다 데이터 간 관계가 더 중요한 문제

예시로 RBAC IAM 시스템을 보자. IAM에서 최종 권한 판단은 개별 엔티티 하나보다 User-Group-Role-Permission-Resource 간의 경로와 정책 조합에 의해 결정되는 경우가 많다.

[Chunk1] User는 Group에 속함
[Chunk2] Group은 Role을 가짐
[Chunk3] Role은 Permission을 가짐

Chunk1, 3만 검색되면 Chunk2가 누락되어 엉뚱한 해석이 된다. 이 구조의 특징은 다음과 같다.

  1. 핵심 정보가 개별 node보다 node 간 관계(edge) 에 더 많이 담긴다
  2. multi-hop이 기본 — 반드시 여러 단계를 거쳐 조회해야 한다
  3. 결과가 집합이 아닌 경로다 — 특정 리스트가 아니라 경로에 대한 설명이 필요하다
  4. Explainability가 중요하다

entity-relation problem: 질문이 엔티티와 그 사이의 관계를 중심으로 구성되는 경로 탐색형 문제

// User A가 Resource B에 접근 가능한가?
(User A) --[has permission?]--> (Resource B)

이 문제에서 Vector RAG는 세 가지 한계를 드러낸다.

  1. Entity disambiguation 실패: "Admin"이라는 키워드가 Role인지 Group인지 구분하지 못한다
  2. Relation loss: 임베딩 기반 retrieval에서는 관계가 텍스트 의미 안에 암묵적으로 흡수되어 명시적 관계 구조를 유지하기 어렵다
  3. Vector search는 관계형 DB의 JOIN처럼 명시적 관계 결합을 기본 retrieval 연산으로 제공하지 않는다

2. multi-hop 관계 질의를 retrieval 단계에서 다루기 어려움

Vector retrieval은 개별 chunk의 의미 유사도를 기준으로 동작하므로 multi-hop 관계를 경로 단위로 안정적으로 복원하기 어렵다. 각 hop이 분리되어 연결된 상태로 가져오지 못하고, 중간 노드가 누락되면 전체 reasoning이 깨진다.

Q. 유저가 해당 리소스에 접근 가능한 이유는?
A. UserGroupRolePermissionResource (4-hop)

3~4 hop 이상의 관계형 질의를 단순 Vector RAG만으로 일관되게 처리하기 어렵다.

3. Top-K retrieval의 구조적 한계

Top-K로 선택된 K개가 모두 유의미한 chunk라는 보장이 없다. 질문과 직접적인 연관성이 없는 chunk가 상위에 노출되면 핵심 정보가 누락되어 엉뚱한 답변을 낼 확률이 높아진다.

4. context fragmentation

chunk 단위로 쪼개지므로 LLM이 연결해서 해석해야 한다. 관계 복원이 retrieval 단계에서 충분히 이루어지지 않으면 LLM이 누락된 연결을 추론에 의존하게 되고, 그만큼 hallucination 위험이 커진다.


Graph RAG의 구성

그래프 기반으로 정보를 탐색해서 LLM에 전달하는 RAG다.

Vector RAG vs Graph RAG

  • Vector RAG: 문서/코드를 벡터로 변환해서 의미가 가까운 데이터를 찾아오는 방식. 포털에서 '사과'를 검색하면 '과일', '농장'이 같이 나오는 것과 유사하다
  • Graph RAG: 데이터를 node와 edge로 연결한 Knowledge Graph를 만들어 명시적 관계를 따라 탐색하는 방식. 지하철 노선도처럼 미리 구조를 그려두고 경로를 찾는다

한계점: 처음 시스템을 만들 때 어떤 것을 node로, 어떤 것을 edge로 둘지 Ontology를 설계해야 하므로 구축 난이도가 높다.

따라서 의미 기반 검색이 필요한 영역에는 Vector retrieval을, 명시적 경로 탐색이 필요한 영역에는 Graph retrieval을 적용하는 hybrid 접근이 유의미한 대안이 된다.

Vector RAG vs Graph RAG 비교

*출처 - https://levelup.gitconnected.com/how-to-enhance-rag-with-knowledge-graphs-1c89ccfd3a6b

동작 흐름

Loading diagram...

내비게이션 비유

  1. Graph Storage (지도 보관소): Neo4j 같은 그래프 전용 DB
  2. Graph Traversal (길 찾기 알고리즘): NetworkX가 수행하는 역할
  3. LLM Generation (내비게이션 성우): 길 찾기 결과를 자연어로 설명
항목Vector RAGGraph RAG
Retrieval 단위문서(chunk)Subgraph
검색 방식Top-K 유사도Traversal (경로 탐색)
결과 형태문서 리스트관계 구조 (path)

Ontology / Entity / Edge 설계

Ontology

그래프에서 어떤 엔티티와 관계를 사용할지 정의한 스키마 — "어떤 질문을 어떤 구조로 풀 것인가"를 결정하는 모델이다.

  • 질문 중심으로 설계한다
  • 너무 단순하거나 복잡해도 안 된다

IAM Ontology 예시:

  • [Entity] User, Group, Role, Permission, Resource
  • [Relation] MEMBER_OF, ASSIGNED_ROLE, GRANTS, APPLIES_TO, DENIES

Entity

그래프의 node로 표현되는 실제 객체 — traversal의 anchor가 되는 단위다.

  • granularity: Permission을 어떻게 쪼갤 것인가
  • identity: Unique ID 필수
  • metadata 포함 여부 고려

Edge

엔티티 간의 의미 있는 관계 표현 — traversal 가능한 방향성과 필요 시 조건(condition) 속성을 함께 설계할 수 있다.

GRANTS {
  condition: "region=KR"
}

User ──MEMBER_OF──> Group
Group ──ASSIGNED_ROLE──> Role
Role ──GRANTS──> Permission
Permission ──APPLIES_TO──> Resource

Knowledge Graph 구축 파이프라인

Graph RAG에서 실제로 가장 어려운 부분은 탐색이 아니라 비정형 소스에서 그래프를 구축하는 과정이다.

[원본 소스 (코드 / 문서 / 텍스트)]
[파싱 / 엔티티 추출]
  - 코드베이스: tree-sitter로 클래스·함수·호출 관계를 AST 파싱
  - 비정형 문서: LLM으로 엔티티·관계 추출 (e.g. Microsoft GraphRAG 방식)
[관계 정규화 → JSON / 중간 포맷으로 저장]
[Graph DB 적재]
  - 실험 단계: NetworkX (인메모리)
  - 실서비스: Neo4j 등 persistent graph DB
[탐색 가능한 Knowledge Graph 완성]

소스 유형별 구축 방식 비교

소스 유형추출 방법특징
코드베이스tree-sitter (AST 파싱)관계가 명시적 — 정확도 높음
구조화 문서 (IAM 정책 등)규칙 기반 파서스키마가 고정된 경우 적합
비정형 텍스트LLM 엔티티·관계 추출유연하지만 추출 품질이 프롬프트에 의존

NetworkX로 IAM 권한 경로 분석하기

NetworkX는 그래프 구조를 메모리 위에서 만들고 node 간 연결 관계를 탐색하는 Python 라이브러리다. 최단 경로 탐색(shortest_path), 연결된 하위 노드 조회(descendants), 네트워크 중심성 분석 등 그래프 이론 알고리즘이 구현되어 있다.

초기 실험 단계에서 별도의 Graph DB 없이 traversal 기반 retrieval을 빠르게 검증할 수 있다. 단, 인메모리 구조이므로 대용량 데이터나 실서비스에서는 Neo4j 등 persistent graph DB로 교체가 필요하다.

목표: 어떤 사용자가, 어떤 경로를 통해, 어떤 리소스 권한을 가지게 되었는가를 분석하는 시스템

도달 가능한 전체 노드 조회

import networkx as nx

# 방향 그래프: User -> Group -> Role -> Permission -> Resource
# 권한이 어떻게 전달되는가의 방향이 중요하다
G = nx.DiGraph()

# jjun은 game-ops-team 그룹에 속하고,
# game-ops-team은 game-data-editor 역할을 가지며,
# game-data-editor는 game-data.write 권한을 부여받고,
# 그 권한은 game-metrics-api 리소스에 적용된다.
G.add_edge("user:jjun", "group:game-ops-team", relation="MEMBER_OF")
G.add_edge("group:game-ops-team", "role:game-data-editor", relation="ASSIGNED_ROLE")
G.add_edge("role:game-data-editor", "permission:game-data.write", relation="GRANTS")
G.add_edge("permission:game-data.write", "resource:game-metrics-api", relation="APPLIES_TO")

# 추가 경로: jjun이 다른 그룹을 통해서도 권한을 가질 수 있다
G.add_edge("user:jjun", "group:live-ops-admin", relation="MEMBER_OF")
G.add_edge("group:live-ops-admin", "role:log-viewer", relation="ASSIGNED_ROLE")
G.add_edge("role:log-viewer", "permission:log.read", relation="GRANTS")
G.add_edge("permission:log.read", "resource:game-metrics-api", relation="APPLIES_TO")

target_user = "user:jjun"

try:
    reachable_nodes = nx.descendants(G, target_user)

    for node in reachable_nodes:
        depth = nx.shortest_path_length(G, source=target_user, target=node)

        if node.startswith("group:"):
            node_type = "GROUP"
        elif node.startswith("role:"):
            node_type = "ROLE"
        elif node.startswith("permission:"):
            node_type = "PERMISSION"
        elif node.startswith("resource:"):
            node_type = "RESOURCE"
        else:
            node_type = "UNKNOWN"

        print(f"  - [{node_type}] {node} (경로 깊이: {depth})")

except nx.NetworkXNodeNotFound:
    print("해당 사용자가 그래프에 존재하지 않습니다.")

nx.descendants() — 특정 사용자가 도달 가능한 권한/리소스 집합 조회

nx.descendants() 실행 결과 — 사용자가 도달 가능한 노드 목록

특정 리소스까지의 접근 경로 조회

import networkx as nx

G = nx.DiGraph()

G.add_edge("user:jjun", "group:game-ops-team", relation="MEMBER_OF")
G.add_edge("group:game-ops-team", "role:game-data-editor", relation="ASSIGNED_ROLE")
G.add_edge("role:game-data-editor", "permission:game-data.write", relation="GRANTS")
G.add_edge("permission:game-data.write", "resource:game-metrics-api", relation="APPLIES_TO")

source_user = "user:jjun"
target_resource = "resource:game-metrics-api"

try:
    path = nx.shortest_path(G, source=source_user, target=target_resource)

    for i in range(len(path) - 1):
        from_node = path[i]
        to_node = path[i + 1]
        relation = G[from_node][to_node]["relation"]
        print(f"  {from_node} --[{relation}]--> {to_node}")

except nx.NetworkXNoPath:
    print("접근 불가: 해당 사용자에서 리소스까지 도달 가능한 권한 경로가 없습니다.")

except nx.NetworkXNodeNotFound:
    print("그래프에 존재하지 않는 노드입니다.")

nx.shortest_path() — 특정 리소스에 대한 접근 경로 복원

단, shortest_path()는 경로 하나만 반환한다. 사용자가 여러 그룹을 통해 동일 리소스에 접근 가능한 경우 all_simple_paths()로 전체 경로를 조회해야 한다.

nx.shortest_path() 실행 결과 — jjun에서 game-metrics-api까지의 권한 경로

Q. jjun이 game-metrics-api에 접근 가능한 이유는?

jjun은 여러 그룹에 속해 있고, 그 그룹을 통해 role을 받고, 그 role이 permission을 부여하며, 결국 game-metrics-api 리소스에 도달한다. Graph RAG는 이 경로를 명시적으로 설명할 수 있다.

실제 서비스에서는 정책 엔진이 최종 allow/deny를 판정하고, Graph는 그 경로를 설명/분석하는 역할을 담당한다.


정리

Vector RAG는 관련 정보를 찾는 데 강하지만, 관계 구조와 경로가 핵심인 문제에서는 한계가 명확하다. Graph RAG는 이를 보완하는 구조지만, 구축 비용이 높고 Ontology 설계가 선행되어야 한다.

둘은 경쟁 관계가 아니라 보완 관계다. 의미 기반 검색에는 Vector를, 경로 탐색과 관계 설명이 필요한 영역에는 Graph를 조합하는 hybrid 접근이 실용적인 대안이다.