์ด๋ฒˆ ํŽธ์€ ๊ฐ™์€ ์œ ํ˜•์˜ ์š”์ฒญ์ด ๋ฐ˜๋ณต๋  ๋•Œ, ์—์ด์ „ํŠธ๊ฐ€ ์ด์ „ ๊ฒฐ๊ณผ๋ฅผ ์žฌํ™œ์šฉํ•ด ๋” ๋น ๋ฅด๊ณ  ์ผ๊ด€๋˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ๊ธฐ๋ณธ ํŒจํ„ด์„ ๋‹ค๋ฃฌ๋‹ค.

flowchart LR
  A[์š”์ฒญ ์ž…๋ ฅ] --> B[CodeAgent]
  B --> C{state.json์—
์ด์ „ ์š”์•ฝ ์žˆ์Œ?}
  C -- ์žˆ์Œ --> D[๊ธฐ์กด ์š”์•ฝ ๋ณด๊ฐ•]
  C -- ์—†์Œ --> E[์‹ ๊ทœ ์š”์•ฝ ์ƒ์„ฑ]
  D --> F[save_state ๋„๊ตฌ๋กœ ์ €์žฅ]
  E --> F
  F --> G[result.json ์ถœ๋ ฅ]

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

  1. state.json์— ์ด์ „ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•œ๋‹ค.
  2. ๋‹ค์Œ ์‹คํ–‰ ๋•Œ state.json์„ ์ฝ์–ด ๋‹ต๋ณ€ ํ’ˆ์งˆ์„ ๋†’์ธ๋‹ค.
  3. ๊ฒฐ๊ณผ๋ฅผ result.json์œผ๋กœ ๋‚จ๊ฒจ ์žฌํ˜„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๊ฒ€์ฆํ•œ๋‹ค.

1) ์ค€๋น„

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

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

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

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. ์ฒซ ์š”์ฒญ ์ƒ์„ฑ

  • ๋„๊ตฌ: ํ…์ŠคํŠธ ํŒŒ์ผ
  • ์ž…๋ ฅ: ์•„๋ž˜ ๋‚ด์šฉ
  • ์‹คํ–‰๋ช…๋ น:
cat <<'TXT' > task.txt
๊ณ ๊ฐ์ง€์› ์š”์•ฝ:
- ๋ฐฐ์†ก ์ง€์—ฐ ๋ฌธ์˜ ์ฆ๊ฐ€
- ๊ฒฐ์ œ ์‹คํŒจ ์ด์Šˆ ๊ฐ„ํ— ๋ฐœ์ƒ
- ํ™˜๋ถˆ ๋ฌธ์˜ ๊ฐ์†Œ
TXT
  • ์„ฑ๊ณตํŒ์ •:
test -f task.txt && echo FILE_OK

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

Step 3-1. day19_stateful_agent.py ์ €์žฅ

  • ๋„๊ตฌ: Python ํŒŒ์ผ
  • ์ž…๋ ฅ: ์•„๋ž˜ ์ฝ”๋“œ
import json
from pathlib import Path
 
from smolagents import CodeAgent, HfApiModel, tool
 
STATE_PATH = Path("state.json")
RESULT_PATH = Path("result.json")
TASK_PATH = Path("task.txt")
 
 
@tool
def load_state() -> str:
    """์ €์žฅ๋œ ์ƒํƒœ(JSON ๋ฌธ์ž์—ด)๋ฅผ ์ฝ๋Š”๋‹ค. ์—†์œผ๋ฉด ๋นˆ ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค."""
    if not STATE_PATH.exists():
        return json.dumps({"history": []}, ensure_ascii=False)
    return STATE_PATH.read_text(encoding="utf-8")
 
 
@tool
def save_state(payload: str) -> str:
    """์ƒํƒœ(JSON ๋ฌธ์ž์—ด)๋ฅผ ์ €์žฅํ•œ๋‹ค."""
    obj = json.loads(payload)
    STATE_PATH.write_text(json.dumps(obj, ensure_ascii=False, indent=2), encoding="utf-8")
    return f"saved:{STATE_PATH}"
 
 
def build_agent() -> CodeAgent:
    model = HfApiModel("Qwen/Qwen2.5-72B-Instruct")
    return CodeAgent(
        tools=[load_state, save_state],
        model=model,
        max_steps=6,
        additional_authorized_imports=["json"],
    )
 
 
if __name__ == "__main__":
    task_text = TASK_PATH.read_text(encoding="utf-8")
 
    prompt = f"""
๋„ˆ๋Š” ๊ณ ๊ฐ์ง€์› ์š”์•ฝ ์–ด์‹œ์Šคํ„ดํŠธ๋‹ค.
๋ฐ˜๋“œ์‹œ ๋‹ค์Œ ์ˆœ์„œ๋กœ ์ง„ํ–‰ํ•ด:
1) load_state ํ˜ธ์ถœ
2) ์ž…๋ ฅ ํ…์ŠคํŠธ๋ฅผ 3์ค„๋กœ ์š”์•ฝ
3) ๊ธฐ์กด history์— ์ด๋ฒˆ ์š”์•ฝ์„ ์ถ”๊ฐ€ํ•œ JSON์„ ๋งŒ๋“ค๊ณ  save_state ํ˜ธ์ถœ
4) ์ตœ์ข…์œผ๋กœ ์•„๋ž˜ JSON๋งŒ ๋ฐ˜ํ™˜
 
์ถœ๋ ฅ ์Šคํ‚ค๋งˆ:
{{
  "summary": ["...", "...", "..."],
  "history_count": 0,
  "applied_memory": true
}}
 
์ž…๋ ฅ:
{task_text}
"""
 
    agent = build_agent()
    result = agent.run(prompt)
 
    # ๋ชจ๋ธ ์ถœ๋ ฅ์ด ๋ฌธ์ž์—ด์ผ ์ˆ˜ ์žˆ์–ด, JSON ํŒŒ์‹ฑ ํ›„ ํŒŒ์ผ ์ €์žฅ
    if isinstance(result, str):
        cleaned = result.strip().removeprefix("```json").removesuffix("```").strip()
        obj = json.loads(cleaned)
    else:
        obj = result
 
    RESULT_PATH.write_text(json.dumps(obj, ensure_ascii=False, indent=2), encoding="utf-8")
    print("saved: result.json")
  • ์„ฑ๊ณตํŒ์ •:
python -m py_compile day19_stateful_agent.py

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


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

Step 4-1. 1์ฐจ ์‹คํ–‰

  • ๋„๊ตฌ: Python
  • ์ž…๋ ฅ: task.txt
  • ์‹คํ–‰๋ช…๋ น:
python day19_stateful_agent.py
cat result.json
cat state.json
  • ์„ฑ๊ณตํŒ์ •:
    • saved: result.json ์ถœ๋ ฅ
    • state.json์˜ history ๊ธธ์ด 1

Step 4-2. 2์ฐจ ์‹คํ–‰(๋ฉ”๋ชจ๋ฆฌ ์ ์šฉ ํ™•์ธ)

  • ๋„๊ตฌ: ํ…์ŠคํŠธ ํŒŒ์ผ + Python
  • ์ž…๋ ฅ: ๋‹ค๋ฅธ ์š”์ฒญ
  • ์‹คํ–‰๋ช…๋ น:
cat <<'TXT' > task.txt
๊ณ ๊ฐ์ง€์› ์š”์•ฝ:
- ๋ฐฐ์†ก ์ง€์—ฐ ๋ฌธ์˜๋Š” ๋น„์Šทํ•œ ์ˆ˜์ค€
- ๊ฒฐ์ œ ์‹คํŒจ ์ด์Šˆ ๊ฐ์†Œ
- ๋ฐ˜ํ’ˆ ๋ฌธ์˜ ์†Œํญ ์ฆ๊ฐ€
TXT
 
python day19_stateful_agent.py
python - <<'PY'
import json
state = json.load(open('state.json', encoding='utf-8'))
res = json.load(open('result.json', encoding='utf-8'))
print('history_len =', len(state.get('history', [])))
print('has_summary =', isinstance(res.get('summary'), list) and len(res['summary']) == 3)
PY
  • ์„ฑ๊ณตํŒ์ •:
    • history_len = 2
    • has_summary = True

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

  • ๋งค๋ฒˆ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ตํ•˜๋ฉด, ๋ฌธ๋งฅ์ด ๋Š๊ฒจ ํ’ˆ์งˆ์ด ํ”๋“ค๋ฆด ์ˆ˜ ์žˆ๋‹ค.
  • ๊ทธ๋ž˜์„œ ์ด์ „ ๊ฒฐ๊ณผ๋ฅผ state.json์— ๋ˆ„์ ํ•ด ๋‹ค์Œ ์‹คํ–‰์— ์ฐธ๊ณ ํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.
  • ์ฆ‰, โ€œ๊ธฐ์–ต(์ƒํƒœ)โ€œ๋ฅผ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ•ด ๋‘๋ฉด, ์ž‘์€ ์ž๋™ํ™”๋„ ์šด์˜ ํ’ˆ์งˆ์ด ์˜ฌ๋ผ๊ฐ„๋‹ค.

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

  1. ๋ฐ˜๋ณต ๋ฆฌํฌํŠธ ์ž๋™ํ™”: ์ผ/์ฃผ๊ฐ„ ์š”์•ฝ์—์„œ ์ง์ „ ๊ฒฐ๊ณผ๋ฅผ ์ฐธ๊ณ ํ•ด ์ผ๊ด€์„ฑ ์œ ์ง€.
  2. ์—…๋ฌด ์ธ์ˆ˜์ธ๊ณ„ ์•ˆ์ •ํ™”: ๋‹ด๋‹น์ž ๊ต์ฒด ์‹œ์—๋„ ํŒŒ์ผ ์ƒํƒœ๋กœ ํžˆ์Šคํ† ๋ฆฌ ์œ ์ง€.
  3. ํ™•์žฅ ์‰ฌ์›€: ๋‹ค์Œ ๋‹จ๊ณ„์—์„œ ์ƒํƒœ์— score, owner, retry_count๋ฅผ ์ถ”๊ฐ€ํ•ด ์šด์˜ ์ง€ํ‘œํ™” ๊ฐ€๋Šฅ.

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

  • smolagents ์„ค์น˜ ์™„๋ฃŒ
  • day19_stateful_agent.py ๋ฌธ๋ฒ• ๊ฒ€์‚ฌ ํ†ต๊ณผ
  • 1์ฐจ ์‹คํ–‰ ํ›„ state.json ์ƒ์„ฑ
  • 2์ฐจ ์‹คํ–‰ ํ›„ history ๊ธธ์ด 2 ํ™•์ธ
  • result.json์— summary/history_count/applied_memory ์กด์žฌ

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

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

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

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