LangChain released langchain-adk 0.3.14 on March 20, 2026. It's the first mainstream Python agent framework to ship native A2A support — the agent-to-agent coordination protocol that Google, Microsoft, Salesforce, and 100+ enterprises are now treating as infrastructure.
The headline from the release notes is "A2A-first integration." What that means in practice: any LangChain agent can now expose itself as an A2A server and call other A2A-compliant agents, regardless of what framework built them. Your LangChain orchestrator can delegate to a Crew.AI specialist. Your Google ADK agent can call a LangChain specialist. The framework boundary stops mattering.
Note: langchain-adk uses plain asyncio for agent orchestration — it is not built on LangGraph and does not require it. If you're currently using LangGraph, langchain-adk is an alternative path, not an integration layer.
That's the promise. Let's look at what it looks like in code.
What A2A Is (If You're Just Catching Up)
A2A is an open protocol for agent-to-agent task delegation. Version 1.0 dropped March 12, 2026, co-owned by Google and the Linux Foundation, with backing from OpenAI, Microsoft, Salesforce, and ServiceNow. Apache 2.0 license.
The mental model: A2A is to agents what HTTP is to web servers. It gives every agent a common language for sending tasks, reporting progress, and returning results — independent of framework or hosting environment.
If you're already using MCP: MCP handles agent-to-tool coordination — your agent calling APIs, reading files, running code. A2A handles agent-to-agent coordination — your agents delegating tasks to each other. They're complementary layers. Google's own framing from the v1.0 announcement positions them exactly that way. You'll end up using both.
Every A2A agent publishes an "Agent Card" at /.well-known/agent-card.json. That card lists its capabilities, input schema, and endpoint. Any A2A client that reads the card knows what it can do and how to talk to it.
If you want the hands-on version: Build Your First A2A Agent Pair in Python (15 Minutes, No Cloud Required) covers the base protocol from scratch.
What Changed in langchain-adk 0.3.14
Before this release, using A2A with LangChain required custom server code — you'd wrap a chain or agent in a FastAPI app, manually implement the A2A task endpoint, write the Agent Card JSON by hand. It worked, but it was 200+ lines of boilerplate that you had to maintain.
0.3.14 ships three additions:
1. A2AServer wrapper for LangChain agents
Wraps any LangChain agent in an A2A-compliant HTTP server. One import, one class, done.
2. A2AAgent for calling external agents
A LangChain-native class that wraps a remote A2A agent as a callable component. Your orchestrator agent calls remote A2A agents exactly like it calls local tools.
3. Auto-generated Agent Cards
Agent Cards are generated from the agent's name, description, and tool list. No manual JSON authoring.
Building a Multi-Agent Pipeline with langchain-adk
Here's the pattern: one orchestrator agent that coordinates tasks, and two specialist agents that handle specific work. All three speak A2A.
Setup:
pip install "langchain-adk[a2a]" langchain-openai uvicorn
Specialist agents (run these in separate processes):
# code_reviewer.py
import uvicorn
from langchain_openai import ChatOpenAI
from langchain.tools import tool
from langchain_adk.a2a import A2AServer, AgentSkill
from langchain_adk.agents.llm_agent import LlmAgent
from langchain_adk.sessions import InMemorySessionService
llm = ChatOpenAI(model="gpt-4o-mini")
@tool
def review_code(code: str) -> str:
"""Review Python code for bugs, style issues, and improvement opportunities."""
response = llm.invoke(f"Review this Python code:\n\n{code}\n\nList issues and improvements.")
return response.content
agent = LlmAgent(
name="code-reviewer-agent",
llm=llm,
tools=[review_code],
description="Reviews Python code for bugs, style issues, and performance problems",
)
# Wrap it as an A2A server
server = A2AServer(
agent=agent,
session_service=InMemorySessionService(),
app_name="code-reviewer",
url="http://localhost:8001",
skills=[
AgentSkill(
id="review",
name="Code Review",
description="Reviews Python code for bugs, style issues, and performance problems",
tags=["python", "review"],
)
],
)
# Serve with uvicorn — Agent Card published at /.well-known/agent-card.json
app = server.as_fastapi_app()
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8001)
# test_generator.py
import uvicorn
from langchain.tools import tool
from langchain_adk.a2a import A2AServer, AgentSkill
from langchain_adk.agents.llm_agent import LlmAgent
from langchain_adk.sessions import InMemorySessionService
# ... similar @tool definition for test generation ...
agent = LlmAgent(name="test-generator-agent", llm=llm, tools=[generate_tests], description="Generates pytest tests")
server = A2AServer(
agent=agent,
session_service=InMemorySessionService(),
app_name="test-generator",
url="http://localhost:8002",
skills=[AgentSkill(id="test", name="Test Generator", description="Generates pytest tests", tags=["python", "testing"])],
)
app = server.as_fastapi_app()
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8002)
Orchestrator agent (calls the specialists):
# orchestrator.py
import asyncio
from langchain_openai import ChatOpenAI
from langchain_adk import A2AAgent
from langchain_adk.agents.react_agent import ReActAgent
from langchain_adk.tools.agent_tool import AgentTool
from langchain_adk.sessions import InMemorySessionService
from langchain_adk.runner import Runner
llm = ChatOpenAI(model="gpt-4o-mini")
# Connect to remote A2A specialists — url is the base server URL, not the agent-card path
code_reviewer = A2AAgent(
name="code-reviewer",
url="http://localhost:8001",
description="Reviews Python code for bugs, style issues, and performance problems",
)
test_generator = A2AAgent(
name="test-generator",
url="http://localhost:8002",
description="Generates pytest tests for Python functions",
)
# AgentTool wraps BaseAgent as a BaseTool so ReActAgent can call it via tool-use
orchestrator = ReActAgent(
name="orchestrator",
llm=llm,
tools=[AgentTool(code_reviewer), AgentTool(test_generator)],
)
async def main():
session_service = InMemorySessionService()
runner = Runner(agent=orchestrator, app_name="pipeline", session_service=session_service)
session = await runner.get_or_create_session(user_id="user", session_id="session-1")
async for event in runner.astream(
user_id="user",
session_id="session-1",
new_message="Review this code and generate tests for the functions that pass review:\n\n" + code,
):
if hasattr(event, "text") and event.text:
print(event.text)
asyncio.run(main())
The orchestrator never imports the specialist code. A2AAgent discovers the remote agent's endpoint at runtime and delegates via the A2A protocol. Swap out a specialist for a different implementation — the orchestrator adapts automatically.
The Framework Portability Test
The real value isn't just LangChain-to-LangChain coordination. It's cross-framework.
Because your specialist agents speak A2A, an AutoGen orchestrator can call them. A CrewAI pipeline can delegate to them. A custom Python agent built with zero framework can call them using the base a2a-sdk client.
# Additional dependencies for the portability section only
pip install "a2a-sdk==0.3.25" httpx
# calling your LangChain specialist from a non-LangChain orchestrator
import asyncio
import httpx
from a2a.client import A2ACardResolver, ClientFactory, ClientConfig, create_text_message_object
BASE_URL = "http://localhost:8001"
async def call_specialist(code: str) -> str:
async with httpx.AsyncClient() as http:
# Resolve the Agent Card
resolver = A2ACardResolver(httpx_client=http, base_url=BASE_URL)
card = await resolver.get_agent_card()
# Create a client and send the task
factory = ClientFactory(config=ClientConfig(httpx_client=http))
client = factory.create(card)
message = create_text_message_object(content=f"Review this code: {code}")
async for event in client.send_message(message):
if hasattr(event, "parts"):
for part in event.parts:
if hasattr(part.root, "text"):
return part.root.text
return ""
asyncio.run(call_specialist(code))
That's the protocol doing its job. The LangChain specialist doesn't know it's being called from a non-LangChain client.
Observability: Tracing Multi-Agent Systems with LangSmith
langchain-adk 0.3.14 hooks into LangChain's standard callback system, so any callback handler you already use works with A2A agents. LangSmith is the most common choice:
from langsmith import Client
from langchain.callbacks import LangChainTracer
tracer = LangChainTracer(project_name="multi-agent-pipeline")
# Pass it to each agent — both specialists and orchestrator
orchestrator = AgentExecutor(agent=agent, tools=tools, callbacks=[tracer])
Because the tracer spans all agents in a task, you get a single trace tree even when the orchestrator delegates to remote specialists. Langfuse, Weights & Biases, or any BaseCallbackHandler subclass works the same way — langchain-adk doesn't require any specific observability provider.
For local development, print callbacks are enough. For production — when an orchestrator delegates to three specialists and one returns a bad result — trace stitching is the difference between "something failed" and "specialist agent 2 hallucinated on this specific input at 14:23 UTC."
When to Use This Pattern
Use A2A-based agent delegation when:
- Different agents need different models (fast model for triage, expensive model for complex reasoning)
- Different agents need different tool sets that you don't want to expose to each other
- You want framework portability — the ability to swap out an agent implementation without touching the orchestrator
- You're scaling to multiple concurrent agents that need to coordinate on shared tasks
Don't reach for it when you have a simple chain that runs sequentially. A2A coordination adds network hops and complexity. For a single-agent flow, keep it simple.
The Bigger Picture
langchain-adk 0.3.14 is significant because LangChain is the Python framework with the most production deployments in the AI developer community. When the most widely-used framework ships A2A-first, the protocol crosses a threshold from "interesting spec" to "thing you'll encounter in the wild."
MCP and A2A are converging on being the two required protocols for production agent systems: MCP handles agent-to-tool (your agent calling APIs, reading files, running code), A2A handles agent-to-agent (your agents delegating to each other). Frameworks that support both are frameworks that can build anything.
If you're building multi-agent Python systems and haven't integrated A2A yet, this release is a reasonable entry point. The LangChain wrapper handles the boilerplate. The protocol handles the coordination.
The AI Dev Toolkit includes five Python scripts that build on these patterns — including an orchestrator template, a multi-agent review pipeline, and a batch processor that distributes work across specialist agents. Get the toolkit here.
Top comments (0)