Summary
Text2Cypher의 한계를 극복한 Self-Correcting Agent 구현. 초기 Cypher 쿼리 생성 후 실행 결과를 검증하고, 실패하면 오류 피드백을 LLM에 전달하여 자동으로 쿼리를 재작성하는 Reactive Loop 패턴. LangGraph를 활용한 실전 Agentic GraphRAG 사례.
Key Claims
- Text2Cypher의 한계 극복 — 초기 쿼리 생성은 완벽하지 않음 (문법 오류, 잘못된 관계명 등)
- 결과 기반 자동 수정 — 빈 결과셋이나 오류 메시지를 피드백으로 활용
- 다중 재시도 — 최대 N회까지 자동으로 쿼리 개선
- 사용자 개입 최소화 — “쿼리가 맞는지 확인해줘” 같은 수정 요청 없음
- 신뢰도 향상 — 각 재시도마다 정확도 증가
동작 원리 (Reactive Loop)
사용자 질문
↓
1️⃣ Text2Cypher: 자연어 → Cypher 생성
↓
2️⃣ 쿼리 실행 & 결과 수집
↓
3️⃣ 결과 검증
├─ 성공 (유의미 결과) → 답변 생성 & 종료
└─ 실패 (빈 결과 또는 오류) → 4️⃣로
↓
4️⃣ 오류 원인 분석
├─ "관계명이 존재하지 않음"
├─ "노드 속성명이 틀림"
├─ "WHERE 절 문법 오류"
└─ ... 등
↓
5️⃣ LLM에게 피드백 전달
"다음 쿼리에 오류가 있었습니다: {error message}
가능한 관계명: [WORKS_AT, MANAGES, OWNS, ...]
다시 작성해주세요."
↓
6️⃣ 개선된 Cypher 재생성 → 2️⃣로 (반복)
↓
최대 재시도 횟수 도달
└─ 최종 답변 또는 오류 보고
Key Concepts Introduced
1. Text2Cypher 기초
from langchain.chains import GraphCypherQAChain
from langchain.graphs import Neo4jGraph
graph = Neo4jGraph(
url="bolt://localhost:7687",
username="neo4j",
password="password"
)
qa_chain = GraphCypherQAChain.from_llm(
llm=ChatOpenAI(model="gpt-4"),
graph=graph,
verbose=True
)
result = qa_chain.run("Alice의 매니저는?")2. Self-Correcting Logic
def validate_result(result):
"""결과가 유의미한지 검증"""
if not result or len(result) == 0:
return False, "Empty result"
if "error" in result.lower():
return False, result
return True, None
# Agent 루프에서 사용
> [!caution] 검토 필요
>
> 원본 자료 재방문 권장 (최초 수집: 2025-02-27)
is_valid, error_msg = validate_result(query_result)
if not is_valid:
feedback = f"쿼리 오류: {error_msg}. 다시 시도해주세요."
# LLM에 피드백 전달3. Error Categorization
| 오류 타입 | 원인 | 해결 방법 |
|---|---|---|
| Empty Result | 관계명 오류 / WHERE 조건 불일치 | 사용 가능한 관계명 제시 |
| Syntax Error | Cypher 문법 오류 | 정정된 문법 제시 |
| Type Mismatch | 속성 타입 불일치 (문자열 vs 숫자) | 타입 변환 방법 제시 |
| Missing Property | 노드 속성 존재 안 함 | 실제 속성명 제시 |
4. Retrying Strategy
max_retries = 3
retry_count = 0
while retry_count < max_retries:
cypher = llm.generate_cypher(user_query)
result = execute_query(cypher)
if validate_result(result):
return result # 성공
# 실패 → 피드백과 함께 재시도
feedback = analyze_error(cypher, result)
retry_count += 1
user_query = f"{user_query}\n[피드백: {feedback}]"
# 모든 재시도 실패 → 오류 보고
return f"최대 {max_retries}회 재시도 후에도 실패했습니다: {feedback}"실전 예시: 단계별 실행
사용자 질문
"2025년 이후 입사한 개발 팀원들의 평균 급여는?"
1차 시도 (실패)
생성된 Cypher:
MATCH (p:Person)-[:EMPLOYED_SINCE]->(d:Date)
WHERE d.year >= 2025
RETURN AVG(p.salary) AS avg_salary오류:
Neo4jError: Property 'EMPLOYED_SINCE' not found in relationships
피드백: “EMPLOYED_SINCE 관계가 없습니다. 사용 가능한 관계: [WORKS_AT, MANAGES, REPORTS_TO]“
2차 시도 (실패)
개선된 Cypher:
MATCH (p:Person)-[r:WORKS_AT]->(c:Company)
WHERE c.name = "Development"
AND r.since >= 2025
RETURN AVG(p.salary) AS avg_salary오류:
Empty result set (no rows)
원인 분석:
- 관계는 맞지만 WHERE 조건이 잘못됨
- Company 노드의 속성이 “name”이 아닐 수 있음
- 또는 2025년 이후 입사자가 없음
피드백: “조건을 재검토해주세요. 가능한 Company 속성: [id, name, industry, size]. 또는 더 넓은 연도 범위를 시도해보세요.”
3차 시도 (성공)
최종 Cypher:
MATCH (p:Person)-[r:WORKS_AT]->(c:Company)
WHERE p.department = "Development"
AND r.start_date >= "2025-01-01"
RETURN AVG(p.salary) AS avg_salary, COUNT(p) AS num_employees결과:
avg_salary: 75000000
num_employees: 5
최종 답변:
"2025년 이후 입사한 개발 팀원은 5명이며, 평균 급여는 7,500만 원입니다."
장점과 활용
장점
| 장점 | 설명 |
|---|---|
| 정확도 향상 | 다중 재시도로 쿼리 정확도 증가 |
| 사용 편의성 | 사용자가 쿼리 문법을 몰라도 됨 |
| 신뢰성 | 자동 오류 복구 |
| 학습 효과 | Agent가 도메인 특성 자동 학습 |
활용 분야
- BI/분석 자동화 — 경영진이 자연어로 쿼리
- 고객 지원 — FAQ 자동 응답
- 데이터 검색 — 사용자 친화적 DB 조회
Reactive Loop vs Proactive Loop
| 구분 | Reactive | Proactive |
|---|---|---|
| 시작 | 오류 발생 후 반응 | 미리 예방 |
| 구현 | 간단함 | 복잡함 (선제 검증) |
| 성능 | 느림 (재시도) | 빠름 (첫 시도 성공) |
| 활용처 | 대부분 GraphRAG | 고 신뢰도 필요 시스템 |
관련 개념
- Agentic AI — 에이전트 루프의 이론 기초
- Text2Cypher — 자연어 → Cypher 변환
- LangGraph — 상태 기반 워크플로우
- Neo4j — 그래프 DB
- GraphRAG — 그래프 기반 RAG
관련 소스: data-to-kg (전체 파이프라인), automated-code-generation-agent (자동 수정 패턴), text2cypher-retriever (기초 Text2Cypher)
인정: YouTube 공원나연 채널 (2025-02-27)