microsoft--ai-agents-for-beginners
239 行
8.4 KiB
Plaintext
239 行
8.4 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Lesson 11 - Agent-to-Agent (A2A) Protocol"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Setup"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"%pip install agent-framework azure-ai-projects azure-identity python-dotenv"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import os\n",
|
|
"import dotenv\n",
|
|
"from agent_framework import tool, 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,
|
|
"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",
|
|
"metadata": {},
|
|
"source": [
|
|
"## What is the A2A Protocol?\n",
|
|
"\n",
|
|
"The **Agent-to-Agent (A2A) protocol** is an open standard that enables AI agents to communicate,\n",
|
|
"discover each other, and collaborate — even when they are built on different frameworks or hosted\n",
|
|
"by different services.\n",
|
|
"\n",
|
|
"Key concepts:\n",
|
|
"\n",
|
|
"- **Discovery** – Agents publish an *Agent Card* that describes their capabilities, making it\n",
|
|
" easy for other agents (or orchestrators) to find the right specialist for a task.\n",
|
|
"- **Message Passing** – Agents exchange structured messages through a common protocol, so a\n",
|
|
" request from one agent can be understood and fulfilled by another regardless of its internal\n",
|
|
" implementation.\n",
|
|
"- **Task Lifecycle** – A2A defines states such as *submitted*, *working*, *completed*, and\n",
|
|
" *failed*, giving the orchestrator full visibility into how a delegated task is progressing.\n",
|
|
"\n",
|
|
"In this lesson we simulate A2A-style collaboration by wiring three specialized travel agents\n",
|
|
"into a workflow where each agent contributes its expertise and passes results to the next."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Creating Specialized Travel Agents"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"currency_agent = client.as_agent(\n",
|
|
" name=\"CurrencyExchangeAgent\",\n",
|
|
" instructions=\"\"\"You are a currency exchange specialist. You help travelers understand:\n",
|
|
"- Current exchange rates between currencies\n",
|
|
"- Best times to exchange money\n",
|
|
"- Tips for getting the best rates\n",
|
|
"When asked about a destination, provide relevant currency information.\"\"\",\n",
|
|
")\n",
|
|
"\n",
|
|
"activity_agent = client.as_agent(\n",
|
|
" name=\"ActivityPlannerAgent\",\n",
|
|
" instructions=\"\"\"You are a local activities specialist. You recommend:\n",
|
|
"- Must-see attractions and hidden gems\n",
|
|
"- Local experiences and cultural activities\n",
|
|
"- Restaurant and dining recommendations\n",
|
|
"Tailor suggestions to the traveler's interests.\"\"\",\n",
|
|
")\n",
|
|
"\n",
|
|
"travel_manager = client.as_agent(\n",
|
|
" name=\"TravelManagerAgent\",\n",
|
|
" instructions=\"\"\"You are a travel manager who coordinates between specialist agents.\n",
|
|
"When planning a trip:\n",
|
|
"1. Gather currency information from the currency specialist\n",
|
|
"2. Get activity recommendations from the activity planner\n",
|
|
"3. Synthesize everything into a cohesive travel brief\n",
|
|
"Present the final plan in an organized, easy-to-read format.\"\"\",\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Multi-Agent Collaboration via Workflow\n",
|
|
"\n",
|
|
"We connect the three agents into a sequential workflow that mirrors A2A message passing:\n",
|
|
"\n",
|
|
"1. **CurrencyExchangeAgent** receives the user request and produces currency guidance.\n",
|
|
"2. **ActivityPlannerAgent** receives the enriched context and adds activity recommendations.\n",
|
|
"3. **TravelManagerAgent** synthesizes both inputs into a final travel brief."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"workflow = WorkflowBuilder(start_executor=currency_agent) \\\n",
|
|
" .add_edge(currency_agent, activity_agent) \\\n",
|
|
" .add_edge(activity_agent, travel_manager) \\\n",
|
|
" .build()\n",
|
|
"\n",
|
|
"last_author = None\n",
|
|
"events = workflow.run(\n",
|
|
" \"Plan a week-long trip to Tokyo. I love food, temples, and technology.\",\n",
|
|
" stream=True,\n",
|
|
")\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",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Understanding A2A in Production\n",
|
|
"\n",
|
|
"In a production environment the A2A protocol unlocks powerful cross-service scenarios:\n",
|
|
"\n",
|
|
"| Capability | Description |\n",
|
|
"|---|---|\n",
|
|
"| **Cross-framework interop** | An agent built with one framework can delegate tasks to an agent built with any other A2A-compliant framework, enabling true cross-organization interoperability. |\n",
|
|
"| **Service boundaries** | Agents can live in separate microservices, cloud regions, or even different organisations while still collaborating seamlessly. |\n",
|
|
"| **Dynamic discovery** | An orchestrator can query an Agent Card registry at runtime to find the best-suited specialist for a given sub-task. |\n",
|
|
"| **Streaming & push notifications** | A2A supports Server-Sent Events (SSE) for real-time progress updates and push notifications for long-running tasks. |\n",
|
|
"\n",
|
|
"The workflow we built above is a simplified, in-process version of this pattern. In a real\n",
|
|
"deployment each agent would expose an HTTP endpoint, publish an Agent Card, and communicate\n",
|
|
"via the A2A JSON-RPC protocol."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Summary\n",
|
|
"\n",
|
|
"In this lesson you learned:\n",
|
|
"\n",
|
|
"1. **What the A2A protocol is** — an open standard for agent-to-agent discovery, messaging,\n",
|
|
" and task management.\n",
|
|
"2. **How to create specialized agents** — a Currency Exchange agent, an Activity Planner agent,\n",
|
|
" and a Travel Manager orchestrator.\n",
|
|
"3. **How to wire agents into a workflow** — using `WorkflowBuilder` to model sequential\n",
|
|
" message passing between agents.\n",
|
|
"4. **How A2A works in production** — enabling cross-framework, cross-service collaboration\n",
|
|
" with dynamic discovery and streaming updates."
|
|
]
|
|
}
|
|
],
|
|
"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": 2
|
|
}
|