Jordi

A2A protocol demo banner

1. What is the Agent‑to‑Agent (A2A) protocol?

Originating from Google’s open specification, A2A defines a lean JSON‑RPC envelope that lets autonomous agents share intents, stream partial results and report progress in real time. By speaking A2A, you can mix and match agents written in any language or framework without inventing yet another bespoke API.

2. Why pair A2A with Microsoft Semantic Kernel?

Semantic Kernel (SK) gives C# developers a first‑class toolkit for wrapping LLM prompts as skills, composing them into pipelines and injecting traditional .NET code where it still shines. When you bolt A2A on top, each SK instance becomes a portable micro‑agent whose skills are instantly discoverable and callable by its peers.

3. Why discovery matters

The most important piece of the puzzle is not messaging or prompts — it's agent discovery.

The discovery service in this repository acts like a temporary memory of the agent ecosystem. Agents register their capabilities (like reverse or upper) with it, including the transport they support and how to reach them. Other agents then poll the /resolve endpoint until the desired skill becomes available, and only then initiate contact.

This approach brings three major benefits:

  • Loose coupling – Agents don’t need to know about each other ahead of time.
  • Late binding – You can add, replace, or scale agents without changing consumers.
  • Transport independence – The discovery layer is completely unaware of how agents talk.

Think of it as DNS for autonomous bots: discover first, communicate second.

A2A protocol demo banner

4. What the repository contains


  • Agent2AgentProtocol.Discovery.Service – a minimal ASP.NET Core API that registers capabilities and resolves them to endpoints.
  • Semantic.Kernel.Agent2AgentProtocol.Example.Agent2 – the responder. It advertises two text‑processing skills: reverse and upper.
  • Semantic.Kernel.Agent2AgentProtocol.Example.Agent1 – the initiator. It hunts for an agent that can handle reverse then streams the outcome back to the console.
  • Semantic.Kernel.Agent2AgentProtocol.Example.Core – shared plumbing: the A2A message models, a pluggable IMessagingTransport, and helper extensions for SK.

5. Cloning and building



        git clone https://github.com/jordiag/semantic-kernel-agent-a2a-protocol-example.git
        cd semantic-kernel-agent-a2a-protocol-example
        dotnet build
        

6. Firing up the demo



        # 1️⃣ Start the discovery service
        dotnet run --project Agent2AgentProtocol.Discovery.Service

        # 2️⃣ Launch the responder (Agent 2)
        dotnet run --project Semantic.Kernel.Agent2AgentProtocol.Example.Agent2

        # 3️⃣ Launch the initiator (Agent 1)
        dotnet run --project Semantic.Kernel.Agent2AgentProtocol.Example.Agent1
        

Agent 2 registers its skills with the discovery service, including the chosen transport and address. Agent 1 polls /resolve until it finds a match, then dispatches a JSON‑RPC request such as reverse:Hello A2A. As the responder streams each chunk, the console shows something like: A|2|A | olleH.

7. Switching transports – zero code changes

The demo defaults to a local NamedPipeTransport for friction‑free testing. To see the exact same conversation traverse the cloud:

  1. Provision an Azure Service Bus namespace and queue.
  2. Set an environment variable called SERVICEBUS_CONNECTIONSTRING.
  3. Flip UseAzureServiceBus = true in both agents’ appsettings.json.

Because both transports implement the same IMessagingTransport interface, no other code changes are required. Feel free to add WebSockets, gRPC or MQTT – the agents will not notice.

8. Anatomy of a capability card

Agent 2 serialises a concise JSON card that lists each skill, its description and the transport payload needed to reach it. Here’s a trimmed example:


        {
        "capabilities": [
        {
        "name": "reverse",
        "description": "Reverses input text",
        "transport": {
        "type": "NamedPipe",
        "address": "sk-agent2"
        }
        }
        ]
        }
        

9. Extending the sample


  • Add skills: Drop a new Semantic Kernel function into TextProcessingFunctions.cs, register it, and voilà – it appears in the capability card.
  • Experiment with transports: Plug in RabbitMQ or Redis streams by implementing IMessagingTransport.
  • Scale out discovery: Swap the in‑memory dictionary for Consul, etcd or an Azure App Configuration store.
  • Track long‑running tasks: Use the TaskManager helper in a2a-dotnet to stream incremental progress.

10. Key takeaways

By separating discovery, transport and skill execution, this tiny solution proves that AI agents can stay loosely coupled yet perfectly interoperable. Clone it, tweak it and watch your own agents strike up a conversation—without caring where or how their messages travel.

Comments

Be the first to post a comment

Post a comment