C#使用A2A协议(1)
1、前言
本人目前认为A2A发展前景不咋地,它没有创造一种新颖的工具,它也没有简化流程。对于生产力的发展,作用有限。若不是十分想了解的,建议直接跳过既可。
2、背景
A2A协议由google提出的,本意是希望能制定一种Agent之间的沟通和交流的协议。愿景非常有点类似Restful API,不管API背后逻辑多么复杂,都可以通过HTTP的Get、Post、Delete等方法进行资源的处理。A2A协议也想实现不同Agent的沟通标准,愿望总是要美好的。
3、A2A具体实现
3.1、入门demo
现用一个简单的Demo,初步入门了解下A2A的协议。
3.1.1、Server端代码
- 1、创建一个控制台程序
- 2、在nuget引入package
dotnet add package A2A --version 0.3.3-preview
dotnet add package A2A.AspNetCore --version 0.3.3-preview - 3、先写一个类,实现了最基本的功能
public class EchoAgent
{public void Attach(ITaskManager taskManager){//Server里面最核心的就是ITaskManager,其基本的功能是定义的各种方法或属性的具体实现//例如:OnMessageReceived就是指,Server端里面的Agent收到消息后,进行处理的具体方法实现,并返回结果//OnAgentCardQuery就是Server端Agent的功能描述。是Agent的能力进行了说明taskManager.OnMessageReceived = ProcessMessageAsync;taskManager.OnAgentCardQuery = GetAgentCardAsync;}//这个方法实现:1、获取是从客户端发送的请求数据。2、内部使用Agent进行处理;3、返回特定格式的数据(A2AResponse)private Task<A2AResponse> ProcessMessageAsync(MessageSendParams messageSendParams, CancellationToken cancellationToken){if (cancellationToken.IsCancellationRequested){return Task.FromCanceled<A2AResponse>(cancellationToken);}// 处理接收到的数据var messageText = messageSendParams.Message.Parts.OfType<TextPart>().First().Text;//这儿其实是需要写Agent的具体功能//举例说明:我们有一个规划路线的Agent。客户端(client)发过来一个信息:请帮我规划一条从A到B的用时最短的自驾路线。//这儿的代码就应该是,将client传给一个Agent,让它返回规划的内容//最终返回的内容,就是messageText//然后再将messageText,组合成特地格式的数据(AgentMessage)。类似微信公众号开发中接口的输出与输入的格式是一定的。//按照格式要求,返回数据。//这儿有点坑,A2A称这个为artifact(产出物)。个人觉得A2A就不是开发人员搞出来的,而是一堆搞信息化的人整出来var message = new AgentMessage(){Role = MessageRole.Agent,MessageId = Guid.NewGuid().ToString(),ContextId = messageSendParams.Message.ContextId,Parts = [new TextPart() {Text = $"Echo: {messageText}"}]};return Task.FromResult<A2AResponse>(message);}//这个方法的主要目的是对外暴露,Agent的能力。private Task<AgentCard> GetAgentCardAsync(string agentUrl, CancellationToken cancellationToken){if (cancellationToken.IsCancellationRequested){return Task.FromCanceled<AgentCard>(cancellationToken);}var capabilities = new AgentCapabilities(){Streaming = true,PushNotifications = false,};return Task.FromResult(new AgentCard(){Name = "Echo Agent",Description = "Agent which will echo every message it receives.",Url = agentUrl,Version = "1.0.0",DefaultInputModes = ["text"],DefaultOutputModes = ["text"],Capabilities = capabilities,Skills = [],});}
}
- 4、将能力进行发布
通过在program.cs中,将服务进行暴露
var builder = WebApplication.CreateBuilder(args);
var app= builder.Build();
//对外暴露的一个健康状态的接口。默认就OK
app.MapGet("/health", () => Results.Ok(new { Status = "Healthy", Timestamp = DateTimeOffset.UtcNow }));
//将刚才实现的单独的一个类(EchoAgent),创建一个实例
//然后将关联到TaskManager中
var taskManager= new TaskManager();
var echoAgent= new EchoAgent();
echoAgent.Attach(taskManager);
//将服务进行映射
app.MapA2A(taskManager, "/echo");
//这个是将Agent服务对外进行声明
app.MapWellKnownAgentCard(taskManager, "/echo");
//支持HTTP
app.MapHttpA2A(taskManager, "/echo");app.Run("http://localhost:5000");
至此,服务端的代码就完成。
3.1.2、客户端的实现
- 1、创建一个
Console程序 - 2、引用package
dotnet add package A2A --version 0.3.3-preview - 3、客户端的代码如下:
internal static class Program
{static async Task Main(string[] args){await MessageBasedCommunicationSample.RunAsync();}
}
上述代码的具体实现:
internal sealed class MessageBasedCommunicationSample
{public static async Task RunAsync(){//通过URL,查看Server端Agent的能力有哪些A2ACardResolver cardResolver = new(new Uri("http://localhost:5000/"));AgentCard echoAgentCard = await cardResolver.GetAgentCardAsync();//通过读取echoAgentCard的序列化的内容,列出Agent有什么能力Console.WriteLine("\n Agent的能力声明(AgentCard):");Console.WriteLine(JsonSerializer.Serialize(echoAgentCard, new JsonSerializerOptions(A2AJsonUtilities.DefaultOptions){WriteIndented = true}));//创建一个Client,用于发起请求等各类操作A2AClient agentClient = new(new Uri(echoAgentCard.Url));//准备好给Server端的Agent的消息(按照指定的格式)AgentMessage userMessage = new(){Role = MessageRole.User,MessageId = Guid.NewGuid().ToString(),Parts = [new TextPart{Text = "你好!这是从客户端发出的"}]};// 4. Send the message using non-streaming APIawait SendMessageAsync(agentClient, userMessage);// 5. Send the message using streaming APIawait SendMessageStreamingAsync(agentClient, userMessage);Console.ReadLine();}//通过非流式接口发送数据给Server端private static async Task SendMessageAsync(A2AClient agentClient, AgentMessage userMessage){Console.WriteLine("\n非流式接口发送数据");Console.WriteLine($" 发送给Server端的数据为: {((TextPart)userMessage.Parts[0]).Text}");// 发送数据并获取响应AgentMessage agentResponse = (AgentMessage)await agentClient.SendMessageAsync(new MessageSendParams { Message = userMessage });//展示响应数据Console.WriteLine($" 收到从服务端发送的数据: {((TextPart)agentResponse.Parts[0]).Text}");}//通过流式接口发送数据给Server端private static async Task SendMessageStreamingAsync(A2AClient agentClient, AgentMessage userMessage){Console.WriteLine("\n流式方式发送数据");Console.WriteLine($" 流式方式发送的参数为: {((TextPart)userMessage.Parts[0]).Text}");//发送数据并获取响应流await foreach (SseItem<A2AEvent> sseItem in agentClient.SendMessageStreamingAsync(new MessageSendParams { Message = userMessage })){AgentMessage agentResponse = (AgentMessage)sseItem.Data;//展示响应数据Console.WriteLine($" 展示流式响应数据: {((TextPart)agentResponse.Parts[0]).Text}");}}
}
3.1.3、运行效果
- 1、服务端运行的效果就是启动一个服务
- 2、客户端运行后,展示的效果如下

4、总结
上面是一个特别简单的一个例子。但从简单的例子中我们可以看到,A2A协议是一个【数据组织格式定义】的协议。类似双方约定好JSON中各个字段组织样式以及具体含义。A2A协议并不是一个新技术,只是一个在已有技术的技术上的数据组织定义而已。
