ν•œ μ€„λ‘œ λ§ν•˜λ©΄, μ—μ΄μ „νŠΈ ν’ˆμ§ˆμ€ β€˜μž˜ λŒμ•„κ°„λ‹€β€™κ°€ μ•„λ‹ˆλΌ β€˜λ°˜λ³΅ 싀행해도 같은 κΈ°μ€€μœΌλ‘œ ν†΅κ³Όν•œλ‹€β€™λ‘œ 관리해야 ν•œλ‹€.
이번 λ³ΈνŽΈμ€ smolagents 기반 μ—μ΄μ „νŠΈμ— 도ꡬ ν…ŒμŠ€νŠΈ + 평가 루프(eval) λ₯Ό λΆ™μ—¬ 싀무 배포 μ „ 신뒰도λ₯Ό ν™•λ³΄ν•˜λŠ” 방법을 닀룬닀.

μ™œ μ§€κΈˆ 평가 루프가 ν•„μš”ν•œκ°€

  • μ—μ΄μ „νŠΈλŠ” 같은 μ§ˆλ¬Έμ—λ„ 도ꡬ 호좜 μˆœμ„œκ°€ λ‹¬λΌμ§ˆ 수 μžˆλ‹€.
  • κ²°κ³Ό λ¬Έμž₯이 μžμ—°μŠ€λŸ¬μ›Œλ„, μ •λ‹΅ 쑰건을 놓칠 수 μžˆλ‹€.
  • λ”°λΌμ„œ λ³Έλ¬Έ 생성 이전에 μžλ™ νŒμ • κΈ°μ€€(성곡/μ‹€νŒ¨) 을 λ¨Όμ € κ³ μ •ν•΄μ•Ό ν•œλ‹€.
flowchart LR
  A[μš”μ²­ μž…λ ₯] --> B[CodeAgent μ‹€ν–‰]
  B --> C[도ꡬ 호좜 둜그 μˆ˜μ§‘]
  C --> D{평가 κ·œμΉ™ 톡과?}
  D -->|Yes| E[배포 후보]
  D -->|No| F[ν”„λ‘¬ν”„νŠΈ/도ꡬ μˆ˜μ •]
  F --> B

μ‹€μŠ΅ λͺ©ν‘œ

  1. smolagents둜 κ°„λ‹¨ν•œ 업무 μ—μ΄μ „νŠΈλ₯Ό λ§Œλ“ λ‹€.
  2. 도ꡬ λ‹¨μœ„ ν…ŒμŠ€νŠΈ(selfcheck)λ₯Ό ν†΅κ³Όμ‹œν‚¨λ‹€.
  3. μƒ˜ν”Œ 과제 μ…‹μœΌλ‘œ 평가(eval) 점수λ₯Ό κ³„μ‚°ν•œλ‹€.
  4. 톡과 κΈ°μ€€ 미달 μ‹œ μˆ˜μ • 포인트λ₯Ό λ°”λ‘œ μ°ΎλŠ”λ‹€.

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](μ˜€νƒˆμž κ·ΈλŒ€λ‘œ 좜λ ₯될 수 있음) κ²°κ³Όμ—μ„œ μ•„λž˜ λ‘˜ λ‹€ true
    • shipping_tool_ok
    • policy_tool_ok

Step 3-2. 평가 κ²°κ³Ό 확인

  • 도ꡬ: 같은 μ‹€ν–‰ 둜그의 [EVAL] JSON
  • μž…λ ₯: λ‚΄μž₯ 3개 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€
  • μ‹€ν–‰λͺ…λ Ή: Step 3-1κ³Ό 동일
  • μ„±κ³΅νŒμ •:
    • score >= 0.67
    • pass: true

4) 초보자용 ν•΄μ„€ (μ‰½κ²Œ μ΄ν•΄ν•˜κΈ°)

  • @tool ν•¨μˆ˜λŠ” μ—μ΄μ „νŠΈκ°€ κΊΌλ‚΄ μ“°λŠ” μž‘μ€ 계산기/사전이닀.
  • selfcheck_tools()λŠ” 도ꡬ가 망가지지 μ•Šμ•˜λŠ”μ§€ ν™•μΈν•˜λŠ” κΈ°λ³Έ 건강검진이닀.
  • run_eval()은 질문 λ¬ΆμŒμ„ 돌렀보고, μ •ν•΄λ‘” ν‚€μ›Œλ“œκ°€ μžˆλŠ”μ§€λ‘œ 톡과λ₯Ό μ •ν•˜λŠ” 채점기닀.

즉, β€œν•œ 번 잘된 데λͺ¨β€κ°€ μ•„λ‹ˆλΌ β€œλ§€λ²ˆ ν†΅κ³Όν•˜λŠ” μ‹œμŠ€ν…œβ€μœΌλ‘œ λ°”κΎΈλŠ” 과정이 평가 루프닀.


5) 싀무 적용 포인트

  1. 릴리즈 게이트: 배포 μ „ score 미달이면 μžλ™ 쀑단.
  2. νšŒκ·€ λ°©μ§€: ν”„λ‘¬ν”„νŠΈ μˆ˜μ • 후에도 κΈ°μ‘΄ μΌ€μ΄μŠ€λ₯Ό λ‹€μ‹œ 돌렀 ν’ˆμ§ˆ ν•˜λ½ 감지.
  3. 운영 둜그 ν‘œμ€€ν™”: [SELFHECK], [EVAL] 같이 νŒŒμ‹± κ°€λŠ₯ν•œ κ³ μ • ν‚€λ₯Ό 두면 λŒ€μ‹œλ³΄λ“œ 연동이 쉬움.
  4. ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€ 뢄리: 이후 eval_cases.json 파일둜 뢄리해 νŒ€μ—μ„œ 곡동 관리.

체크리슀트

  • κ°€μƒν™˜κ²½ 생성/ν™œμ„±ν™” μ™„λ£Œ
  • smolagents import 성곡
  • HF_TOKEN λ˜λŠ” API ν‚€ μ„€μ • μ™„λ£Œ
  • selfcheck 2개 ν•­λͺ© true
  • eval score 0.67 이상
  • μ‹€νŒ¨ μΌ€μ΄μŠ€ 1개 이상 원인 기둝

μ°Έκ³  링크 (μš°μ„ μˆœμœ„)

  1. https://github.com/huggingface/agents-course
  2. https://huggingface.co/learn/agents-course
  3. https://huggingface.co/docs/smolagents

μƒμ„±ν˜• AI ν™œμš© κ³ μ§€

이 λ¬Έμ„œλŠ” μƒμ„±ν˜• AIλ₯Ό ν™œμš©ν•΄ μ΄ˆμ•ˆμ„ μž‘μ„±ν–ˆκ³ , μ˜ˆμ‹œ μ½”λ“œ/절차/ν‘œν˜„μ€ μ‚¬λžŒ κ²€ν†  ν›„ ν™•μ •ν–ˆλ‹€.