마이클 알바다 『AI 에이전트 엔지니어링 』 한빛미디어(2026), 168-180
베이스라인 RAG 시스템은 문서를 청크로 나누고, 각 청크를 벡터 공간에 임베딩한 뒤 쿼리 시점에 시맨틱하게 유사한 청크를 검색해 LLM 프롬프트에 추가하는 방식으로 동작한다.
예를 들어 "스티브 잡스가 무슨 일을 해왔는가?" 라는 질문에 스티브 잡스가 한 일에 대한 사실만으로 시맨틱 청킹이 되어 있지 않다면, 스티브 잡스의 다른 정보가 LLM 프롬프트에 섞인다.
그래프 데이터베이스나 지식 그래프를 이용해 서로 연결된 데이터를 저장, 조회
데이터 안의 복잡한 관계와 컨텍스트를 표현하는 그래프에서 노드와 엣지를 분석
기존 Baseline RAG를 구축할 때와 마찬가지로 다음 과정이 필요
1. 데이터 수집
2. 데이터 전처리
3. 엔티티 추출

4. 관계 추출
5. Ontology 설계
6. 그래프 생성
7. 통합 및 검증
8. 유지보수와 업데이트

GraphRAG 시스템 구축을 위한 Neo4j Cypher 쿼리의 기초 문법, 제약 조건, 변수 범위, 그리고 벡터 유사도 기반의 지능형 홉 탐색 전략을 정리
(p:Entity {id: "E001"})-[:OWNED_BY]->(related)
// 노드 생성 예시
MERGE (p:Entity {id: "E001"})
ON CREATE SET p.name = "Elon Musk", p.type = "Person"
// 관계 생성 예시
MATCH (a:Entity {name: "Tesla"}), (b:Entity {name: "Elon Musk"})
MERGE (a)-[r:OWNED_BY]->(b)
SET r.share = "13%"
패턴 매칭을 통해 데이터를 검색합니다. 화살표 방향을 통해 관계를 명시합니다.
// 특정 노드와 연결된 모든 이웃 찾기
MATCH (e:Entity {name: "Tesla"})-[r]->(neighbor)
RETURN e.name, type(r) AS relationship, neighbor.name
데이터 무결성을 위해 특정 규칙을 강제합니다.
| 제약 종류 | Cypher 예시 | 설명 |
|---|---|---|
| Unique | CREATE CONSTRAINT FOR (e:Entity) REQUIRE e.id IS UNIQUE | 특정 속성값 중복 방지 |
| Existence | CREATE CONSTRAINT FOR (p:Person) REQUIRE p.name IS NOT NULL | 속성 필수 존재 강제 |
| Node Key | CREATE CONSTRAINT FOR (c:City) REQUIRE (c.id) IS NODE KEY | Unique + Existence 결합 |
WITH 절을 사용해야 합니다.특정 깊이까지의 연결 고리를 추적합니다.
// 1~3홉 사이의 모든 경로 탐색 (무방향)
MATCH path = (n:Entity {name: "AI"})-[*1..3]-(related)
RETURN path
두 엔티티 사이의 가장 짧은 연결 고리를 찾습니다. 복잡한 관계 속에서 두 개념이 어떻게 가장 밀접하게 연관되었는지 추출할 때 유용합니다.
MATCH (a:Entity {name: "Microsoft"}), (b:Entity {name: "OpenAI"})
MATCH p = shortestPath((a)-[*..5]-(b))
RETURN p
Neo4j에 노드별 임베딩(LIST<FLOAT>)이 저장되어 있을 때, 사용자 질문과의 유사도를 실시간으로 계산하며 탐색하는 기법입니다.
Neo4j 버전 5.x 이상부터는 LIST 형식으로 임베딩 벡터를 속성에 저장할 수 있으며, 이를 위한 Vector Index를 생성할 수 있습니다.
CREATE VECTOR INDEX entity_embeddings FOR (e:Entity) ON (e.embedding)
OPTIONS {indexConfig: {
`vector.dimensions`: 1536,
`vector.similarity_function`: 'cosine'
}}
전체 그래프를 탐색하되, 질문 벡터와 유사도가 낮은 노드는 경로에서 제외합니다.
// 모든 경로상의 노드가 질문과 유사도 0.8 이상인 경우만 탐색
// 방법 A: 반복적 홉 탐색 (탐색의 매 단계마다 유사도를 체크하여 '가지치기'를 수행)
MATCH (current:Entity {id: $currentId})-[r]->(next:Entity)
WITH next, vector.similarity.cosine(next.embedding, $queryVector) AS similarity
WHERE similarity > 0.8
RETURN next.id, next.name, similarity
// 방법 B: 하이브리드 탐색 (전체 경로 후 필터링)
MATCH path = (start:Entity {name: "시작지점"})-[*1..3]-(target:Entity)
WHERE ALL(n IN nodes(path) WHERE vector.similarity.cosine(n.embedding, $queryVector) > 0.8)
RETURN path, target.name
벡터 인덱스로 후보군을 먼저 좁힌 후, 그 주변 홉을 탐색하여 효율을 높입니다.
// 1. 질문과 유사한 노드 Top 5를 먼저 찾음
CALL db.index.vector.queryNodes('entity_embeddings', 5, $queryVector)
YIELD node AS startNode, score
// 2. 찾은 노드들로부터 1~2홉 이내의 지식만 확장
MATCH (startNode)-[r*1..2]-(neighbor)
RETURN startNode.name, type(last(r)), neighbor.name
(a)-(b) 처럼 화살표를 생략하여 양방향 탐색이 가능합니다.[:WORKS_AT*])을 명시하면 탐색 속도가 비약적으로 향상됩니다.*) 사용 시 반드시 최대 깊이(*..3)를 제한하여 무한 루프를 방지해야 합니다.