์ด๋ฒˆ ํŽธ์€ ์—์ด์ „ํŠธ๊ฐ€ ๋„๊ตฌ๋ฅผ ํ˜ธ์ถœํ•œ ๋’ค, ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”๋กœ ๋ฏฟ์ง€ ์•Š๊ณ  **๊ฒ€์ฆ ๊ฒŒ์ดํŠธ(validate gate)**๋ฅผ ๊ฑฐ์ณ ์‹ ๋ขฐ๋„๋ฅผ ๋†’์ด๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฃฌ๋‹ค.

flowchart LR
  A[์‚ฌ์šฉ์ž ์š”์ฒญ] --> B[CodeAgent]
  B --> C[fetch_price ๋„๊ตฌ ํ˜ธ์ถœ]
  C --> D[์›์‹œ ๊ฒฐ๊ณผ]
  D --> E{๊ฒ€์ฆ ๊ฒŒ์ดํŠธ\nํ•„์ˆ˜ ํ•„๋“œ/ํƒ€์ž…/๋ฒ”์œ„}
  E -- ํ†ต๊ณผ --> F[result.json ์ €์žฅ]
  E -- ์‹คํŒจ --> G[์—๋Ÿฌ ์‚ฌ์œ  ๋ฐ˜ํ™˜\n์žฌ์‹œ๋„ ์œ ๋„]

์‹ค์Šต ๋ชฉํ‘œ

  1. ๋„๊ตฌ ๊ฒฐ๊ณผ๋ฅผ JSON ์Šคํ‚ค๋งˆ๋กœ ๊ฒ€์ฆํ•œ๋‹ค.
  2. ๊ฒ€์ฆ ์‹คํŒจ ์‹œ ์ฆ‰์‹œ ์‹คํŒจ ์ฒ˜๋ฆฌํ•˜๊ณ  ์›์ธ์„ ๋‚จ๊ธด๋‹ค.
  3. ์„ฑ๊ณต ์‹œ result.json์œผ๋กœ ๋‚จ๊ฒจ ์ž๋™ํ™” ํŒŒ์ดํ”„๋ผ์ธ์— ์—ฐ๊ฒฐํ•œ๋‹ค.

1) ์ค€๋น„

Step 1-1. ์ž‘์—… ํด๋” ์ƒ์„ฑ

  • ๋„๊ตฌ: ํ„ฐ๋ฏธ๋„
  • ์ž…๋ ฅ: ์—†์Œ
  • ์‹คํ–‰๋ช…๋ น:
mkdir -p ~/hf-agents-day20 && cd ~/hf-agents-day20
  • ์„ฑ๊ณตํŒ์ •:
pwd

์ถœ๋ ฅ์ด ~/hf-agents-day20

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
  • ์‹คํ–‰๋ช…๋ น:
export HF_TOKEN="hf_xxx"
  • ์„ฑ๊ณตํŒ์ •:
echo ${HF_TOKEN:+set}

์ถœ๋ ฅ set


2) ์—์ด์ „ํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

Step 2-1. day20_validation_gate.py ์ €์žฅ

  • ๋„๊ตฌ: Python ํŒŒ์ผ
  • ์ž…๋ ฅ: ์•„๋ž˜ ์ฝ”๋“œ
import json
from pathlib import Path
from datetime import datetime
 
from smolagents import CodeAgent, HfApiModel, tool
 
RESULT_PATH = Path("result.json")
 
 
@tool
def fetch_price(product: str) -> str:
    """์ƒํ’ˆ ์ด๋ฆ„์„ ๋ฐ›์•„ ๊ฐ€๊ฒฉ ์ •๋ณด๋ฅผ JSON ๋ฌธ์ž์—ด๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค."""
    mock_db = {
        "keyboard": {"product": "keyboard", "price": 59000, "currency": "KRW"},
        "mouse": {"product": "mouse", "price": 32000, "currency": "KRW"},
    }
    data = mock_db.get(product.lower(), {"product": product, "price": -1, "currency": ""})
    return json.dumps(data, ensure_ascii=False)
 
 
def validate_payload(payload: dict) -> tuple[bool, str]:
    required = ["product", "price", "currency"]
    for key in required:
        if key not in payload:
            return False, f"missing:{key}"
 
    if not isinstance(payload["price"], int):
        return False, "price_not_int"
    if payload["price"] <= 0:
        return False, "price_out_of_range"
    if payload["currency"] not in ["KRW", "USD", "EUR"]:
        return False, "currency_not_allowed"
 
    return True, "ok"
 
 
def build_agent() -> CodeAgent:
    model = HfApiModel("Qwen/Qwen2.5-72B-Instruct")
    return CodeAgent(
        tools=[fetch_price],
        model=model,
        max_steps=5,
        additional_authorized_imports=["json"],
    )
 
 
if __name__ == "__main__":
    product = "keyboard"
 
    prompt = f"""
๋„ˆ๋Š” ๊ฐ€๊ฒฉ์กฐํšŒ ์–ด์‹œ์Šคํ„ดํŠธ๋‹ค.
๋ฐ˜๋“œ์‹œ fetch_price('{product}')๋ฅผ ํ˜ธ์ถœํ•˜๊ณ ,
๋„๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ JSON์œผ๋กœ ๋ฐ˜ํ™˜ํ•ด.
์„ค๋ช… ๋ฌธ์žฅ ์—†์ด JSON๋งŒ ์ถœ๋ ฅ.
"""
 
    agent = build_agent()
    raw = agent.run(prompt)
 
    if isinstance(raw, str):
        cleaned = raw.strip().removeprefix("```json").removesuffix("```").strip()
        payload = json.loads(cleaned)
    else:
        payload = raw
 
    ok, reason = validate_payload(payload)
    output = {
        "ok": ok,
        "reason": reason,
        "checked_at": datetime.utcnow().isoformat() + "Z",
        "data": payload,
    }
 
    RESULT_PATH.write_text(json.dumps(output, ensure_ascii=False, indent=2), encoding="utf-8")
    print("saved: result.json")
 
    if not ok:
        raise SystemExit(f"validation_failed:{reason}")
  • ์„ฑ๊ณตํŒ์ •:
python -m py_compile day20_validation_gate.py

์˜ค๋ฅ˜ ์—†์ด ์ข…๋ฃŒ๋˜๋ฉด ํ†ต๊ณผ


3) ์‹คํ–‰ ๋ฐ ๊ฒ€์ฆ

Step 3-1. ์ •์ƒ ์ผ€์ด์Šค ์‹คํ–‰

  • ๋„๊ตฌ: Python
  • ์ž…๋ ฅ: ๊ธฐ๋ณธ๊ฐ’ product = "keyboard"
  • ์‹คํ–‰๋ช…๋ น:
python day20_validation_gate.py
cat result.json
  • ์„ฑ๊ณตํŒ์ •:
    • saved: result.json ์ถœ๋ ฅ
    • result.json์˜ ok๊ฐ€ true
    • reason์ด ok

Step 3-2. ์‹คํŒจ ์ผ€์ด์Šค ํ™•์ธ(๊ฒ€์ฆ ๊ฒŒ์ดํŠธ ๋™์ž‘)

  • ๋„๊ตฌ: ํŒŒ์ผ ํŽธ์ง‘ + Python
  • ์ž…๋ ฅ: product = "unknown_item"๋กœ ๋ณ€๊ฒฝ
  • ์‹คํ–‰๋ช…๋ น:
# ์ฝ”๋“œ์—์„œ product ๊ฐ’์„ unknown_item์œผ๋กœ ๋ฐ”๊พผ ๋’ค
python day20_validation_gate.py
  • ์„ฑ๊ณตํŒ์ •:
    • ํ”„๋กœ์„ธ์Šค๊ฐ€ validation_failed:price_out_of_range๋กœ ์ข…๋ฃŒ
    • result.json์— ok: false ๊ธฐ๋ก

์ดˆ๋ณด์ž์šฉ ์‰ฌ์šด ์„ค๋ช…

  • ์—์ด์ „ํŠธ๊ฐ€ ๋„๊ตฌ๋ฅผ ์ž˜ ํ˜ธ์ถœํ•ด๋„, ๊ฒฐ๊ณผ๊ฐ’์ด ๋น„์ •์ƒ์ผ ์ˆ˜ ์žˆ๋‹ค.
  • ๊ทธ๋ž˜์„œ โ€œ๋„๊ตฌ ํ˜ธ์ถœ ์„ฑ๊ณตโ€๊ณผ โ€œ์—…๋ฌด์— ์“ธ ์ˆ˜ ์žˆ๋Š” ๊ฐ’โ€์„ ๋ถ„๋ฆฌํ•ด์„œ ๋ณธ๋‹ค.
  • ๊ฒ€์ฆ ๊ฒŒ์ดํŠธ๋Š” ์ด ๋‘˜์„ ๋ถ„๋ฆฌํ•ด ์ž๋™ํ™” ์‚ฌ๊ณ ๋ฅผ ์ค„์—ฌ์ค€๋‹ค.

์‹ค๋ฌด ์ ์šฉ ํฌ์ธํŠธ

  1. ์ •์‚ฐ/๊ฐ€๊ฒฉ/์žฌ๊ณ  ์ž๋™ํ™”: ๋ฒ”์œ„ ๋ฐ– ์ˆซ์ž๋ฅผ ์ฆ‰์‹œ ์ฐจ๋‹จ.
  2. ํ‹ฐ์ผ“ ๋ผ์šฐํŒ…: ํ•„์ˆ˜ ํ•„๋“œ ๋ˆ„๋ฝ ์‹œ ์‚ฌ๋žŒ ๊ฒ€ํ†  ํ๋กœ ๋ณด๋ƒ„.
  3. API ๋น„์šฉ ์ ˆ๊ฐ: ์ž˜๋ชป๋œ ๊ฒฐ๊ณผ๋ฅผ ํ›„์† ๋‹จ๊ณ„๋กœ ๋„˜๊ธฐ์ง€ ์•Š์•„ ์žฌ์ฒ˜๋ฆฌ ๋น„์šฉ ๊ฐ์†Œ.

์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • smolagents ์„ค์น˜ ์™„๋ฃŒ
  • day20_validation_gate.py ๋ฌธ๋ฒ• ๊ฒ€์‚ฌ ํ†ต๊ณผ
  • ์ •์ƒ ์ผ€์ด์Šค์—์„œ ok=true ํ™•์ธ
  • ์‹คํŒจ ์ผ€์ด์Šค์—์„œ validation_failed ์ข…๋ฃŒ ํ™•์ธ
  • result.json์— ok/reason/data ๊ตฌ์กฐ ํ™•์ธ

์ฐธ๊ณ  ๋งํฌ (์šฐ์„ ์ˆœ์œ„)

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

์ƒ์„ฑํ˜• AI ํ™œ์šฉ ๊ณ ์ง€

์ด ๋ฌธ์„œ๋Š” ์ƒ์„ฑํ˜• AI๋ฅผ ํ™œ์šฉํ•ด ์ดˆ์•ˆ์„ ์ž‘์„ฑํ–ˆ๊ณ , ์‹ค์Šต ์ ˆ์ฐจ(๋„๊ตฌ/์ž…๋ ฅ/์‹คํ–‰๋ช…๋ น/์„ฑ๊ณตํŒ์ •)์™€ ์˜ˆ์‹œ ์ฝ”๋“œ๋Š” ์‚ฌ๋žŒ์ด ๊ฒ€ํ† ํ•ด ํ™•์ •ํ–ˆ๋‹ค.