ํ ์ค๋ก ๋งํ๋ฉด, Agentic RAG์ โ๋ฌธ์ ๊ฒ์ ๋๊ตฌโ๋ฅผ ์์ด์ ํธ์๊ฒ ์ฃผ๋ฉด, ์์ด์ ํธ๊ฐ ์ค์ค๋ก ์ธ์ ยท๋ฌด์์ ๊ฒ์ํ ์ง ๊ฒฐ์ ํ๋ค๋ ๊ฒ์ด๋ค. ์ด๋ฒ ๋ณธํธ 14๋ HF Agents Course Unit 3์ Agentic RAG ์ ์ค์ผ์ด์ค๋ฅผ smolagents๋ก ์ฌํํ๋ค.
ํ ์ค ๊ฒฐ๋ก
smolagents์ Tool๋ก RAG ๊ฒ์๊ธฐ๋ฅผ ๊ฐ์ธ๋ฉด, ์์ด์ ํธ๊ฐ ์ง๋ฌธ์ ๋ง์ถฐ ์๋์ผ๋ก ๋ฌธ์๋ฅผ ๊ฒ์ยท์์ฝยทํํฐ๋งํ๋ โ์ง๋ฅํ ์ ๋ณด ์กฐ์โ๋ฅผ 20๋ถ์ ๋ง๋ค ์ ์๋ค.
๋งฅ๋ฝ ๋ณด์
์ง๊ธ๊น์ง ์๋ฆฌ์ฆ์์ ๋ค๋ฃฌ ํต์ฌ:
- ๋ณธํธ 01: ์ฒซ CodeAgent ์คํ
- ๋ณธํธ 05: ReAct ๋๊ตฌ ์ ํ ํ๋ฆ
- ๋ณธํธ 08: ์น๊ฒ์ ์์ฝ ์์ด์ ํธ
์ด๋ฒ์ ๊ฒ์ ๋์์ด ์น์ด ์๋๋ผ ๋ก์ปฌ ๋ฌธ์๋ผ๋ ์ ์ด ๋ค๋ฅด๋ค. ์์ด์ ํธ๊ฐ ๋๊ตฌ๋ก โ๋ฌธ์ ๊ฒ์โ์ ํธ์ถํ๋ฉด, RAG ํ์ดํ๋ผ์ธ์ด ์๋ฒ ๋ฉ โๆฃ็ดข โ ์ปจํ ์คํธ ์ฃผ์ ์ ์ํํ๋ค.
1. Agentic RAG์ด ์ผ๋ฐ RAG๊ณผ ๋ค๋ฅธ ์
| ๊ตฌ๋ถ | ์ผ๋ฐ RAG | Agentic RAG |
|---|---|---|
| ๊ฒ์ ์์ | ์ฌ์ฉ์ ์ง๋ฌธ โ 1ํ ๊ฒ์ | ์์ด์ ํธ๊ฐ ํ์์๋ง๋ค ๋คํ ๊ฒ์ |
| ๊ฒ์ ์ ๋ต | ๊ณ ์ (similarity top-k) | ์์ด์ ํธ๊ฐ ์ฟผ๋ฆฌ ์ฌ์์ฑ, ํํฐ ์ ํ |
| ๋ต๋ณ ์์ฑ | ๊ฒ์ ๊ฒฐ๊ณผ โ LLM 1ํ | ์์ด์ ํธ๊ฐ ๊ฒ์ฆ ํ ์ถ๊ฐ ๊ฒ์ ๊ฐ๋ฅ |
| ๋๊ตฌ ํ์ฅ | ๋ถ๊ฐ | ๋ ์จ API, ๊ณ์ฐ๊ธฐ ๋ฑ ๋ค๋ฅธ ๋๊ตฌ์ ์กฐํฉ |
flowchart LR U[์ฌ์ฉ์ ์ง๋ฌธ] --> A[CodeAgent] A -->|๋๊ตฌ ํธ์ถ| R[RAG ๊ฒ์ Tool] R -->|๊ฒฐ๊ณผ ์์| A2[์ฟผ๋ฆฌ ์ฌ์์ฑ] A2 -->|์ฌ๊ฒ์| R R -->|๊ฒฐ๊ณผ ์ถฉ๋ถ| S[๋ต๋ณ ์์ฑ] A -->|๋ค๋ฅธ ๋๊ตฌ| W[๋ ์จ API ๋ฑ] W --> S S --> U
์ค๋ฌด ํฌ์ธํธ: ๊ณ ๊ฐ ์ง์, ๋ด๋ถ ๋ฌธ์ QA, ์ปดํ๋ผ์ด์ธ์ค ์กฐํ ๋ฑ โ์ ํํ ์ถ์ฒ๊ฐ ํ์ํ ์ง๋ฌธโ์ Agentic RAG์ด ๊ฐ๋ ฅํ๋ค.
2. ์ค์ต: ์ํ๋ ๋์ ๊ฐ๋ผ ํํฐ ํธ์คํธ
HF Agents Course์ ์๋๋ฆฌ์ค๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๋ค. ์ํ๋ ๋(์์ด์ ํธ)๊ฐ ๊ฐ๋ผ ํํฐ์ ํธ์คํธ ์ญํ ์ ํ๋ฉฐ, ๊ฒ์คํธ ์ ๋ณด ๋ฌธ์์์ ๋ต์ ์ฐพ์์ผ ํ๋ค.
2-1. ์ฌ์ ์ค๋น
# ํจํค์ง ์ค์น
pip install smolagents langchain-community sentence-transformers faiss-cpu
# ํ๊ฒฝ๋ณ์ (OpenAI ์ฌ์ฉ ์)
export OPENAI_API_KEY="sk-..."
# ๋๋ HF ํ ํฐ
export HF_TOKEN="hf_..."์ฑ๊ณต ํ์ : python -c "import smolagents; print(smolagents.__version__)" ์ ์๋ฌ๊ฐ ์์ผ๋ฉด OK.
2-2. ๊ฒ์คํธ ์ ๋ณด ๋ฐ์ดํฐ์ ์ค๋น
# guest_data.py
from datasets import load_dataset
# HF Agents Course์์ ์ ๊ณตํ๋ ๊ฒ์คํธ ๋ฐ์ดํฐ
guest_dataset = load_dataset("agents-course/unit3-invitees", split="train")
# ํ์ธ
print(f"๊ฒ์คํธ ์: {len(guest_dataset)}")
print(guest_dataset[0])์ฑ๊ณต ํ์ : ๊ฒ์คํธ ์์ ์ฒซ ๋ฒ์งธ ๋ ์ฝ๋๊ฐ ์ ์ ์ถ๋ ฅ๋๋ฉด OK.
2-3. RAG ๊ฒ์ ๋๊ตฌ ๋ง๋ค๊ธฐ
# rag_tool.py
from smolagents import Tool
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from datasets import load_dataset
class GuestInfoRetrieverTool(Tool):
name = "guest_info_retriever"
description = (
"๊ฐ๋ผ ํํฐ ๊ฒ์คํธ์ ๋ํ ์ ๋ณด๋ฅผ ๊ฒ์ํฉ๋๋ค. "
"๊ฒ์คํธ์ ์ด๋ฆ, ์ง์
, ๊ด์ฌ์ฌ, ์ด๋ ์ด์ ๋ฑ์ ์ ์ ์์ต๋๋ค."
)
inputs = {
"query": {
"type": "string",
"description": "๊ฒ์คํธ์ ๊ดํ ์ง๋ฌธ ์: 'Tesla์ ์ฐฝ๋ฆฝ์๋ ๋๊ตฌ์ธ๊ฐ?'"
}
}
output_type = "string"
def __init__(self, **kwargs):
super().__init__(**kwargs)
# ์๋ฒ ๋ฉ ๋ชจ๋ธ (๊ฒฝ๋)
embeddings = HuggingFaceEmbeddings(
model_name="all-MiniLM-L6-v2"
)
# ๊ฒ์คํธ ๋ฐ์ดํฐ๋ฅผ ํ
์คํธ๋ก ๋ณํ
guest_ds = load_dataset("agents-course/unit3-invitees", split="train")
docs = []
for guest in guest_ds:
text = (
f"์ด๋ฆ: {guest.get('name', 'N/A')}. "
f"์ง์
: {guest.get('role', 'N/A')}. "
f"๊ด์ฌ์ฌ: {guest.get('interests', 'N/A')}. "
f"์ด๋ ์ด์ : {guest.get('invitation_reason', 'N/A')}. "
)
docs.append(text)
# FAISS ์ธ๋ฑ์ค ์์ฑ
splitter = RecursiveCharacterTextSplitter(
chunk_size=300, chunk_overlap=30
)
split_docs = splitter.create_documents(docs)
self.db = FAISS.from_documents(split_docs, embeddings)
def forward(self, query: str) -> str:
results = self.db.similarity_search(query, k=3)
if not results:
return "ํด๋น ๊ฒ์คํธ์ ๋ํ ์ ๋ณด๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค."
return "\n---\n".join([doc.page_content for doc in results])2-4. ์์ด์ ํธ ์คํ
# alfred_agent.py
from smolagents import CodeAgent, HfApiModel, OpenAIServerModel
from rag_tool import GuestInfoRetrieverTool
# ๋ชจ๋ธ ์ ํ (๋ ์ค ํ๋)
model = HfApiModel("Qwen/Qwen2.5-72B-Instruct")
# model = OpenAIServerModel("gpt-4o-mini")
# ๋๊ตฌ ์ธ์คํด์ค
guest_tool = GuestInfoRetrieverTool()
# ์์ด์ ํธ ์์ฑ
alfred = CodeAgent(
tools=[guest_tool],
model=model,
max_steps=5,
name="alfred",
description="๊ฐ๋ผ ํํฐ ํธ์คํธ ์ํ๋ ๋. ๊ฒ์คํธ ์ ๋ณด๋ฅผ ๊ฒ์ํด ๋ต๋ณํฉ๋๋ค."
)
# ์ง๋ฌธ!
result = alfred.run("Tesla์ ๊ด๋ จ๋ ๊ฒ์คํธ๊ฐ ๋๊ตฌ์ธ๊ฐ์?")
print(result)์ฑ๊ณต ํ์ : Tesla ์ฐฝ๋ฆฝ์/๊ด๋ จ ์ธ๋ฌผ ์ ๋ณด๊ฐ ํฌํจ๋ ์๋ต์ด ๋์ค๋ฉด OK.
2-5. ๊ธ์ง ์ฃผ์ ๊ฐ๋๋ ์ผ ์ถ๊ฐ
# alfred_guarded.py
from smolagents import CodeAgent, HfApiModel, Tool
from rag_tool import GuestInfoRetrieverTool
class TopicGuardTool(Tool):
"""์ ์นยท์ข
๊ต ์ฃผ์ ๋ฅผ ์ฐจ๋จํ๋ ๊ฐ๋๋ ์ผ ๋๊ตฌ"""
name = "topic_guard"
description = "์ง๋ฌธ์ด ๊ธ์ง๋ ์ฃผ์ (์ ์น, ์ข
๊ต)์ธ์ง ํ์ธํฉ๋๋ค."
inputs = {
"question": {
"type": "string",
"description": "ํ์ธํ ์ง๋ฌธ"
}
}
output_type = "string"
FORBIDDEN = ["์ ์น", "์ ๋น", "์ ๊ฑฐ", "์ข
๊ต", "์ ์", "๊ต๋ฆฌ"]
def forward(self, question: str) -> str:
if any(kw in question for kw in self.FORBIDDEN):
return "BLOCKED: ๊ฐ๋ผ ํํฐ์์๋ ์ ์น์ ์ข
๊ต ์ฃผ์ ๋ฅผ ํผํด์ฃผ์ธ์."
return "OK: ์์ ํ ์ฃผ์ ์
๋๋ค."
guest_tool = GuestInfoRetrieverTool()
guard_tool = TopicGuardTool()
alfred = CodeAgent(
tools=[guest_tool, guard_tool],
model=HfApiModel("Qwen/Qwen2.5-72B-Instruct"),
max_steps=6,
)
# ์ ์ ์ง๋ฌธ
print("=== ์ ์ ์ง๋ฌธ ===")
print(alfred.run("ํํฐ์์ ๊ฐ์ฅ ๊ณผํ์ ๊ด์ฌ ์๋ ๊ฒ์คํธ๋?"))
# ๊ธ์ง ์ง๋ฌธ
print("\n=== ๊ธ์ง ์ง๋ฌธ ===")
print(alfred.run("์ด๋ค ๊ฒ์คํธ๊ฐ ๋ณด์ ์ ๋น์ ์ง์งํ๋์?"))์ฑ๊ณต ํ์ :
- ์ ์ ์ง๋ฌธ โ ๊ฒ์คํธ ๊ด์ฌ์ฌ ๊ธฐ๋ฐ ๋ต๋ณ ์ถ๋ ฅ
- ๊ธ์ง ์ง๋ฌธ โ โBLOCKEDโ ๋๋ ๊ฑฐ๋ถ ๋ฉ์์ง ์ถ๋ ฅ
3. Agentic RAG ํ๋ฆ ๋์
sequenceDiagram participant U as ์ฌ์ฉ์ participant A as Alfred (CodeAgent) participant G as TopicGuard participant R as RAG ๊ฒ์๊ธฐ participant DB as FAISS ์ธ๋ฑ์ค U->>A: "Tesla ๊ด๋ จ ๊ฒ์คํธ ๋๊ตฌ?" A->>G: ์ฃผ์ ์์ ํ์ธ G-->>A: "OK" A->>R: guest_info_retriever("Tesla ๊ด๋ จ") R->>DB: similarity_search("Tesla") DB-->>R: ์์ 3๊ฐ ๋ฌธ์ R-->>A: ๊ฒ์คํธ ์ ๋ณด ํ ์คํธ A->>A: ์ปจํ ์คํธ ๊ธฐ๋ฐ ๋ต๋ณ ์์ฑ A-->>U: "์ผ๋ก ๋จธ์คํฌ, Tesla CEO..."
4. ์ค๋ฌด ์ ์ฉ ํฌ์ธํธ
| ์๋๋ฆฌ์ค | ์ ์ฉ ๋ฐฉ๋ฒ |
|---|---|
| ๊ณ ๊ฐ ์ง์ | ์ ํ ๋งค๋ด์ผยทFAQ๋ฅผ FAISS์ ์์ธ โ ์์ด์ ํธ๊ฐ ๋ด๋น์ ๋ฐฐ์ + ๋ต๋ณ |
| ๋ด๋ถ ์ํค | ์ฌ๋ด ๋ฌธ์๋ฅผ ์๋ฒ ๋ฉ โ โํด๊ฐ ์ ์ฑ ์ด ์ด๋ป๊ฒ ๋๋์?โ ์ง๋ฌธ์ ์๋ ๋ต๋ณ |
| ์ปดํ๋ผ์ด์ธ์ค | ๊ท์ ๋ฌธ์ ๊ฒ์ + ๊ฐ๋๋ ์ผ๋ก ์น์ธ ํ์ ํญ๋ชฉ ์ฐจ๋จ |
| ๋ฆฌ์์น | ๋ ผ๋ฌธ/๋ณด๊ณ ์๋ฅผ RAG๋ก ๊ฒ์ + ์น๊ฒ์ ๋๊ตฌ์ ์กฐํฉ |
ํต์ฌ ์ฐจ์ด: ์ผ๋ฐ RAG์ 1ํ ๊ฒ์์ผ๋ก ๋๋์ง๋ง, Agentic RAG์ ์์ด์ ํธ๊ฐ โ๊ฒฐ๊ณผ๊ฐ ๋ถ์ถฉ๋ถํ๋ฉด ๋ค์ ๊ฒ์โ์ ์ค์ค๋ก ๊ฒฐ์ ํ๋ค. ๋ณธํธ 11์์ ๋ค๋ฃฌ
planning_interval๊ณผ ๊ฒฐํฉํ๋ฉด ๋ ์ ๊ตํ ๊ฒ์ ์ ๋ต์ด ๊ฐ๋ฅํ๋ค.
5. ๋ง๋ฌด๋ฆฌ
์ด๋ฒ ๋ณธํธ์์ ๋ค๋ฃฌ ๊ฒ:
- Agentic RAG = ์์ด์ ํธ + RAG ๊ฒ์ ๋๊ตฌ + ์์จ ํ๋จ
smolagents.Tool๋ก RAG ๊ฒ์๊ธฐ๋ฅผ ๊ฐ์ธ๋ฉด ์ฆ์ ๋๊ตฌํTopicGuard์ฒ๋ผ ๊ฐ๋๋ ์ผ๋ ๋๊ตฌ๋ก ๊ตฌํ ๊ฐ๋ฅ- FAISS +
sentence-transformers๋ก ๋ก์ปฌ ๊ฒ์ ๊ตฌ์ถ
๋ค์ ์๊ณ
์ค์ตํธ 07์์๋ ์ด๋ฒ Agentic RAG์ ๋ฐํ์ผ๋ก ์ฌ๋ด ๋ฌธ์ QA ๋ฏธ๋ ํ๋ก์ ํธ๋ฅผ ํธ์ฆ์จ์ผ๋ก ์งํํ๋ค.
์ฐธ๊ณ ๋งํฌ
- HF Agents Course โ Unit 3 Agentic RAG
- smolagents ๊ณต์ ๋ฌธ์
- ์ด์ ํธ: ๋ณธํธ 13 โ ์์ด์ ํธ ์ค์ผ์คํธ๋ ์ด์ ๊ณผ ์คํ ์ ์ด
์ด ๊ธ์ ์์ฑํ AI(GPT-5.3)์ ๋์์ ๋ฐ์ ์์ฑ๋์์ต๋๋ค. ๋ด์ฉ ๊ฒํ ํ ๊ฒ์ํฉ๋๋ค.