A2A (Agent-to-Agent) - Getting Started
Overview
LlmTornado A2A provides a framework for building distributed agent systems where multiple agents can communicate and collaborate across network boundaries. The A2A architecture enables scalable, modular agent systems with standardized communication protocols.
Introduction
Agent-to-Agent (A2A) communication enables:
- Distributed Agent Systems: Deploy agents across multiple servers
- Modular Architecture: Independent agent services that can be composed
- Scalability: Scale individual agent services independently
- Interoperability: Standardized communication between different agent types
- Isolation: Agents run in isolated environments (containers)
Installation
Download the template to create A2A LlmTornado Agents!:
bash
From the Github Templates Folder download the Template Zip for A2A.AgentServerArchitecture Overview
Agent Runtime Configuration
Provides the necessary configuration and context for agents to operate within their environment. Defines how agents behave and interact.
csharp
public class MyA2ARuntime : BaseA2ATornadoRuntimeConfiguration
{
public override AgentCard DescribeAgentCard(string agentUrl)
{
return new AgentCard
{
Name = "MyAgent",
Description = "A specialized agent for specific tasks",
Url = agentUrl,
Capabilities = new[] { "task1", "task2" }
};
}
}A2A Agent Server
Main A2A API that runs the Agent Runtime and manages agent interactions. This is where agents are built and executed. (Try out the tempalte!)
- Hosts individual agents as services
- Exposes agents via REST API
- Handles incoming requests and routes to agents
- Manages agent lifecycle
- Ready to use Template
Quick Start
Creating Your First A2A Agent
csharp
using LlmTornado.A2A;
using LlmTornado.Agents;
// 1. Define your runtime configuration
public class A2ATornadoAgentSample
{
TornadoAgent Agent;
TornadoApi Client;
public A2ATornadoAgentSample()
{
Client = new TornadoApi(LlmTornado.Code.LLmProviders.OpenAi, Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? "");
string instructions = @"
You are an expert assistant designed to help users with a variety of tasks.
You can perform tasks such as answering questions, providing recommendations, and assisting with problem-solving.
You should always strive to provide accurate and helpful information to the user.
";
Agent = new TornadoAgent(
client: Client,
model: ChatModel.OpenAi.Gpt5.V5,
name: "Assistant",
instructions: instructions,
streaming: true);
}
public BaseA2ATornadoRuntimeConfiguration Build()
{
IRuntimeConfiguration runtimeConfig = new SingletonRuntimeConfiguration(Agent); //Add your Runtime Configuration here
return new SampleRuntimeConfiguration(
runtimeConfig: runtimeConfig,
name: "LlmTornado.A2A.AgentServer", //Name of your agent server
version: "1.0.0" //Version of your agent server
);
}
}
/// <summary>
/// Define the Agent Capabilities here
/// </summary>
public class SampleRuntimeConfiguration : BaseA2ATornadoRuntimeConfiguration
{
/// <summary>
/// Initializes a new instance of the A2ATornadoRuntimeService
/// </summary>
public SampleRuntimeConfiguration(IRuntimeConfiguration runtimeConfig, string name, string version) : base(runtimeConfig, name, version) { }
/// <summary>
/// Defines a static Agent Card for the agent
/// </summary>
/// <returns></returns>
public override AgentCard DescribeAgentCard(string agentUrl)
{
AgentCapabilities capabilities = new AgentCapabilities()
{
Streaming = true,
PushNotifications = false,
};
AgentSkill chattingSkill = new AgentSkill()
{
Id = "chatting_skill",
Name = "Chatting feature",
Description = "Agent to chat with and search the web.",
Tags = ["chat", "llm-tornado"],
Examples =
[
"Hello, what's up?",
],
};
return new AgentCard()
{
Name = AgentName,
Description = "Agent to chat with and search the web",
Url = agentUrl, // Placeholder URL
Version = AgentVersion,
DefaultInputModes = ["text"],
DefaultOutputModes = ["text"],
Capabilities = capabilities,
Skills = [chattingSkill],
};
}
}Creating A2A Agents
BaseA2ATornadoRuntimeConfiguration
When creating a new A2A Runtime configuration, inherit from BaseA2ATornadoRuntimeConfiguration and implement the abstract method DescribeAgentCard(string agentUrl):
csharp
public class TaskAgentRuntime : BaseA2ATornadoRuntimeConfiguration
{
public TaskAgentRuntime(IRuntimeConfiguration runtimeConfig, string name, string version) : base(runtimeConfig, name, version) { }
public override AgentCard DescribeAgentCard(string agentUrl)
{
AgentCapabilities capabilities = new AgentCapabilities()
{
Streaming = true,
PushNotifications = false,
};
AgentSkill chattingSkill = new AgentSkill()
{
Id = "chatting_skill",
Name = "Chatting feature",
Description = "Agent to chat with and search the web.",
Tags = ["chat", "llm-tornado"],
Examples =
[
"Hello, what's up?",
],
};
return new AgentCard()
{
Name = AgentName,
Description = "Agent to chat with and search the web",
Url = agentUrl, // Placeholder URL
Version = AgentVersion,
DefaultInputModes = ["text"],
DefaultOutputModes = ["text"],
Capabilities = capabilities,
Skills = [chattingSkill],
};
}
}Communication Protocol
A2A agents communicate using a standardized protocol:
csharp
// Request format
public class A2ARequest
{
public string AgentId { get; set; }
public string Message { get; set; }
public Dictionary<string, object>? Context { get; set; }
}
// Response format
public class A2AResponse
{
public string AgentId { get; set; }
public string Response { get; set; }
public Dictionary<string, object>? Metadata { get; set; }
}Deployment
Docker Deployment
Each agent runs in its own Docker container:
dockerfile
# Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY . .
ENTRYPOINT ["dotnet", "MyAgent.dll"]bash
# Build image
docker build -t my-weather-agent .
# Run with API key
docker run -p 5000:80 \
-e OPENAI_API_KEY=your_api_key \
my-weather-agentDocker Compose
Orchestrate multiple agents:
yaml
version: '3.8'
services:
weather-agent:
image: weather-agent:latest
ports:
- "5001:80"
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
task-agent:
image: task-agent:latest
ports:
- "5002:80"
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}Best Practices
Agent Design
- Keep agents focused on specific domains
- Define clear capabilities in agent cards
- Implement proper error handling
- Use versioning for breaking changes
Communication
- Use standardized message formats
- Include context when needed
- Handle timeouts gracefully
- Implement retry logic
Security
- Validate all incoming requests
- Use authentication/authorization
- Sanitize inputs and outputs
- Encrypt sensitive data
Monitoring
- Log all agent interactions
- Track performance metrics
- Monitor agent health
- Implement alerting
Next Steps
Explore the detailed documentation for each component:
- Agent Server - Building and deploying agent servers