microsoft--ai-agents-for-beginners
284 行
11 KiB
Plaintext
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
|
|
} |