๋ชฉํ‘œ

Hugging Face Agents Course ํ๋ฆ„์„ ๋”ฐ๋ผ, smolagents ๊ธฐ๋ฐ˜ ๋ฏธ๋‹ˆ ํ”„๋กœ์ ํŠธ(๋„๊ตฌํ˜• ์—์ด์ „ํŠธ)๋ฅผ ๋กœ์ปฌ์—์„œ ์žฌํ˜„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋๊นŒ์ง€ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ (์šฐ์„ ์ˆœ์œ„):

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

์‹ค์Šต ์‹œ๋‚˜๋ฆฌ์˜ค

์š”์ฒญ: โ€œ์„œ์šธ ์˜ค๋Š˜ ๋‚ ์”จ๋ฅผ ํ™•์ธํ•˜๊ณ , ์šฐ์‚ฐ ํ•„์š” ์—ฌ๋ถ€๋ฅผ ํ•œ ์ค„๋กœ ํŒ๋‹จํ•ด์ค˜โ€

์—์ด์ „ํŠธ๋Š” ๋‹ค์Œ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • get_weather(city): Open-Meteo API ํ˜ธ์ถœ
  • summarize(text): ํŒ๋‹จ ๋ฌธ์žฅ ์ƒ์„ฑ
flowchart TD
    A[์‚ฌ์šฉ์ž ์š”์ฒญ ์ž…๋ ฅ] --> B[CodeAgent ์‹คํ–‰]
    B --> C[get_weather ๋„๊ตฌ ํ˜ธ์ถœ]
    C --> D[๊ธฐ์˜จ/๊ฐ•์ˆ˜ํ™•๋ฅ  ํŒŒ์‹ฑ]
    D --> E[summarize ๋„๊ตฌ ํ˜ธ์ถœ]
    E --> F[์ตœ์ข… ๋‹ต๋ณ€ ๋ฐ˜ํ™˜]

1) ์ค€๋น„

๋„๊ตฌ

  • Python 3.10+
  • pip
  • (์„ ํƒ) .env ๋กœ๋“œ ๋„๊ตฌ

์ž…๋ ฅ

  • ์œ„์น˜: Seoul
  • ๋ชจ๋ธ: Qwen/Qwen2.5-Coder-32B-Instruct (Hugging Face Inference API ๊ธฐ์ค€ ์˜ˆ์‹œ)

์‹คํ–‰ ๋ช…๋ น

mkdir -p ~/lab/hf-agents-mini && cd ~/lab/hf-agents-mini
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install smolagents requests python-dotenv

์„ฑ๊ณต ํŒ์ •

  • pip show smolagents ๊ฒฐ๊ณผ๊ฐ€ ์ถœ๋ ฅ๋จ
  • ๊ฐ€์ƒํ™˜๊ฒฝ ํ”„๋กฌํ”„ํŠธ (.venv) ํ™•์ธ

2) ์ฝ”๋“œ ์ž‘์„ฑ

mini_project.py

import os
import requests
from smolagents import CodeAgent, tool
from smolagents.models import InferenceClientModel
 
@tool
def get_weather(city: str) -> str:
    """๋„์‹œ๋ช…์œผ๋กœ ํ˜„์žฌ ๊ธฐ์˜จ/๊ฐ•์ˆ˜ํ™•๋ฅ ์„ ์กฐํšŒํ•œ๋‹ค."""
    geo = requests.get(
        "https://geocoding-api.open-meteo.com/v1/search",
        params={"name": city, "count": 1, "language": "en", "format": "json"},
        timeout=15,
    ).json()
 
    if not geo.get("results"):
        return f"๋„์‹œ๋ฅผ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค: {city}"
 
    lat = geo["results"][0]["latitude"]
    lon = geo["results"][0]["longitude"]
 
    weather = requests.get(
        "https://api.open-meteo.com/v1/forecast",
        params={
            "latitude": lat,
            "longitude": lon,
            "current": "temperature_2m,precipitation_probability",
        },
        timeout=15,
    ).json()
 
    current = weather.get("current", {})
    t = current.get("temperature_2m", "N/A")
    p = current.get("precipitation_probability", "N/A")
    return f"{city} ํ˜„์žฌ ๊ธฐ์˜จ {t}ยฐC, ๊ฐ•์ˆ˜ํ™•๋ฅ  {p}%"
 
@tool
def summarize(text: str) -> str:
    """๋‚ ์”จ ๋ฌธ์žฅ์„ ๋ฐ”ํƒ•์œผ๋กœ ์šฐ์‚ฐ ํ•„์š” ์—ฌ๋ถ€๋ฅผ ํ•œ ์ค„๋กœ ์š”์•ฝํ•œ๋‹ค."""
    return f"์š”์•ฝ: {text}. ๊ฐ•์ˆ˜ํ™•๋ฅ ์ด 50% ์ด์ƒ์ด๋ฉด ์šฐ์‚ฐ ๊ถŒ์žฅ."
 
model = InferenceClientModel(
    model_id="Qwen/Qwen2.5-Coder-32B-Instruct",
    token=os.getenv("HF_TOKEN"),
)
 
agent = CodeAgent(
    model=model,
    tools=[get_weather, summarize],
)
 
if __name__ == "__main__":
    task = "์„œ์šธ ์˜ค๋Š˜ ๋‚ ์”จ๋ฅผ ํ™•์ธํ•˜๊ณ  ์šฐ์‚ฐ ํ•„์š” ์—ฌ๋ถ€๋ฅผ ํ•œ ์ค„๋กœ ์•Œ๋ ค์ค˜."
    result = agent.run(task)
    print(result)

์„ฑ๊ณต ํŒ์ •

  • ํŒŒ์ผ ์ €์žฅ ์™„๋ฃŒ
  • ๋ฌธ๋ฒ• ์˜ค๋ฅ˜ ์—†์Œ (python -m py_compile mini_project.py ํ†ต๊ณผ)

3) ์‹คํ–‰

์‹คํ–‰ ๋ช…๋ น

export HF_TOKEN="hf_xxx"
python mini_project.py

์„ฑ๊ณต ํŒ์ •

  • ์ตœ์ข… ์ถœ๋ ฅ์— ์„œ์šธ ํ˜„์žฌ ๊ธฐ์˜จ ๊ณผ ์šฐ์‚ฐ ๊ด€๋ จ ๋ฌธ๊ตฌ ํฌํ•จ
  • ์˜ˆ์™ธ ์ข…๋ฃŒ ์—†์ด ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ ์ฝ”๋“œ 0

4) ๊ฒ€์ฆ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • ๋„๊ตฌ ํ˜ธ์ถœ 2๊ฐœ(get_weather, summarize)๊ฐ€ ์‹ค์ œ ์‚ฌ์šฉ๋จ
  • ์ž…๋ ฅ ๋„์‹œ๋ฅผ ๋ฐ”๊ฟ”๋„ ๋™์ž‘ํ•จ (์˜ˆ: Busan)
  • ๊ฐ•์ˆ˜ํ™•๋ฅ  ์ˆ˜์น˜๊ฐ€ ์‘๋‹ต์— ํฌํ•จ๋จ
  • ํ•œ ์ค„ ์š”์•ฝ ๊ฒฐ๊ณผ๊ฐ€ ์ƒ์„ฑ๋จ

ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… (3+)

  1. 401 Unauthorized / ๋ชจ๋ธ ํ˜ธ์ถœ ์‹คํŒจ

    • ์›์ธ: HF_TOKEN ๋ˆ„๋ฝ/๋งŒ๋ฃŒ
    • ํ•ด๊ฒฐ: ์ƒˆ ํ† ํฐ ์žฌ๋ฐœ๊ธ‰ ํ›„ export HF_TOKEN=... ์žฌ์„ค์ •
  2. ModuleNotFoundError: smolagents

    • ์›์ธ: ๊ฐ€์ƒํ™˜๊ฒฝ ๋ฏธํ™œ์„ฑํ™” ๋˜๋Š” ์„ค์น˜ ๋ˆ„๋ฝ
    • ํ•ด๊ฒฐ: source .venv/bin/activate && pip install smolagents
  3. Open-Meteo ํƒ€์ž„์•„์›ƒ (ReadTimeout)

    • ์›์ธ: ๋„คํŠธ์›Œํฌ ์ง€์—ฐ
    • ํ•ด๊ฒฐ: timeout 15โ†’30 ์ฆ๊ฐ€, ์žฌ์‹œ๋„ ๋กœ์ง ์ถ”๊ฐ€
  4. ๋„์‹œ ๊ฒ€์ƒ‰ ์‹คํŒจ (results ์—†์Œ)

    • ์›์ธ: ์ž…๋ ฅ ๋„์‹œ๋ช… ํ‘œ๊ธฐ ์ด์Šˆ
    • ํ•ด๊ฒฐ: ์˜๋ฌธ ํ‘œ๊ธฐ ์‚ฌ์šฉ(์˜ˆ: Seoul, Busan) ๋˜๋Š” ๊ตญ๊ฐ€ ์ฝ”๋“œ ํ™•์žฅ

ํ™•์žฅ ๊ณผ์ œ

  • ๋„์‹œ ๋ชฉ๋ก(์„œ์šธ/๋ถ€์‚ฐ/๋Œ€๊ตฌ)์„ ์ˆœ์ฐจ ํ‰๊ฐ€ํ•ด ์šฐ์‚ฐ ํ•„์š” ๋„์‹œ๋งŒ ์ถœ๋ ฅ
  • ToolCallingAgent ๋ฒ„์ „์œผ๋กœ ํฌํŒ…ํ•ด ํ˜ธ์ถœ ์ถ”์  ๋กœ๊ทธ ๋น„๊ต
  • ๊ฒฐ๊ณผ๋ฅผ Markdown ๋ฆฌํฌํŠธ ํŒŒ์ผ๋กœ ์ €์žฅ

์ƒ์„ฑํ˜• AI ํ™œ์šฉ ๊ณ ์ง€: ์ด ๋ฌธ์„œ๋Š” ์ƒ์„ฑํ˜• AI๋กœ ์ดˆ์•ˆ์„ ๊ตฌ์„ฑํ•œ ๋’ค, ์‹ค์Šต ์žฌํ˜„์„ฑ(๋ช…๋ น/๊ฒ€์ฆ/์˜ค๋ฅ˜ ๋Œ€์‘)์„ ๊ธฐ์ค€์œผ๋กœ ์‚ฌ๋žŒ์ด ๊ฒ€ํ† ยท์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.