GraphRAG 스킬
플랫한 청크 대신 지식 그래프를 기반으로 한 검색 증강 생성입니다. 문서에서 엔터티와 관계를 추출하여 그래프 데이터베이스에 저장하고, 쿼리 시 LLM이 그래프 구조를 따라 추론합니다.
그래프가 벡터보다 나은 이유
벡터 검색은 유사한 청크를 찾습니다. 연결 관계를 따라갈 수는 없습니다.
- "X 공장 정전에 영향을 받은 공급업체는?"는
정전 → 영향 → 공장 → 공급 → 공급업체라는 두 단계의 연결을 따라야 하지만, 어떤 단일 청크도 이 전체 관계를 담고 있지 않습니다. - "프로젝트 Y에 대해 우리가 아는 모든 것을 요약해 주세요."는 Y 주변 엔터티의 커뮤니티 전체가 필요하며, 가장 유사한 문단 열 개가 아닙니다.
질문이 단일 사실 조회라면 일반 벡터 RAG를 사용하세요. 더 간단합니다. 질문이 관계를 가로지르는 경우 GraphRAG를 고려하세요.
기술 스택
- Kuzu — 임베디드 그래프 데이터베이스 (
pip install kuzu), 서버 실행 불필요, Cypher 쿼리 언어. 여기서 시작하세요. - Neo4j — 임베디드 한계를 넘어설 때: 다중 사용자, 더 큰 그래프, Bloom 시각화. 동일한 Cypher 스킬을 그대로 사용할 수 있습니다.
- LLM 추출 — 엔터티/관계 추출을 위한 구조화된 출력을 제공하는 모든 강력한 모델.
파이프라인
1. 먼저 스키마를 정의하세요
추출기가 자유롭게 타입을 만들도록 두지 마세요. 같은 관계에 대해 40가지 철자 변형이 생깁니다. 노드와 엣지 타입을 미리 선언하세요:
CREATE NODE TABLE Person(name STRING, PRIMARY KEY(name));
CREATE NODE TABLE Project(name STRING, status STRING, PRIMARY KEY(name));
CREATE NODE TABLE Document(title STRING, date DATE, PRIMARY KEY(title));
CREATE REL TABLE WORKS_ON(FROM Person TO Project, role STRING);
CREATE REL TABLE MENTIONS(FROM Document TO Person);
CREATE REL TABLE MENTIONS_PROJECT(FROM Document TO Project);
스키마는 작게 유지하세요(5-10개 노드 타입). 나중에 확장할 수 있지만, 지저분한 그래프를 저렴하게 다시 추출할 수는 없습니다.
2. 엔터티와 관계 추출하기
문서를 청크로 나누고(500-1000 토큰, 중첩 포함), 추출기로 프롬프트를 보냅니다:
다음 텍스트에서 엔터티와 관계를 추출하세요.
허용 노드 타입: Person, Project, Document
허용 엣지 타입: WORKS_ON (Person→Project), MENTIONS (Document→Person),
MENTIONS_PROJECT (Document→Project)
규칙:
- 이름 정규화 ("J. Smith"와 "John Smith"는 동일한 Person)
- 텍스트에 명시되거나 명확히 암시된 관계만 추출
- JSON 반환: {"nodes": [...], "edges": [...]}
텍스트:
<chunk>
10-20개 청크를 수동으로 점검하세요. 추출 품질이 모든 다운스트림의 상한선입니다. 노이즈가 많은 그래프는 노이즈가 많은 답변을 만듭니다.
3. Kuzu에 로드하기
import kuzu
db = kuzu.Database("./knowledge.kz")
conn = kuzu.Connection(db)
# 스키마 생성 후, 추출된 노드/엣지당 파라미터화된 MERGE/CREATE 수행
로드 시 중복 제거 (MERGE on primary key) — 동일한 엔터티가 여러 청크에 나타납니다.
4. 쿼리 패턴
로컬 조회 — 엔터티에 연결된 모든 것:
MATCH (p:Person {name: $name})-[r]-(neighbor)
RETURN type(r), neighbor;
다중 홉 추론 — 그래프를 따라 관계 추적:
// 정전에 관한 문서에서 언급된 프로젝트에 누가 참여하고 있나?
MATCH (d:Document)-[:MENTIONS_PROJECT]->(proj:Project)<-[:WORKS_ON]-(p:Person)
WHERE d.title CONTAINS 'outage'
RETURN DISTINCT p.name, proj.name;
전역 요약 — 커뮤니티 탐지 후 각 커뮤니티 요약:
// 밀집된 연결 클러스터 찾기 (한 번 실행, 커뮤니티 ID를 노드에 저장)
CALL show_tables(); // 그런 다음 그래프의 커뮤니티 탐지 기능 사용
LLM으로 각 커뮤니티를 요약하세요: "이 엔터티들은 주제 X를 중심으로 모여 있습니다." 이것이 GraphRAG의 "전역 쿼리"입니다 — "이 문서들의 주요 주제는 무엇인가요?"와 같은 질문입니다.
5. LLM으로 답변하기
작동하는 쿼리 패턴:
- 에이전트가 질문을 1-3개의 Cypher 쿼리로 변환
- 결과가 구조화된 행으로 반환
- LLM이 행 으로부터 답변을 합성, 노드/엣지 증거 인용
- 쿼리 결과가 없으면 에이전트가 재구성 — 그래프 내용을 절대 환각하지 않음
시간적 지식 (에이전트 메모리)
세션 간 에이전트 메모리를 위해 엣지에 시간을 추가하세요: VALID_FROM /
VALID_TO 타임스탬프, 대체된 사실은 삭제 대신 표시. 이것은
시간적 지식 그래프 패턴입니다 (Graphiti/Zep 참조): "사용자가 예전에는 X를 선호했지만,
지금은 Y를 선호함"이 덮어쓰기되지 않고 쿼리 가능하게 유지됩니다.
안티 패턴
- 스키마 없이 추출. 자유 형식 추출은 아무도 쿼리할 수 없는 그래프를 만듭니다.
- 모든 것에 GraphRAG 사용. 깔끔한 문서에서 단일 사실 조회? 벡터 검색이 더 저렴하고 좋습니다. 관계가 중요한 곳에 그래프를 사용하세요.
- 추출을 맹목적으로 신뢰. 모든 파이프라인에는 점검 루프가 필요합니다; 추출 오류는 조용히 누적됩니다.
- 거대한 청크. 약 1000 토큰을 넘어가면 엔터티 추출 품질이 저하됩니다 — 모델이 관계를 놓치기 시작합니다. 더 작은 청크, 더 많이.
- 로드 시 중복 제거 없음. "John Smith", "J. Smith", "Smith"가 세 개의 노드로 존재하면 다중 홉 쿼리가 조용히 깨집니다.