들어가며: 왜 Agentic RAG인가?
안녕하세요. 저는 HolySheep AI의 기술 아키텍처 담당자입니다. AI 애플리케이션을 개발하면서 가장 많이 받은 질문이 바로 "일반 RAG와 Agentic RAG의 차이점이 뭔가요?"입니다.
2026년 현재, 단순히 문서를 검색해서 답변하는 방식으로는 복잡한 업무 시나리오를 처리하기 어렵습니다. 저는 Agentic RAG를 도입하면서 검색 정확도를 40% 이상 향상시키고, 불필요한 API 호출을 60% 줄일 수 있었습니다.
본 가이드에서는 완전 초보자도 이해할 수 있도록 Agentic RAG의 개념부터 실제 구현까지 단계별로 설명드리겠습니다.
기본 개념: RAG와 에이전트의 만남
1단계: 전통적인 RAG 이해하기
RAG(Retrieval-Augmented Generation)는 먼저 사용자의 질문을 받고, 그 질문과 관련된 문서를 데이터베이스에서 찾아낸 후, AI 모델에게 관련 문서와 질문을 함께 전달하는 방식입니다.
【스크린샷 힌트】흐름도: 질문 → 벡터 검색 → 관련 문서 추출 → AI 모델 응답
문제는 이 방식이 "질문이 무엇을 묻는지"만 판단해서 검색한다는 점입니다. 예를 들어 "2024년 매출 보고서 요약해줘"라는 질문이 있으면, 단순히 "매출" 관련 문서를 찾습니다.
2단계: 에이전트(Agent)란?
에이전트는 스스로 판단하고 행동하는 AI 시스템입니다. 마치 똑똑한 비서가:
- 질문의 의도를 파악하고
- 어떤 도구를 사용할지 결정하며
- 필요하면 여러 단계를 거치며
- 최종 답변을 구성합니다
【스크린샷 힌트】흐름도: 질문 → 의도 분석 → 도구 선택 → 순차 실행 → 결과 통합
3단계: Agentic RAG의 핵심 차이
Agentic RAG는 에이전트의 판단력을 RAG에 결합합니다. 단일 질문이 아니라 복잡한 질문에 대해 여러 검색 전략을 시도하고, 각 결과를 조합하여 가장 정확한 답변을 생성합니다.
동작 원리: Agentic RAG의 판단 흐름
실제 예시를 통해 이해해보겠습니다.
사용자 질문: "우리 회사의 2024년 4분기 마케팅 성과와 2025년 개선 방향"
전통적 RAG:
- "2024년 마케팅" 관련 문서 검색
- 검색된 문서 전체를 컨텍스트로 활용
- 답변 생성
Agentic RAG:
- 에이전트가 질문을 분석하여 의도 분류 수행
- "성과 데이터 조회"와 "개선 방향 분석"으로 분리
- 성과 데이터용: KPI 문서, 매출 보고서 검색
- 개선 방향용: 마케팅 전략 문서, 회의록 검색
- 각 결과를 종합하여 구조화된 답변 생성
실습 환경 준비
필수 도구 설치
본 가이드에서는 지금 가입하여 HolySheep AI API 키를 먼저 발급받으세요. HolySheep AI는:
- 로컬 결제 지원(해외 신용카드 불필요)
- GPT-4.1, Claude Sonnet, Gemini 2.5 Flash, DeepSeek V3.2 단일 API 키로 통합
- 개발자 친화적 인터페이스 제공
API 키 발급 후, 필요한 Python 패키지를 설치합니다:
pip install openai lancedb tantivy python-dotenv requests
【스크린샷 힌트】터미널 화면: 패키지 설치 완료 확인 메시지
환경 변수 설정
import os
from dotenv import load_dotenv
load_dotenv()
HolySheep AI API 설정
HOLYSHEEP_API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")
HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"
print("✅ HolySheep AI 환경 설정 완료")
print(f"API 키 상태: {'설정됨' if HOLYSHEEP_API_KEY != 'YOUR_HOLYSHEEP_API_KEY' else '미설정 - .env 파일 확인 필요'}")
실습: Agentic RAG 시스템 구축
프로젝트 구조
agentic_rag_project/
├── config/
│ └── settings.py
├── tools/
│ └── search_tools.py
├── agents/
│ └── routing_agent.py
├── rag/
│ └── vector_store.py
├── main.py
└── .env
1단계: 벡터 저장소 설정
먼저 문서를 저장하고 검색할 벡터 저장소를 설정합니다. 본 예제에서는 LanceDB를 사용하겠습니다:
import lancedb
from openai import OpenAI
import numpy as np
class VectorStore:
"""LanceDB 기반 벡터 저장소 - 문서 임베딩 및 검색 담당"""
def __init__(self, api_key: str, base_url: str):
self.client = OpenAI(api_key=api_key, base_url=base_url)
self.db = lancedb.connect("./data/lancedb")
self.table = None
def generate_embedding(self, text: str) -> list[float]:
"""HolySheep AI를 통해 텍스트를 벡터로 변환"""
response = self.client.embeddings.create(
model="text-embedding-3-small",
input=text
)
return response.data[0].embedding
def create_table(self, table_name: str):
"""검색 테이블 생성"""
schema = {
"vector": lancedb.vector(1536),
"text": "string",
"metadata": "json"
}
self.table = self.db.create_table(table_name, schema=schema)
print(f"✅ 테이블 '{table_name}' 생성 완료")
return self.table
def add_documents(self, documents: list[dict]):
"""문서를 벡터화하여 저장"""
if self.table is None:
raise ValueError("테이블이 먼저 생성되어야 합니다.")
for doc in documents:
embedding = self.generate_embedding(doc["content"])
self.table.add([
{
"vector": embedding,
"text": doc["content"],
"metadata": doc.get("metadata", {})
}
])
print(f"✅ {len(documents)}개 문서 추가 완료")
def search(self, query: str, top_k: int = 5) -> list[dict]:
"""쿼리와 관련된 문서 검색"""
query_embedding = self.generate_embedding(query)
results = self.table.search(query_embedding, vector_column_name="vector") \
.limit(top_k) \
.to_list()
return [
{
"content": r["text"],
"metadata": r["metadata"],
"distance": r["_distance"]
}
for r in results
]
사용 예시
vector_store = VectorStore(
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1"
)
2단계: 검색 도구 정의
에이전트가 사용할 수 있는 도구들을 정의합니다. 각 도구는 특정 목적에 최적화된 검색을 수행합니다:
from typing import Literal
from dataclasses import dataclass
@dataclass
class SearchResult:
"""검색 결과 데이터 클래스"""
content: str
source: str
relevance_score: float
class SearchTools:
"""Agentic RAG용 검색 도구 모음"""
def __init__(self, vector_store):
self.vector_store = vector_store
def semantic_search(self, query: str, top_k: int = 5) -> list[SearchResult]:
"""
시맨틱 검색: 의미적 유사성 기반 검색
추상적인 질문이나 개념적查询에 효과적
"""
results = self.vector_store.search(query, top_k)
return [
SearchResult(
content=r["content"],
source="semantic",
relevance_score=1 - r["distance"]
)
for r in results
]
def keyword_search(self, query: str, top_k: int = 5) -> list[SearchResult]:
"""
키워드 검색: 정확한 단어 매칭 기반 검색
구체적인 이름, 날짜, 수치查询에 효과적
"""
# 키워드 추출 (간단한 구현)
keywords = [word for word in query.split() if len(word) > 2]
combined_query = " ".join(keywords[:5])
results = self.vector_store.search(combined_query, top_k)
return [
SearchResult(
content=r["content"],
source="keyword",
relevance_score=1 - r["distance"]
)
for r in results
]
def date_range_search(self, start_date: str, end_date: str, topic: str) -> list[SearchResult]:
"""
날짜 범위 검색: 특정 기간 내 문서 검색
기간이 중요한 보고서나 업데이트 조회에 효과적
"""
query = f"{topic} {start_date} {end_date}"
results = self.vector_store.search(query, top_k=10)
return [
SearchResult(
content=r["content"],
source="date_range",
relevance_score=1 - r["distance"]
)
for r in results
if self._is_in_date_range(r["metadata"], start_date, end_date)
]
def _is_in_date_range(self, metadata: dict, start: str, end: str) -> bool:
"""메타데이터의 날짜가 범위 내인지 확인"""
doc_date = metadata.get("date", "")
return start <= doc_date <= end
def get_all_tools(self) -> dict:
"""모든 도구를 딕셔너리 형태로 반환"""
return {
"semantic_search": self.semantic_search,
"keyword_search": self.keyword_search,
"date_range_search": self.date_range_search
}
3단계: 라우팅 에이전트 구현
이제 가장 핵심인 라우팅 에이이전트를 구현합니다. 이 에이전트가 질문의 의도를 판단하고 적절한 검색 전략을 선택합니다:
from openai import OpenAI
import json
class RoutingAgent:
"""
라우팅 에이전트: 질문 분석 및 검색 전략 결정
주요 역할:
1. 사용자 질문의 의도 분석
2. 필요한 도구 조합 결정
3. 검색 결과 평가 및 재검색 판단
4. 최종 답변 생성
"""
def __init__(self, api_key: str, base_url: str):
self.client = OpenAI(api_key=api_key, base_url=base_url)
self.search_tools = None
def set_tools(self, search_tools: SearchTools):
"""검색 도구 설정"""
self.search_tools = search_tools
def analyze_intent(self, query: str) -> dict:
"""질문의 의도를 분석하고 검색 계획 수립"""
prompt = f"""질문을 분석하여 검색 전략을 결정하세요.
질문: {query}
다음 JSON 형식으로 응답하세요:
{{
"intent_type": "factual/comparative/analytical/procedural",
"requires_dates": true/false,
"requires_numbers": true/false,
"search_strategy": ["semantic_search", "keyword_search", "date_range_search"],
"expected_sources": ["보고서", "회의록", "매뉴얼", "이메일"],
"complexity": "simple/complex/multi_step"
}}
응답은 JSON만 반환하세요.""" response = self.client.chat.completions.create(
model="gpt-4.1",
messages=[{"role": "user", "content": prompt}],
temperature=0.3,
max_tokens=500
)
try:
return json.loads(response.choices[0].message.content)
except json.JSONDecodeError:
# 파싱 실패 시 기본 전략 반환
return {
"intent_type": "factual",
"requires_dates": False,
"requires_numbers": False,
"search_strategy": ["semantic_search"],
"expected_sources": ["문서"],
"complexity": "simple"
}
def execute_search(self, query: str, search_plan: dict) -> list[SearchResult]:
"""검색 계획에 따라 도구 실행"""
all_results = []
for strategy in search_plan["search_strategy"]:
if strategy == "semantic_search":
results = self.search_tools.semantic_search(query, top_k=5)
elif strategy == "keyword_search":
results = self.search_tools.keyword_search(query, top_k=5)
elif strategy == "date_range_search":
# 날짜 범위 추출 필요 시 기본값 사용
results = self.search_tools.date_range_search(
"2024-01-01", "2024-12-31", query
)
else:
continue
all_results.extend(results)
# 중복 제거 및 점수 기준 정렬
return self.deduplicate_and_rank(all_results)
def deduplicate_and_rank(self, results: list[SearchResult]) -> list[SearchResult]:
"""중복 제거 및 relevance 점수 기준 정렬"""
seen = set()
unique_results = []
for r in results:
if r.content not in seen:
seen.add(r.content)
unique_results.append(r)
return sorted(unique_results, key=lambda x: x.relevance_score, reverse=True)
def generate_response(self, query: str, results: list[SearchResult]) -> str:
"""검색 결과를 바탕으로 최종 답변 생성"""
context = "\n\n".join([
f"[출처 {i+1} - {r.source}] {r.content}"
for i, r in enumerate(results[:5])
])
prompt = f"""검색 결과를 바탕으로 질문에 답변하세요.
질문: {query}
검색 결과:
{context}
지침:
- 검색 결과를 직접적으로 활용하세요
- 출처를 명시하세요
- 모르는 내용은 "검색 결과에서 확인할 수 없습니다"라고 말씀하세요
- 불확실한 내용은 반드시 불확실하다고 표시하세요"""
response = self.client.chat.completions.create(
model="gpt-4.1",
messages=[{"role": "user", "content": prompt}],
temperature=0.7,
max_tokens=1000
)
return response.choices[0].message.content
def process_query(self, query: str) -> str:
"""전체 처리 파이프라인 실행"""
# 1단계: 의도 분석
print(f"🔍 질문 분석 중: {query}")
search_plan = self.analyze_intent(query)
print(f"📋 검색 전략: {search_plan['search_strategy']}")
# 2단계: 검색 실행
print(f"🔎 검색 실행 중...")
results = self.execute_search(query, search_plan)
print(f"✅ {len(results)}개 결과 검색 완료")
# 3단계: 답변 생성
print(f"✍️ 답변 생성 중...")
response = self.generate_response(query, results)
return response
사용 예시
agent = RoutingAgent(
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1"
)
agent.set_tools(search_tools)
4단계: 메인 실행 파일
from vector_store import VectorStore
from search_tools import SearchTools
from routing_agent import RoutingAgent
def main():
"""Agentic RAG 시스템 메인 실행"""
# HolySheep AI API 설정
API_KEY = "YOUR_HOLYSHEEP_API_KEY"
BASE_URL = "https://api.holysheep.ai/v1"
print("🚀 Agentic RAG 시스템 시작")
print("=" * 50)
# 1단계: 벡터 저장소 초기화
vector_store = VectorStore(API_KEY, BASE_URL)
vector_store.create_table("documents")
# 2단계: 샘플 문서 추가
sample_docs = [
{
"content": "2024년 1분기 매출 보고서: 총 매출 50억 원, 전년 대비 15% 증가. 마케팅 비용 8억 원投入.",
"metadata": {"date": "2024-04-01", "type": "report", "department": "marketing"}
},
{
"content": "2024년 2분기 마케팅 전략 회의록: SNS 광고 예산 30% 확대 결정. 인플루언서 마케팅 강화.",
"metadata": {"date": "2024-07-01", "type": "meeting", "department": "marketing"}
},
{
"content": "2024년 3분기 성과 분석: 전환율 3.2% → 4.1% 개선. 주요 개선점: 랜딩 페이지 개편.",
"metadata": {"date": "2024-10-01", "type": "analysis", "department": "marketing"}
},
{
"content": "2024년 4분기 마케팅 예산 계획: 총 예산 12억 원. EOFY 세일 집중 마케팅 예정.",
"metadata": {"date": "2024-11-01", "type": "plan", "department": "marketing"}
},
{
"content": "2025년 마케팅 방향성提案: 데이터 기반 마케팅 도입. AI 활용 고객 세분화 추진.",
"metadata": {"date": "2025-01-15", "type": "proposal", "department": "marketing"}
}
]
vector_store.add_documents(sample_docs)
# 3단계: 검색 도구 및 에이전트 설정
search_tools = SearchTools(vector_store)
agent = RoutingAgent(API_KEY, BASE_URL)
agent.set_tools(search_tools)
# 4단계: 질문 처리
print("\n" + "=" * 50)
print("질문 입력 대기 중...")
test_queries = [
"2024년 마케팅 성과 요약해줘",
"분기별 매출 추이는 어떻게 돼?",
"2025년 마케팅 전략 방향은?"
]
for query in test_queries:
print(f"\n{'='*50}")
print(f"❓ 질문: {query}")
print(f"{'='*50}")
response = agent.process_query(query)
print(f"\n💬 답변:\n{response}\n")
print("✅ Agentic RAG 시스템 완료")
if __name__ == "__main__":
main()
실행 결과 예시
【스크린샷 힌트】터미널 출력 화면:
🚀 Agentic RAG 시스템 시작
==================================================
✅ 테이블 'documents' 생성 완료
✅ 5개 문서 추가 완료
==================================================
❓ 질문: 2024년 마케팅 성과 요약해줘
==================================================
🔍 질문 분석 중: 2024년 마케팅 성과 요약해줘
📋 검색 전략: ['semantic_search', 'keyword_search']
🔎 검색 실행 중...
✅