Files
2026-07-13 12:59:43 +08:00

233 lines
8.1 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "a1b2c3d4",
"metadata": {},
"source": [
"# Lesson 08 - Multi-Agent Design Pattern"
]
},
{
"cell_type": "markdown",
"id": "b2c3d4e5",
"metadata": {},
"source": [
"## Setup"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c3d4e5f6",
"metadata": {},
"outputs": [],
"source": [
"import logging\n",
"logging.getLogger(\"agent_framework.foundry\").setLevel(logging.ERROR)\n",
"\n",
"%pip install agent-framework azure-ai-projects azure-identity python-dotenv --quiet\n",
"\n",
"import os\n",
"import asyncio\n",
"import dotenv\n",
"\n",
"from agent_framework import AgentResponseUpdate, WorkflowBuilder\n",
"from agent_framework.foundry import FoundryChatClient\n",
"from azure.identity import DefaultAzureCredential\n",
"\n",
"dotenv.load_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",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d4e5f6a7",
"metadata": {},
"outputs": [],
"source": [
"# Create the Microsoft Foundry client\n",
"client = FoundryChatClient(\n",
" project_endpoint=endpoint,\n",
" model=deployment_name,\n",
" credential=DefaultAzureCredential()\n",
")"
]
},
{
"cell_type": "markdown",
"id": "e5f6a7b8",
"metadata": {},
"source": [
"## Why Multi-Agent Systems?\n",
"\n",
"Real-world tasks like trip planning involve many different kinds of expertise — logistics, local knowledge, budgeting, and more. A single agent trying to handle everything quickly becomes unwieldy.\n",
"\n",
"Multi-agent systems solve this through **specialization**: each agent focuses on one area of expertise, producing higher-quality results than a generalist. They also improve **scalability** — you can add new agents (e.g., a flight specialist, a restaurant critic) without rewriting the existing workflow. The agents compose together through a structured pipeline, passing context from one to the next."
]
},
{
"cell_type": "markdown",
"id": "f6a7b8c9",
"metadata": {},
"source": [
"## Creating Specialized Agents"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a7b8c9d0",
"metadata": {},
"outputs": [],
"source": [
"planner_agent = client.as_agent(\n",
" name=\"TravelPlanner\",\n",
" instructions=\"You are a travel planning specialist. Create detailed trip itineraries based on the traveler's preferences. Include daily schedules, must-see attractions, and logistical tips.\",\n",
")\n",
"\n",
"concierge_agent = client.as_agent(\n",
" name=\"TravelConcierge\",\n",
" instructions=\"You are a travel concierge who reviews and enhances trip plans. Review the plan for completeness, add local insider tips, suggest restaurants, and identify potential issues. Provide your feedback in a constructive format.\",\n",
")"
]
},
{
"cell_type": "markdown",
"id": "b8c9d0e1",
"metadata": {},
"source": [
"## Building a Sequential Workflow\n",
"\n",
"`WorkflowBuilder` lets you wire agents into a directed graph. Here we create a simple two-step pipeline: the **TravelPlanner** drafts the itinerary, then the **TravelConcierge** reviews and enhances it."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c9d0e1f2",
"metadata": {},
"outputs": [],
"source": [
"workflow = WorkflowBuilder(start_executor=planner_agent) \\\n",
" .add_edge(planner_agent, concierge_agent) \\\n",
" .build()\n",
"\n",
"last_author = None\n",
"events = workflow.run(\"Plan a 5-day trip to Paris for a food-loving couple on a $3000 budget.\", stream=True)\n",
"async for event in events:\n",
" if event.type == \"output\" and isinstance(event.data, AgentResponseUpdate):\n",
" update = event.data\n",
" author = update.author_name\n",
" if author != last_author:\n",
" if last_author is not None:\n",
" print()\n",
" print(f\"\\n{'='*50}\")\n",
" print(f\"🤖 {author}:\")\n",
" print(f\"{'='*50}\")\n",
" last_author = author\n",
" print(update.text, end=\"\", flush=True)"
]
},
{
"cell_type": "markdown",
"id": "d0e1f2a3",
"metadata": {},
"source": [
"## Adding More Agents to the Workflow\n",
"\n",
"One of the biggest advantages of the multi-agent pattern is how easy it is to extend. Below we add a **BudgetReviewer** agent that checks the plan against the traveler's budget, flags items that might push costs over the limit, and suggests money-saving alternatives. The workflow now runs three agents in sequence:\n",
"\n",
"```\n",
"TravelPlanner → TravelConcierge → BudgetReviewer\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e1f2a3b4",
"metadata": {},
"outputs": [],
"source": [
"budget_agent = client.as_agent(\n",
" name=\"BudgetReviewer\",\n",
" instructions=\"You are a budget-conscious travel advisor. Review the proposed trip plan and concierge enhancements against the traveler's stated budget. Estimate costs for flights, hotels, meals, and activities. Flag anything that risks exceeding the budget and suggest cost-saving alternatives while preserving the trip's quality.\",\n",
")\n",
"\n",
"extended_workflow = WorkflowBuilder(start_executor=planner_agent) \\\n",
" .add_edge(planner_agent, concierge_agent) \\\n",
" .add_edge(concierge_agent, budget_agent) \\\n",
" .build()\n",
"\n",
"last_author = None\n",
"events = extended_workflow.run(\"Plan a 5-day trip to Paris for a food-loving couple on a $3000 budget.\", stream=True)\n",
"async for event in events:\n",
" if event.type == \"output\" and isinstance(event.data, AgentResponseUpdate):\n",
" update = event.data\n",
" author = update.author_name\n",
" if author != last_author:\n",
" if last_author is not None:\n",
" print()\n",
" print(f\"\\n{'='*50}\")\n",
" print(f\"🤖 {author}:\")\n",
" print(f\"{'='*50}\")\n",
" last_author = author\n",
" print(update.text, end=\"\", flush=True)"
]
},
{
"cell_type": "markdown",
"id": "f2a3b4c5",
"metadata": {},
"source": [
"## Summary\n",
"\n",
"In this lesson you learned how to:\n",
"\n",
"1. **Create specialized agents** — each with a focused role (planning, concierge, budget review).\n",
"2. **Wire agents into a sequential workflow** using `WorkflowBuilder` and `add_edge`.\n",
"3. **Stream output** from a multi-agent pipeline, tracking which agent is speaking.\n",
"4. **Extend a workflow** by adding new agents to the chain without modifying existing ones.\n",
"\n",
"The multi-agent design pattern keeps each agent simple while producing richer, more thoroughly reviewed results than any single agent could achieve alone."
]
}
],
"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
}