์ด๋ฒ 2ํธ์ ์์ด์ ํธ๊ฐ ์ค์ ๋ก ์ผ์ ํ๊ฒ ๋ง๋๋ ํต์ฌ์ธ Tool Calling์ ๋ค๋ฃฌ๋ค. ๋ชฉํ๋ โ๋๊ตฌ๋ฅผ ๋ถ์ธ๋คโ ์์ค์ด ์๋๋ผ, ์คํจํ์ง ์๋ ๋๊ตฌ ์ธํฐํ์ด์ค๋ฅผ ์ค๊ณํ๊ณ ์คํ ๋ฃจํ์ ์์ ์ ์ผ๋ก ์ฐ๊ฒฐํ๋ ๊ฒ์ด๋ค.
flowchart LR A[User Goal] --> B[Planner] B --> C[Tool Router] C --> D[Tool 1: Search] C --> E[Tool 2: Fetch] C --> F[Tool 3: Summarize] D --> G[Observation] E --> G F --> G G --> H[Final Answer]
0) 30์ด ์์ฝ
- Tool Calling์ โ๋ชจ๋ธ์ด ๋ฐ๊นฅ ์ธ์๊ณผ ์ฐ๊ฒฐ๋๋ ์ ์ถ๋ ฅ ๊ท์ฝโ์ด๋ค.
- ์ฑ๋ฅ๋ณด๋ค ๋จผ์ ๋๊ตฌ ๊ณ์ฝ(schema), ์คํจ ์ฒ๋ฆฌ, ๊ฒ์ฆ ๊ท์น์ ๊ณ ์ ํด์ผ ์ด์์ด ๋๋ค.
- ์ค๋ ์ฐ์ถ๋ฌผ:
๋๊ตฌ 3๊ฐ + ์คํ ๋ฃจํ + ์คํจ ๋์์ด ํฌํจ๋ ๋ฏธ๋ ์์ด์ ํธ ์ค๊ณ/์คํ๋ณธ.
1) ์ Tool Calling์ด ์ค์ํ ๊น
LLM์ด ์๋ฌด๋ฆฌ ๋๋ํด๋, ์ต์ ๋ฐ์ดํฐยท์ฌ๋ด ๋ฐ์ดํฐยท์คํ ๋ช ๋ น์ ์ค์ค๋ก ๊ฐ์ ธ์ค์ง ๋ชปํ๋ค. Tool Calling์ ์ด ํ๊ณ๋ฅผ ๋๋ ๊ตฌ์กฐ๋ค.
ํต์ฌ ํจ๊ณผ:
- ์ต์ ์ฑ ํ๋ณด: ๊ฒ์/์กฐํ ๋๊ตฌ๋ก ์ค์๊ฐ ์ ๋ณด ๋ฐ์
- ์ฌํ์ฑ ํ๋ณด: ๊ฐ์ ์ ๋ ฅ์ด๋ฉด ๊ฐ์ ์ ์ฐจ๋ก ์คํ
- ์ฑ ์์ฑ ํ๋ณด: ์ด๋ค ๋๊ตฌ๋ฅผ ์ ํธ์ถํ๋์ง ์ถ์ ๊ฐ๋ฅ
2) ๋๊ตฌ ์ค๊ณ ์์น (์ค๋ฌด์ฉ)
์์น 1) ์ ๋ ฅ์ ์ข๊ฒ, ์ถ๋ ฅ์ ๋ช ํํ๊ฒ
- ์
๋ ฅ ํ๋๋ ์ต์ํ (
query,limit์ฒ๋ผ) - ์ถ๋ ฅ์ ๊ตฌ์กฐํ (
title,url,snippet)
์์น 2) ์คํจ๋ฅผ ์ ์ ํ๋ก์ฐ๋ก ์ทจ๊ธ
- timeout, empty result, invalid input์ ์์ธ๊ฐ ์๋๋ผ ๋ถ๊ธฐ ์ฒ๋ฆฌ
์์น 3) ๋๊ตฌ๋ณ ์ฑ๊ณต ํ์ ๊ธฐ์ค ์ ์
- Search ์ฑ๊ณต: ์ต์ 3๊ฐ ์ ํจ ๋งํฌ
- Fetch ์ฑ๊ณต: ๋ณธ๋ฌธ ๊ธธ์ด n์ ์ด์
- Summarize ์ฑ๊ณต: ๊ธ์ง์ด/๊ณผ์ฅ์ด ํํฐ ํต๊ณผ
sequenceDiagram participant U as User participant A as Agent participant S as Search Tool participant F as Fetch Tool participant M as Summarize Tool U->>A: ์ค๋ AI ๋ด์ค ๋ธ๋ฆฌํ A->>S: query="AI news", limit=5 S-->>A: urls[5] A->>F: fetch(urls) F-->>A: articles A->>M: summarize(articles) M-->>A: brief A-->>U: TOP3 + ๊ทผ๊ฑฐ ๋งํฌ
3) ์ค์ต A โ ๋๊ตฌ ๊ณ์ฝ์ ๋ง๋ค๊ธฐ
์๋์ฒ๋ผ ๋จผ์ ๋๊ตฌ ์คํค๋ง๋ถํฐ ์ ๋๋ค.
{
"tool": "web_search",
"input": {
"query": "string",
"limit": "integer(1~10)"
},
"output": [
{"title": "string", "url": "string", "snippet": "string"}
],
"failure": ["timeout", "empty", "rate_limit"]
}์ฑ๊ณต ํ์ :
- ์ ๋ ฅ ์ ํจ์ฑ ๊ฒ์ฌ ์กด์ฌ
- ์ถ๋ ฅ ํ๋ ๊ณ ์
- ์คํจ ์ฝ๋ 3์ข ์ ์
4) ์ค์ต B โ Python ๋ฏธ๋ ๋ฃจํ ๊ตฌํ
4-0) 5๋ถ ํต์คํํธ (๋จผ์ 1ํ ์ฑ๊ณต)
- ๋ฌธ์ ํ๋จ ์ค์ต ํ์ผ ๋ค์ด๋ก๋์์
hf-agents-day2-tool-calling.zip์ ๋ฐ๋๋ค. - ์์ถ ํด์ ํ ํด๋๋ก ์ด๋ํ๋ค.
- ์๋ 3์ค์ ์คํํ๋ค.
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt && python day2_tool_calling.py์ค๋น
- ๋๊ตฌ: Python 3.10+
- ํ์ผ:
day2_tool_calling.py
์คํ
python day2_tool_calling.py์คํ ๊ฒฐ๊ณผ ์์ (์ ์/์คํจ)
์ ์ ์์:
{'ok': True, 'count': 3, 'result': [...]} ์คํจ ์์:
{'ok': False, 'stage': 'search', 'error': 'invalid_query'}์ฝ๋
from dataclasses import dataclass
from typing import Dict, List, Optional
@dataclass
class ToolResult:
ok: bool
data: List[Dict]
error: Optional[str] = None
def web_search(query: str, limit: int = 5) -> ToolResult:
if not query or not query.strip():
return ToolResult(ok=False, data=[], error="invalid_query")
mock_results = [
{"title": "AI News A", "url": "https://example.com/a", "snippet": "update A"},
{"title": "AI News B", "url": "https://example.com/b", "snippet": "update B"},
{"title": "AI News C", "url": "https://example.com/c", "snippet": "update C"},
{"title": "AI News D", "url": "https://example.com/d", "snippet": "update D"},
{"title": "AI News E", "url": "https://example.com/e", "snippet": "update E"},
]
return ToolResult(ok=True, data=mock_results[:limit])
def validate(items: List[Dict]) -> ToolResult:
if len(items) < 3:
return ToolResult(ok=False, data=[], error="insufficient_results")
valid = [x for x in items if x.get("url", "").startswith("https://")]
if len(valid) < 3:
return ToolResult(ok=False, data=[], error="invalid_url_format")
return ToolResult(ok=True, data=valid)
def summarize(items: List[Dict]) -> ToolResult:
if not items:
return ToolResult(ok=False, data=[], error="empty_input")
summaries = [
{
"summary": f"{item['title']} - ํต์ฌ ํ ์ค ์์ฝ",
"url": item["url"],
}
for item in items[:3]
]
return ToolResult(ok=True, data=summaries)
def run_briefing(query: str):
searched = web_search(query, limit=5)
if not searched.ok:
return {"ok": False, "stage": "search", "error": searched.error}
validated = validate(searched.data)
if not validated.ok:
return {"ok": False, "stage": "validate", "error": validated.error}
summarized = summarize(validated.data)
if not summarized.ok:
return {"ok": False, "stage": "summarize", "error": summarized.error}
return {"ok": True, "count": len(summarized.data), "result": summarized.data}
if __name__ == "__main__":
output = run_briefing("today ai updates")
print(output)์ฑ๊ณต ํ์ :
-
ok=True๊ฒฐ๊ณผ ์ถ๋ ฅ -
count=3ํ์ธ - ์คํจ ์
stage,error๊ฐ ์ถ๋ ฅ๋จ
5) ์ค์ต C โ HF/smolagents ์ฐ๊ฒฐ ํฌ์ธํธ
smolagents๋ฅผ ์ธ ๋๋ ํต์ฌ์ ๋์ผํ๋ค. ์ค์ํ ๊ฑด ๋ชจ๋ธ์ด ์๋๋ผ ํด์ ๊ณ์ฝ ํ์ง์ด๋ค.
# pip install smolagents
from smolagents import tool
@tool
def get_stock_price(symbol: str) -> str:
"""์ฃผ์ ์ฌ๋ณผ์ ์
๋ ฅ๋ฐ์ ๊ฐ๊ฒฉ ์์ฝ์ ๋ฐํ"""
# ์ค์ ๋ก๋ ์ธ๋ถ API ํธ์ถ
return f"{symbol}: 123.45 USD"์ฒดํฌํฌ์ธํธ:
- ํจ์ ์ค๋ช (docstring)์ ๋ชจ๋ธ์ด ์ฝ๊ณ ์ ํํ๋ค.
- ํจ์ ์ ๋ ฅ ํ์ ์ด ์ ๋งคํ๋ฉด ์คํธ์ถ์ด ๋์ด๋๋ค.
6) ํธ๋ฌ๋ธ์ํ TOP 5
- ๋๊ตฌ ๋ฏธํธ์ถ: ํ๋กฌํํธ์ โ๋๊ตฌ ์ฌ์ฉ ์กฐ๊ฑดโ์ ๋ช ์ํ์ง ์์
- ์คํธ์ถ: ๋๊ตฌ ์ค๋ช ์ด ๋ชจํธํจ
- ์ถ๋ ฅ ํ์ฑ ์คํจ: JSON ์คํค๋ง ๊ณ ์ ์ ํจ
- ๋ฌดํ ์ฌ์๋: retry ์ํ ๋ถ์ฌ
- ์ฌ์ค ์ค๋ฅ: ์์ฝ ๊ฒฐ๊ณผ ๊ฒ์ฆ ๋จ๊ณ ๋๋ฝ
7) ์ค๋ ์ ์ถ๋ฌผ
### HF Day2 ์ ์ถ๋ฌผ
- ๋ชฉํ ์์
:
- ์ฌ์ฉ ๋๊ตฌ(3๊ฐ):
- ๋๊ตฌ ๊ณ์ฝ์(schema):
- ์คํจ ์ฒ๋ฆฌ ๊ท์น(์ต์ 3๊ฐ):
- ์คํ ๊ฒฐ๊ณผ(์ฑ๊ณต/์คํจ ๋ก๊ทธ):
- ๊ฐ์ ํฌ์ธํธ(๋ค์ ํธ ๋ฐ์):8) ๋ค์ ํธ ์๊ณ (03ํธ)
03ํธ์์๋ Tool Calling์ ๋ง๋ ํ๋กฌํํธ ์ค๊ณ ํจํด์ ๋ค๋ฃฌ๋ค.
- ์์คํ /๊ฐ๋ฐ์/์ฌ์ฉ์ ์ญํ ๋ถ๋ฆฌ
- ๋๊ตฌ ์ ํ ๊ธฐ์ค ๋ฌธ์ฅ ํ ํ๋ฆฟ
- hallucination ์ค์ด๋ ์ถ๋ ฅ ๊ฐ๋๋ ์ผ
์ฐธ๊ณ ๋งํฌ
- https://github.com/huggingface/agents-course
- https://huggingface.co/learn/agents-course
- https://huggingface.co/docs/smolagents
์ค์ต ํ์ผ ๋ค์ด๋ก๋
ํ์ผ์ด ๋ธ๋ผ์ฐ์ ์์ ๋ฐ๋ก ์ด๋ฆฌ๋ฉด, ์ฐํด๋ฆญ ํ **โ๋ค๋ฅธ ์ด๋ฆ์ผ๋ก ์ ์ฅโ**์ ์ ํํด ๋ค์ด๋ก๋ํ๋ฉด ๋ฉ๋๋ค.
์์ฑํ AI ํ์ฉ ๊ณ ์ง
์ด ๋ฌธ์๋ ์์ฑํ AI๋ฅผ ํ์ฉํด ์ด์ ์์ฑ ๋ฐ ๊ตฌ์กฐํ๋ฅผ ์ํํ์ผ๋ฉฐ, ์ต์ข ๊ณต๊ฐ ์ ์ฌ๋์ด ๊ฒํ ยท๋ณด์ ํ๋ค.