GraphRAG는 전통 RAG의 한계를 극복하고자 지식 그래프를 검색 파이프라인에 통합한 아키텍처다. 비구조화 텍스트의 의미적 검색과 그래프 기반의 관계 추론을 결합함으로써, 단순 문서 검색을 어서 맥락을 이해하는 추론이 가능해진다. 본문에서는 컨테이너 환경 없이 순수 파이썬生태계로 고가용성 GraphRAG를 구축하는 방법을 살펴본다.
아키텍처 설계 및 기술 선정
목표는 다음과 같은 제약 하에서 설계되었다: 로컬 환경에서의 완전한 실행, 부 API 의존성 최소화, 모듈 간 느슨한 결합. 이를 위해 각 구성 요소를 다음과 같이 선정했다.
- 오케스트레이션: LangChain — 복잡한 체인 구성과 컴포넌트 교체가 용이하며, 다양한 벡터 저장소 및 LLM 어댑터를 표준화된 인터페이스로 추상화할 수 있다.
- 그래프 저장소: Neo4j Aura — 호스팅형 서비스로 운영 부담을 제거하며, Cypher 쿼리를 통한 복잡한 관계 탐색이 가능하다.
- 벡터 인덱스: FAISS — 메타의 오픈소스 라이브러리로, 근사 최근접 이웑(ANN) 검색을 CPU 환경에서도 고성능으로 수행한다. Milvus 대비 추가 데몬 없이
pip설치로 바로 사용할 수 있다. - 추론 엔진: Qwen-7B — Alibaba Cloud의 7B 파라미터 오픈 모델로, 상용 API 없이 로컬 GPU/CPU에서 자체 호스팅이 가능하다.
핵심 장애물과 대응 전략
장애물 1: 컨테이너 런타임 부재
많은 RAG 튜토리얼이 Docker Compose 기반으로 Milvus, Neo4j 등을 묶어 배포하지만, 엔터프라이즈 환경에서는 컨테이너 권한 문제나 보안 정책으로 인해 Docker 사용이 제한되는 경우가 있다. 이를 해결하기 위해 두 가지 접근을 취했다.
Neo4j Aura 마이그레이션: 온프레미스 Neo4j 대신 클라우드 호스팅 서비스를 활용한다. 연결 정보는 환경 변수로 외부화하며, 애플리케이션 시작 시점에 연결 풀을 검증한다.
# .env
GRAPH_DB_URI=neo4j+s://xxxxxxxx.databases.neo4j.io
GRAPH_DB_USER=neo4j
GRAPH_DB_PASS=<your-password>
GRAPH_DB_NAME=neo4j
FAISS 도입: Milvus의 분산 아키텍처 대신 FAISS의 단일 프로세스 인덱스를 채택했다. faiss-cpu 패키지 설치 후, IndexFlatIP 또는 IndexHNSWFlat 등의 인덱스 타입을 상황에 맞게 선택하여 디스크에 직렬화/역직렬화하는 방식으로 영속성을 확보한다.
장애물 2: 외부 API 불안정성
OpenAI 등 상용 API는 네트워크 지연이나 서비스 중단 시 전체 시스템을 마비시킬 수 있다. 이에 계층적 폴백(fallback) 체계를 구축했다.
| 우선순위 | 모델 | 트리거 조건 |
|---|---|---|
| 1차 | OpenAI GPT-4 | API 키 유효 및 응답 정상 |
| 2차 | Qwen-7B (로컬) | 1차 실패 또는 타임아웃 |
| 3차 | Stub LLM | 모든 LLM 초기화 실패 시 |
Qwen-7B의 로컬 배포를 간소화하기 위해, transformers와 llama-cpp-python 래퍼를 감싼 설정 마법사를 별도로 개발했다. 사용자는 GGUF 포맷의 모델 파일 경로만 지정하면, 양자화 설정과 컨텍스트 윈도우 크기가 자동으로 최적화된다.
장애물 3: 순환 참조 및 의존성 지옥
LangChain 생태계의 방대한 하위 의존성과 프로젝트 내 모듈 간 양방향 참조는 잦은 원인이 되었다. 이를 해결하기 위해:
- 지연 임포트: 모듈 최상단이 아닌 함수 내부에서
import를 수행하여 초기화 시점의 순환 참조를 회피 - 프로토콜 클래스:
typing.Protocol로 인터페이스를 정의하고, 실제 구현체는 실행 시점에 DI 컨테이너로 주입 - 선택적 의존 분리:
requirements-core.txt와requirements-optional.txt로 분리하여, 필수 기능만으로 먼저 실행 가능하도록 구성
시스템 구조와 구현 세부
계층별 역할
전체 시스템은 다섯 개의 논리 계층으로 구성된다.
- 설정 계층:
pydantic-settings기반의 검증된 설정 객체. 환경 변수,.env파일, 기본값의 우선순위를 명확히 한다. - 영속 계층: Neo4j(관계 데이터)와 FAISS(벡터 데이터)를 동시에 운영하며, 분산 트랜잭션은 없지만 각 저장소의 커밋/롤백 로직을 애플리케이션 레벨에서 조율한다.
- 처리 계층:
unstructured와langchain-text-splitters를 활용한 문서 파싱 및 의미 기반 청킹. 토큰 경계와 문장 경계를 동시에 고려한RecursiveSemanticSplitter를 커스텀 구현했다. - 추론 계층:
BaseLLM프로토콜을 구현한Gpt4Provider,Qwen7BProvider,StubProvider를 동일 인터페이스로 통합. - 응용 계층:
GraphRAGEngine클래스가 문서 수집, 인덱싱, 하이브리드 검색, 응답 생성의 전체 라이프사이클을 관리한다.
하이브리드 검색 메커니즘
사용자 질의가 들어오면 다음과 같은 병렬 검색이 수행된다.
class HybridRetriever:
def __init__(self, neo4j_repo, faiss_idx, merger):
self.graph_store = neo4j_repo
self.vector_index = faiss_idx
self.result_merger = merger
def retrieve(self, question: str, top_k: int = 5) -> RetrievedContext:
# 병렬 실행
graph_future = self._async_graph_query(question)
vector_future = self._async_vector_search(question, top_k)
graph_hits = graph_future.result()
vector_hits = vector_future.result()
# 점수 기반 재랭킹 및 중복 제거
fused = self.result_merger.combine(graph_hits, vector_hits)
return fused
그래프 검색은 엔티티 추출 → Cypher 생성 → 관계 탐색의 파이프라인을 따며, 벡터 검색은 질의 임베딩과의 코사인 유사도를 기준으로 수행된다. 두 결과는 RRF(Reciprocal Rank Fusion) 알고리즘으로 통합된다.
지식 그래프 자동 구축
문서 처리 파이프라인의 핵심은 비구조화 텍스트에서 구조화된 지식을 자동 추출하는 것이다.
def build_knowledge_subgraph(self, text_chunk: str) -> SubGraph:
extraction_prompt = self._load_prompt("entity_relation_extraction")
# LLM으로부터 JSON 형식의 엔티티-관계 트리플 추출
raw_output = self.llm.generate(
extraction_prompt.format(input=text_chunk),
response_format={"type": "json_object"}
)
triples = self._validate_and_parse(raw_output)
# Neo4j에 MERGE 수행 (중복 생성 방지)
with self.neo4j.session() as sess:
for subj, rel, obj in triples:
sess.run(
"MERGE (a:Entity {name: $s}) "
"MERGE (b:Entity {name: $o}) "
"MERGE (a)-[r:RELATES {type: $r}]->(b)",
s=subj, r=rel, o=obj
)
return SubGraph(triples=triples)
실전 배포 가이드
1. 환경 구성
git clone <repository> && cd graphrag-system
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# 환경 변수 설정
cp env.template .env
# 에디터로 .env 수정
2. 로컬 LLM 활성화 (선택)
python scripts/bootstrap_qwen.py \
--model-id Qwen/Qwen-7B-Chat-GGUF \
--quantization q4_k_m \
--target-dir ./models/
3. 시스템 기동 및 검증
# 클라우드 모드로 실행 (Neo4j Aura + FAISS 메모리 인덱스)
python -m app.main --profile cloud
# 기능 검증
python examples/verify_end_to_end.py
4. 프로그래밍 인터페이스
from app.engine import KnowledgeEngine
engine = KnowledgeEngine.from_config()
with engine.session() as sess:
# 문서 적재
doc_meta = sess.ingest(
source="annual_report_2024.pdf",
metadata={"department": "finance", "year": 2024}
)
# 질의응답
answer = sess.ask(
"2024년도 R&D 투자 대비 매출 성장률은?",
retrieval_mode="hybrid" # "vector" | "graph" | "hybrid"
)
print(answer.text)
print(answer.citations)
적용 분야 및 기대 효과
본 아키텍처는 다음과 같은 환경에서 특히 효과적이다.
- 금융 규제 분석: 방대한 보고서에서 엔티티(기업, 인물, 상품) 간 관계를 추출하고, 질의 시점에 관련 규정 조항을 정확히 인용
- 제조업 기술 문서 관리: 장비별 매뉴얼, 불량 이력, 부품 호환성 정보를 그래프로 연결하여 현장 기술자의 진단을 지원
- 병원 임상 기록 시스템: 환자-증상-처방-검사 결과의 복합 관계를 시간축 그래프로 모델링
특히 Qwen-7B의 로컬 배포로 민감한 내부 문서가 외부 API로 유출될 위험을 원천 차단할 수 있으며, FAISS + Neo4j Aura 조합으로 초기 인프라 구축 비용을 사실상 제로에 가깝게 줄일 수 있다.
향후 개선 방향
- 추론 가속: vLLM 또는 TensorRT-LLM 도입으로 Qwen-7B의 처리량 향상
- 스키마 진화: Neo4j의 스키마 버저닝과 마이그레이션 도구 구축
- 관리 인터페이스: 지식 그래프 시각화 및 수동 정정 워크플로우 제공
- 멀티모달 확장: 이미지/표 내용을 CLIP 임베딩으로 벡터화하여 텍스트와 통합 검색