ํ ์ค๋ก ๋งํ๋ฉด, ์์ด์ ํธ ํ์ง์ โ์ ๋์๊ฐ๋คโ๊ฐ ์๋๋ผ โ๋ฐ๋ณต ์คํํด๋ ๊ฐ์ ๊ธฐ์ค์ผ๋ก ํต๊ณผํ๋คโ๋ก ๊ด๋ฆฌํด์ผ ํ๋ค.
์ด๋ฒ ๋ณธํธ์ smolagents ๊ธฐ๋ฐ ์์ด์ ํธ์ ๋๊ตฌ ํ
์คํธ + ํ๊ฐ ๋ฃจํ(eval) ๋ฅผ ๋ถ์ฌ ์ค๋ฌด ๋ฐฐํฌ ์ ์ ๋ขฐ๋๋ฅผ ํ๋ณดํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃฌ๋ค.
์ ์ง๊ธ ํ๊ฐ ๋ฃจํ๊ฐ ํ์ํ๊ฐ
- ์์ด์ ํธ๋ ๊ฐ์ ์ง๋ฌธ์๋ ๋๊ตฌ ํธ์ถ ์์๊ฐ ๋ฌ๋ผ์ง ์ ์๋ค.
- ๊ฒฐ๊ณผ ๋ฌธ์ฅ์ด ์์ฐ์ค๋ฌ์๋, ์ ๋ต ์กฐ๊ฑด์ ๋์น ์ ์๋ค.
- ๋ฐ๋ผ์ ๋ณธ๋ฌธ ์์ฑ ์ด์ ์ ์๋ ํ์ ๊ธฐ์ค(์ฑ๊ณต/์คํจ) ์ ๋จผ์ ๊ณ ์ ํด์ผ ํ๋ค.
flowchart LR A[์์ฒญ ์ ๋ ฅ] --> B[CodeAgent ์คํ] B --> C[๋๊ตฌ ํธ์ถ ๋ก๊ทธ ์์ง] C --> D{ํ๊ฐ ๊ท์น ํต๊ณผ?} D -->|Yes| E[๋ฐฐํฌ ํ๋ณด] D -->|No| F[ํ๋กฌํํธ/๋๊ตฌ ์์ ] F --> B
์ค์ต ๋ชฉํ
smolagents๋ก ๊ฐ๋จํ ์ ๋ฌด ์์ด์ ํธ๋ฅผ ๋ง๋ ๋ค.- ๋๊ตฌ ๋จ์ ํ ์คํธ(selfcheck)๋ฅผ ํต๊ณผ์ํจ๋ค.
- ์ํ ๊ณผ์ ์ ์ผ๋ก ํ๊ฐ(eval) ์ ์๋ฅผ ๊ณ์ฐํ๋ค.
- ํต๊ณผ ๊ธฐ์ค ๋ฏธ๋ฌ ์ ์์ ํฌ์ธํธ๋ฅผ ๋ฐ๋ก ์ฐพ๋๋ค.
1) ์ค๋น: ํด๋/ํ๊ฒฝ/ํจํค์ง
Step 1-1. ์์ ํด๋ ์์ฑ
- ๋๊ตฌ: ํฐ๋ฏธ๋
- ์ ๋ ฅ: ์์
- ์คํ๋ช ๋ น:
mkdir -p ~/hf-agents-day15 && cd ~/hf-agents-day15- ์ฑ๊ณตํ์ :
pwd๊ฒฐ๊ณผ๊ฐ~/hf-agents-day15
Step 1-2. ๊ฐ์ํ๊ฒฝ + ํจํค์ง ์ค์น
- ๋๊ตฌ: Python 3.10+
- ์ ๋ ฅ: ์์
- ์คํ๋ช ๋ น:
python3 -m venv .venv
source .venv/bin/activate
pip install -U smolagents- ์ฑ๊ณตํ์ :
python -c "import smolagents; print('OK')"์ถ๋ ฅ์ OK๊ฐ ๋์ค๋ฉด ํต๊ณผ.
Step 1-3. ๋ชจ๋ธ ํค ์ค์
- ๋๊ตฌ: ํ๊ฒฝ๋ณ์
- ์
๋ ฅ:
HF_TOKEN๋๋ OpenAI ํธํ ํค - ์คํ๋ช ๋ น:
export HF_TOKEN="hf_xxx"
# ๋๋
export OPENAI_API_KEY="sk-xxx"- ์ฑ๊ณตํ์ : ํค๊ฐ ๋น์ด ์์ง ์์ (
echo ${HF_TOKEN:+set})
2) ์์ ์ฝ๋ ์์ฑ (๋๊ตฌ + ์์ด์ ํธ + ํ๊ฐ)
์๋ ํ์ผ์ ๊ทธ๋๋ก ์ ์ฅํ๋ค.
day15_eval_loop.py
import json
from dataclasses import dataclass
from typing import List, Dict
from smolagents import CodeAgent, HfApiModel, tool
@tool
def shipping_cost(weight_kg: float, distance_km: int, urgent: bool = False) -> str:
"""๋ฌด๊ฒ/๊ฑฐ๋ฆฌ/๊ธด๊ธ ์ฌ๋ถ๋ก ๋ฐฐ์ก๋น๋ฅผ ๊ณ์ฐํ๋ค."""
base = 2500
weight_fee = int(weight_kg * 400)
distance_fee = int(distance_km * 3)
urgent_fee = 3000 if urgent else 0
total = base + weight_fee + distance_fee + urgent_fee
return json.dumps({"total_krw": total}, ensure_ascii=False)
@tool
def policy_lookup(topic: str) -> str:
"""๊ฐ๋จํ ๋ด๋ถ ์ ์ฑ
์กฐํ ๋๊ตฌ"""
table = {
"refund": "๊ฐ๋ด ์ 7์ผ ์ด๋ด ์ ์ก ํ๋ถ ๊ฐ๋ฅ",
"delivery": "ํ์ผ 15์ ์ด์ ์ฃผ๋ฌธ์ ๋น์ผ ์ถ๊ณ ",
"warranty": "์ ์์ ํ ๊ธฐ๋ณธ ๋ณด์ฆ 1๋
"
}
return table.get(topic.lower(), "์ ์ฑ
์์")
def build_agent():
model = HfApiModel("Qwen/Qwen2.5-72B-Instruct")
return CodeAgent(
tools=[shipping_cost, policy_lookup],
model=model,
max_steps=6,
)
def selfcheck_tools() -> Dict:
s1 = json.loads(shipping_cost(2.0, 100, False))
s2 = policy_lookup("refund")
return {
"shipping_tool_ok": s1["total_krw"] == 3600,
"policy_tool_ok": "ํ๋ถ" in s2,
}
@dataclass
class Case:
q: str
must_include: List[str]
def run_eval(agent, cases: List[Case]) -> Dict:
results = []
passed = 0
for c in cases:
out = str(agent.run(c.q))
ok = all(token in out for token in c.must_include)
passed += 1 if ok else 0
results.append({"question": c.q, "ok": ok, "output": out})
score = passed / len(cases)
return {
"total": len(cases),
"passed": passed,
"score": round(score, 2),
"pass": score >= 0.67,
"results": results,
}
if __name__ == "__main__":
tool_state = selfcheck_tools()
print("[SELFHECK]", json.dumps(tool_state, ensure_ascii=False))
agent = build_agent()
eval_cases = [
Case(
q="๋ฌด๊ฒ 2kg, ๊ฑฐ๋ฆฌ 100km ์ผ๋ฐ ๋ฐฐ์ก๋น๋ฅผ ๊ณ์ฐํด์ค.",
must_include=["3600"],
),
Case(
q="ํ๋ถ ์ ์ฑ
์์ฝํด์ค.",
must_include=["7์ผ", "ํ๋ถ"],
),
Case(
q="๋ฌด๊ฒ 1kg, ๊ฑฐ๋ฆฌ 50km, ๊ธด๊ธ ๋ฐฐ์ก๋น ๊ณ์ฐ ํ ํ ์ค ์์ฝ.",
must_include=["6050"],
),
]
report = run_eval(agent, eval_cases)
print("[EVAL]", json.dumps(report, ensure_ascii=False, indent=2))3) ์คํ: selfcheck โ eval
Step 3-1. ๋๊ตฌ ๋จ์ ์ ๊ฒ
- ๋๊ตฌ:
day15_eval_loop.py - ์ ๋ ฅ: ์์
- ์คํ๋ช ๋ น:
python day15_eval_loop.py- ์ฑ๊ณตํ์ :
[SELFHECK](์คํ์ ๊ทธ๋๋ก ์ถ๋ ฅ๋ ์ ์์) ๊ฒฐ๊ณผ์์ ์๋ ๋ ๋คtrueshipping_tool_okpolicy_tool_ok
Step 3-2. ํ๊ฐ ๊ฒฐ๊ณผ ํ์ธ
- ๋๊ตฌ: ๊ฐ์ ์คํ ๋ก๊ทธ์
[EVAL]JSON - ์ ๋ ฅ: ๋ด์ฅ 3๊ฐ ํ ์คํธ ์ผ์ด์ค
- ์คํ๋ช ๋ น: Step 3-1๊ณผ ๋์ผ
- ์ฑ๊ณตํ์ :
score >= 0.67pass: true
4) ์ด๋ณด์์ฉ ํด์ค (์ฝ๊ฒ ์ดํดํ๊ธฐ)
@toolํจ์๋ ์์ด์ ํธ๊ฐ ๊บผ๋ด ์ฐ๋ ์์ ๊ณ์ฐ๊ธฐ/์ฌ์ ์ด๋ค.selfcheck_tools()๋ ๋๊ตฌ๊ฐ ๋ง๊ฐ์ง์ง ์์๋์ง ํ์ธํ๋ ๊ธฐ๋ณธ ๊ฑด๊ฐ๊ฒ์ง์ด๋ค.run_eval()์ ์ง๋ฌธ ๋ฌถ์์ ๋๋ ค๋ณด๊ณ , ์ ํด๋ ํค์๋๊ฐ ์๋์ง๋ก ํต๊ณผ๋ฅผ ์ ํ๋ ์ฑ์ ๊ธฐ๋ค.
์ฆ, โํ ๋ฒ ์๋ ๋ฐ๋ชจโ๊ฐ ์๋๋ผ โ๋งค๋ฒ ํต๊ณผํ๋ ์์คํ โ์ผ๋ก ๋ฐ๊พธ๋ ๊ณผ์ ์ด ํ๊ฐ ๋ฃจํ๋ค.
5) ์ค๋ฌด ์ ์ฉ ํฌ์ธํธ
- ๋ฆด๋ฆฌ์ฆ ๊ฒ์ดํธ: ๋ฐฐํฌ ์
score๋ฏธ๋ฌ์ด๋ฉด ์๋ ์ค๋จ. - ํ๊ท ๋ฐฉ์ง: ํ๋กฌํํธ ์์ ํ์๋ ๊ธฐ์กด ์ผ์ด์ค๋ฅผ ๋ค์ ๋๋ ค ํ์ง ํ๋ฝ ๊ฐ์ง.
- ์ด์ ๋ก๊ทธ ํ์คํ:
[SELFHECK],[EVAL]๊ฐ์ด ํ์ฑ ๊ฐ๋ฅํ ๊ณ ์ ํค๋ฅผ ๋๋ฉด ๋์๋ณด๋ ์ฐ๋์ด ์ฌ์. - ํ
์คํธ ์ผ์ด์ค ๋ถ๋ฆฌ: ์ดํ
eval_cases.jsonํ์ผ๋ก ๋ถ๋ฆฌํด ํ์์ ๊ณต๋ ๊ด๋ฆฌ.
์ฒดํฌ๋ฆฌ์คํธ
- ๊ฐ์ํ๊ฒฝ ์์ฑ/ํ์ฑํ ์๋ฃ
-
smolagentsimport ์ฑ๊ณต -
HF_TOKEN๋๋ API ํค ์ค์ ์๋ฃ - selfcheck 2๊ฐ ํญ๋ชฉ true
- eval score 0.67 ์ด์
- ์คํจ ์ผ์ด์ค 1๊ฐ ์ด์ ์์ธ ๊ธฐ๋ก
์ฐธ๊ณ ๋งํฌ (์ฐ์ ์์)
- https://github.com/huggingface/agents-course
- https://huggingface.co/learn/agents-course
- https://huggingface.co/docs/smolagents
์์ฑํ AI ํ์ฉ ๊ณ ์ง
์ด ๋ฌธ์๋ ์์ฑํ AI๋ฅผ ํ์ฉํด ์ด์์ ์์ฑํ๊ณ , ์์ ์ฝ๋/์ ์ฐจ/ํํ์ ์ฌ๋ ๊ฒํ ํ ํ์ ํ๋ค.