์ด๋ฒ ํธ์ โ์ฌ๋์ด ์ฝ๊ธฐ ์ข์ ๋ต๋ณโ์์ ํ ๋จ๊ณ ๋ ๋์๊ฐ, ์๋ํ๊ฐ ๋ฐ๋ก ๋จน์ ์ ์๋ 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[์๋ํ ํ์ดํ๋ผ์ธ ์ ๋ฌ]
์ค์ต ๋ชฉํ
smolagentsCodeAgent๋ก ๊ฒ์ ๊ธฐ๋ฐ ๋ต๋ณ์ ๋ง๋ ๋ค.- ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋์ 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๊ฐsources2๊ฐ ์ด์- ์ค๋ฅ ์์ด ์ข ๋ฃ ์ฝ๋ 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- ์ฑ๊ณตํ์ :
- ๋๋ฝ ํจํค์ง/ํ๊ฒฝ๋ณ์ ์ฆ์ ํ์ ๊ฐ๋ฅ
์ค๋ฌด ์ ์ฉ ํฌ์ธํธ
- ์ถ๋ ฅ ๊ณ์ฝ์ ์ฝ๋๋ก ๊ฒ์ฆ
- โ๋์ถฉ ๋ง๋ ๋ตโ ๋์ โ์๋ํ๊ฐ ์๋น ๊ฐ๋ฅํ ๋ตโ์ ๋ณด์ฅ
- ์คํจ๋ฅผ ์กฐ์ฉํ ๋๊ธฐ์ง ์๊ธฐ
- ๊ฒ์ฆ ์คํจ ์ ์ฆ์ ์ข ๋ฃํ๋ฉด ๋ฐ์ดํฐ ์ค์ผ ๋ฐฉ์ง ๊ฐ๋ฅ
- ์ต์ ์คํค๋ง๋ถํฐ ์์
topic/key_points/sources3ํ๋๋ง์ผ๋ก๋ ๋๋ถ๋ถ์ ๋ฆฌ์์น ์๋ํ ์์ ๊ฐ๋ฅ
- ํฅํ ํ์ฅ ๊ฒฝ๋ก๊ฐ ๋ช
ํ
- ๋ค์ ๋จ๊ณ: Pydantic ๋ชจ๋ธ ๊ฒ์ฆ, ์ฌ์๋ ์ ์ฑ , ๋ก๊ทธ ์ ์ฌ
์์ฃผ ๋งํ๋ ๋ฌธ์
- ๋ชจ๋ธ์ด JSON ์ธ ํ
์คํธ๋ฅผ ์์ด ์ถ๋ ฅ
- ํด๊ฒฐ: ์์คํ ํ๋กฌํํธ์ โ์ฝ๋๋ธ๋ก ๊ธ์ง/์ค๋ช ๋ฌธ ๊ธ์งโ๋ฅผ ๋ช ์
- sources๊ฐ 1๊ฐ๋ง ๋์ค๋ ๋ฌธ์
- ํด๊ฒฐ: ์คํค๋ง ๊ท์น + ๊ฒ์ฆ assert๋ก ๊ฐ์
- ๊ฒ์ ํ์ง์ด ๋ค์ฅ๋ ์ฅํจ
- ํด๊ฒฐ: ์ง๋ฌธ์ ๊ธฐ๊ฐ/๋๋ฉ์ธ/๊ด์ (์: ์ด์๋น์ฉ, SLA)์ ๋ช ์
์ฒดํฌ๋ฆฌ์คํธ
- ๊ฐ์ํ๊ฒฝ/ํจํค์ง ์ค์น ์๋ฃ
- API ํค/๋ชจ๋ธ ์ค์ ์๋ฃ
- JSON ์ถ๋ ฅ ํ์ฑ ์ฑ๊ณต
-
key_points=3,sources>=2๊ฒ์ฆ ์ฑ๊ณต - ์คํจ ์ ์ค๋ฅ๋ฌธ์ผ๋ก ์์ธ ํ์ธ ๊ฐ๋ฅ
์ฐธ๊ณ ๋งํฌ (์ฐ์ ์์)
- https://github.com/huggingface/agents-course
- https://huggingface.co/learn/agents-course
- https://huggingface.co/docs/smolagents
์์ฑํ AI ํ์ฉ ๊ณ ์ง
์ด ๋ฌธ์๋ ์์ฑํ AI๋ฅผ ํ์ฉํด ์ด์ ๊ตฌ์ฑ, ์ค์ต ์ฝ๋ ์ ๋ฆฌ, ์ฒดํฌ๋ฆฌ์คํธ ๊ตฌ์กฐํ๋ฅผ ์ํํ์ผ๋ฉฐ, ์ต์ข ๋ฐํ ์ ์ฌ๋์ด ๋งํฌ/๋ช ๋ น/์ถ๋ ฅ ๊ณ์ฝ์ ๊ฒํ ํ๋ค.