项目文件夹

文件
2026-07-13 12:59:43 +08:00

284 行
11 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "lesson-intro",
"metadata": {},
"source": [
"# Lesson 03 - 에이전트 디자인 패턴\n",
"\n",
"이번 레슨에서는 효과적인 AI 에이전트를 구축하기 위한 세 가지 기본 디자인 패턴을 살펴봅니다:\n",
"\n",
"1. **명확한 에이전트 지침** — 에이전트 행동을 안내하는 정밀하고 역할을 정의하는 프롬프트 작성\n",
"2. **Pydantic 모델을 활용한 구조화된 출력** — 에이전트가 예측 가능하고 검증된 데이터를 반환하도록 보장\n",
"3. **단일 책임 에이전트** — 각각 한 가지 일을 잘 수행하는 집중적인 에이전트 설계\n",
"\n",
"각 패턴을 **여행지 추천 시스템** 시나리오에 적용하며, 점진적으로 여행지 추천, 가용성 확인, 그리고 물류 처리 기능을 갖춘 시스템을 구축해나갑니다.\n"
]
},
{
"cell_type": "markdown",
"id": "setup-header",
"metadata": {},
"source": [
"## 설정\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "setup-code",
"metadata": {},
"outputs": [],
"source": [
"%pip install agent-framework azure-ai-projects azure-identity pydantic python-dotenv --quiet"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "imports",
"metadata": {},
"outputs": [],
"source": [
"import logging\n",
"logging.getLogger(\"agent_framework.foundry\").setLevel(logging.ERROR)\n",
"\n",
"import os\n",
"import asyncio\n",
"import dotenv\n",
"from typing import Annotated\n",
"from pydantic import BaseModel\n",
"from agent_framework import tool\n",
"from agent_framework.foundry import FoundryChatClient\n",
"from azure.identity import DefaultAzureCredential\n",
"\n",
"dotenv.load_dotenv(dotenv.find_dotenv())\n",
"\n",
"endpoint = os.getenv(\"AZURE_AI_PROJECT_ENDPOINT\")\n",
"deployment_name = os.getenv(\"AZURE_AI_MODEL_DEPLOYMENT_NAME\")\n",
"\n",
"missing = [k for k, v in {\n",
" \"AZURE_AI_PROJECT_ENDPOINT\": endpoint,\n",
" \"AZURE_AI_MODEL_DEPLOYMENT_NAME\": deployment_name\n",
"}.items() if not v]\n",
"\n",
"if missing:\n",
" raise ValueError(\n",
" f\"Missing required environment variables: {', '.join(missing)}. \"\n",
" \"Please set them as environment variables (e.g., in your .env file or shell environment).\"\n",
" )\n",
"\n",
"provider = FoundryChatClient(\n",
" project_endpoint=endpoint,\n",
" model=deployment_name,\n",
" credential=DefaultAzureCredential()\n",
")"
]
},
{
"cell_type": "markdown",
"id": "pattern1-header",
"metadata": {},
"source": [
"## 패턴 1: 명확한 에이전트 지침\n",
"\n",
"가장 효과적인 패턴은 또한 가장 간단합니다: 에이전트를 위해 명확하고 상세한 지침을 작성하는 것입니다.\n",
"\n",
"좋은 지침은 다음을 정의합니다:\n",
"- <strong>누구인지</strong> (페르소나와 어조)\n",
"- **무엇을 해야 하는지** (단계별 책임)\n",
"- **어떻게 행동해야 하는지** (제약 조건과 스타일)\n",
"\n",
"아래에서는 모든 응답을 형성하는 명확한 지침을 가진 여행 컨시어지 에이전트를 만듭니다.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "pattern1-code",
"metadata": {},
"outputs": [],
"source": [
"agent = provider.as_agent(\n",
" name=\"TravelConcierge\",\n",
" instructions=\"\"\"You are a luxury travel concierge named Alex. Your role is to:\n",
"1. Understand the traveler's preferences (budget, climate, activities)\n",
"2. Check destination availability before making recommendations\n",
"3. Provide detailed, personalized travel suggestions\n",
"4. Always mention visa requirements and best travel seasons\n",
"Be warm, professional, and enthusiastic about travel.\"\"\",\n",
")\n",
"\n",
"response = await agent.run(\n",
" \"I'd love a week-long vacation somewhere with great food and history. Budget around $2500.\"\n",
")\n",
"print(response)"
]
},
{
"cell_type": "markdown",
"id": "pattern2-header",
"metadata": {},
"source": [
"## 패턴 2: Pydantic 모델을 사용한 구조화된 출력\n",
"\n",
"자유 형식 텍스트는 대화에 유용하지만, 하류 시스템에서는 구조화된 데이터가 필요합니다. \n",
"<strong>Pydantic 모델</strong>과 <strong>도구 함수</strong>를 결합하면:\n",
"\n",
"- 에이전트 출력에 대한 정확한 스키마를 정의할 수 있습니다 \n",
"- 응답을 자동으로 검증할 수 있습니다 \n",
"- 에이전트 결과를 애플리케이션 로직에 신뢰성 있게 통합할 수 있습니다 \n",
"\n",
"또한, 에이전트가 실제 데이터를 기반으로 추천할 수 있도록 목적지 세부 정보를 반환하는 도구도 소개합니다.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "pattern2-code",
"metadata": {},
"outputs": [],
"source": [
"class DestinationRecommendation(BaseModel):\n",
" destination: str\n",
" available: bool\n",
" best_season: str\n",
" highlights: list[str]\n",
" estimated_budget_usd: int\n",
"\n",
"\n",
"class TravelRecommendations(BaseModel):\n",
" recommendations: list[DestinationRecommendation]\n",
" personalized_note: str\n",
"\n",
"\n",
"@tool(approval_mode=\"never_require\")\n",
"def get_destination_details(destination: Annotated[str, \"The destination to look up\"]) -> str:\n",
" \"\"\"Get details about a vacation destination.\"\"\"\n",
" details = {\n",
" \"Barcelona\": \"Available. Best: May-Jun. Beach, architecture, nightlife. ~$2000/week\",\n",
" \"Tokyo\": \"Available. Best: Mar-Apr. Culture, food, technology. ~$2500/week\",\n",
" \"Cape Town\": \"Not available. Best: Nov-Mar. Nature, wine, adventure. ~$1800/week\",\n",
" }\n",
" return details.get(destination, f\"{destination}: No information available.\")\n",
"\n",
"\n",
"structured_agent = provider.as_agent(\n",
" name=\"StructuredTravelExpert\",\n",
" instructions=\"You are a travel expert. Recommend destinations based on traveler preferences. Use the get_destination_details tool.\",\n",
" tools=[get_destination_details],\n",
")\n",
"\n",
"response = await structured_agent.run(\n",
" \"Recommend 3 destinations for a culture-loving traveler with a $2500 budget\"\n",
")\n",
"\n",
"if response:\n",
" print(response)"
]
},
{
"cell_type": "markdown",
"id": "pattern3-header",
"metadata": {},
"source": [
"## 패턴 3: 단일 책임 에이전트\n",
"\n",
"복잡한 작업은 각각 단일 책임을 가진 여러 집중된 에이전트로 작업을 분할할 때 이점이 있습니다:\n",
"\n",
"- 장소와 이용 가능성에 대해 아는 **목적지 전문가**\n",
"- 항공편, 호텔 및 일정 관리를 담당하는 **물류 계획자**\n",
"\n",
"이는 소프트웨어 공학 원칙인 <em>관심사의 분리</em>를 반영합니다 — 각 에이전트는 독립적으로 테스트, 유지 보수 및 개선하기가 더 쉽습니다.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "pattern3-code",
"metadata": {},
"outputs": [],
"source": [
"destination_agent = provider.as_agent(\n",
" name=\"DestinationExpert\",\n",
" tools=[get_destination_details],\n",
" instructions=\"\"\"You are a destination research specialist. Your only job is to:\n",
"1. Evaluate destinations based on traveler preferences\n",
"2. Check availability using the provided tool\n",
"3. Return a short ranked list with pros/cons\n",
"Do NOT discuss flights, hotels, or logistics — another agent handles that.\"\"\",\n",
")\n",
"\n",
"logistics_agent = provider.as_agent(\n",
" name=\"LogisticsPlanner\",\n",
" instructions=\"\"\"You are a travel logistics planner. Your only job is to:\n",
"1. Create a day-by-day itinerary for the chosen destination\n",
"2. Suggest flight and hotel options within the stated budget\n",
"3. Note visa requirements and travel insurance recommendations\n",
"Do NOT recommend destinations — another agent handles that.\"\"\",\n",
")\n",
"\n",
"# Step 1: Destination Expert picks the best options\n",
"dest_response = await destination_agent.run(\n",
" \"I want a week of culture and food for under $2500. Where should I go?\"\n",
")\n",
"print(\"=== Destination Expert ===\")\n",
"print(dest_response)\n",
"\n",
"# Step 2: Logistics Planner builds the trip plan\n",
"logistics_response = await logistics_agent.run(\n",
" f\"Plan a week-long trip based on this recommendation:\\n{dest_response}\"\n",
")\n",
"print(\"\\n=== Logistics Planner ===\")\n",
"print(logistics_response)"
]
},
{
"cell_type": "markdown",
"id": "summary",
"metadata": {},
"source": [
"## 요약\n",
"\n",
"이번 수업에서는 여행 추천 시나리오에 세 가지 에이전트 디자인 패턴을 적용했습니다:\n",
"\n",
"| 패턴 | 핵심 아이디어 | 이점 |\n",
"|---|---|---|\n",
"| **명확한 지침** | 페르소나, 책임 및 제약 조건을 먼저 정의 | 일관되고 브랜드에 맞는 에이전트 행동 |\n",
"| **구조화된 출력** | 응답 형식으로 Pydantic 모델 사용 | 검증되고 기계가 읽을 수 있는 결과 |\n",
"| **단일 책임** | 각 에이전트에 하나의 집중된 작업 부여 | 테스트, 유지보수, 조합이 용이 |\n",
"\n",
"이 패턴들은 자연스럽게 조합됩니다 — 명확한 지침과 구조화된 출력을 단일 책임 에이전트 내에서 결합하여 견고하고 실제 운영 가능한 시스템을 구축할 수 있습니다.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**면책 조항**:\n이 문서는 AI 번역 서비스 [Co-op Translator](https://github.com/Azure/co-op-translator)를 사용하여 번역되었습니다. 정확성을 기하기 위해 노력하고 있으나, 자동 번역은 오류나 부정확한 부분이 있을 수 있음을 유의하시기 바랍니다. 원본 문서의 원어본이 권위 있는 자료로 간주되어야 합니다. 중요한 정보의 경우, 전문가의 인간 번역을 권장합니다. 이 번역 사용으로 인해 발생하는 오해나 잘못된 해석에 대해 당사는 책임을 지지 않습니다.\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.13"
}
},
"nbformat": 4,
"nbformat_minor": 5
}