561 lines
23 KiB
Plaintext
561 lines
23 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "69f48405",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Travel Recommendations with Concurrent Orchestration\n",
|
||
"\n",
|
||
"This notebook demonstrates **concurrent orchestration** using the Microsoft Agent Framework. We'll build a travel recommendation system with three specialized agents that work in parallel to provide comprehensive travel insights.\n",
|
||
"\n",
|
||
"## What You'll Learn:\n",
|
||
"1. **Concurrent Orchestration**: Running multiple agents in parallel (fan-out/fan-in pattern)\n",
|
||
"2. **ConcurrentBuilder**: High-level API for building concurrent workflows\n",
|
||
"3. **Travel Recommendations**: Three specialized agents working together\n",
|
||
"4. **Default Aggregation**: Combining multiple agent responses\n",
|
||
"5. **Performance Benefits**: Parallel execution vs sequential processing\n",
|
||
"\n",
|
||
"\n",
|
||
"## Three Specialized Agents:\n",
|
||
"\n",
|
||
"1. **Attractions Agent**: Tourist attractions, activities, landmarks\n",
|
||
"2. **Dining Agent**: Local cuisine, restaurants, food experiences\n",
|
||
"3. **History Agent**: Historical facts, cultural significance, context"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "1c8918b5",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"import asyncio\n",
|
||
"import json\n",
|
||
"import os\n",
|
||
"from typing import Any, cast\n",
|
||
"\n",
|
||
"from agent_framework import (\n",
|
||
" Executor,\n",
|
||
" Message,\n",
|
||
" WorkflowBuilder,\n",
|
||
" WorkflowContext,\n",
|
||
" handler,\n",
|
||
")\n",
|
||
"from agent_framework.foundry import FoundryChatClient\n",
|
||
"from azure.identity import AzureCliCredential\n",
|
||
"from dotenv import load_dotenv\n",
|
||
"from IPython.display import HTML, display\n",
|
||
"from pydantic import BaseModel\n",
|
||
"\n",
|
||
"print(\"All imports successful!\")\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "2733c34d",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Step 1: Define Pydantic Models for Structured Outputs\n",
|
||
"\n",
|
||
"These models define the schema that each specialized agent will return. This ensures consistent and parseable responses from all agents."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "0d144c4c",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Step 1: Define Pydantic Models for Structured Outputs\n",
|
||
"\n",
|
||
"These models define the schema that each specialized agent will return. This ensures consistent and parseable responses from all agents."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "e0749818",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"class AttractionsRecommendation(BaseModel):\n",
|
||
" \"\"\"Tourist attractions and activities recommendations.\"\"\"\n",
|
||
"\n",
|
||
" destination: str\n",
|
||
" top_attractions: list[str]\n",
|
||
" activities: list[str]\n",
|
||
" best_time_to_visit: str\n",
|
||
" transportation_tips: str \n",
|
||
"\n",
|
||
"\n",
|
||
"class DiningRecommendation(BaseModel):\n",
|
||
" \"\"\"Food and dining recommendations.\"\"\"\n",
|
||
"\n",
|
||
" destination: str\n",
|
||
" local_cuisine: str\n",
|
||
" must_try_dishes: list[str]\n",
|
||
" recommended_restaurants: list[str]\n",
|
||
" food_experiences: list[str]\n",
|
||
" dining_etiquette: str\n",
|
||
"\n",
|
||
"\n",
|
||
"class HistoryRecommendation(BaseModel):\n",
|
||
" \"\"\"Historical and cultural information.\"\"\"\n",
|
||
"\n",
|
||
" destination: str\n",
|
||
" historical_significance: str\n",
|
||
" cultural_highlights: list[str]\n",
|
||
" important_periods: list[str]\n",
|
||
" cultural_experiences: list[str]\n",
|
||
" interesting_facts: list[str]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "979521fb",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Step 2: Load Environment Variables and Configure the Foundry Provider\n",
|
||
"\n",
|
||
"Use `FoundryChatClient` with keyless `AzureCliCredential` authentication, matching the pattern used in lessons 01–13.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "c5179ca3",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Load environment variables\n",
|
||
"load_dotenv()\n",
|
||
"\n",
|
||
"# Configure the Microsoft Foundry provider with keyless authentication\n",
|
||
"provider = FoundryChatClient(\n",
|
||
" project_endpoint=os.environ[\"AZURE_AI_PROJECT_ENDPOINT\"],\n",
|
||
" model=os.environ[\"AZURE_AI_MODEL_DEPLOYMENT_NAME\"],\n",
|
||
" credential=AzureCliCredential(),\n",
|
||
")\n",
|
||
"\n",
|
||
"print(\"Microsoft Foundry provider configured successfully!\")\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "8e4eb398",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Step 3: Create Three Specialized Travel Agents\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "6a9571c6",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Agent 1: Tourist Attractions Expert\n",
|
||
"attractions_agent = provider.as_agent(\n",
|
||
" name=\"attractions-agent\",\n",
|
||
" instructions=(\n",
|
||
" \"You are a tourism expert specializing in attractions and activities. \"\n",
|
||
" \"When given a travel destination, provide comprehensive recommendations for \"\n",
|
||
" \"tourist attractions, activities, best times to visit, and transportation tips. \"\n",
|
||
" \"Focus on popular landmarks, unique experiences, and practical travel advice. \"\n",
|
||
" \"Return structured JSON matching the AttractionsRecommendation schema.\"\n",
|
||
" ),\n",
|
||
")\n",
|
||
"\n",
|
||
"# Agent 2: Food and Dining Expert\n",
|
||
"dining_agent = provider.as_agent(\n",
|
||
" name=\"dining-agent\",\n",
|
||
" instructions=(\n",
|
||
" \"You are a culinary expert specializing in local food and dining experiences. \"\n",
|
||
" \"When given a travel destination, provide recommendations for local cuisine, \"\n",
|
||
" \"must-try dishes, recommended restaurants, and unique food experiences. \"\n",
|
||
" \"Include dining etiquette and cultural food customs. \"\n",
|
||
" \"Return structured JSON matching the DiningRecommendation schema.\"\n",
|
||
" ),\n",
|
||
")\n",
|
||
"\n",
|
||
"\n",
|
||
"# Agent 3: History and Culture Expert\n",
|
||
"history_agent = provider.as_agent(\n",
|
||
" name=\"history-agent\",\n",
|
||
" instructions=(\n",
|
||
" \"You are a historian and cultural expert. \"\n",
|
||
" \"When given a travel destination, provide historical context, cultural significance, \"\n",
|
||
" \"important historical periods, cultural experiences, and interesting facts. \"\n",
|
||
" \"Focus on helping travelers understand the cultural heritage and historical importance. \"\n",
|
||
" \"Return structured JSON matching the HistoryRecommendation schema.\"\n",
|
||
" ),\n",
|
||
")\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "2b22d245",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Step 4: Build the Concurrent Workflow\n",
|
||
"\n",
|
||
"`WorkflowBuilder` with a small dispatcher executor and `add_fan_out_edges`:\n",
|
||
"1. **Dispatcher** broadcasts the same input to all three agents\n",
|
||
"2. **Three agents** run in parallel\n",
|
||
"3. **Output** collects each agent's response separately"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "4bad34b0",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# A passthrough executor that broadcasts the user input to every agent in parallel.\n",
|
||
"class InputDispatcher(Executor):\n",
|
||
" \"\"\"Forward the user input unchanged to all participating agents.\"\"\"\n",
|
||
"\n",
|
||
" @handler\n",
|
||
" async def forward(self, text: str, ctx: WorkflowContext[str]) -> None:\n",
|
||
" await ctx.send_message(text)\n",
|
||
"\n",
|
||
"\n",
|
||
"dispatcher = InputDispatcher(id=\"dispatcher\")\n",
|
||
"agents = [attractions_agent, dining_agent, history_agent]\n",
|
||
"\n",
|
||
"workflow = (\n",
|
||
" WorkflowBuilder(\n",
|
||
" start_executor=dispatcher,\n",
|
||
" output_executors=agents,\n",
|
||
" )\n",
|
||
" .add_fan_out_edges(dispatcher, agents)\n",
|
||
" .build()\n",
|
||
")\n",
|
||
"\n",
|
||
"display(HTML(\"\"\"\n",
|
||
"<div style='padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 8px; margin: 10px 0;'>\n",
|
||
" <h3 style='margin: 0 0 15px 0;'>Concurrent Workflow Built Successfully!</h3>\n",
|
||
" <p style='margin: 0; line-height: 1.6;'>\n",
|
||
" <strong>Architecture:</strong><br>\n",
|
||
" • Input → <strong>Dispatcher</strong> (fan-out)<br>\n",
|
||
" • <strong>3 Agents</strong> run in parallel (attractions, dining, history)<br>\n",
|
||
" • Output → 3 AgentResponse objects, one per agent\n",
|
||
" </p>\n",
|
||
"</div>\n",
|
||
"\"\"\"))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "e920f2f6",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Step 5: Test Case 1 - Tokyo Travel Recommendations\n",
|
||
"\n",
|
||
"Let's test our concurrent workflow with Tokyo as the destination. All three agents will work simultaneously to provide comprehensive travel recommendations."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "090ae929",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"async def display_travel_recommendations(destination: str):\n",
|
||
" \"\"\"Run the concurrent workflow and display formatted results.\"\"\"\n",
|
||
"\n",
|
||
" display(HTML(f\"\"\"\n",
|
||
" <div style='padding: 20px; background: #fff3e0; border-left: 4px solid #ff9800; border-radius: 8px; margin: 20px 0;'>\n",
|
||
" <h3 style='margin: 0 0 10px 0; color: #e65100;'>Processing Travel Recommendations for {destination}</h3>\n",
|
||
" <p style='margin: 0;'><strong>Status:</strong> Running 3 agents concurrently...</p>\n",
|
||
" </div>\n",
|
||
" \"\"\"))\n",
|
||
"\n",
|
||
" # Run the workflow. With WorkflowBuilder(output_executors=[a1, a2, a3]),\n",
|
||
" # outputs is a list of AgentResponse objects in the same order as output_executors.\n",
|
||
" events = await workflow.run(f\"I want comprehensive travel recommendations for {destination}\")\n",
|
||
" outputs = events.get_outputs()\n",
|
||
"\n",
|
||
" # Display results header\n",
|
||
" display(HTML(f\"\"\"\n",
|
||
" <div style='padding: 25px; background: linear-gradient(135deg, #4caf50 0%, #8bc34a 100%); color: white; border-radius: 12px;\n",
|
||
" box-shadow: 0 4px 12px rgba(76,175,80,0.3); margin: 20px 0;'>\n",
|
||
" <h2 style='margin: 0 0 20px 0;'>Complete Travel Guide for {destination}</h2>\n",
|
||
" <p style='margin: 0; font-size: 14px; opacity: 0.9;'>Generated by 3 concurrent agents</p>\n",
|
||
" </div>\n",
|
||
" \"\"\"))\n",
|
||
"\n",
|
||
" sections = [\n",
|
||
" (\"attractions-agent\", AttractionsRecommendation, display_attractions_section),\n",
|
||
" (\"dining-agent\", DiningRecommendation, display_dining_section),\n",
|
||
" (\"history-agent\", HistoryRecommendation, display_history_section),\n",
|
||
" ]\n",
|
||
"\n",
|
||
" for i, (agent_name, schema, render) in enumerate(sections):\n",
|
||
" if i >= len(outputs):\n",
|
||
" continue\n",
|
||
" text = outputs[i].text\n",
|
||
" try:\n",
|
||
" data = schema.model_validate_json(text)\n",
|
||
" render(data)\n",
|
||
" except Exception as e:\n",
|
||
" display(HTML(f\"\"\"\n",
|
||
" <div style='padding: 15px; background: #ffcdd2; border-left: 4px solid #f44336; border-radius: 4px; margin: 10px 0;'>\n",
|
||
" <strong>Error parsing {agent_name} response:</strong> {str(e)}\n",
|
||
" <details><summary>Raw response</summary>{text}</details>\n",
|
||
" </div>\n",
|
||
" \"\"\"))\n",
|
||
"\n",
|
||
"\n",
|
||
"def display_attractions_section(data: AttractionsRecommendation):\n",
|
||
" \"\"\"Display attractions recommendations in a formatted section.\"\"\"\n",
|
||
" attractions_list = \"\".join([f\"<li>{attraction}</li>\" for attraction in data.top_attractions])\n",
|
||
" activities_list = \"\".join([f\"<li>{activity}</li>\" for activity in data.activities])\n",
|
||
"\n",
|
||
" display(HTML(f\"\"\"\n",
|
||
" <div style='padding: 20px; background: #e3f2fd; border-radius: 8px; margin: 15px 0; border-left: 4px solid #2196f3;'>\n",
|
||
" <h3 style='margin: 0 0 15px 0; color: #1976d2;'>🏛️ Tourist Attractions & Activities</h3>\n",
|
||
" <div style='margin-bottom: 15px;'>\n",
|
||
" <h4 style='margin: 0 0 8px 0; color: #333;'>Top Attractions:</h4>\n",
|
||
" <ul style='margin: 0; padding-left: 20px; color: #555;'>{attractions_list}</ul>\n",
|
||
" </div>\n",
|
||
" <div style='margin-bottom: 15px;'>\n",
|
||
" <h4 style='margin: 0 0 8px 0; color: #333;'>Recommended Activities:</h4>\n",
|
||
" <ul style='margin: 0; padding-left: 20px; color: #555;'>{activities_list}</ul>\n",
|
||
" </div>\n",
|
||
" <div style='margin-bottom: 10px;'>\n",
|
||
" <strong style='color: #333;'>Best Time to Visit:</strong> {data.best_time_to_visit}\n",
|
||
" </div>\n",
|
||
" <div>\n",
|
||
" <strong style='color: #333;'>Transportation Tips:</strong> {data.transportation_tips}\n",
|
||
" </div>\n",
|
||
" </div>\n",
|
||
" \"\"\"))\n",
|
||
"\n",
|
||
"\n",
|
||
"def display_dining_section(data: DiningRecommendation):\n",
|
||
" \"\"\"Display dining recommendations in a formatted section.\"\"\"\n",
|
||
" dishes_list = \"\".join(\n",
|
||
" [f\"<li>{dish}</li>\" for dish in data.must_try_dishes])\n",
|
||
" restaurants_list = \"\".join(\n",
|
||
" [f\"<li>{restaurant}</li>\" for restaurant in data.recommended_restaurants])\n",
|
||
" experiences_list = \"\".join(\n",
|
||
" [f\"<li>{exp}</li>\" for exp in data.food_experiences])\n",
|
||
"\n",
|
||
" display(HTML(f\"\"\"\n",
|
||
" <div style='padding: 20px; background: #fff3e0; border-radius: 8px; margin: 15px 0; border-left: 4px solid #ff9800;'>\n",
|
||
" <h3 style='margin: 0 0 15px 0; color: #f57c00;'>🍜 Food & Dining Experiences</h3>\n",
|
||
" <div style='margin-bottom: 15px;'>\n",
|
||
" <strong style='color: #333;'>Local Cuisine:</strong> {data.local_cuisine}\n",
|
||
" </div>\n",
|
||
" <div style='margin-bottom: 15px;'>\n",
|
||
" <h4 style='margin: 0 0 8px 0; color: #333;'>Must-Try Dishes:</h4>\n",
|
||
" <ul style='margin: 0; padding-left: 20px; color: #555;'>{dishes_list}</ul>\n",
|
||
" </div>\n",
|
||
" <div style='margin-bottom: 15px;'>\n",
|
||
" <h4 style='margin: 0 0 8px 0; color: #333;'>Recommended Restaurants:</h4>\n",
|
||
" <ul style='margin: 0; padding-left: 20px; color: #555;'>{restaurants_list}</ul>\n",
|
||
" </div>\n",
|
||
" <div style='margin-bottom: 15px;'>\n",
|
||
" <h4 style='margin: 0 0 8px 0; color: #333;'>Food Experiences:</h4>\n",
|
||
" <ul style='margin: 0; padding-left: 20px; color: #555;'>{experiences_list}</ul>\n",
|
||
" </div>\n",
|
||
" <div>\n",
|
||
" <strong style='color: #333;'>Dining Etiquette:</strong> {data.dining_etiquette}\n",
|
||
" </div>\n",
|
||
" </div>\n",
|
||
" \"\"\"))\n",
|
||
"\n",
|
||
"\n",
|
||
"def display_history_section(data: HistoryRecommendation):\n",
|
||
" \"\"\"Display history recommendations in a formatted section.\"\"\"\n",
|
||
" highlights_list = \"\".join(\n",
|
||
" [f\"<li>{highlight}</li>\" for highlight in data.cultural_highlights])\n",
|
||
" periods_list = \"\".join(\n",
|
||
" [f\"<li>{period}</li>\" for period in data.important_periods])\n",
|
||
" experiences_list = \"\".join(\n",
|
||
" [f\"<li>{exp}</li>\" for exp in data.cultural_experiences])\n",
|
||
" facts_list = \"\".join(\n",
|
||
" [f\"<li>{fact}</li>\" for fact in data.interesting_facts])\n",
|
||
"\n",
|
||
" display(HTML(f\"\"\"\n",
|
||
" <div style='padding: 20px; background: #f3e5f5; border-radius: 8px; margin: 15px 0; border-left: 4px solid #9c27b0;'>\n",
|
||
" <h3 style='margin: 0 0 15px 0; color: #7b1fa2;'>📚 History & Culture</h3>\n",
|
||
" <div style='margin-bottom: 15px;'>\n",
|
||
" <strong style='color: #333;'>Historical Significance:</strong> {data.historical_significance}\n",
|
||
" </div>\n",
|
||
" <div style='margin-bottom: 15px;'>\n",
|
||
" <h4 style='margin: 0 0 8px 0; color: #333;'>Cultural Highlights:</h4>\n",
|
||
" <ul style='margin: 0; padding-left: 20px; color: #555;'>{highlights_list}</ul>\n",
|
||
" </div>\n",
|
||
" <div style='margin-bottom: 15px;'>\n",
|
||
" <h4 style='margin: 0 0 8px 0; color: #333;'>Important Historical Periods:</h4>\n",
|
||
" <ul style='margin: 0; padding-left: 20px; color: #555;'>{periods_list}</ul>\n",
|
||
" </div>\n",
|
||
" <div style='margin-bottom: 15px;'>\n",
|
||
" <h4 style='margin: 0 0 8px 0; color: #333;'>Cultural Experiences:</h4>\n",
|
||
" <ul style='margin: 0; padding-left: 20px; color: #555;'>{experiences_list}</ul>\n",
|
||
" </div>\n",
|
||
" <div>\n",
|
||
" <h4 style='margin: 0 0 8px 0; color: #333;'>Interesting Facts:</h4>\n",
|
||
" <ul style='margin: 0; padding-left: 20px; color: #555;'>{facts_list}</ul>\n",
|
||
" </div>\n",
|
||
" </div>\n",
|
||
" \"\"\"))\n",
|
||
"\n",
|
||
"\n",
|
||
"# Test with Tokyo\n",
|
||
"await display_travel_recommendations(\"Tokyo\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "454fa849",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Step 6: Test Case 2 - Paris Travel Recommendations"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "8a23dbc4",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"await display_travel_recommendations(\"Paris\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "7b173674",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Step 7: Performance Analysis - Concurrent vs Sequential\n",
|
||
"\n",
|
||
"Let's measure the performance difference between concurrent and sequential execution to demonstrate the benefits of concurrent orchestration.\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "e0badd2e",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"import time\n",
|
||
"\n",
|
||
"\n",
|
||
"async def measure_concurrent_performance(destination: str):\n",
|
||
" \"\"\"Measure concurrent execution time.\"\"\"\n",
|
||
" start_time = time.time()\n",
|
||
"\n",
|
||
" events = await workflow.run(f\"I want travel recommendations for {destination}\")\n",
|
||
" outputs = events.get_outputs()\n",
|
||
"\n",
|
||
" end_time = time.time()\n",
|
||
" return end_time - start_time, len(outputs)\n",
|
||
"\n",
|
||
"\n",
|
||
"async def measure_sequential_performance(destination: str):\n",
|
||
" \"\"\"Measure sequential execution time.\"\"\"\n",
|
||
" # Build a sequential workflow that chains the same agents one after another.\n",
|
||
" sequential_workflow = (\n",
|
||
" WorkflowBuilder(\n",
|
||
" start_executor=attractions_agent,\n",
|
||
" output_executors=[attractions_agent, dining_agent, history_agent],\n",
|
||
" )\n",
|
||
" .add_chain([attractions_agent, dining_agent, history_agent])\n",
|
||
" .build()\n",
|
||
" )\n",
|
||
" start_time = time.time()\n",
|
||
"\n",
|
||
" events = await sequential_workflow.run(f\"I want travel recommendations for {destination}\")\n",
|
||
" outputs = events.get_outputs()\n",
|
||
"\n",
|
||
" end_time = time.time()\n",
|
||
" return end_time - start_time, len(outputs)\n",
|
||
"\n",
|
||
"\n",
|
||
"async def performance_comparison():\n",
|
||
" \"\"\"Compare concurrent vs sequential performance.\"\"\"\n",
|
||
" test_destination = \"Barcelona\"\n",
|
||
"\n",
|
||
" display(HTML(\"\"\"\n",
|
||
" <div style='padding: 20px; background: #fff3e0; border-left: 4px solid #ff9800; border-radius: 8px; margin: 20px 0;'>\n",
|
||
" <h3 style='margin: 0 0 10px 0; color: #e65100;'>Performance Comparison Test</h3>\n",
|
||
" <p style='margin: 0;'>Testing with destination: <strong>Barcelona</strong></p>\n",
|
||
" </div>\n",
|
||
" \"\"\"))\n",
|
||
"\n",
|
||
" # Test concurrent execution\n",
|
||
" print(\"Running concurrent workflow...\")\n",
|
||
" concurrent_time, concurrent_count = await measure_concurrent_performance(test_destination)\n",
|
||
"\n",
|
||
" # Test sequential execution\n",
|
||
" print(\"Running sequential workflow...\")\n",
|
||
" sequential_time, sequential_count = await measure_sequential_performance(test_destination)\n",
|
||
"\n",
|
||
" # Calculate performance improvement\n",
|
||
" improvement = ((sequential_time - concurrent_time) / sequential_time) * 100\n",
|
||
"\n",
|
||
" display(HTML(f\"\"\"\n",
|
||
" <div style='padding: 25px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 12px;\n",
|
||
" box-shadow: 0 4px 12px rgba(102,126,234,0.4); margin: 20px 0;'>\n",
|
||
" <h2 style='margin: 0 0 20px 0;'>Performance Results</h2>\n",
|
||
" <div style='display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px;'>\n",
|
||
" <div style='background: rgba(255,255,255,0.1); padding: 15px; border-radius: 8px;'>\n",
|
||
" <h4 style='margin: 0 0 10px 0;'>⚡ Concurrent Execution</h4>\n",
|
||
" <p style='margin: 0; font-size: 24px; font-weight: bold;'>{concurrent_time:.2f}s</p>\n",
|
||
" <p style='margin: 5px 0 0 0; font-size: 14px; opacity: 0.9;'>{concurrent_count} agent responses</p>\n",
|
||
" </div>\n",
|
||
" <div style='background: rgba(255,255,255,0.1); padding: 15px; border-radius: 8px;'>\n",
|
||
" <h4 style='margin: 0 0 10px 0;'>🔄 Sequential Execution</h4>\n",
|
||
" <p style='margin: 0; font-size: 24px; font-weight: bold;'>{sequential_time:.2f}s</p>\n",
|
||
" <p style='margin: 5px 0 0 0; font-size: 14px; opacity: 0.9;'>{sequential_count} agent responses</p>\n",
|
||
" </div>\n",
|
||
" </div>\n",
|
||
" <div style='background: rgba(255,255,255,0.15); padding: 15px; border-radius: 8px;'>\n",
|
||
" <h4 style='margin: 0 0 10px 0;'>Performance Improvement</h4>\n",
|
||
" <p style='margin: 0; font-size: 20px; font-weight: bold;'>{improvement:.1f}% faster</p>\n",
|
||
" <p style='margin: 5px 0 0 0; font-size: 14px; opacity: 0.9;'>\n",
|
||
" Saved {sequential_time - concurrent_time:.2f} seconds with concurrent execution\n",
|
||
" </p>\n",
|
||
" </div>\n",
|
||
" </div>\n",
|
||
" \"\"\"))\n",
|
||
"\n",
|
||
"\n",
|
||
"# Run performance comparison\n",
|
||
"await performance_comparison()"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": ".venv (3.12.12)",
|
||
"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.12"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 5
|
||
}
|