GPT한테 여러번 물어보면서 작성하였습니다
https://arxiv.org/abs/2507.04127
BYOKG-RAG: Multi-Strategy Graph Retrieval for Knowledge Graph Question Answering
Knowledge graph question answering (KGQA) presents significant challenges due to the structural and semantic variations across input graphs. Existing works rely on Large Language Model (LLM) agents for graph traversal and retrieval; an approach that is sen
arxiv.org

🧭 Chapter 1: 기술 배경 – 기존 GraphRAG 방식의 한계와 BYOKG-RAG의 등장
🔍 GraphRAG는 충분하지 않다
GraphRAG는 RAG(Retrieval-Augmented Generation)의 그래프 버전으로,
질문에 대응되는 서브그래프를 추출하여 LLM에게 전달하는 구조입니다.
하지만 이 방식에는 구조적인 한계가 존재합니다:
- ✅ 정적인 리트리버는 새로운 질문 유형에 적응하기 어렵다
- ✅ **단일 방식의 탐색(Triplet 기반)**은 복잡한 다중 관계나 추론을 놓친다
- ✅ LLM이 에이전트처럼 그래프를 따라가는 방식은 엔티티 링크 오류나 실패한 탐색 루트로 이어지기 쉽다
- ✅ 커스텀 KG에서의 적용이 어렵고, Zero-shot 대응이 제한적
💡 BYOKG-RAG의 설계 철학
Amazon의 BYOKG-RAG(BYO = Bring Your Own)는 다음 철학을 바탕으로 설계되었습니다:
“LLM이 직접 추론을 모두 하도록 두지 말고,
다양한 전략을 가진 리트리버들이 그래프 정보를 정제해서
LLM이 최종 판단만 하게 하자.”
즉, 구조적으로 정리된 정보가 먼저 수집되고,
그 위에 LLM이 효율적으로 reasoning을 수행하는 구조입니다.
🧠 Chapter 2: 전체 파이프라인 동작 개요
BYOKG-RAG의 전체 흐름은 다음과 같습니다:
User Question
↓
[1] LLM 기반 아티팩트 생성 (KGLinker)
↓
[2] Entity Linking (Fuzzy/Embedding 매칭)
↓
[3] Multi-Strategy Retrieval
- Triplet 기반
- Path 기반
- Cypher Query 기반
↓
[4] Iterative Refinement (링킹 및 경로 재조정)
↓
[5] Final Answer Synthesis (LLM으로 응답 생성)
① KGLinker: 질문 → 그래프 아티팩트 생성
- LLM이 아래 4가지 요소를 생성:
- 질문 속 엔티티 추출
- 관계 경로 예측 (메타패스)
- 실행 가능한 Cypher 쿼리
- 답안 후보 추론
LLM이 단순한 “생성자”가 아니라,
탐색을 위한 설계자/초안 도출자로서의 역할을 맡게 됩니다.
② Entity Linking: 그래프와 연결
- Fuzzy string matching, embedding similarity를 통해
LLM의 텍스트 기반 개체를 그래프 노드에 매핑합니다.
이 단계가 실패하면 추론은 오작동하기 때문에,
BYOKG-RAG는 후속 단계에서 이 매핑을 반복적으로 재검토합니다.
③ Multi-strategy Retrieval: 3가지 리트리버 병렬 작동
| 전략 | 설명 |
| Triplet Retriever | 1~2 hop 범위 내 (head, relation, tail) 탐색 |
| Path Retriever | LLM이 제시한 메타패스를 따라 다중 홉 추론 |
| Query Executor | LLM이 생성한 Cypher 스타일 쿼리를 직접 실행 |
이 전략들은 개별적으로도 작동하지만,
같은 질문에 대해 병렬·보완적으로 작동함으로써 정답에 가까운 컨텍스트를 수집합니다.
④ Iterative Refinement: 실패했을 때 다시 시작하기
- 링크가 불확실하거나, 탐색 경로가 틀렸을 경우
- 이전 응답을 기반으로 LLM이 다시 아티팩트를 생성하도록 유도
- 자기 교정(self-repairing) 구조 내장
⑤ 응답 생성: ResponseSynthesizer
- Triplet + Path + Cypher에서 수집한 컨텍스트를
요약 정리 후 LLM에 넣어 최종 정답을 생성합니다.
토큰 수 제한 등을 고려해 컨텍스트 스코어링 및 필터링 전략도 적용됩니다.
.
📊 Chapter 3: 실험 결과 및 벤치마크
🎯 주요 성능 개선
- GraphRAG 대비 평균 +4.5% 정확도 향상
- 다양한 그래프(KGs)에서 테스트:
- Freebase, CronQuestions, Med-KG 등

⚖️ 비교 포인트
| 기준 | GraphRAG | BYOKG-RAG |
| 전략 | 단일 (서브그래프 추출) | 다중 전략 (Triplet + Path + Query) |
| 그래프 적응성 | 낮음 | 높음 (BYO KG) |
| Zero-shot 대응 | 제한적 | 우수 |
| 실패 복구 능력 | 없음 | 반복 개선 가능 |
💻 Chapter 4: 실제 구현 키포인트
🧾 프롬프트 설계
- LLM이 추론 artifacts를 잘 생성하도록 지시어 구성 필요
- 예:
Q: "Where was X born and what genre is linked to that place?"
→ Entities, Relations, Query, Draft Answer
🔗 엔티티 매칭 기법
- Fuzzy string match (difflib)
- Embedding 기반 semantic match
- Top-K 후보를 모두 유지하여 불확실성 대응
🔁 반복 추론 구조
- 매 iteration마다:
- 링크 실패 or 정답 불일치 여부 확인
- LLM 재호출로 artifacts 수정
- graph schema + 이전 컨텍스트를 프롬프트에 포함시켜 재추론 강화
📏 토큰 길이 & 컨텍스트 제어
- Retrieval 결과가 많을 경우:
- TF-IDF / semantic score로 우선순위 정렬
- 최종 LLM 입력은 2048~4096 토큰 이하로 유지
- Optional: chunking + voting
🌟 Chapter 5: 응용 가능 사례
✅ 1. 도메인 사용자 정의 그래프 QA
- 의료, 법률, 정부, 특허 등
- 구조화된 도메인 지식 그래프에 대해 고정 쿼리 없이 유연한 질문 대응
✅ 2. 벡터 + 그래프 통합 Q&A 시스템
- 벡터 DB로 개별 문서 정보 검색
- 트리플 기반 KG로 관계 추론
→ 두 소스를 합쳐 “정보 + 맥락 + 논리” 기반 QA 가능
✅ 3. LangChain, Streamlit 등과의 통합
- Retrieval 모듈을 LangChain의 GraphRetriever로 래핑
- Streamlit 기반 Q&A UI 데모
- AWS Bedrock/Claude 또는 OpenAI 연결도 가능
✅ 마무리 요약: 왜 이 구조가 중요한가?
기존 KG QA 시스템이 겪는
“링크 오류”, “탐색 실패”, “비적응성” 문제를
BYOKG-RAG는 다중 전략 + 반복 보정으로 해결한다.
🚀 목표: BYOKG-RAG에서 핵심 부분 SCRATCH 코드
✅ 1. KGLinker: 그래프 탐색을 위한 아티팩트 생성
- LLM이 직접 그래프를 따라가는 대신, 질의에 대해
👉 엔티티, 관계 경로, Cypher 쿼리, 답안 후보를 한 번에 생성 - 이걸 통해 탐색을 위한 목적 정보를 추출하고,
이후 다양한 리트리버가 이 정보를 실행에 옮긴다.
✅ 2. Multi-strategy Graph Retrieval
- 세 가지 리트리버가 병렬 또는 보완적으로 작동:
- EntityLinker: 실제 그래프와 매핑
- TripletRetriever: 근접 노드 기반 추론
- PathRetriever: 메타패스 기반 멀티홉 reasoning
- QueryExecutor: Cypher 실행
즉, 단일 agent에 의존하는 대신 **"의미 기반 artifact → 전략적 탐색 → 보강된 정답 생성"**이라는 구조화된 추론 방식이 핵심입니다.
import difflib
import openai
import os
from typing import Dict, List
# Set your OpenAI API key
openai.api_key = os.getenv("OPENAI_API_KEY")
# ----------------------------
# KGLinker: Use GPT to extract graph artifacts
# ----------------------------
def call_kg_linker(question: str, schema_hint: str = "") -> Dict[str, List[str]]:
prompt = f"""
You are a graph reasoning assistant. Given a user question and a knowledge graph schema, extract:
1. Entities mentioned in the question.
2. A plausible relationship path (metapath) connecting the entities (e.g., Person -> born_in -> Place -> associated_with -> Genre).
3. A Cypher-style query that could be executed on a property graph.
4. A guess for the final answer (if possible).
Question: "{question}"
Schema: "{schema_hint}"
Respond in JSON format with keys: "entities", "paths", "cypher", "guess".
""".strip()
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
temperature=0.2
)
content = response['choices'][0]['message']['content']
return eval(content) # Only for controlled testing environments
# ----------------------------
# EntityLinker: Fuzzy match to actual graph nodes
# ----------------------------
def fuzzy_entity_link(entities: List[str], graph_nodes: List[str]) -> Dict[str, str]:
linked = {}
for entity in entities:
match = difflib.get_close_matches(entity, graph_nodes, n=1, cutoff=0.6)
linked[entity] = match[0] if match else None
return linked
# ----------------------------
# TripletRetriever: Get 1-hop triplets from node
# ----------------------------
def get_one_hop_triplets(graph: nx.MultiDiGraph, node: str) -> List[Tuple[str, str, str]]:
triplets = []
if node in graph:
for neighbor, edges in graph[node].items():
for key in edges:
relation = edges[key]["relation"]
triplets.append((node, relation, neighbor))
return triplets
# Run full pipeline
question = "What genre of film is associated with the place where Wynton Marsalis was born?"
schema_hint = "Person -> born_in -> Place -> associated_with -> Genre"
kg_artifacts = call_kg_linker(question, schema_hint)
linked_entities = fuzzy_entity_link(kg_artifacts["entities"], list(G.nodes))
triplet_context = []
for ent in linked_entities.values():
if ent:
triplet_context.extend(get_one_hop_triplets(G, ent))
kg_artifacts, linked_entities, triplet_context[:5] # Limit preview
✅ 3. Iterative Refinement (자기보정 구조)
- 처음 추론이 부족하거나 틀릴 경우
→ LLM이 다시 엔티티, 경로, 쿼리를 생성하면서 정답 가능성을 높임
import random
from typing import Tuple, List
# Simulate LLM generation artifacts (stub for retry)
def mock_llm_generate_artifacts(question: str, attempt: int = 1) -> Tuple[List[str], List[str], str, str]:
"""Fake KGLinker artifacts for demonstration."""
if attempt == 1:
return (
["Wynton Marsalis"], # entities
["Person -> born_in -> Place"], # paths
"MATCH (p:Person)-[:born_in]->(c:City) RETURN c", # cypher
"New Orleans" # guess
)
elif attempt == 2:
return (
["Wynton Marsalis", "New Orleans"],
["Person -> born_in -> Place -> associated_with -> Genre"],
"MATCH (p:Person)-[:born_in]->(c:City)-[:associated_with]->(g:Genre) RETURN g",
"Backstage Musical"
)
else:
return (
["Wynton Marsalis", "New Orleans"],
["Person -> born_in -> Place -> associated_with -> Genre"],
"MATCH (p)-[:born_in]->(c)-[:associated_with]->(g) RETURN g",
"Backstage Musical"
)
# Simple iterative refinement controller
def iterative_refinement(question: str, expected_answer: str, max_attempts: int = 3) -> Tuple[int, str]:
for attempt in range(1, max_attempts + 1):
entities, paths, cypher, guess = mock_llm_generate_artifacts(question, attempt)
print(f"Attempt {attempt} → guess: {guess}")
if expected_answer.lower() in guess.lower():
return attempt, guess
return max_attempts, "No correct guess"
# Test the refinement
question = "What genre of film is associated with the place where Wynton Marsalis was born?"
expected_answer = "Backstage Musical"
attempt_used, final_guess = iterative_refinement(question, expected_answer)
(attempt_used, final_guess)
BYOKG-RAG 논문의 본질적 요약
“LLM이 직접 그래프를 추론하지 말고,
다양한 전략으로 정보를 수집해 LLM이 더 잘 추론할 수 있게 도와주자.”
기존 KG QA 시스템은 **단일 전략(주로 서브그래프 추출)**에 의존하며,
LLM이 직접 그래프를 탐색하거나, 고정된 retriever로만 정답을 찾는 구조였습니다.
하지만 현실은 그렇지 않죠 — 그래프는 복잡하고, 질문은 모호하며, 노이즈는 많습니다.
BYOKG-RAG는 이 문제를 해결하기 위해 4가지 핵심 전략을 조합합니다:
📌 핵심 구조 요약
- KGLinker: LLM이 질문을 분석해
- entities, paths, cypher, draft_answer 등 의미 있는 아티팩트를 생성
- Multi-strategy Retrieval
- Triplet, Path, Cypher 3가지 방식으로 그래프를 탐색
- 각 전략은 서로 보완적
- Entity Linking
- LLM이 생성한 개체 → 실제 그래프 노드에 매핑 (fuzzy or embedding 기반)
- Iterative Refinement
- 결과가 부정확하면 다시 처음부터 반복
- LLM이 스스로 탐색을 수정하는 자기보정 구조
✅ 장점 (Strengths)
| 항목 | 설명 |
| 🔁 유연성 | 다양한 형태의 질문, 그래프 구조에 적응 가능 (Bring Your Own KG) |
| 🧠 정밀도 | 단일 리트리버보다 더 많은 컨텍스트 확보 가능 |
| 🚫 튜닝 불필요 | Zero-shot/few-shot 설정에서도 높은 정확도 |
| 🔄 반복 가능 | 초기 실패 시 재시도(Iterative Refinement)로 개선 |
| 🧩 조합 전략 | 엔티티, 경로, 쿼리 추론을 분리해 처리하므로 안정성 향상 |
⚠️ 단점 또는 한계 (Weaknesses)
| 항목 | 설명 |
| 💰 비용 | 여러 번 LLM 호출 + 다양한 리트리버 실행 → 비용 상승 가능 |
| 🐌 속도 | 전략별 탐색 + 반복 구조 → 실시간 응답에는 다소 느릴 수 있음 |
| 🧱 설계 복잡성 | 구조가 단순한 GraphRAG보다 시스템 설계와 디버깅이 어려움 |
| 🎯 의존성 | LLM의 추론 능력(예: 엔티티 추출 정확도)에 여전히 의존 |
🎯 결국 이걸 적용하면 어떤 효과?
“지식 그래프 기반 QA 시스템이, 처음 보는 질문에도 더 정확하게 응답할 수 있다.”
| 효과 | 설명 |
| ✅ 정확도 향상 | 여러 전략을 조합하여 정답 후보의 신뢰도 높임 |
| ✅ 도메인 일반화 | 그래프 구조가 달라도 작동 (Freebase, 의료 그래프 등 모두 가능) |
| ✅ 훈련 데이터 없음 | Supervised retriever 훈련 없이도 좋은 성능 가능 |
| ✅ RAG 확장성 확보 | 텍스트 + 그래프 RAG 융합에도 활용 가능 |
🧠 정리된 한 문장 요약
BYOKG-RAG은 LLM이 ‘무작정 생성’하는 구조를 벗어나,
그래프 기반 추론을 전략적으로 조직화하고 조정함으로써
정확하고 확장 가능한 질문응답을 가능하게 한다.
🙋♂️ 추천 활용 시나리오
- 기업 내 사내 지식그래프 기반 QA 봇
- 의료/법률/특허 등 도메인 특화 KGQA 시스템
- 벡터 + 그래프 기반 하이브리드 RAG 구축
🔧 실무 적용을 고민 중이라면?
- 그래프 구조가 명확하고 관계성이 중요한 데이터셋을 갖고 있다면 적극 도입 고려
- 실시간 서비스보단 “정확한 응답”이 중요한 상황에 적합
- LLM 호출비용과 latency는 최적화 전략 필요 (캐시, 압축, 모델 소형화 등)
'관심있는 주제 > Agentic AI' 카테고리의 다른 글
| 리뷰-Risk Management for the Agentic AI Lifecycle (4) | 2025.06.03 |
|---|