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" 생성
항목VectorText2Cypher
의존성텍스트 유사도쿼리 구조
환각 위험높음없음
정확도중간높음
복잡 쿼리약함강함

구현 단계

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 데이터만으로 답변 생성
  • 거짓 정보 생성 불가능

온톨로지 설계와의 연관

온톨로지 기반 지식그래프의 실제 질의 시스템:

  1. 온톨로지 정의 → DB 스키마
  2. 인스턴스 저장 → 지식그래프
  3. Text2Cypher → 자연어 쿼리 자동 변환
  4. 구조화 검색 → 높은 정확도
  5. RAG 생성 → 신뢰성 높은 답변

한계와 개선점

현재 한계

❌ 매우 복잡한 쿼리는 완벽하지 않을 수 있음
❌ 도메인 특화 용어 이해 부족 가능
❌ 다중 의도 질문(ambiguous) 처리 어려움

개선 방향

✅ 더 많은 예시 제공 (Few-shot → Many-shot)
✅ Fine-tuning으로 특정 도메인 최적화
✅ Human-in-the-loop: 생성된 쿼리 검증 단계 추가


관련 개념: Cypher Query Language, Graph RAG, RAG, Neo4j

참고: text2cypher-retriever