05. 고급: LangGraph를 활용한 Self-RAG
기존 RAG의 문제점
표준 RAG는 직선 파이프라인입니다: 검색 → 생성. 하지만 다음과 같은 상황에서는 어떻게 될까요?
- 검색된 문서가 질문과 관련이 없는 경우?
- 생성된 답변이 문서를 넘어서 환각하는 경우?
- 답변이 기술적으로는 맞지만 유용하지 않은 경우?
기존 RAG는 눈이 멀었습니다—이러한 실패를 감지하거나 수정할 수 없습니다.
Self-RAG란?
**Self-RAG (자기 성찰적 RAG)**는 시스템이 다음을 수행할 수 있는 피드백 루프를 추가합니다:
- 문서 평가: 검색된 내용이 실제로 관련이 있는가?
- 생성 평가: 답변이 문서에 근거하는가?
- 수정: 문제가 있으면 재검색하거나 재생성
핵심 인사이트: Self-RAG는 RAG를 파이프라인에서 자체 실패를 감지하고 수정할 수 있는 제어 루프로 변환합니다.
LangGraph 아키텍처
Self-RAG는 조건부 엣지가 있는 상태 머신으로 자연스럽게 표현됩니다:
구현
Step 1: 상태 정의
평가와 루프에 필요한 모든 정보 추적:
from typing import TypedDict, List
class GraphState(TypedDict):
question: str
documents: List[str]
generation: str
relevance: str # "yes" 또는 "no"
hallucination: str # "yes" 또는 "no"
useful: str # "yes" 또는 "no"Step 2: 노드 구축
def retrieve(state: GraphState):
"""벡터 스토어에서 문서 검색"""
print("---검색---")
question = state["question"]
# 프로덕션: 실제 벡터 스토어 사용
docs = vector_store.similarity_search(question, k=3)
return {"documents": [doc.page_content for doc in docs]}Step 3: 조건부 엣지
흐름을 제어하는 결정 로직:
def decide_to_generate(state: GraphState) -> str:
"""문서 관련성에 따라 라우팅"""
if state["relevance"] == "yes":
print("---문서 관련 있음: 생성---")
return "generate"
else:
print("---문서 관련 없음: 웹 검색---")
return "web_search"
def decide_to_finish(state: GraphState) -> str:
"""환각 확인에 따라 라우팅"""
if state["hallucination"] == "no":
print("---답변 근거 있음: 완료---")
return "finish"
else:
print("---환각: 재생성---")
return "regenerate"Step 4: 그래프 구축
from langgraph.graph import StateGraph, END
workflow = StateGraph(GraphState)
# 노드 추가
workflow.add_node("retrieve", retrieve)
workflow.add_node("grade_documents", grade_documents)
workflow.add_node("generate", generate)
workflow.add_node("grade_generation", grade_generation)
workflow.add_node("web_search", web_search)
# 진입점 설정
workflow.set_entry_point("retrieve")
# 엣지 추가
workflow.add_edge("retrieve", "grade_documents")
workflow.add_edge("web_search", "grade_documents")
workflow.add_edge("generate", "grade_generation")
# 조건부 엣지
workflow.add_conditional_edges(
"grade_documents",
decide_to_generate,
{
"generate": "generate",
"web_search": "web_search"
}
)
workflow.add_conditional_edges(
"grade_generation",
decide_to_finish,
{
"finish": END,
"regenerate": "generate"
}
)
# 컴파일
app = workflow.compile()Step 5: 에이전트 실행
inputs = {"question": "AI 에이전트란 무엇인가요?"}
for output in app.stream(inputs):
for key, value in output.items():
print(f"완료: {key}")
# 출력:
# ---검색---
# 완료: retrieve
# ---문서 평가---
# ---문서 관련 있음: 생성---
# 완료: grade_documents
# ---생성---
# 완료: generate
# ---생성 평가---
# ---답변 근거 있음: 완료---
# 완료: grade_generationSelf-RAG 평가 기준
| 확인 항목 | 질문 | 실패 시 |
|---|---|---|
| 관련성 | 문서가 주제에 관한 것인가? | 재검색 또는 웹 검색 |
| 근거 | 답변이 문서에 의해 뒷받침되는가? | 재생성 |
| 유용성 | 답변이 질문을 다루는가? | 다른 프롬프트로 재생성 |
비교: 기존 RAG vs Self-RAG
| 측면 | 기존 RAG | Self-RAG |
|---|---|---|
| 아키텍처 | 파이프라인 | 제어 루프 |
| 오류 처리 | 없음 | 자동 수정 |
| 환각 | 감지 안 됨 | 감지 및 수정 |
| 지연 시간 | 낮음 (단일 패스) | 높음 (여러 패스) |
| 신뢰성 | 변동적 | 더 일관적 |
| 비용 | 낮음 | 높음 (더 많은 LLM 호출) |
고급: CRAG (Corrective RAG)
CRAG는 더 정교한 수정 전략으로 Self-RAG를 확장합니다:
실습 내용
노트북에서 다음을 수행합니다:
상태 스키마 정의
모든 평가 정보를 추적하기 위한 TypedDict 생성
평가 노드 구축
구조화된 출력으로 문서 및 생성 평가기 구현
조건부 로직 추가
라우팅을 위한 결정 함수 생성
그래프 시각화
LangGraph의 내장 시각화 사용
엣지 케이스 테스트
다른 경로를 트리거하는 쿼리 시도
핵심 요점
- 피드백 루프가 자기 수정 가능하게 - 기존 RAG는 조용히 실패; Self-RAG는 감지하고 수정
- 평가를 위한 구조화된 출력 - 신뢰할 수 있는 yes/no 결정을 위해 Pydantic 모델 사용
- LangGraph가 간단하게 - 조건부 엣지가 라우팅 로직을 자연스럽게 표현
- 트레이드오프: 지연 시간 vs 신뢰성 - 더 많은 검사는 더 많은 LLM 호출을 의미하지만 오류는 적어짐
참고 자료 & 추가 학습
학술 논문
-
"Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection" - Asai et al., 2023
- arXiv:2310.11511 (opens in a new tab)
- 자기 성찰적 검색의 기초
-
"Corrective Retrieval Augmented Generation" - Yan et al., 2024
-
"Active Retrieval Augmented Generation" - Jiang et al., 2023
- arXiv:2305.06983 (opens in a new tab)
- 무엇을 검색할지뿐 아니라 언제 검색할지
-
"FLARE: Active Retrieval Augmented Generation" - Jiang et al., 2023
- arXiv:2305.06983 (opens in a new tab)
- 전방 참조 능동적 검색
관련 튜토리얼
- LangGraph Adaptive RAG: 튜토리얼 (opens in a new tab)
- LangGraph CRAG: 튜토리얼 (opens in a new tab)
다음 단계
Week 2를 완료한 것을 축하합니다! 주말 프로젝트로 이동하여 이러한 리플렉션 패턴을 코드 생성에 적용하는 자가 수정 코더를 구축하세요.