# Agentic RAG (에이전틱 RAG) ## 정의 LLM이 검색 도구의 사용을 **자율적으로 결정**하는 RAG 기법. 전통 RAG의 모든 쿼리에 자동 검색하는 방식을 벗어나, 에이전트 패러다임으로 LLM이 "검색이 필요한가?"를 판단한 후 선택적으로 검색을 수행한다. ## 핵심 원리 ### 파이프라인 비교 ``` 전통 RAG: 쿼리 → [항상 검색] → 문서 취득 → LLM 생성 → 답변 Agentic RAG: 쿼리 → LLM 판단 → {검색 필요?} ├─ YES: 검색 → 문서 취득 └─ NO: (스킵) ↓ LLM 생성 → 답변 ``` ### 수식 **의사결정 함수:** $\text{should_search}(q) = \text{LLM}("검색이 필요한가? 쿼리: " + q) \in \{\text{YES}, \text{NO}\}$ **조건부 검색:** $d = \begin{cases} \text{Retrieve}(q) & \text{if } \text{should_search}(q) = \text{YES} \\ \emptyset & \text{otherwise} \end{cases}$ **최종 생성:** $a = \text{LLM}(q, d)$ ### 에이전트 루프 ``` 상태: (질문, 컨텍스트, 단계) ↓ LLM 호출 (현재 상태 분석) ↓ 출력: {Think, Act(search), Answer} ├─ Think: 현재 상황 분석 ├─ Act(search): 검색 도구 호출 │ ↓ │ 도구 실행 │ ↓ │ 결과 추가 │ └─ Answer: 최종 답변 ↓ 종료 또는 다음 루프 ``` ## 사용 사례 ### 1. 간단한 질문 (검색 불필요) ``` 질문: "파이썬의 len() 함수는 뭐예요?" LLM 판단: "기본 내장 함수, 검색 불필요" → 검색 스킵 → LLM이 직접 답변 효과: 응답 시간 단축, 토큰 절감 ``` ### 2. 복잡한 질문 (검색 필수) ``` 질문: "2024년 최신 LLM 벤치마크 결과는?" LLM 판단: "최신 정보 필요, 검색 필수" → 검색 실행 → 검색 결과 통합 → 최신 정보 포함 답변 효과: 최신성 보장, 할루시네이션 방지 ``` ### 3. 다단계 추론 (반복 검색) ``` 질문: "RAG와 Fine-tuning의 성능을 비교하면?" Loop 1: LLM: "RAG 정보 필요" → 검색: "RAG 성능 벤치마크" Loop 2: LLM: "Fine-tuning 정보 필요" → 검색: "Fine-tuning 성능 벤치마크" Loop 3: LLM: "충분한 정보 확보, 비교 가능" → 답변 생성 효과: 복잡한 비교 분석 가능 ``` ## 구현 예시 ### 기본 구조 (LangGraph) ```python from langgraph.graph import StateGraph, END from typing import TypedDict, List class State(TypedDict): question: str context: str history: List[str] def agent_node(state: State) -> State: """LLM 에이전트 판단""" prompt = f""" 현재 정보: {state['context']} 질문: {state['question']} 다음 중 선택하세요: 1. search: 검색이 필요함 2. answer: 답변 가능 """ decision = llm.predict(prompt) return {"history": state["history"] + [decision]} def should_search(state: State) -> str: """검색 필요 여부 판단""" last_decision = state["history"][-1] if "search" in last_decision: return "search" else: return "answer" def retriever_node(state: State) -> State: """검색 실행""" docs = retriever.get_relevant_documents(state["question"]) context = "\n".join([d.page_content for d in docs]) return {"context": context} # 워크플로우 구성 workflow = StateGraph(State) workflow.add_node("agent", agent_node) workflow.add_node("retriever", retriever_node) workflow.add_conditional_edges( "agent", should_search, {"search": "retriever", "answer": END} ) workflow.add_edge("retriever", "agent") workflow.set_entry_point("agent") ``` ## 장점 vs 단점 ### 장점 | 항목 | 설명 | |------|------| | **성능** | 불필요한 검색 제거 → 응답 시간 ↓ | | **비용** | 토큰 사용 감소 → API 비용 ↓ | | **유연성** | 동적 의사결정으로 다양한 시나리오 대응 | | **정확도** | 필요한 경우만 검색 → 할루시네이션 방지 | ### 단점 | 항목 | 설명 | |------|------| | **복잡성** | 에이전트 루프 + 상태 관리 필요 | | **예측 불가** | LLM 판단이 항상 정확하지 않음 | | **오버헤드** | 판단 LLM 호출 추가 비용 | | **디버깅** | 다단계 루프로 인한 디버깅 어려움 | ## 최적화 전략 ### 1. 명시적 지시 ```python system_prompt = """ 검색 도구를 사용해야 할 경우: 1. 최신 정보 필요 (시간 민감) 2. 특정 도메인 전문 지식 3. 통계 데이터나 벤치마크 4. 사실 검증이 중요한 경우 검색 스킵 가능한 경우: 1. 일반적인 개념 설명 2. 논리적 추론만 필요 3. 학습자의 이해도 확인 """ ``` ### 2. 최대 반복 제한 ```python MAX_ITERATIONS = 5 def should_continue(state: State) -> bool: return len(state["history"]) < MAX_ITERATIONS ``` ### 3. 검색 결과 평가 ```python def evaluate_search_results(docs: List) -> float: """검색 결과의 관련성 점수""" if not docs: return 0.0 scores = [d.metadata.get("score", 0) for d in docs] return sum(scores) / len(scores) ``` ## 성능 비교 ``` 시나리오별 성능 (시간, 토큰): 질문 유형 | 전통 RAG | Agentic RAG | 개선 ---------|---------|-----------|----- 간단한 질문 | 2.0s, 500토큰 | 0.5s, 50토큰 | 75% 단축 복잡한 질문 | 2.5s, 700토큰 | 4.0s, 800토큰 | -60% (여러 루프) 평균 | 2.2s, 600토큰 | 1.8s, 300토큰 | 35% 개선 ``` ## 열린 질문 1. **판단 정확성**: LLM이 검색 필요성을 정확히 판단하려면? 2. **루프 제어**: 무한 루프를 방지하면서 필요한 반복은 보장할까? 3. **문맥 축적**: 여러 루프에서 컨텍스트를 효율적으로 관리할 방법은? 4. **사용자 제어**: 사용자가 검색 정책(aggressive vs. conservative)을 제어할 수 있을까? 5. **평가 지표**: Agentic RAG의 성능을 어떻게 정량화할까?