chore: import upstream snapshot with attribution
This commit is contained in:
+348
@@ -0,0 +1,348 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3a045dd3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 🔄 Basic Agent Workflows with Microsoft Foundry (Python)\n",
|
||||
"\n",
|
||||
"## 📋 Workflow Orchestration Tutorial\n",
|
||||
"\n",
|
||||
"This notebook introduces the powerful **Workflow Builder** capabilities of the Microsoft Agent Framework. Learn how to create sophisticated, multi-step agent workflows that can handle complex business processes and coordinate multiple AI operations seamlessly.\n",
|
||||
"\n",
|
||||
"> **Migration note:** This sample previously referenced GitHub Models. GitHub Models is deprecated (retiring July 2026), so it now uses **Microsoft Foundry** through the `FoundryChatClient`, which targets the Azure OpenAI **Responses API**.\n",
|
||||
"\n",
|
||||
"## 🎯 Learning Objectives\n",
|
||||
"\n",
|
||||
"### 🏗️ **Workflow Architecture**\n",
|
||||
"- **Workflow Builder**: Design and orchestrate complex multi-step processes\n",
|
||||
"- **Event-Driven Execution**: Handle workflow events and state transitions\n",
|
||||
"- **Visual Workflow Design**: Create and visualize workflow structures\n",
|
||||
"- **Microsoft Foundry Integration**: Leverage AI models within workflow contexts\n",
|
||||
"\n",
|
||||
"### 🔄 **Process Orchestration**\n",
|
||||
"- **Sequential Operations**: Chain multiple agent tasks in logical order\n",
|
||||
"- **Conditional Logic**: Implement decision points and branching workflows\n",
|
||||
"- **Error Handling**: Robust error recovery and workflow resilience\n",
|
||||
"- **State Management**: Track and manage workflow execution state\n",
|
||||
"\n",
|
||||
"### 📊 **Enterprise Workflow Patterns**\n",
|
||||
"- **Business Process Automation**: Automate complex organizational workflows\n",
|
||||
"- **Multi-Agent Coordination**: Coordinate multiple specialized agents\n",
|
||||
"- **Scalable Execution**: Design workflows for enterprise-scale operations\n",
|
||||
"- **Monitoring & Observability**: Track workflow performance and outcomes\n",
|
||||
"\n",
|
||||
"## ⚙️ Prerequisites & Setup\n",
|
||||
"\n",
|
||||
"### 📦 **Required Dependencies**\n",
|
||||
"\n",
|
||||
"Install the Agent Framework with workflow capabilities:\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"pip install agent-framework -U\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🔑 **Microsoft Foundry Configuration**\n",
|
||||
"\n",
|
||||
"Sign in with the Azure CLI (`az login`) so `AzureCliCredential` can authenticate, then set your Microsoft Foundry project details.\n",
|
||||
"\n",
|
||||
"**Environment Setup (.env file):**\n",
|
||||
"```env\n",
|
||||
"AZURE_AI_PROJECT_ENDPOINT=https://<your-project>.services.ai.azure.com\n",
|
||||
"AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4o-mini\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🏢 **Enterprise Use Cases**\n",
|
||||
"\n",
|
||||
"**Business Process Examples:**\n",
|
||||
"- **Customer Onboarding**: Multi-step verification and setup workflows\n",
|
||||
"- **Content Pipeline**: Automated content creation, review, and publishing\n",
|
||||
"- **Data Processing**: ETL workflows with AI-powered transformation\n",
|
||||
"- **Quality Assurance**: Automated testing and validation processes\n",
|
||||
"\n",
|
||||
"**Workflow Benefits:**\n",
|
||||
"- 🎯 **Reliability**: Deterministic execution with error recovery\n",
|
||||
"- 📈 **Scalability**: Handle high-volume process automation\n",
|
||||
"- 🔍 **Observability**: Complete audit trails and monitoring\n",
|
||||
"- 🔧 **Maintainability**: Visual design and modular components\n",
|
||||
"\n",
|
||||
"## 🎨 Workflow Design Patterns\n",
|
||||
"\n",
|
||||
"### Basic Workflow Structure\n",
|
||||
"```mermaid\n",
|
||||
"graph TD\n",
|
||||
" A[Start] --> B[Agent Task 1]\n",
|
||||
" B --> C{Decision Point}\n",
|
||||
" C -->|Success| D[Agent Task 2]\n",
|
||||
" C -->|Failure| E[Error Handler]\n",
|
||||
" D --> F[End]\n",
|
||||
" E --> F\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"**Key Components:**\n",
|
||||
"- **WorkflowBuilder**: Main orchestration engine\n",
|
||||
"- **WorkflowEvent**: Event handling and communication\n",
|
||||
"- **WorkflowViz**: Visual workflow representation and debugging\n",
|
||||
"\n",
|
||||
"Let's build your first intelligent workflow! 🚀\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c0863be7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Already covered by repo-level requirements.txt; left for reference.\n",
|
||||
"# !pip install agent-framework -U"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "580e76d9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Core components for building sophisticated agent workflows\n",
|
||||
"from agent_framework import WorkflowBuilder, WorkflowEvent, WorkflowViz\n",
|
||||
"from agent_framework.foundry import FoundryChatClient\n",
|
||||
"from azure.identity import AzureCliCredential\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5fe71939",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 📦 Import Environment and System Utilities\n",
|
||||
"# Essential libraries for configuration and environment management\n",
|
||||
"\n",
|
||||
"import os # 🔧 Environment variable access\n",
|
||||
"from dotenv import load_dotenv # 📁 Secure configuration loading"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cf183974",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 🔧 Initialize Environment Configuration\n",
|
||||
"# Load Microsoft Foundry project settings from .env file\n",
|
||||
"load_dotenv()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7a679634",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Configure the Microsoft Foundry client with keyless authentication.\n",
|
||||
"# FoundryChatClient targets the Azure OpenAI Responses API.\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"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ba45c08b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"REVIEWER_NAME = \"Concierge\"\n",
|
||||
"REVIEWER_INSTRUCTIONS = \"\"\"\n",
|
||||
" You are an are hotel concierge who has opinions about providing the most local and authentic experiences for travelers.\n",
|
||||
" The goal is to determine if the front desk travel agent has recommended the best non-touristy experience for a traveler.\n",
|
||||
" If so, state that it is approved.\n",
|
||||
" If not, provide insight on how to refine the recommendation without using a specific example. \n",
|
||||
" \"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d9f520ff",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"FRONTDESK_NAME = \"FrontDesk\"\n",
|
||||
"FRONTDESK_INSTRUCTIONS = \"\"\"\n",
|
||||
" You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers.\n",
|
||||
" The goal is to provide the best activities and locations for a traveler to visit.\n",
|
||||
" Only provide a single recommendation per response.\n",
|
||||
" You're laser focused on the goal at hand.\n",
|
||||
" Don't waste time with chit chat.\n",
|
||||
" Consider suggestions when refining an idea.\n",
|
||||
" \"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ad4819e0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"reviewer_agent = provider.as_agent(\n",
|
||||
" name=REVIEWER_NAME,\n",
|
||||
" instructions=REVIEWER_INSTRUCTIONS,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"front_desk_agent = provider.as_agent(\n",
|
||||
" name=FRONTDESK_NAME,\n",
|
||||
" instructions=FRONTDESK_INSTRUCTIONS,\n",
|
||||
")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "150bb29b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"workflow = (\n",
|
||||
" WorkflowBuilder(start_executor=front_desk_agent)\n",
|
||||
" .add_edge(front_desk_agent, reviewer_agent)\n",
|
||||
" .build()\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e913c773",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"Generating workflow visualization...\")\n",
|
||||
"viz = WorkflowViz(workflow)\n",
|
||||
"# Print out the mermaid string.\n",
|
||||
"print(\"Mermaid string: \\n=======\")\n",
|
||||
"print(viz.to_mermaid())\n",
|
||||
"print(\"=======\")\n",
|
||||
"# Print out the DiGraph string.\n",
|
||||
"print(\"DiGraph string: \\n=======\")\n",
|
||||
"print(viz.to_digraph())\n",
|
||||
"print(\"=======\")\n",
|
||||
"# SVG export needs the optional graphviz extra plus the graphviz system binary;\n",
|
||||
"# fall back gracefully if it is not available.\n",
|
||||
"try:\n",
|
||||
" svg_file = viz.export(format=\"svg\")\n",
|
||||
" print(f\"SVG file saved to: {svg_file}\")\n",
|
||||
"except ImportError as e:\n",
|
||||
" svg_file = None\n",
|
||||
" print(f\"SVG export skipped (install graphviz to enable): {e}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5fe90eb5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class DatabaseEvent(WorkflowEvent): ..."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e802947c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Display the exported workflow SVG inline in the notebook\n",
|
||||
"\n",
|
||||
"from IPython.display import SVG, display, HTML\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"print(f\"Attempting to display SVG file at: {svg_file}\")\n",
|
||||
"\n",
|
||||
"if svg_file and os.path.exists(svg_file):\n",
|
||||
" try:\n",
|
||||
" # Preferred: direct SVG rendering\n",
|
||||
" display(SVG(filename=svg_file))\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"⚠️ Direct SVG render failed: {e}. Falling back to raw HTML.\")\n",
|
||||
" try:\n",
|
||||
" with open(svg_file, \"r\", encoding=\"utf-8\") as f:\n",
|
||||
" svg_text = f.read()\n",
|
||||
" display(HTML(svg_text))\n",
|
||||
" except Exception as inner:\n",
|
||||
" print(f\"❌ Fallback HTML render also failed: {inner}\")\n",
|
||||
"else:\n",
|
||||
" print(\"❌ SVG file not found. Ensure viz.export(format='svg') ran successfully.\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a0651dfc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Workflow.run_stream is no longer part of the public API; the current Workflow\n",
|
||||
"# returns a results object whose `get_outputs()` produces the AgentResponse from\n",
|
||||
"# each output executor. The reviewer (last stage) is the only output here.\n",
|
||||
"events = await workflow.run(\"I would like to go to Paris.\")\n",
|
||||
"outputs = events.get_outputs()\n",
|
||||
"result = outputs[0].text if outputs else \"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ad9e0c48",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"result.replace(\"None\", \"\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv (3.12.11)",
|
||||
"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.11"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelInfo": {
|
||||
"defaultKernelName": "csharp",
|
||||
"items": [
|
||||
{
|
||||
"aliases": [],
|
||||
"name": "csharp"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
+388
@@ -0,0 +1,388 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0f298ce0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# ⏩ Sequential Agent Workflows with Microsoft Foundry (Python)\n",
|
||||
"\n",
|
||||
"## 📋 Advanced Sequential Processing Tutorial\n",
|
||||
"\n",
|
||||
"This notebook demonstrates **sequential workflow patterns** using the Microsoft Agent Framework. You'll learn how to build sophisticated multi-step processing pipelines where agents execute in a specific order, passing data and context between stages.\n",
|
||||
"\n",
|
||||
"> **Migration note:** This sample previously referenced GitHub Models. GitHub Models is deprecated (retiring July 2026), so it now uses **Microsoft Foundry** through the `FoundryChatClient`, which targets the Azure OpenAI **Responses API**.\n",
|
||||
"\n",
|
||||
"## 🎯 Learning Objectives\n",
|
||||
"\n",
|
||||
"### 🔄 **Sequential Processing Patterns**\n",
|
||||
"- **Linear Workflow Design**: Create step-by-step processing pipelines\n",
|
||||
"- **Data Flow Management**: Pass information between sequential agents\n",
|
||||
"- **Stage-Gate Processing**: Implement checkpoints and validation stages\n",
|
||||
"- **Progress Tracking**: Monitor workflow execution and intermediate results\n",
|
||||
"\n",
|
||||
"### 🏗️ **Enterprise Pipeline Architecture**\n",
|
||||
"- **Business Process Modeling**: Map real business processes to agent workflows\n",
|
||||
"- **Quality Assurance**: Multi-stage validation and review processes\n",
|
||||
"- **Document Processing**: Sequential document analysis and transformation\n",
|
||||
"- **Content Production**: Editorial workflows with review and approval stages\n",
|
||||
"\n",
|
||||
"### 📊 **Advanced Workflow Features**\n",
|
||||
"- **Context Preservation**: Maintain state across workflow stages\n",
|
||||
"- **Error Propagation**: Handle failures in sequential processing\n",
|
||||
"- **Performance Optimization**: Efficient sequential execution patterns\n",
|
||||
"- **Audit Trails**: Complete tracking of sequential operations\n",
|
||||
"\n",
|
||||
"## ⚙️ Prerequisites & Setup\n",
|
||||
"\n",
|
||||
"### 📦 **Dependencies**\n",
|
||||
"```bash\n",
|
||||
"pip install agent-framework -U\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🔑 **Configuration**\n",
|
||||
"\n",
|
||||
"Sign in with the Azure CLI (`az login`) so `AzureCliCredential` can authenticate, then set your Microsoft Foundry project details.\n",
|
||||
"\n",
|
||||
"```env\n",
|
||||
"AZURE_AI_PROJECT_ENDPOINT=https://<your-project>.services.ai.azure.com\n",
|
||||
"AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4o-mini\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"## 🏢 **Enterprise Sequential Workflow Use Cases**\n",
|
||||
"\n",
|
||||
"### 📝 **Document Processing Pipeline**\n",
|
||||
"```\n",
|
||||
"Raw Document → Content Extraction → Analysis → Validation → Final Output\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🔍 **Quality Assurance Workflow** \n",
|
||||
"```\n",
|
||||
"Initial Review → Technical Validation → Compliance Check → Final Approval\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 📰 **Content Production Pipeline**\n",
|
||||
"```\n",
|
||||
"Research → Writing → Editing → Review → Publishing\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 💼 **Business Process Automation**\n",
|
||||
"```\n",
|
||||
"Data Collection → Processing → Analysis → Report Generation → Distribution\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"## 🎨 **Sequential Workflow Design Principles**\n",
|
||||
"\n",
|
||||
"- **🔗 Linear Progression**: Each stage depends on the previous stage's output\n",
|
||||
"- **📋 State Management**: Preserve context and data across all stages\n",
|
||||
"- **🛡️ Error Handling**: Graceful failure management in any stage\n",
|
||||
"- **📊 Progress Monitoring**: Track completion and performance at each stage\n",
|
||||
"- **🔄 Stage Reusability**: Design reusable workflow components\n",
|
||||
"\n",
|
||||
"Let's build sophisticated sequential processing workflows! 🚀\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a3dc4927",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Already covered by repo-level requirements.txt; left for reference.\n",
|
||||
"# !pip install agent-framework -U"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fec2cf19",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from agent_framework import (\n",
|
||||
" Message,\n",
|
||||
" WorkflowBuilder,\n",
|
||||
" WorkflowEvent,\n",
|
||||
" WorkflowViz,\n",
|
||||
")\n",
|
||||
"from agent_framework.foundry import FoundryChatClient\n",
|
||||
"from azure.identity import AzureCliCredential\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5d1a0590",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"import os\n",
|
||||
"import base64\n",
|
||||
"from dotenv import load_dotenv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cbbeaf06",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"load_dotenv()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b1ff1a7b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Configure the Microsoft Foundry client with keyless authentication.\n",
|
||||
"# FoundryChatClient targets the Azure OpenAI Responses API.\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"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0d64a0a0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"SalesAgentName = \"Sales-Agent\"\n",
|
||||
"SalesAgentInstructions = \"You are my furniture sales consultant, you can find different furniture elements from the pictures and give me a purchase suggestion\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "26b38cbf",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PriceAgentName = \"Price-Agent\"\n",
|
||||
"PriceAgentInstructions = \"\"\"You are a furniture pricing specialist and budget consultant. Your responsibilities include:\n",
|
||||
" 1. Analyze furniture items and provide realistic price ranges based on quality, brand, and market standards\n",
|
||||
" 2. Break down pricing by individual furniture pieces\n",
|
||||
" 3. Provide budget-friendly alternatives and premium options\n",
|
||||
" 4. Consider different price tiers (budget, mid-range, premium)\n",
|
||||
" 5. Include estimated total costs for room setups\n",
|
||||
" 6. Suggest where to find the best deals and shopping recommendations\n",
|
||||
" 7. Factor in additional costs like delivery, assembly, and accessories\n",
|
||||
" 8. Provide seasonal pricing insights and best times to buy\n",
|
||||
" Always format your response with clear price breakdowns and explanations for the pricing rationale.\"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8dad49b7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"QuoteAgentName = \"Quote-Agent\"\n",
|
||||
"QuoteAgentInstructions = \"\"\"You are a assistant that create a quote for furniture purchase.\n",
|
||||
" 1. Create a well-structured quote document that includes:\n",
|
||||
" 2. A title page with the document title, date, and client name\n",
|
||||
" 3. An introduction summarizing the purpose of the document\n",
|
||||
" 4. A summary section with total estimated costs and recommendations\n",
|
||||
" 5. Use clear headings, bullet points, and tables for easy readability\n",
|
||||
" 6. All quotes are presented in markdown form\"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c9a55d69",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sales_agent = provider.as_agent(\n",
|
||||
" name=SalesAgentName,\n",
|
||||
" instructions=SalesAgentInstructions,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"price_agent = provider.as_agent(\n",
|
||||
" name=PriceAgentName,\n",
|
||||
" instructions=PriceAgentInstructions,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"quote_agent = provider.as_agent(\n",
|
||||
" name=QuoteAgentName,\n",
|
||||
" instructions=QuoteAgentInstructions,\n",
|
||||
")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b3ac64f0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"workflow = (\n",
|
||||
" WorkflowBuilder(start_executor=sales_agent)\n",
|
||||
" .add_edge(sales_agent, price_agent)\n",
|
||||
" .add_edge(price_agent, quote_agent)\n",
|
||||
" .build()\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "12eb6379",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"Generating workflow visualization...\")\n",
|
||||
"viz = WorkflowViz(workflow)\n",
|
||||
"# Print out the mermaid string.\n",
|
||||
"print(\"Mermaid string: \\n=======\")\n",
|
||||
"print(viz.to_mermaid())\n",
|
||||
"print(\"=======\")\n",
|
||||
"# Print out the DiGraph string.\n",
|
||||
"print(\"DiGraph string: \\n=======\")\n",
|
||||
"print(viz.to_digraph())\n",
|
||||
"print(\"=======\")\n",
|
||||
"# SVG export needs the optional graphviz extra (`pip install graphviz`) plus the\n",
|
||||
"# graphviz system binary; if it's not available, fall back to the text strings above.\n",
|
||||
"try:\n",
|
||||
" svg_file = viz.export(format=\"svg\")\n",
|
||||
" print(f\"SVG file saved to: {svg_file}\")\n",
|
||||
"except ImportError as e:\n",
|
||||
" svg_file = None\n",
|
||||
" print(f\"SVG export skipped (install graphviz to enable): {e}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "57b86a4e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class DatabaseEvent(WorkflowEvent): ..."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "466f110e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Display the exported workflow SVG inline in the notebook\n",
|
||||
"\n",
|
||||
"from IPython.display import SVG, display, HTML\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"print(f\"Attempting to display SVG file at: {svg_file}\")\n",
|
||||
"\n",
|
||||
"if svg_file and os.path.exists(svg_file):\n",
|
||||
" try:\n",
|
||||
" # Preferred: direct SVG rendering\n",
|
||||
" display(SVG(filename=svg_file))\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"⚠️ Direct SVG render failed: {e}. Falling back to raw HTML.\")\n",
|
||||
" try:\n",
|
||||
" with open(svg_file, \"r\", encoding=\"utf-8\") as f:\n",
|
||||
" svg_text = f.read()\n",
|
||||
" display(HTML(svg_text))\n",
|
||||
" except Exception as inner:\n",
|
||||
" print(f\"❌ Fallback HTML render also failed: {inner}\")\n",
|
||||
"else:\n",
|
||||
" print(\"❌ SVG file not found. Ensure viz.export(format='svg') ran successfully.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e0c32e98",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"image_path = \"../imgs/home.png\"\n",
|
||||
"with open(image_path, \"rb\") as image_file:\n",
|
||||
" image_b64 = base64.b64encode(image_file.read()).decode()\n",
|
||||
"image_uri = f\"data:image/png;base64,{image_b64}\"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "417e237d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Note: the original notebook used a multimodal ChatMessage with an image of a\n",
|
||||
"# living room. The current Message class no longer ships TextContent/DataContent\n",
|
||||
"# helpers, so this migration uses a textual description of the same scene to\n",
|
||||
"# keep the lesson focused on sequential workflow mechanics.\n",
|
||||
"message = Message(\n",
|
||||
" role=\"user\",\n",
|
||||
" text=(\n",
|
||||
" \"I am furnishing a modern living room and want pieces that fit a warm, \"\n",
|
||||
" \"inviting style: a comfortable three-seat sofa, two accent armchairs, a \"\n",
|
||||
" \"wooden coffee table, a TV stand, a floor lamp, and a soft area rug. \"\n",
|
||||
" \"Please find appropriate furniture and give the corresponding price for \"\n",
|
||||
" \"each piece, then produce a final purchase quote.\"\n",
|
||||
" ),\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bb76bba5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Workflow.run_stream is no longer part of the public API; the current Workflow\n",
|
||||
"# returns a results object whose `get_outputs()` produces the AgentResponse from\n",
|
||||
"# each output executor. The final stage (quote_agent) is the only output here.\n",
|
||||
"events = await workflow.run(message)\n",
|
||||
"outputs = events.get_outputs()\n",
|
||||
"result = outputs[0].text if outputs else \"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a8db5dbb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"result.replace(\"None\", \"\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "agentenv",
|
||||
"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.10"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "795c70a9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# ⚡ Concurrent Agent Workflows with Microsoft Foundry (Python)\n",
|
||||
"\n",
|
||||
"## 📋 Advanced Parallel Processing Tutorial\n",
|
||||
"\n",
|
||||
"This notebook demonstrates **concurrent workflow patterns** using the Microsoft Agent Framework. You'll learn how to build high-performance, parallel processing workflows where multiple AI agents execute simultaneously, dramatically improving throughput and enabling sophisticated multi-threaded business processes.\n",
|
||||
"\n",
|
||||
"> **Migration note:** This sample previously referenced GitHub Models. GitHub Models is deprecated (retiring July 2026), so it now uses **Microsoft Foundry** through the `FoundryChatClient`, which targets the Azure OpenAI **Responses API**.\n",
|
||||
"\n",
|
||||
"## 🎯 Learning Objectives\n",
|
||||
"\n",
|
||||
"### 🚀 **Concurrent Processing Fundamentals**\n",
|
||||
"- **Parallel Agent Execution**: Run multiple agents simultaneously for maximum efficiency\n",
|
||||
"- **Workflow Orchestration**: Coordinate concurrent operations while maintaining data consistency\n",
|
||||
"- **Performance Optimization**: Achieve significant speedup through parallel processing\n",
|
||||
"- **Resource Management**: Efficiently utilize AI model resources across concurrent operations\n",
|
||||
"\n",
|
||||
"### 🏗️ **Advanced Concurrency Patterns**\n",
|
||||
"- **Fork-Join Processing**: Split work across multiple agents and merge results\n",
|
||||
"- **Pipeline Parallelism**: Overlapping execution stages for continuous throughput\n",
|
||||
"- **Load Balancing**: Distribute work evenly across available agent resources\n",
|
||||
"- **Synchronization Points**: Coordinate concurrent agents at critical workflow stages\n",
|
||||
"\n",
|
||||
"### 🏢 **Enterprise Concurrent Applications**\n",
|
||||
"- **High-Volume Document Processing**: Process multiple documents simultaneously\n",
|
||||
"- **Real-Time Content Analysis**: Concurrent analysis of incoming data streams\n",
|
||||
"- **Batch Processing Optimization**: Maximize throughput for large-scale operations\n",
|
||||
"- **Multi-Modal Analysis**: Parallel processing of different content types (text, images, data)\n",
|
||||
"\n",
|
||||
"## ⚙️ Prerequisites & Setup\n",
|
||||
"\n",
|
||||
"### 📦 **Required Dependencies**\n",
|
||||
"\n",
|
||||
"Install Agent Framework with concurrent workflow capabilities:\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"pip install agent-framework -U\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🔑 **Microsoft Foundry Configuration**\n",
|
||||
"\n",
|
||||
"Sign in with the Azure CLI (`az login`) so `AzureCliCredential` can authenticate, then set your Microsoft Foundry project details.\n",
|
||||
"\n",
|
||||
"**Environment Setup (.env file):**\n",
|
||||
"```env\n",
|
||||
"AZURE_AI_PROJECT_ENDPOINT=https://<your-project>.services.ai.azure.com\n",
|
||||
"AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4o-mini\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"**Concurrent Processing Considerations:**\n",
|
||||
"- **Rate Limits**: Monitor Azure OpenAI rate limits for concurrent requests\n",
|
||||
"- **Resource Usage**: Consider memory and CPU usage with multiple concurrent agents\n",
|
||||
"- **Error Handling**: Implement robust error recovery for parallel operations\n",
|
||||
"\n",
|
||||
"### 🏗️ **Concurrent Workflow Architecture**\n",
|
||||
"\n",
|
||||
"```mermaid\n",
|
||||
"graph TD\n",
|
||||
" A[Workflow Start] --> B[Concurrent Execution]\n",
|
||||
" B --> C[Agent Pool 1]\n",
|
||||
" B --> D[Agent Pool 2]\n",
|
||||
" B --> E[Agent Pool 3]\n",
|
||||
" C --> F[Result Aggregation]\n",
|
||||
" D --> F\n",
|
||||
" E --> F\n",
|
||||
" F --> G[Final Output]\n",
|
||||
" \n",
|
||||
" H[Microsoft Foundry] --> C\n",
|
||||
" H --> D\n",
|
||||
" H --> E\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"**Key Benefits:**\n",
|
||||
"- **⚡ Performance**: Significant speedup through parallel execution\n",
|
||||
"- **📈 Scalability**: Handle increased workloads without proportional time increase\n",
|
||||
"- **🔄 Efficiency**: Better utilization of available computational resources\n",
|
||||
"- **🎯 Throughput**: Process more work in the same amount of time\n",
|
||||
"\n",
|
||||
"## 🎨 **Concurrent Workflow Design Patterns**\n",
|
||||
"\n",
|
||||
"### 🔍 **Research & Analysis Pipeline**\n",
|
||||
"```\n",
|
||||
"Research Task → Parallel Research Agents → Content Synthesis → Quality Review\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 📊 **Data Processing Workflow**\n",
|
||||
"```\n",
|
||||
"Input Data → Concurrent Processing Agents → Result Aggregation → Final Report\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🎭 **Content Creation Pipeline**\n",
|
||||
"```\n",
|
||||
"Content Brief → Parallel Content Generators → Review & Merge → Final Content\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🔄 **Multi-Stage Processing**\n",
|
||||
"```\n",
|
||||
"Input → Stage 1 (Concurrent) → Stage 2 (Concurrent) → Stage 3 (Sequential) → Output\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"## 🏢 **Enterprise Performance Benefits**\n",
|
||||
"\n",
|
||||
"### ⚡ **Throughput Optimization**\n",
|
||||
"- **Parallel Execution**: Multiple agents working simultaneously\n",
|
||||
"- **Resource Utilization**: Maximum efficiency of available AI model capacity\n",
|
||||
"- **Time Reduction**: Significant decrease in total processing time\n",
|
||||
"- **Scalable Architecture**: Easily add more concurrent agents as needed\n",
|
||||
"\n",
|
||||
"### 🛡️ **Reliability & Resilience**\n",
|
||||
"- **Fault Tolerance**: Individual agent failures don't stop the entire workflow\n",
|
||||
"- **Error Isolation**: Problems in one concurrent branch don't affect others\n",
|
||||
"- **Graceful Degradation**: System continues operating even with reduced agent capacity\n",
|
||||
"- **Recovery Mechanisms**: Automatic retry and error handling for failed operations\n",
|
||||
"\n",
|
||||
"### 📊 **Monitoring & Observability**\n",
|
||||
"- **Concurrent Execution Tracking**: Monitor progress of all parallel operations\n",
|
||||
"- **Performance Metrics**: Measure speedup and efficiency gains\n",
|
||||
"- **Resource Usage Analytics**: Optimize concurrent agent allocation\n",
|
||||
"- **Bottleneck Identification**: Find and resolve performance constraints\n",
|
||||
"\n",
|
||||
"Let's build high-performance concurrent AI workflows! 🚀\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "81f035d2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Already covered by repo-level requirements.txt; left for reference.\n",
|
||||
"# !pip install agent-framework -U"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c171c539",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from typing import Any\n",
|
||||
"\n",
|
||||
"from agent_framework import (\n",
|
||||
" Executor,\n",
|
||||
" Message,\n",
|
||||
" WorkflowBuilder,\n",
|
||||
" WorkflowContext,\n",
|
||||
" WorkflowViz,\n",
|
||||
" handler,\n",
|
||||
")\n",
|
||||
"from agent_framework.foundry import FoundryChatClient\n",
|
||||
"from azure.identity import AzureCliCredential\n",
|
||||
"from dotenv import load_dotenv\n",
|
||||
"\n",
|
||||
"load_dotenv()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6ce4663e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Configure the Microsoft Foundry client with keyless authentication.\n",
|
||||
"# FoundryChatClient targets the Azure OpenAI Responses API.\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"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ae0b1744",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"ResearcherAgentName = \"Researcher-Agent\"\n",
|
||||
"ResearcherAgentInstructions = \"You are my travel researcher, working with me to analyze the destination, list relevant attractions, and make detailed plans for each attraction.\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "339ca225",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PlanAgentName = \"Plan-Agent\"\n",
|
||||
"PlanAgentInstructions = \"You are my travel planner, working with me to create a detailed travel plan based on the researcher's findings.\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "36381824",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"research_agent = provider.as_agent(\n",
|
||||
" name=ResearcherAgentName,\n",
|
||||
" instructions=ResearcherAgentInstructions,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"plan_agent = provider.as_agent(\n",
|
||||
" name=PlanAgentName,\n",
|
||||
" instructions=PlanAgentInstructions,\n",
|
||||
")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cc9f8593",
|
||||
"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 = [research_agent, plan_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",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5c7ede3e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"Generating workflow visualization...\")\n",
|
||||
"viz = WorkflowViz(workflow)\n",
|
||||
"# Print out the mermaid string.\n",
|
||||
"print(\"Mermaid string: \\n=======\")\n",
|
||||
"print(viz.to_mermaid())\n",
|
||||
"print(\"=======\")\n",
|
||||
"# Print out the DiGraph string.\n",
|
||||
"print(\"DiGraph string: \\n=======\")\n",
|
||||
"print(viz.to_digraph())\n",
|
||||
"print(\"=======\")\n",
|
||||
"# SVG export needs the optional graphviz extra plus the graphviz system binary;\n",
|
||||
"# fall back gracefully if it is not available.\n",
|
||||
"try:\n",
|
||||
" svg_file = viz.export(format=\"svg\")\n",
|
||||
" print(f\"SVG file saved to: {svg_file}\")\n",
|
||||
"except ImportError as e:\n",
|
||||
" svg_file = None\n",
|
||||
" print(f\"SVG export skipped (install graphviz to enable): {e}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c329766a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from IPython.display import SVG, display, HTML\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"print(f\"Attempting to display SVG file at: {svg_file}\")\n",
|
||||
"\n",
|
||||
"if svg_file and os.path.exists(svg_file):\n",
|
||||
" try:\n",
|
||||
" # Preferred: direct SVG rendering\n",
|
||||
" display(SVG(filename=svg_file))\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"⚠️ Direct SVG render failed: {e}. Falling back to raw HTML.\")\n",
|
||||
" try:\n",
|
||||
" with open(svg_file, \"r\", encoding=\"utf-8\") as f:\n",
|
||||
" svg_text = f.read()\n",
|
||||
" display(HTML(svg_text))\n",
|
||||
" except Exception as inner:\n",
|
||||
" print(f\"❌ Fallback HTML render also failed: {inner}\")\n",
|
||||
"else:\n",
|
||||
" print(\"❌ SVG file not found. Ensure viz.export(format='svg') ran successfully.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ccf93181",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"events = await workflow.run(\"Plan a trip to Seattle in December\")\n",
|
||||
"outputs = events.get_outputs()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3b71d9c7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if outputs:\n",
|
||||
" print(\"===== Final Aggregated Responses =====\")\n",
|
||||
" # outputs is a list of AgentResponse objects, one per output executor\n",
|
||||
" # (research_agent then plan_agent), in the order given to output_executors.\n",
|
||||
" for i, response in enumerate(outputs, start=1):\n",
|
||||
" print(f\"{'-' * 60}\\n\\n{i:02d}:\\n{response.text}\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "agentenv",
|
||||
"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.10"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
+518
@@ -0,0 +1,518 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "73c153de",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 🔀 Conditional Agent Workflows with Microsoft Foundry (Python)\n",
|
||||
"\n",
|
||||
"## 📋 Advanced Decision-Based Workflow Tutorial\n",
|
||||
"\n",
|
||||
"This notebook demonstrates **conditional workflow patterns** using Microsoft Foundry and the Microsoft Agent Framework. You'll learn how to build intelligent, decision-driven workflows that dynamically route processing based on content analysis, business rules, and AI-powered decision making.\n",
|
||||
"\n",
|
||||
"## 🎯 Learning Objectives\n",
|
||||
"\n",
|
||||
"### 🧠 **Intelligent Decision Making**\n",
|
||||
"- **Conditional Logic**: Implement dynamic branching based on AI analysis and business rules\n",
|
||||
"- **Content-Aware Routing**: Route workflow paths based on content analysis and classification\n",
|
||||
"- **Adaptive Processing**: Adjust workflow behavior based on real-time conditions and data\n",
|
||||
"- **Azure AI Integration**: Leverage Microsoft Foundry's advanced capabilities for decision making\n",
|
||||
"\n",
|
||||
"### 🔀 **Advanced Workflow Patterns**\n",
|
||||
"- **Decision Trees**: Build complex decision structures with multiple branching points\n",
|
||||
"- **Rule-Based Processing**: Implement business logic and compliance requirements\n",
|
||||
"- **Dynamic Workflow Modification**: Adapt workflows based on runtime conditions\n",
|
||||
"- **Context-Aware Operations**: Make decisions based on accumulated workflow context\n",
|
||||
"\n",
|
||||
"### 🏢 **Enterprise Conditional Applications**\n",
|
||||
"- **Document Classification**: Route documents to appropriate processing workflows\n",
|
||||
"- **Customer Service Triage**: Automatically route inquiries to specialized handling workflows\n",
|
||||
"- **Compliance Processing**: Apply different validation rules based on content type and regulations\n",
|
||||
"- **Quality Assurance**: Route content through different review processes based on quality metrics\n",
|
||||
"\n",
|
||||
"## ⚙️ Prerequisites & Setup\n",
|
||||
"\n",
|
||||
"### 📦 **Installation & Dependencies**\n",
|
||||
"\n",
|
||||
"This workflow requires specific installation steps for Microsoft Foundry integration:\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"\n",
|
||||
"pip install agent-framework-azure-ai -U \n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🔑 **Microsoft Foundry Configuration**\n",
|
||||
"\n",
|
||||
"**Required Azure Resources:**\n",
|
||||
"- Microsoft Foundry workspace with appropriate models deployed\n",
|
||||
"- Azure subscription with necessary permissions\n",
|
||||
"- Azure CLI authentication configured\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Authentication Setup:**\n",
|
||||
"```bash\n",
|
||||
"# Azure CLI authentication\n",
|
||||
"az login\n",
|
||||
"az account set --subscription \"your-subscription-id\"\n",
|
||||
"azd auth login\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🏗️ **Conditional Workflow Architecture**\n",
|
||||
"\n",
|
||||
"```mermaid\n",
|
||||
"graph TD\n",
|
||||
" A[Input Document/Request] --> B[Initial Analysis Agent]\n",
|
||||
" B --> C{Decision Point}\n",
|
||||
" C -->|Condition 1| D[Workflow Path A]\n",
|
||||
" C -->|Condition 2| E[Workflow Path B]\n",
|
||||
" C -->|Condition 3| F[Workflow Path C]\n",
|
||||
" D --> G[Specialized Processing A]\n",
|
||||
" E --> H[Specialized Processing B]\n",
|
||||
" F --> I[Specialized Processing C]\n",
|
||||
" G --> J[Result Integration]\n",
|
||||
" H --> J\n",
|
||||
" I --> J\n",
|
||||
" J --> K[Final Output]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"**Key Components:**\n",
|
||||
"- **Analysis Agents**: AI agents that evaluate content and make routing decisions\n",
|
||||
"- **Decision Points**: Conditional logic that determines workflow paths\n",
|
||||
"- **Specialized Processors**: Different agents optimized for specific content types or scenarios\n",
|
||||
"- **Integration Layer**: Combines results from different workflow paths\n",
|
||||
"\n",
|
||||
"## 🎨 **Conditional Workflow Design Patterns**\n",
|
||||
"\n",
|
||||
"### 📋 **Document Processing Triage**\n",
|
||||
"```\n",
|
||||
"Document Input → Content Analysis → Classification → Specialized Processing Workflow\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🎯 **Customer Service Routing**\n",
|
||||
"```\n",
|
||||
"Customer Inquiry → Intent Analysis → Urgency Assessment → Route to Specialist Team\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🔍 **Quality Assurance Workflow**\n",
|
||||
"```\n",
|
||||
"Content Input → Quality Metrics → Risk Assessment → Appropriate Review Process\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 📊 **Business Intelligence Pipeline**\n",
|
||||
"```\n",
|
||||
"Data Input → Source Analysis → Processing Rules → Specialized Analytics Workflow\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"## 🏢 **Enterprise Benefits**\n",
|
||||
"\n",
|
||||
"### 🎯 **Intelligent Automation**\n",
|
||||
"- **Smart Routing**: Automatically direct work to the most appropriate processing path\n",
|
||||
"- **Adaptive Behavior**: Workflows that learn and adapt based on patterns and outcomes\n",
|
||||
"- **Business Rule Integration**: Incorporate complex business logic and compliance requirements\n",
|
||||
"- **Context-Aware Processing**: Make decisions based on full workflow context and history\n",
|
||||
"\n",
|
||||
"### 📈 **Operational Efficiency**\n",
|
||||
"- **Reduced Manual Intervention**: Automated decision making reduces need for human routing\n",
|
||||
"- **Specialized Processing**: Each workflow path optimized for specific scenarios\n",
|
||||
"- **Resource Optimization**: Efficient allocation of processing resources based on content type\n",
|
||||
"- **Faster Time-to-Resolution**: Direct routing to appropriate specialists and processes\n",
|
||||
"\n",
|
||||
"### 🛡️ **Governance & Control**\n",
|
||||
"- **Audit Trails**: Complete logging of decision points and routing rationale\n",
|
||||
"- **Compliance Enforcement**: Automatic application of regulatory and policy requirements\n",
|
||||
"- **Risk Management**: Route high-risk content through enhanced security and review processes\n",
|
||||
"- **Quality Assurance**: Ensure appropriate level of review based on content characteristics\n",
|
||||
"\n",
|
||||
"### 📊 **Analytics & Optimization**\n",
|
||||
"- **Decision Analytics**: Track effectiveness of routing decisions and workflow paths\n",
|
||||
"- **Performance Metrics**: Measure efficiency of different workflow branches\n",
|
||||
"- **Continuous Improvement**: Identify optimization opportunities in conditional logic\n",
|
||||
"- **Business Intelligence**: Gain insights into content patterns and processing requirements\n",
|
||||
"\n",
|
||||
"Let's build intelligent, decision-driven AI workflows! 🚀"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d0a6c7c7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! pip install agent-framework-azure-ai -U "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1c80c16f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"requirements.txt & constraints.txt - in ./Installation\n",
|
||||
"\n",
|
||||
"please copy .env.examples as .env"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "43ce2a42",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Note** choose gpt-4.1-mini"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "453e5695",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"from dataclasses import dataclass\n",
|
||||
"from typing_extensions import Literal\n",
|
||||
"from pydantic import BaseModel"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8710bd54",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from azure.identity.aio import AzureCliCredential\n",
|
||||
"from dotenv import load_dotenv\n",
|
||||
"\n",
|
||||
"from agent_framework import HostedWebSearchTool\n",
|
||||
"from agent_framework.azure import AzureAIAgentClient\n",
|
||||
"from agent_framework import (\n",
|
||||
" AgentExecutor,\n",
|
||||
" AgentExecutorRequest,\n",
|
||||
" AgentExecutorResponse,\n",
|
||||
" HostedCodeInterpreterTool,\n",
|
||||
" ChatMessage,\n",
|
||||
" Role,\n",
|
||||
" WorkflowBuilder,\n",
|
||||
" WorkflowContext,\n",
|
||||
" WorkflowEvent,\n",
|
||||
" executor,\n",
|
||||
" WorkflowViz\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"from azure.ai.agents.models import BingGroundingTool,CodeInterpreterTool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "52042c20",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"load_dotenv()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c0d46d0e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"EvangelistInstructions = \"\"\"\n",
|
||||
"You are a technology evangelist create a first draft for a technical tutorials.\n",
|
||||
"1. Each knowledge point in the outline must include a link. Follow the link to access the content related to the knowledge point in the outline. Expand on that content.\n",
|
||||
"2. Each knowledge point must be explained in detail.\n",
|
||||
"3. Rewrite the content according to the entry requirements, including the title, outline, and corresponding content. It is not necessary to follow the outline in full order.\n",
|
||||
"4. The content must be more than 200 words.\n",
|
||||
"4. Output draft as Markdown format. set 'draft_content' to the draft content.\n",
|
||||
"5. return result as JSON with fields 'draft_content' (string).\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"ContentReviewerInstructions = \"\"\"\n",
|
||||
"You are a content reviewer for a publishing company. You need to check whether the tutorial's draft content meets the following requirements:\n",
|
||||
"\n",
|
||||
"1. The draft content less than 200 words, set 'review_result' to 'No' and 'reason' to 'Content is too short'. If the draft content is more than 200 words, set 'review_result' to 'Yes' and 'reason' to 'The content is good'.\n",
|
||||
"2. set 'draft_content' to the original draft content.\n",
|
||||
"3. return result as JSON with fields 'review_result' (one of Yes, No) and 'reason' (string) and 'draft_content' (string).\n",
|
||||
"\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"PublisherInstructions = \"\"\"\n",
|
||||
"You are the content publisher ,run code to save the tutorial's draft content as a Markdown file. Saved file's name is marked with current date and time, such as yearmonthdayhourminsec. Note that if it is 1-9, you need to add 0, such as 20240101123045.md. \n",
|
||||
"\"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a51cd795",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"OUTLINE_Content =\"\"\"\n",
|
||||
"# Introduce AI Agent\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## What's AI Agent\n",
|
||||
"\n",
|
||||
"https://github.com/microsoft/ai-agents-for-beginners/tree/main/01-intro-to-ai-agents\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"***Note*** Don's create any sample code \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## Introduce Microsoft Foundry Agent Service \n",
|
||||
"\n",
|
||||
"https://learn.microsoft.com/en-us/azure/ai-foundry/agents/overview\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"***Note*** Don's create any sample code \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## Microsoft Agent Framework \n",
|
||||
"\n",
|
||||
"https://github.com/microsoft/agent-framework/tree/main/docs/docs-templates\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"***Note*** Don's create any sample code \n",
|
||||
"\"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b9c19b90",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"conn_id = os.environ[\"BING_CONNECTION_ID\"] # Ensure the BING_CONNECTION_NAME environment variable is set\n",
|
||||
"\n",
|
||||
"# Initialize the Bing Grounding tool\n",
|
||||
"bing = BingGroundingTool(connection_id=conn_id)\n",
|
||||
"\n",
|
||||
"code_interpreter = CodeInterpreterTool()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c7b615a0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class EvangelistAgent(BaseModel):\n",
|
||||
" draft_content: str\n",
|
||||
"\n",
|
||||
"class ReviewAgent(BaseModel):\n",
|
||||
" review_result: Literal[\"Yes\", \"No\"]\n",
|
||||
" reason: str\n",
|
||||
" draft_content: str\n",
|
||||
"\n",
|
||||
"class PublisherAgent(BaseModel):\n",
|
||||
" file_path: str\n",
|
||||
"\n",
|
||||
"@dataclass\n",
|
||||
"class ReviewResult:\n",
|
||||
" review_result: str\n",
|
||||
" reason: str\n",
|
||||
" draft_content: str\n",
|
||||
"\n",
|
||||
"@executor(id=\"to_reviewer_result\")\n",
|
||||
"async def to_reviewer_result(response: AgentExecutorResponse, ctx: WorkflowContext[ReviewResult]) -> None:\n",
|
||||
"\n",
|
||||
" print(f\"Raw response from reviewer agent: {response.agent_run_response.text}\")\n",
|
||||
"\n",
|
||||
" parsed = ReviewAgent.model_validate_json(response.agent_run_response.text)\n",
|
||||
" await ctx.send_message(\n",
|
||||
" ReviewResult(\n",
|
||||
" review_result=parsed.review_result,\n",
|
||||
" reason=parsed.reason,\n",
|
||||
" draft_content=parsed.draft_content,\n",
|
||||
" )\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def select_targets(review: ReviewResult, target_ids: list[str]) -> list[str]:\n",
|
||||
" # Order: [handle_review, submit_to_email_assistant, summarize_email, handle_uncertain]\n",
|
||||
" handle_review_id, save_draft_id = target_ids\n",
|
||||
" if review.review_result == \"Yes\":\n",
|
||||
" return [save_draft_id]\n",
|
||||
" else:\n",
|
||||
" return [handle_review_id]\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"@executor(id=\"handle_review\")\n",
|
||||
"async def handle_review(review: ReviewResult, ctx: WorkflowContext[str]) -> None:\n",
|
||||
" if review.review_result == \"No\":\n",
|
||||
" await ctx.yield_output(f\"Review failed: {review.reason}, please revise the draft.\")\n",
|
||||
" else:\n",
|
||||
" await ctx.send_message(\n",
|
||||
" AgentExecutorRequest(messages=[ChatMessage(Role.USER, text=review.draft_content)], should_respond=True)\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"@executor(id=\"save_draft\")\n",
|
||||
"async def save_draft(review: ReviewResult, ctx: WorkflowContext[AgentExecutorRequest]) -> None:\n",
|
||||
" # Only called for long NotSpam emails by selection_func\n",
|
||||
" await ctx.send_message(\n",
|
||||
" AgentExecutorRequest(messages=[ChatMessage(Role.USER, text=review.draft_content)], should_respond=True)\n",
|
||||
" )\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fe774ad9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from IPython.display import SVG, display, HTML"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a21415e7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class DatabaseEvent(WorkflowEvent): ..."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "281c577c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"async with (\n",
|
||||
" AzureCliCredential() as credential,\n",
|
||||
" AzureAIAgentClient(async_credential=credential) as chat_client,\n",
|
||||
" ): \n",
|
||||
" try:\n",
|
||||
" evangelist_agent = AgentExecutor(chat_client.create_agent(\n",
|
||||
" instructions= (EvangelistInstructions),\n",
|
||||
" tools=[HostedWebSearchTool()],\n",
|
||||
" # response_format=EvangelistAgent\n",
|
||||
" ), id=\"evangelist_agent\")\n",
|
||||
" reviewer_agent = AgentExecutor(chat_client.create_agent(\n",
|
||||
" instructions=(ContentReviewerInstructions),\n",
|
||||
" # response_format=ReviewAgent\n",
|
||||
" ), id=\"reviewer_agent\")\n",
|
||||
" publisher_agent = AgentExecutor(chat_client.create_agent(\n",
|
||||
" instructions=PublisherInstructions,\n",
|
||||
" tools=HostedCodeInterpreterTool(),\n",
|
||||
" response_format=PublisherAgent\n",
|
||||
" ), id=\"publisher_agent\")\n",
|
||||
"\n",
|
||||
" workflow = (\n",
|
||||
" WorkflowBuilder()\n",
|
||||
" .set_start_executor(evangelist_agent)\n",
|
||||
" .add_edge(evangelist_agent, reviewer_agent)\n",
|
||||
" .add_edge(reviewer_agent, to_reviewer_result)\n",
|
||||
" .add_multi_selection_edge_group(\n",
|
||||
" to_reviewer_result,\n",
|
||||
" [handle_review, save_draft],\n",
|
||||
" selection_func=select_targets,\n",
|
||||
" )\n",
|
||||
" .add_edge(save_draft, publisher_agent)\n",
|
||||
" .build()\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" # workflow = SequentialBuilder().participants([evangelist_chat_agent, reviewer_chat_agent, publisher_chat_agent]).build()\n",
|
||||
" print(\"Generating workflow visualization...\")\n",
|
||||
" viz = WorkflowViz(workflow)\n",
|
||||
" # Print out the mermaid string.\n",
|
||||
" print(\"Mermaid string: \\n=======\")\n",
|
||||
" print(viz.to_mermaid())\n",
|
||||
" print(\"=======\")\n",
|
||||
" # Print out the DiGraph string.\n",
|
||||
" print(\"DiGraph string: \\n=======\")\n",
|
||||
" print(viz.to_digraph())\n",
|
||||
" print(\"=======\")\n",
|
||||
" svg_file = viz.export(format=\"svg\")\n",
|
||||
" print(f\"SVG file saved to: {svg_file}\")\n",
|
||||
"\n",
|
||||
" if svg_file and os.path.exists(svg_file):\n",
|
||||
" try:\n",
|
||||
" # Preferred: direct SVG rendering\n",
|
||||
" display(SVG(filename=svg_file))\n",
|
||||
" except Exception as e:\n",
|
||||
" print(f\"⚠️ Direct SVG render failed: {e}. Falling back to raw HTML.\")\n",
|
||||
" try:\n",
|
||||
" with open(svg_file, \"r\", encoding=\"utf-8\") as f:\n",
|
||||
" svg_text = f.read()\n",
|
||||
" display(HTML(svg_text))\n",
|
||||
" except Exception as inner:\n",
|
||||
" print(f\"❌ Fallback HTML render also failed: {inner}\")\n",
|
||||
" else:\n",
|
||||
" print(\"❌ SVG file not found. Ensure viz.export(format='svg') ran successfully.\")\n",
|
||||
"\n",
|
||||
" \n",
|
||||
" task = \"\"\"\n",
|
||||
" You are a evangelist , need to write a draft based on the following outline and the content provided in the link corresponding to the outline. After draft create , the reviewer check it , if it meets the requirements, it will be submitted to the publisher and save it as a Markdown file, otherwise need to rewrite draft until it meets the requirements.\n",
|
||||
" The provided outline content and related links is as follows:\n",
|
||||
"\n",
|
||||
" \"\"\" + OUTLINE_Content\n",
|
||||
"\n",
|
||||
" \n",
|
||||
" async for event in workflow.run_stream(task):\n",
|
||||
" if isinstance(event, DatabaseEvent):\n",
|
||||
" print(f\"{event}\")\n",
|
||||
" if isinstance(event, WorkflowEvent):\n",
|
||||
" print(f\"Workflow output: {event.data}\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" finally:\n",
|
||||
" print(\"done\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2a0cf9db",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "agentenv",
|
||||
"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.10"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelInfo": {
|
||||
"defaultKernelName": "csharp",
|
||||
"items": [
|
||||
{
|
||||
"aliases": [],
|
||||
"name": "csharp"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user