5편. 일상에서 쓰는 AI 에이전트 만들기 — Google Colab 실습

시리즈: AI 에이전트 직접 만들어보기 | 5편 / 5편 (마지막 편)

안녕하세요! 드디어 마지막 편이에요! 🎊

3, 4편에서 에이전트의 구조와 패턴을 배웠는데, 이번엔 진짜 인터넷에서 실시간 데이터를 가져오는 에이전트를 만들어볼 거예요.

에이전트실제 데이터 출처결과물
1번오늘 뉴스 요약 에이전트Google 뉴스 RSS (무료)뉴스 핵심 요약 파일
2번여행 일정 에이전트Open-Meteo 날씨 API (무료)여행 일정표 파일
3번레시피 추천 에이전트TheMealDB API (무료)레시피 + 재료 파일

세 API 모두 무료이고 API 키가 필요 없어요! 🎉 오늘도 한 셀씩 따라오시면 반드시 동작해요! 💪

💡 3, 4편에서 쓴 노트북을 이어서 사용하거나, 새 노트북을 만들어 따라오세요!


공통 준비 셀

셀 1 — 패키지 설치

이번 편에서는 feedparser가 추가로 필요해요. (뉴스 RSS 읽기용)

!pip install anthropic feedparser -q
print("✅ 설치 완료!")

셀 2 — 라이브러리 import & Claude 연결

import anthropic
import requests
import feedparser
import re
import json
import time
from google.colab import userdata

client = anthropic.Anthropic(api_key=userdata.get('ANTHROPIC_API_KEY'))
print("✅ Claude 연결 완료!")

셀 3 — 재시도 함수 (API 오류 대비)

def call_claude(**kwargs):
    """API가 일시적으로 바쁠 때 자동으로 재시도해요."""
    for attempt in range(3):
        try:
            return client.messages.create(**kwargs)
        except anthropic.APIStatusError as e:
            if e.status_code in (500, 529) and attempt < 2:
                wait = (attempt + 1) * 15
                print(f"  ⏳ API가 잠시 바빠요. {wait}초 후 재시도... ({attempt + 1}/3)")
                time.sleep(wait)
            else:
                raise

print("✅ 재시도 함수 준비 완료!")

💡 서버 오류가 뜨면 어떻게 되나요?

  • 529: 동시에 요청이 너무 많이 몰릴 때 잠깐 나는 오류예요.
  • 500: Anthropic 서버에 일시적인 문제가 생겼을 때 나는 오류예요.

두 경우 모두 위의 call_claude() 함수가 자동으로 최대 3번 재시도해줘요.


에이전트 1번: 오늘 뉴스 요약 에이전트 ⭐⭐

Google 뉴스 RSS에서 실시간 뉴스를 가져와서 핵심만 요약해주는 에이전트예요.

나 :       "오늘 AI 관련 뉴스 요약해줘"

에이전트 : ① search_news 도구 사용 → Google 뉴스에서 실시간 검색
          ② save_to_file 도구 사용 → news_summary.txt 저장
          ③ 답변: "요약 완료했어요!"

셀 4 — 뉴스 도구 2개 만들기

def search_news(keyword: str) -> str:
    """Google 뉴스 RSS에서 키워드로 최신 뉴스를 가져옵니다."""
    print(f"  🔍 Google 뉴스 검색 중: '{keyword}'")

    url = f"https://news.google.com/rss/search?q={keyword}&hl=ko&gl=KR&ceid=KR:ko"
    feed = feedparser.parse(url)

    if not feed.entries:
        return f"'{keyword}' 관련 뉴스를 찾을 수 없어요."

    result = f"'{keyword}' 최신 뉴스 (5건):\n\n"
    for i, entry in enumerate(feed.entries[:5], 1):
        # HTML 태그 제거
        summary = re.sub(r'<[^>]+>', '', entry.get('summary', ''))[:120]
        result += f"{i}. {entry.title}\n"
        result += f"   {summary}...\n\n"

    return result.strip()


def save_to_file(filename: str, content: str) -> str:
    """내용을 파일로 저장합니다."""
    print(f"  💾 저장 중: '{filename}'")
    with open(f"/content/{filename}", "w", encoding="utf-8") as f:
        f.write(content)
    return f"✅ '/content/{filename}' 저장 완료!"


TOOLS_NEWS = [
    {
        "name": "search_news",
        "description": "Google 뉴스에서 키워드로 최신 뉴스를 검색합니다.",
        "input_schema": {
            "type": "object",
            "properties": {
                "keyword": {"type": "string", "description": "검색할 키워드 (예: 'AI', '주식', '날씨')"}
            },
            "required": ["keyword"]
        }
    },
    {
        "name": "save_to_file",
        "description": "내용을 파일로 저장합니다.",
        "input_schema": {
            "type": "object",
            "properties": {
                "filename": {"type": "string", "description": "파일 이름 (예: news.txt)"},
                "content":  {"type": "string", "description": "저장할 내용"}
            },
            "required": ["filename", "content"]
        }
    }
]


def execute_news_tool(name: str, inputs: dict) -> str:
    if name == "search_news":
        return search_news(inputs["keyword"])
    elif name == "save_to_file":
        return save_to_file(inputs["filename"], inputs["content"])
    return f"알 수 없는 도구: {name}"


print("✅ 뉴스 도구 2개 준비 완료!")

셀 5 — 뉴스 요약 에이전트 함수

def run_news_agent(task: str, max_steps: int = 10):
    """뉴스 요약 에이전트를 실행해요."""
    print(f"\n{'='*50}")
    print(f"📰 뉴스 요약 요청: {task}")
    print(f"{'='*50}\n")

    messages = [{"role": "user", "content": task}]
    step = 1

    while step <= max_steps:
        print(f"🤔 [Step {step}] 생각 중...")

        response = call_claude(
            model="claude-opus-4-6",
            max_tokens=2048,
            system="뉴스를 검색해서 핵심 내용을 한국어로 간결하게 요약하고 파일로 저장하세요.",
            tools=TOOLS_NEWS,
            messages=messages
        )

        if response.stop_reason == "tool_use":
            messages.append({"role": "assistant", "content": response.content})
            tool_results = []

            for block in response.content:
                if block.type == "tool_use":
                    print(f"🛠️  도구 사용: {block.name}")
                    result = execute_news_tool(block.name, block.input)
                    print(f"   → {result[:80]}{'...' if len(result) > 80 else ''}\n")
                    tool_results.append({
                        "type": "tool_result",
                        "tool_use_id": block.id,
                        "content": result
                    })

            messages.append({"role": "user", "content": tool_results})

        elif response.stop_reason == "end_turn":
            print(f"{'='*50}")
            print("✅ 완료!")
            print(f"{'='*50}\n")
            for block in response.content:
                if hasattr(block, "text"):
                    print(f"💬 결과: {block.text}")
            break

        step += 1
    else:
        print(f"⚠️ 최대 스텝({max_steps})에 도달해서 종료했어요.")

print("✅ 뉴스 요약 에이전트 준비 완료!")

셀 6 — 뉴스 요약 에이전트 실행!

run_news_agent(
    "오늘 AI 관련 최신 뉴스를 요약해서 'news_summary.txt'로 저장해줘."
)

이런 출력이 나오면 성공이에요! 🎉

==================================================
📰 뉴스 요약 요청: 오늘 AI 관련 최신 뉴스를...
==================================================

🤔 [Step 1] 생각 중...
🛠️  도구 사용: search_news
  🔍 Google 뉴스 검색 중: 'AI'
   → 'AI' 최신 뉴스 (5건): 1. 챗GPT 사용자 5억 명 돌파...

🤔 [Step 2] 생각 중...
🛠️  도구 사용: save_to_file
  💾 저장 중: 'news_summary.txt'
   → ✅ '/content/news_summary.txt' 저장 완료!

🤔 [Step 3] 생각 중...
==================================================
✅ 완료!
==================================================

💬 결과: AI 뉴스 5건을 요약했어요!
'news_summary.txt'에 저장했습니다.
AI 에이전트 실행시 저장 news_summary.txt 이미지

다른 키워드로 바꿔보세요!

run_news_agent("오늘 주식 시장 뉴스 요약해서 'stock_news.txt'로 저장해줘.")
run_news_agent("오늘 날씨 관련 뉴스 요약해서 'weather_news.txt'로 저장해줘.")

에이전트 2번: 여행 일정 에이전트 ⭐⭐

Open-Meteo API에서 실시간 날씨를 가져와서 날씨에 딱 맞는 여행 일정을 짜주는 에이전트예요.

나 :       "도쿄 3박 4일 여행 일정 짜줘"

에이전트 : ① get_weather 도구 사용 → Open-Meteo에서 실시간 날씨 조회
          ② get_attractions 도구 사용 → 주요 명소 정보 조회
          ③ save_to_file 도구 사용 → travel_plan.txt 저장
          ④ 답변: "일정표 완성했어요!"

셀 7 — 여행 도구 3개 만들기

# 날씨 코드 → 설명 변환표
WEATHER_CODE = {
    0: "☀️ 맑음", 1: "🌤️ 대체로 맑음", 2: "⛅ 구름 많음", 3: "☁️ 흐림",
    45: "🌫️ 안개", 48: "🌫️ 짙은 안개",
    51: "🌦️ 이슬비", 61: "🌧️ 비", 71: "🌨️ 눈",
    80: "🌧️ 소나기", 95: "⛈️ 뇌우"
}

def get_weather(city: str) -> str:
    """Open-Meteo API로 여행지의 실시간 날씨와 3일 예보를 가져옵니다."""
    print(f"  🌤️  날씨 조회 중: {city} (Open-Meteo API)")

    # 1단계: 도시명 → 위도/경도 변환
    geo_url = (
        f"https://geocoding-api.open-meteo.com/v1/search"
        f"?name={city}&count=1&language=ko"
    )
    geo = requests.get(geo_url, timeout=10).json()

    if not geo.get("results"):
        return f"'{city}'의 위치를 찾을 수 없어요."

    loc = geo["results"][0]
    lat, lon = loc["latitude"], loc["longitude"]
    city_name = loc["name"]

    # 2단계: 날씨 조회
    weather_url = (
        f"https://api.open-meteo.com/v1/forecast"
        f"?latitude={lat}&longitude={lon}"
        f"&current_weather=true"
        f"&daily=temperature_2m_max,temperature_2m_min,precipitation_sum,weathercode"
        f"&timezone=auto&forecast_days=4"
    )
    w = requests.get(weather_url, timeout=10).json()
    current = w["current_weather"]
    daily = w["daily"]

    current_desc = WEATHER_CODE.get(int(current["weathercode"]), "날씨 정보")
    result  = f"📍 {city_name}\n"
    result += f"현재: {current_desc}, {current['temperature']}°C\n\n"
    result += "4일 예보:\n"
    for i in range(len(daily["time"])):
        desc = WEATHER_CODE.get(int(daily["weathercode"][i]), "")
        result += (
            f"  {daily['time'][i]}: {desc} "
            f"최고 {daily['temperature_2m_max'][i]}°C / "
            f"최저 {daily['temperature_2m_min'][i]}°C, "
            f"강수 {daily['precipitation_sum'][i]}mm\n"
        )

    return result.strip()


def get_attractions(city: str) -> str:
    """도시의 주요 명소 정보를 반환합니다."""
    print(f"  🗺️  명소 조회 중: {city}")

    # 주요 도시 큐레이션 데이터 (여행 가이드 기반)
    attractions_db = {
        "도쿄": [
            "신주쿠 — 쇼핑·먹거리 밀집지 (소요 3~4시간)",
            "아사쿠사·센소지 — 에도 시대 전통 분위기 (소요 2시간)",
            "시부야 스크램블 교차로 — 포토스팟 (소요 1시간)",
            "우에노 공원 — 벚꽃 명소·박물관 밀집 (소요 2~3시간)",
            "하라주쿠 다케시타 거리 — 개성 있는 패션·디저트 (소요 1~2시간)",
            "도쿄 스카이트리 — 야경 전망대 (소요 2시간)",
        ],
        "파리": [
            "에펠탑 — 파리의 상징 (소요 2시간)",
            "루브르 박물관 — 세계 최대 미술관 (소요 3~4시간)",
            "몽마르트르 언덕 — 예술가 거리·사크레쾨르 성당 (소요 2시간)",
            "샹젤리제 거리 — 쇼핑·카페 (소요 2시간)",
            "베르사유 궁전 — 당일치기 추천 (소요 4시간)",
        ],
        "제주": [
            "성산일출봉 — 유네스코 세계유산 (소요 2시간)",
            "협재해변 — 에메랄드빛 바다 (소요 2시간)",
            "한라산 — 트레킹 (소요 6~8시간)",
            "우도 — 자전거 여행·스노클링 (소요 4시간)",
            "천지연폭포 — 야간 개장 (소요 1시간)",
        ],
        "방콕": [
            "왓 프라깨우(에메랄드 사원) — 왕궁 (소요 3시간)",
            "차오프라야강 보트 투어 (소요 2시간)",
            "짜뚜짝 주말 시장 — 쇼핑 (소요 3~4시간)",
            "카오산 로드 — 배낭여행자 거리 (저녁 추천)",
            "아이콘 시암 — 대형 쇼핑몰 (소요 2~3시간)",
        ],
    }

    for key, places in attractions_db.items():
        if key in city:
            return f"{key} 주요 명소:\n" + "\n".join(f"  - {p}" for p in places)

    return f"{city}의 주요 관광지를 참고해서 일정을 짜주세요."


TOOLS_TRAVEL = [
    {
        "name": "get_weather",
        "description": "여행지의 실시간 날씨와 예보를 가져옵니다. 도시 이름을 넣으세요.",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "도시 이름 (예: '도쿄', '파리', '제주')"}
            },
            "required": ["city"]
        }
    },
    {
        "name": "get_attractions",
        "description": "도시의 주요 관광 명소와 소요 시간을 가져옵니다.",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "도시 이름"}
            },
            "required": ["city"]
        }
    },
    {
        "name": "save_to_file",
        "description": "여행 일정표를 파일로 저장합니다.",
        "input_schema": {
            "type": "object",
            "properties": {
                "filename": {"type": "string", "description": "파일 이름"},
                "content":  {"type": "string", "description": "저장할 내용"}
            },
            "required": ["filename", "content"]
        }
    }
]


def execute_travel_tool(name: str, inputs: dict) -> str:
    if name == "get_weather":
        return get_weather(inputs["city"])
    elif name == "get_attractions":
        return get_attractions(inputs["city"])
    elif name == "save_to_file":
        return save_to_file(inputs["filename"], inputs["content"])
    return f"알 수 없는 도구: {name}"


print("✅ 여행 도구 3개 준비 완료!")
print("   날씨: Open-Meteo API (실시간) ✅")

셀 8 — 여행 일정 에이전트 함수

def run_travel_agent(task: str, max_steps: int = 10):
    """여행 일정 에이전트를 실행해요."""
    print(f"\n{'='*50}")
    print(f"✈️  여행 일정 요청: {task}")
    print(f"{'='*50}\n")

    messages = [{"role": "user", "content": task}]
    step = 1

    while step <= max_steps:
        print(f"🤔 [Step {step}] 생각 중...")

        response = call_claude(
            model="claude-opus-4-6",
            max_tokens=3000,
            system=(
                "여행 플래너로서 일정을 짜주세요.\n"
                "1) 여행지 날씨를 먼저 확인하세요.\n"
                "2) 주요 명소를 조회하세요.\n"
                "3) 실제 날씨를 반영해서 일정을 작성하고 파일로 저장하세요.\n"
                "형식: 날짜별 오전 / 오후 / 저녁 활동 + 날씨 준비물 팁"
            ),
            tools=TOOLS_TRAVEL,
            messages=messages
        )

        if response.stop_reason == "tool_use":
            messages.append({"role": "assistant", "content": response.content})
            tool_results = []

            for block in response.content:
                if block.type == "tool_use":
                    print(f"🛠️  도구 사용: {block.name}({list(block.input.values())[0]})")
                    result = execute_travel_tool(block.name, block.input)
                    print(f"   → {result[:80]}{'...' if len(result) > 80 else ''}\n")
                    tool_results.append({
                        "type": "tool_result",
                        "tool_use_id": block.id,
                        "content": result
                    })

            messages.append({"role": "user", "content": tool_results})

        elif response.stop_reason == "end_turn":
            print(f"{'='*50}")
            print("✅ 일정 완성!")
            print(f"{'='*50}\n")
            for block in response.content:
                if hasattr(block, "text"):
                    print(f"💬 결과: {block.text}")
            break

        step += 1
    else:
        print(f"⚠️ 최대 스텝({max_steps})에 도달해서 종료했어요.")

print("✅ 여행 일정 에이전트 준비 완료!")

셀 9 — 여행 일정 에이전트 실행!

run_travel_agent(
    "도쿄 3박 4일 여행 일정 짜줘. 실제 날씨 반영해서 'tokyo_plan.txt'로 저장해줘."
)

이런 출력이 나오면 성공이에요! 🎉

==================================================
✈️  여행 일정 요청: 도쿄 3박 4일 여행 일정 짜줘...
==================================================

🤔 [Step 1] 생각 중...
🛠️  도구 사용: get_weather(도쿄)
  🌤️  날씨 조회 중: 도쿄 (Open-Meteo API)
   → 📍 Tokyo 현재: ☀️ 맑음, 17.3°C  4일 예보: 2025-04-01...

🤔 [Step 2] 생각 중...
🛠️  도구 사용: get_attractions(도쿄)
  🗺️  명소 조회 중: 도쿄
   → 도쿄 주요 명소: 신주쿠, 아사쿠사·센소지...

🤔 [Step 3] 생각 중...
🛠️  도구 사용: save_to_file(tokyo_plan.txt)
  💾 저장 중: 'tokyo_plan.txt'
   → ✅ '/content/tokyo_plan.txt' 저장 완료!

🤔 [Step 4] 생각 중...
==================================================
✅ 일정 완성!
==================================================

💬 결과: 도쿄 3박 4일 일정을 실제 날씨 기반으로 완성했어요!
'tokyo_plan.txt'에서 확인하세요!
AI 에이전트 실행시 저장 tokyo_plan.txt 이미지

다른 여행지도 해보세요!

run_travel_agent("제주도 1박 2일 여행 일정 짜줘. 'jeju_plan.txt'로 저장해줘.")
run_travel_agent("방콕 4박 5일 여행 일정 짜줘. 'bangkok_plan.txt'로 저장해줘.")

에이전트 3번: 레시피 추천 에이전트 ⭐⭐⭐

TheMealDB API에서 실제 레시피를 검색해서 가진 재료로 만들 수 있는 요리를 추천해주는 에이전트예요.

나 :       "달걀, 감자, 양파 있어. 뭐 만들 수 있어?"

에이전트 : ① find_recipes 도구 사용 → TheMealDB에서 레시피 검색
          ② get_recipe_detail 도구 사용 → 상세 재료·조리법 조회
          ③ save_to_file 도구 사용 → recipe.txt 저장
          ④ 답변: "레시피 추천 완료했어요!"

셀 10 — 레시피 도구 3개 만들기

def find_recipes(ingredients: str) -> str:
    """TheMealDB에서 재료별로 검색한 후보 요리 목록을 반환합니다.
    Claude가 전체 재료를 보고 가장 잘 맞는 요리를 고릅니다."""
    print(f"  🍳 레시피 후보 검색 중... (TheMealDB API)")

    # 각 재료를 영어로 변환해 개별 검색 후 합산
    items = [i.strip() for i in ingredients.split(",")]
    all_meals = {}

    for item in items[:3]:  # 최대 3개 재료로 검색
        # Claude로 한글 → 영어 변환
        resp = call_claude(
            model="claude-opus-4-6",
            max_tokens=10,
            messages=[{"role": "user", "content": f"'{item}'을 영어 단어 하나로만. 단어만 출력."}]
        )
        eng = resp.content[0].text.strip().lower()
        print(f"    {item} → {eng}")

        url = f"https://www.themealdb.com/api/json/v1/1/filter.php?i={eng}"
        meals = requests.get(url, timeout=10).json().get("meals") or []
        for meal in meals[:5]:
            all_meals[meal["idMeal"]] = meal["strMeal"]

    if not all_meals:
        return "입력한 재료로 검색된 요리가 없어요. 다른 재료를 써보세요."

    result = f"보유 재료: {ingredients}\n\n검색된 요리 후보:\n"
    for mid, name in list(all_meals.items())[:8]:
        result += f"- {name} (ID: {mid})\n"
    result += "\nClaude가 위 후보 중 재료에 가장 잘 맞는 요리를 선택해줄 거예요."

    return result.strip()


def get_recipe_detail(meal_id: str) -> str:
    """TheMealDB API로 레시피 상세 정보를 가져옵니다."""
    print(f"  📖 레시피 상세 조회 중: ID {meal_id}")

    url = f"https://www.themealdb.com/api/json/v1/1/lookup.php?i={meal_id}"
    resp = requests.get(url, timeout=10).json()
    meals = resp.get("meals")

    if not meals:
        return "레시피 상세 정보를 찾을 수 없어요."

    meal = meals[0]
    result  = f"🍽️  {meal['strMeal']}\n"
    result += f"카테고리: {meal['strCategory']} | 원산지: {meal['strArea']}\n\n"
    result += "필요한 재료:\n"
    for i in range(1, 21):
        ing     = meal.get(f"strIngredient{i}", "").strip()
        measure = meal.get(f"strMeasure{i}", "").strip()
        if ing:
            result += f"  - {ing}: {measure}\n"
    result += f"\n조리 방법 (앞부분):\n{meal['strInstructions'][:400]}...\n"

    return result.strip()


TOOLS_RECIPE = [
    {
        "name": "find_recipes",
        "description": "가진 재료로 만들 수 있는 요리를 TheMealDB에서 검색합니다.",
        "input_schema": {
            "type": "object",
            "properties": {
                "ingredients": {
                    "type": "string",
                    "description": "가진 재료 목록 (예: '달걀, 감자, 양파')"
                }
            },
            "required": ["ingredients"]
        }
    },
    {
        "name": "get_recipe_detail",
        "description": "레시피 ID로 상세 재료와 조리법을 가져옵니다.",
        "input_schema": {
            "type": "object",
            "properties": {
                "meal_id": {"type": "string", "description": "레시피 ID (find_recipes에서 얻은 ID)"}
            },
            "required": ["meal_id"]
        }
    },
    {
        "name": "save_to_file",
        "description": "레시피를 파일로 저장합니다.",
        "input_schema": {
            "type": "object",
            "properties": {
                "filename": {"type": "string", "description": "파일 이름"},
                "content":  {"type": "string", "description": "저장할 내용"}
            },
            "required": ["filename", "content"]
        }
    }
]


def execute_recipe_tool(name: str, inputs: dict) -> str:
    if name == "find_recipes":
        return find_recipes(inputs["ingredients"])
    elif name == "get_recipe_detail":
        return get_recipe_detail(inputs["meal_id"])
    elif name == "save_to_file":
        return save_to_file(inputs["filename"], inputs["content"])
    return f"알 수 없는 도구: {name}"


print("✅ 레시피 도구 3개 준비 완료!")
print("   데이터: TheMealDB API (실시간) ✅")

셀 11 — 레시피 추천 에이전트 함수

def run_recipe_agent(task: str, max_steps: int = 10):
    """레시피 추천 에이전트를 실행해요."""
    print(f"\n{'='*50}")
    print(f"🍽️  레시피 요청: {task}")
    print(f"{'='*50}\n")

    messages = [{"role": "user", "content": task}]
    step = 1

    while step <= max_steps:
        print(f"🤔 [Step {step}] 생각 중...")

        response = call_claude(
            model="claude-opus-4-6",
            max_tokens=3000,
            system=(
                "요리 전문가로서 레시피를 추천해주세요.\n"
                "1) find_recipes로 만들 수 있는 요리를 검색하세요.\n"
                "2) 가장 적합한 요리 1개를 골라 get_recipe_detail로 상세 레시피를 조회하세요.\n"
                "3) 레시피를 한국어로 번역해서 파일로 저장하세요.\n"
                "저장 형식: 요리명 / 재료 목록 / 조리 순서"
            ),
            tools=TOOLS_RECIPE,
            messages=messages
        )

        if response.stop_reason == "tool_use":
            messages.append({"role": "assistant", "content": response.content})
            tool_results = []

            for block in response.content:
                if block.type == "tool_use":
                    print(f"🛠️  도구 사용: {block.name}")
                    result = execute_recipe_tool(block.name, block.input)
                    print(f"   → {result[:80]}{'...' if len(result) > 80 else ''}\n")
                    tool_results.append({
                        "type": "tool_result",
                        "tool_use_id": block.id,
                        "content": result
                    })

            messages.append({"role": "user", "content": tool_results})

        elif response.stop_reason == "end_turn":
            print(f"{'='*50}")
            print("✅ 레시피 추천 완료!")
            print(f"{'='*50}\n")
            for block in response.content:
                if hasattr(block, "text"):
                    print(f"💬 결과: {block.text}")
            break

        step += 1
    else:
        print(f"⚠️ 최대 스텝({max_steps})에 도달해서 종료했어요.")

print("✅ 레시피 추천 에이전트 준비 완료!")

셀 12 — 레시피 추천 에이전트 실행!

run_recipe_agent(
    "냉장고에 달걀, 감자, 양파가 있어. "
    "오늘 저녁 뭐 만들면 좋을지 추천해주고, "
    "재료와 조리법을 'recipe_today.txt'로 저장해줘."
)

이런 출력이 나오면 성공이에요! 🎉

==================================================
🍽️  레시피 요청: 냉장고에 달걀, 감자, 양파가 있어...
==================================================

🤔 [Step 1] 생각 중...
🛠️  도구 사용: find_recipes
  🍳 레시피 후보 검색 중... (TheMealDB API)
    달걀 → egg
    감자 → potato
    양파 → onion
   → 보유 재료: 달걀, 감자, 양파  검색된 요리 후보: Shakshuka, Potato...

🤔 [Step 2] 생각 중...
🛠️  도구 사용: get_recipe_detail
  📖 레시피 상세 조회 중: ID 52772
   → 🍽️ Shakshuka 카테고리: Breakfast | 원산지: Tunisian...

🤔 [Step 3] 생각 중...
🛠️  도구 사용: save_to_file
  💾 저장 중: 'recipe_today.txt'
   → ✅ '/content/recipe_today.txt' 저장 완료!

🤔 [Step 4] 생각 중...
==================================================
✅ 레시피 추천 완료!
==================================================

💬 결과: 달걀, 감자, 양파를 모두 활용한 샥슈카를 추천해요!
재료와 한국어 조리법을 'recipe_today.txt'에 저장했습니다.
AI 에이전트 실행시 저장 recipe_today.txt 이미지

다른 재료로도 해보세요!

run_recipe_agent(
    "닭고기, 마늘, 버터가 있어. 저녁 메뉴 추천해서 'recipe2.txt'로 저장해줘."
)

세 에이전트를 비교해봐요

에이전트 1 (뉴스 요약)에이전트 2 (여행 일정)에이전트 3 (레시피 추천)
실제 APIGoogle 뉴스 RSSOpen-Meteo APITheMealDB API
도구 정의셀 4셀 7셀 10
도구 목록search_newsget_weather (실시간)find_recipes (실시간)
save_to_file ← 재사용!get_attractionsget_recipe_detail (실시간)
save_to_file ← 재사용!save_to_file ← 재사용!
함수 정의셀 5셀 8셀 11
실행셀 6셀 9셀 12

패턴이 완전히 동일해요! 도구 안에 real API를 넣었을 뿐이에요. 🎯


시리즈 전체 정리

5편에 걸쳐 함께 만든 것들이에요:

핵심 내용만든 것
1편AI 에이전트 = LLM + Tools + Memory + Planning(개념 이해)
2편MCP = 에이전트와 도구를 연결하는 표준 규격(개념 이해)
3편에이전트의 기본 패턴: while 루프 + 도구 실행계산기 / 리서치 / 번역 에이전트
4편멀티 에이전트: 오케스트레이터 / 파이프라인 / 병렬 처리AI 팀 협업 시스템
5편실제 API 연동: 실시간 데이터를 쓰는 에이전트뉴스 요약 / 여행 일정 / 레시피 추천

마치며

5편의 여정이 드디어 끝났어요! 🎉

처음엔 “AI 에이전트가 뭔지도 몰랐는데”에서 시작해서, 이제는 인터넷에서 실시간 데이터를 가져오는 에이전트를 직접 만들 수 있게 됐어요.

오늘 배운 핵심을 기억하세요:

도구 함수 안에 real API를 넣으면
에이전트가 실시간 세상과 연결돼요.

이 패턴이면 날씨 알림 봇, 실시간 주가 분석 에이전트, 맛집 추천 에이전트 등 무엇이든 만들 수 있어요.

직접 만들어보다가 막히는 부분이 있으면 댓글로 남겨주세요! 함께 해결해봐요. 😊

긴 시리즈 끝까지 함께해주셔서 진심으로 감사해요! 🙏


제목상태
1편AI 에이전트란 무엇인가요?✅ 완료
2편MCP란 무엇인가요? 도구를 에이전트에 연결하는 방법✅ 완료
3편나만의 에이전트 첫 번째 만들기 (Colab 실습)✅ 완료
4편멀티 에이전트 설계 패턴 (Colab 실습)✅ 완료
5편일상에서 쓰는 AI 에이전트 만들기 (Colab 실습)✅ 현재 글