์ด๋ฒˆ ํŽธ์€ โ€œ์‚ฌ๋žŒ์ด ์ฝ๊ธฐ ์ข‹์€ ๋‹ต๋ณ€โ€์—์„œ ํ•œ ๋‹จ๊ณ„ ๋” ๋‚˜์•„๊ฐ€, ์ž๋™ํ™”๊ฐ€ ๋ฐ”๋กœ ๋จน์„ ์ˆ˜ ์žˆ๋Š” JSON ์ถœ๋ ฅ ๊ณ„์•ฝ์„ ๋งŒ๋“œ๋Š” ์‹ค์Šต์ด๋‹ค.
ํ•ต์‹ฌ์€ ๊ฐ„๋‹จํ•˜๋‹ค: ์—์ด์ „ํŠธ ์„ฑ๋Šฅ๋ณด๋‹ค ๋จผ์ € ์ถœ๋ ฅ ์Šคํ‚ค๋งˆ๋ฅผ ๊ณ ์ •ํ•˜๋ฉด, n8n/์Šคํฌ๋ฆฝํŠธ ์—ฐ๋™ ์‹คํŒจ๊ฐ€ ํฌ๊ฒŒ ์ค„์–ด๋“ ๋‹ค.

  • ์ด์ „ ํŽธ: ๐Ÿค— 16. ์‹ค์ŠตํŽธ 04
  • ๋‹ค์Œ ํ™•์žฅ: JSON Schema ๊ฒ€์ฆ + ์žฌ์‹œ๋„ ์ •์ฑ…(ValidationError ์‹œ 1ํšŒ ์ž๋™ ์žฌ์ƒ์„ฑ)

ํ•œ ์ค„ ๊ฒฐ๋ก 

์—์ด์ „ํŠธ๋ฅผ ์—…๋ฌด์— ๋ถ™์ผ ๋•Œ๋Š” โ€œ์ •๋‹ต๋ฅ โ€๋ณด๋‹ค ๋จผ์ € โ€œํŒŒ์‹ฑ ๊ฐ€๋Šฅ์„ฑ(๊ตฌ์กฐํ™” ์ถœ๋ ฅ)โ€œ์„ ๊ณ ์ •ํ•˜๋ผ.

flowchart LR
  U[์‚ฌ์šฉ์ž ์ž…๋ ฅ] --> A[CodeAgent]
  A --> T[DuckDuckGoSearchTool]
  T --> A
  A --> J[JSON ๋ฌธ์ž์—ด ์ƒ์„ฑ]
  J --> V[ํŒŒ์ด์ฌ json ๊ฒ€์ฆ]
  V --> O[์ž๋™ํ™” ํŒŒ์ดํ”„๋ผ์ธ ์ „๋‹ฌ]

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

  • smolagents CodeAgent๋กœ ๊ฒ€์ƒ‰ ๊ธฐ๋ฐ˜ ๋‹ต๋ณ€์„ ๋งŒ๋“ ๋‹ค.
  • ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜๋“œ์‹œ JSON ๊ณ„์•ฝ์œผ๋กœ ์ถœ๋ ฅํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.
  • ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ์ฆ‰์‹œ ์‹คํŒจ ์›์ธ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ ๋‹ค.

์ค€๋น„๋ฌผ

  • ๋„๊ตฌ: Python 3.10+, ํ„ฐ๋ฏธ๋„
  • ์ž…๋ ฅ: API ํ‚ค 1๊ฐœ(OpenAI ํ˜ธํ™˜)
  • ์ž‘์—… ํด๋” ์˜ˆ์‹œ: ~/hf-agents-lesson17

์‹ค๋ฌด ํŒ: ํŒ€ ๋‚ด ์ž๋™ํ™” ์—ฐ๋™์ด ๋ชฉ์ ์ด๋ฉด, ์ž์—ฐ์–ด ํ’ˆ์งˆ๋ณด๋‹ค ๋จผ์ € โ€œํŒŒ์‹ฑ 100%โ€ ๋ชฉํ‘œ๋ฅผ ๋‘๋Š” ๊ฒŒ ์œ ์ง€๋ณด์ˆ˜์— ์œ ๋ฆฌํ•˜๋‹ค.


1) ํ™˜๊ฒฝ ์ค€๋น„

  • ๋„๊ตฌ: ํ„ฐ๋ฏธ๋„
  • ์ž…๋ ฅ: ๊ฐ€์ƒํ™˜๊ฒฝ + ํŒจํ‚ค์ง€
  • ์‹คํ–‰๋ช…๋ น:
mkdir -p ~/hf-agents-lesson17
cd ~/hf-agents-lesson17
python3 -m venv .venv
source .venv/bin/activate
pip install -U smolagents litellm duckduckgo-search
  • ์„ฑ๊ณตํŒ์ •:
    • (.venv) ํ‘œ์‹œ
    • ์„ค์น˜ ์—๋Ÿฌ ์—†์Œ

2) ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •

  • ๋„๊ตฌ: ํ„ฐ๋ฏธ๋„
  • ์ž…๋ ฅ: ๋ชจ๋ธ/API ํ‚ค
  • ์‹คํ–‰๋ช…๋ น:
export OPENAI_API_KEY="YOUR_API_KEY"
export MODEL_ID="openai/gpt-4o-mini"
  • ์„ฑ๊ณตํŒ์ •:
    • echo $MODEL_ID ๊ฐ’ ํ™•์ธ ๊ฐ€๋Šฅ
    • OPENAI_API_KEY ๊ธธ์ด๊ฐ€ 1๋ณด๋‹ค ํผ

3) JSON ๊ณ„์•ฝ ์—์ด์ „ํŠธ ์ž‘์„ฑ

  • ๋„๊ตฌ: ์—๋””ํ„ฐ ๋˜๋Š” ํ„ฐ๋ฏธ๋„
  • ์ž…๋ ฅ: ์•„๋ž˜ ์ฝ”๋“œ
  • ์‹คํ–‰๋ช…๋ น:
cat > lesson17_json_contract_agent.py <<'PY'
from __future__ import annotations
 
import json
import os
from typing import Any
 
from smolagents import CodeAgent, DuckDuckGoSearchTool, LiteLLMModel
 
 
SYSTEM_PROMPT = """
๋„ˆ๋Š” ์‹ค๋ฌด ๋ฆฌ์„œ์น˜ ๋ณด์กฐ ์—์ด์ „ํŠธ๋‹ค.
๋ฐ˜๋“œ์‹œ JSON ๋ฌธ์ž์—ด๋งŒ ์ถœ๋ ฅํ•˜๋ผ(์ฝ”๋“œ๋ธ”๋ก ๊ธˆ์ง€, ์„ค๋ช…๋ฌธ ๊ธˆ์ง€).
์Šคํ‚ค๋งˆ:
{
  "topic": "string",
  "key_points": ["string", "string", "string"],
  "sources": ["https://...", "https://..."]
}
๊ทœ์น™:
- key_points๋Š” ์ •ํ™•ํžˆ 3๊ฐœ
- sources๋Š” ์ตœ์†Œ 2๊ฐœ
- ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑ
""".strip()
 
 
def build_agent() -> CodeAgent:
    model_id = os.getenv("MODEL_ID", "openai/gpt-4o-mini")
    model = LiteLLMModel(model_id=model_id)
    return CodeAgent(
        tools=[DuckDuckGoSearchTool()],
        model=model,
        system_prompt=SYSTEM_PROMPT,
        additional_authorized_imports=["json", "re"],
    )
 
 
def validate_payload(payload: dict[str, Any]) -> None:
    assert isinstance(payload.get("topic"), str) and payload["topic"].strip()
    assert isinstance(payload.get("key_points"), list) and len(payload["key_points"]) == 3
    assert all(isinstance(x, str) and x.strip() for x in payload["key_points"])
    assert isinstance(payload.get("sources"), list) and len(payload["sources"]) >= 2
    assert all(isinstance(x, str) and x.startswith("http") for x in payload["sources"])
 
 
def main() -> None:
    question = "์ค‘์†Œ SaaS ํŒ€์ด AI ์—์ด์ „ํŠธ๋ฅผ ๋„์ž…ํ•  ๋•Œ 30์ผ ๋‚ด ์ฒด๊ฐ ๊ฐ€๋Šฅํ•œ ์šด์˜ ์ด์  3๊ฐ€์ง€๋ฅผ ์ •๋ฆฌํ•ด์ค˜"
    agent = build_agent()
    raw = str(agent.run(question)).strip()
 
    try:
        data = json.loads(raw)
        validate_payload(data)
    except Exception as e:
        raise SystemExit(f"JSON ๊ณ„์•ฝ ๊ฒ€์ฆ ์‹คํŒจ: {e}\n์›๋ฌธ ์ถœ๋ ฅ:\n{raw}")
 
    print(json.dumps(data, ensure_ascii=False, indent=2))
 
 
if __name__ == "__main__":
    main()
PY
  • ์„ฑ๊ณตํŒ์ •:
    • lesson17_json_contract_agent.py ํŒŒ์ผ ์ƒ์„ฑ
    • ์ฝ”๋“œ์— json.loads + ๊ฒ€์ฆ ๋กœ์ง ํฌํ•จ

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

  • ๋„๊ตฌ: Python
  • ์ž…๋ ฅ: ์งˆ๋ฌธ 1๊ฐœ(์ฝ”๋“œ ๋‚ด๋ถ€ ๊ธฐ๋ณธ๊ฐ’)
  • ์‹คํ–‰๋ช…๋ น:
python lesson17_json_contract_agent.py
  • ์„ฑ๊ณตํŒ์ •:
    • JSON ํ˜•ํƒœ๋กœ ์ถœ๋ ฅ๋จ
    • key_points ์ •ํ™•ํžˆ 3๊ฐœ
    • sources 2๊ฐœ ์ด์ƒ
    • ์˜ค๋ฅ˜ ์—†์ด ์ข…๋ฃŒ ์ฝ”๋“œ 0

5) ์‹คํŒจ ๋ณต๊ตฌ(์ดˆ๋ณด์ž ์ฒดํฌ)

  • ๋„๊ตฌ: ํ„ฐ๋ฏธ๋„
  • ์ž…๋ ฅ: ์ง„๋‹จ ๋ช…๋ น
  • ์‹คํ–‰๋ช…๋ น:
pip show smolagents litellm duckduckgo-search
 
python - <<'PY'
import os
print("OPENAI_API_KEY set:", bool(os.getenv("OPENAI_API_KEY")))
print("MODEL_ID:", os.getenv("MODEL_ID", "openai/gpt-4o-mini"))
PY
  • ์„ฑ๊ณตํŒ์ •:
    • ๋ˆ„๋ฝ ํŒจํ‚ค์ง€/ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ฆ‰์‹œ ํŒŒ์•… ๊ฐ€๋Šฅ

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

  1. ์ถœ๋ ฅ ๊ณ„์•ฝ์„ ์ฝ”๋“œ๋กœ ๊ฒ€์ฆ
    • โ€œ๋Œ€์ถฉ ๋งž๋Š” ๋‹ตโ€ ๋Œ€์‹  โ€œ์ž๋™ํ™”๊ฐ€ ์†Œ๋น„ ๊ฐ€๋Šฅํ•œ ๋‹ตโ€์„ ๋ณด์žฅ
  2. ์‹คํŒจ๋ฅผ ์กฐ์šฉํžˆ ๋„˜๊ธฐ์ง€ ์•Š๊ธฐ
    • ๊ฒ€์ฆ ์‹คํŒจ ์‹œ ์ฆ‰์‹œ ์ข…๋ฃŒํ•˜๋ฉด ๋ฐ์ดํ„ฐ ์˜ค์—ผ ๋ฐฉ์ง€ ๊ฐ€๋Šฅ
  3. ์ตœ์†Œ ์Šคํ‚ค๋งˆ๋ถ€ํ„ฐ ์‹œ์ž‘
    • topic/key_points/sources 3ํ•„๋“œ๋งŒ์œผ๋กœ๋„ ๋Œ€๋ถ€๋ถ„์˜ ๋ฆฌ์„œ์น˜ ์ž๋™ํ™” ์‹œ์ž‘ ๊ฐ€๋Šฅ
  4. ํ–ฅํ›„ ํ™•์žฅ ๊ฒฝ๋กœ๊ฐ€ ๋ช…ํ™•
    • ๋‹ค์Œ ๋‹จ๊ณ„: Pydantic ๋ชจ๋ธ ๊ฒ€์ฆ, ์žฌ์‹œ๋„ ์ •์ฑ…, ๋กœ๊ทธ ์ ์žฌ

์ž์ฃผ ๋ง‰ํžˆ๋Š” ๋ฌธ์ œ

  1. ๋ชจ๋ธ์ด JSON ์™ธ ํ…์ŠคํŠธ๋ฅผ ์„ž์–ด ์ถœ๋ ฅ
    • ํ•ด๊ฒฐ: ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ์— โ€œ์ฝ”๋“œ๋ธ”๋ก ๊ธˆ์ง€/์„ค๋ช…๋ฌธ ๊ธˆ์ง€โ€๋ฅผ ๋ช…์‹œ
  2. sources๊ฐ€ 1๊ฐœ๋งŒ ๋‚˜์˜ค๋Š” ๋ฌธ์ œ
    • ํ•ด๊ฒฐ: ์Šคํ‚ค๋งˆ ๊ทœ์น™ + ๊ฒ€์ฆ assert๋กœ ๊ฐ•์ œ
  3. ๊ฒ€์ƒ‰ ํ’ˆ์งˆ์ด ๋“ค์‘ฅ๋‚ ์‘ฅํ•จ
    • ํ•ด๊ฒฐ: ์งˆ๋ฌธ์— ๊ธฐ๊ฐ„/๋„๋ฉ”์ธ/๊ด€์ (์˜ˆ: ์šด์˜๋น„์šฉ, SLA)์„ ๋ช…์‹œ

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

  • ๊ฐ€์ƒํ™˜๊ฒฝ/ํŒจํ‚ค์ง€ ์„ค์น˜ ์™„๋ฃŒ
  • API ํ‚ค/๋ชจ๋ธ ์„ค์ • ์™„๋ฃŒ
  • JSON ์ถœ๋ ฅ ํŒŒ์‹ฑ ์„ฑ๊ณต
  • key_points=3, sources>=2 ๊ฒ€์ฆ ์„ฑ๊ณต
  • ์‹คํŒจ ์‹œ ์˜ค๋ฅ˜๋ฌธ์œผ๋กœ ์›์ธ ํ™•์ธ ๊ฐ€๋Šฅ

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

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

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

์ด ๋ฌธ์„œ๋Š” ์ƒ์„ฑํ˜• AI๋ฅผ ํ™œ์šฉํ•ด ์ดˆ์•ˆ ๊ตฌ์„ฑ, ์‹ค์Šต ์ฝ”๋“œ ์ •๋ฆฌ, ์ฒดํฌ๋ฆฌ์ŠคํŠธ ๊ตฌ์กฐํ™”๋ฅผ ์ˆ˜ํ–‰ํ–ˆ์œผ๋ฉฐ, ์ตœ์ข… ๋ฐœํ–‰ ์ „ ์‚ฌ๋žŒ์ด ๋งํฌ/๋ช…๋ น/์ถœ๋ ฅ ๊ณ„์•ฝ์„ ๊ฒ€ํ† ํ–ˆ๋‹ค.