Text2Cypher
정의
LLM이 사용자의 자연어 질문을 Neo4j Cypher 쿼리로 자동 변환하는 기술. 사용자가 Cypher 문법을 모르더라도 자연어로 질문하면 정확한 데이터베이스 쿼리를 생성한다.
작동 원리
사용자: "톰 행크스가 출연한 영화는?"
↓
[LLM + DB 스키마 + 예시]
↓
자동 생성 Cypher:
MATCH (a:Actor)-[:ACTED_IN]->(m:Movie)
WHERE a.name = "Tom Hanks"
RETURN m.title
↓
Neo4j 실행
↓
정확한 결과 반환
핵심 기술 요소
1. DB 스키마 제공
LLM에 제공되는 구조화 정보:
- 노드 타입: Movie, Actor, User, Genre, …
- 프로퍼티: title (String), duration (Int), rating (Float), …
- 관계: ACTED_IN, BELONGS_TO, RATED, …
- 방향성: → (단방향), ← (역방향)
2. Few-shot Examples (예시 기반 학습)
예시 1:
질문: "Toy Story에 출연한 배우들은?"
Cypher:
MATCH (m:Movie)-[:ACTED_IN]-(a:Actor)
WHERE m.title = "Toy Story"
RETURN a.name
예시 2:
질문: "코미디 영화 5개 추천"
Cypher:
MATCH (m:Movie)-[:BELONGS_TO]->(g:Genre)
WHERE g.name = "Comedy"
RETURN m.title LIMIT 5
3. 프롬프트 엔지니어링
시스템: "Neo4j Cypher 쿼리 생성 전담"
입력: [스키마] + [예시] + [사용자 질문]
제약:
- 스키마에 없는 속성 사용 금지
- 결과는 순수 Cypher만 반환
- 설명은 제공하지 말 것
출력: Cypher 쿼리
Vector Retriever와의 비교
Vector Retriever
- 임베딩 벡터 기반 유사도 검색
- 문제: “로맨스” 단어가 줄거리에 없으면 못 찾음
- 예: 줄거리에서 유사한 문장을 검색 → 텍스트 블럭 반환
Text2Cypher
- 쿼리 기반 구조화 검색
- 장점: 의도(intent)를 정확히 파악 → 정확한 속성 필터링
- 예: “로맨스 영화” →
WHERE genre.name = "Romance"생성
| 항목 | Vector | Text2Cypher |
|---|---|---|
| 의존성 | 텍스트 유사도 | 쿼리 구조 |
| 환각 위험 | 높음 | 없음 |
| 정확도 | 중간 | 높음 |
| 복잡 쿼리 | 약함 | 강함 |
구현 단계
1단계: DB 스키마 추출
# 자동 추출 함수
schema = extract_db_schema(driver)
# 결과:
# Node Types:
# - Movie: title (String), plot (String), ...
# - Actor: name (String), ...
# Relationships:
# - (Movie)-[ACTED_IN]->(Actor)
# - (Movie)-[BELONGS_TO]->(Genre)2단계: 예시 쿼리 정의
examples = [
{
"question": "Toy Story에 출연한 배우는?",
"cypher": "MATCH (m:Movie)-[:ACTED_IN]-(a) WHERE m.title = 'Toy Story' RETURN a.name"
},
{
"question": "2024년 개봉한 영화 5개",
"cypher": "MATCH (m:Movie) WHERE m.year = 2024 RETURN m.title LIMIT 5"
}
]3단계: Text2Cypher Retriever 초기화
from neo4j_genai.retrievers import Text2CypherRetriever
retriever = Text2CypherRetriever(
driver=neo4j_driver,
llm=ChatOpenAI(model="gpt-4"),
neo4j_schema=schema_text,
examples=examples
)4단계: 쿼리 실행
results = retriever.search("로맨스 영화 Top 5")
# 내부 과정:
# 1. LLM이 Cypher 쿼리 생성
# 2. Neo4j에서 쿼리 실행
# 3. 결과 반환실제 예제
복잡한 다중 조건 쿼리
사용자: “2023년 이후 코미디 영화 중에서 평점이 4.0 이상인 영화의 제목과 평점을 출연 배우 수가 많은 순서대로 보여줘”
자동 생성 Cypher:
MATCH (m:Movie)-[:BELONGS_TO]->(g:Genre),
(m)-[:ACTED_IN]-(a:Actor)
WHERE g.name = "Comedy"
AND m.year >= 2023
AND m.rating >= 4.0
RETURN m.title, m.rating, COUNT(a) AS actor_count
ORDER BY actor_count DESC→ 단순 텍스트 유사도 검색으로는 불가능한 복잡한 쿼리 자동 생성
Graph RAG에서의 활용
RAG 파이프라인
사용자 질문
↓
[Text2Cypher] → Cypher 쿼리 생성
↓
[Neo4j 실행] → 구조화 데이터
↓
[프롬프트] = "질문 + 검색 결과"
↓
[LLM] → 최종 답변 생성
환각 방지
- 검색 결과가 DB에 실제 존재하는 데이터만
- LLM은 DB 데이터만으로 답변 생성
- 거짓 정보 생성 불가능
온톨로지 설계와의 연관
온톨로지 기반 지식그래프의 실제 질의 시스템:
- 온톨로지 정의 → DB 스키마
- 인스턴스 저장 → 지식그래프
- Text2Cypher → 자연어 쿼리 자동 변환
- 구조화 검색 → 높은 정확도
- RAG 생성 → 신뢰성 높은 답변
한계와 개선점
현재 한계
❌ 매우 복잡한 쿼리는 완벽하지 않을 수 있음
❌ 도메인 특화 용어 이해 부족 가능
❌ 다중 의도 질문(ambiguous) 처리 어려움
개선 방향
✅ 더 많은 예시 제공 (Few-shot → Many-shot)
✅ Fine-tuning으로 특정 도메인 최적화
✅ Human-in-the-loop: 생성된 쿼리 검증 단계 추가
관련 개념: Cypher Query Language, Graph RAG, RAG, Neo4j