239 lines
8.4 KiB
Plaintext
239 lines
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
|
||
}
|