Project code
The runnable project this guide walks through
A2A Documentation
The protocol specification
Architecture
Each specialist runs as an A2A service that publishes an agent card at
/.well-known/agent-card.json. Market data is synthetic, so the tools need no market data feed.
Before you start
Clone the project and install its dependencies. Python 3.10 or later.- A Google Cloud project with billing and the Vertex AI API enabled
- Application Default Credentials, from
gcloud auth application-default login - Llama 3.3 accepted in Model Garden, which is a separate per-model license step
- For Agent Engine deployment only: a GCS staging bucket and permission to create Agent Engine resources
BEAR_MODEL, BULL_MODEL, ORCHESTRATOR_MODEL), so you can point one at a different Vertex model without touching the agent code.
Trace both frameworks into one project
Two frameworks need two kinds of instrumentation, and both write into a single tracer provider so the orchestrator and the specialists land in the same Arize AX project. ADK is instrumented directly. Pydantic AI emits OpenTelemetry GenAI spans, soOpenInferenceSpanProcessor translates them into attributes Arize AX reads as LLM spans.
Custom span processors go in register(span_processors=[...]), which keeps them alongside the exporter Arize AX sets up for you.
tracing.py
Give each agent its MCP tools
Both agents get their tools from an MCP server they spawn over stdio, and the two frameworks express that differently. Pydantic AI takes a transport, ADK takes connection params. Launching withsys.executable rather than "python" keeps the server in the same interpreter as the agent, which matters inside a virtualenv where python may not exist.
Advertise each agent with an agent card
An agent card is how one agent tells another what it can do, without either knowing the other’s implementation. Skills carry examples, which is what lets the orchestrator decide when a specialist is worth calling.Bridge Pydantic AI to A2A
ADK ships an A2A executor, so the Bull agent needs no bridge. Pydantic AI does not, so the Bear agent supplies one:BearAgentExecutor turns an A2A task into an agent run and reports progress back through the TaskUpdater.
Two details make it behave under failure. The agent is built lazily, because Agent Engine pickles the executor to deploy it and an initialized agent holding an MCP subprocess is not picklable. And the build happens inside the try, so a failure (bad credentials, a model the project cannot access) is reported to the caller as a failed task instead of escaping as a server-level JSON-RPC error the orchestrator cannot interpret.
Call the specialists over A2A
The orchestrator imports neither specialist.RemoteA2aAgent fetches each agent card and AgentTool presents the remote agent as a tool, which is the whole substitutability argument: swap either specialist’s framework, or move it to another host, and this code does not change.
orchestrator.py
Run it
One command starts both agents and sends a single query:Read the traces in Arize AX
Open thea2a-trading-agents project. One query produces roughly 100 spans:
CHAINinvocation [trading_strategy_orchestrator], the orchestrator runAGENTandLLMspans for each agent’s reasoning, carrying the model name, so you can confirm the Bear agent ran on Gemini while the Bull agent ran on LlamaTOOLspans for the A2A calls (execute_tool bear_risk_analyst) and for every MCP tool the specialists invoke (execute_tool risk_scanner,tools/call risk_scanner)
a2a-sdk emits its own internal spans. Event-queue plumbing (EventQueue.dequeue_event and friends) accounts for most of the span count and carries no OpenInference span kind, so those rows sit uncategorized. Filter on attributes.openinference.span.kind to get to agent behavior.
Deploy to Vertex AI Agent Engine
deploy_agent_engine.py turns each specialist into a managed service with an authenticated A2A endpoint, and the orchestrator reaches them through Google-signed requests instead of localhost. It needs the GCS staging bucket and Agent Engine permissions listed above.
Takeaway
- A2A makes the framework an implementation detail. The orchestrator calls a Pydantic AI agent and an ADK agent the same way, through cards and tasks, and neither specialist knows what the other is.
- Instrument per framework, export to one project. ADK is instrumented directly and Pydantic AI through a translating span processor, but both write into a single tracer provider, so one project shows the whole system.
- Trace context stops at the A2A boundary. Plan on correlating traces across agents rather than reading one tree, which is the main thing that separates multi-agent observability from single-process observability.