当前位置: 首页 > news >正文

[A2A协议与实现-09].NET SDK客户端的设计与实现

A2A的协议提供了四组核心操作的输入和输出数据结构(可以参考我的前面的文章从Protobuf消息详解A2A协议四大核心操作),如何进一步知道具体采用的传输协议,我就可以直接利用HttpClient来编写A2A客户端代码,实际上前面的演示都是这么做得。实际上A2A官方针对.NET的SDK提供了客户端实现。

1. IA2AClient

A2A协议与实现-03:从Protobuf消息详解A2A协议四大核心操作从协议的角度解读了A2A的四组核心操作,A2A协议与实现-08:基于MAF的A2A Server设计与实现介绍了IA2ARequestHandler接口,我们说它是A2A服务端SDK对A2A协议的表达,如下这个IA2AClient具有与IA2ARequestHandler接口完全一致的定义,则是客户端SDK针对A2A协议的表达。我们自然可以利用它的实现来执行A2A的四组核心操作。

publicinterfaceIA2AClient{// 1. Agent调用Task<SendMessageResponse>SendMessageAsync(SendMessageRequestrequest,CancellationTokencancellationToken=default);IAsyncEnumerable<StreamResponse>SendStreamingMessageAsync(SendMessageRequestrequest,CancellationTokencancellationToken=default);// 2. 后台任务管理Task<AgentTask>GetTaskAsync(GetTaskRequestrequest,CancellationTokencancellationToken=default);Task<ListTasksResponse>ListTasksAsync(ListTasksRequestrequest,CancellationTokencancellationToken=default);Task<AgentTask>CancelTaskAsync(CancelTaskRequestrequest,CancellationTokencancellationToken=default);IAsyncEnumerable<StreamResponse>SubscribeToTaskAsync(SubscribeToTaskRequestrequest,CancellationTokencancellationToken=default);// 3. 基于后台任务的通知推送配置管理Task<TaskPushNotificationConfig>CreateTaskPushNotificationConfigAsync(CreateTaskPushNotificationConfigRequestrequest,CancellationTokencancellationToken=default);Task<TaskPushNotificationConfig>GetTaskPushNotificationConfigAsync(GetTaskPushNotificationConfigRequestrequest,CancellationTokencancellationToken=default);Task<ListTaskPushNotificationConfigResponse>ListTaskPushNotificationConfigAsync(ListTaskPushNotificationConfigRequestrequest,CancellationTokencancellationToken=default);TaskDeleteTaskPushNotificationConfigAsync(DeleteTaskPushNotificationConfigRequestrequest,CancellationTokencancellationToken=default);// 4. AgetCard扩展Task<AgentCard>GetExtendedAgentCardAsync(GetExtendedAgentCardRequestrequest,CancellationTokencancellationToken=default);}

2. 针对JSON-RPC的实现

既然是对A2A协议的表达,IA2AClient接口自然与具体的传输协议无关,但是具体的实现则不得不考虑底层采用的传输协议。如下所示的A2AClient类型是针对JSON-RPC的实现。我们在初始化A2AClient对象的时候只需要提供A2A Server的基础地址和一个可选的HttpClient对象。具体的实现很简单,不外乎就是使用操作对应的Method为请求封装成JSON-RPC封套以POST形式发送。如果采用流式调用,由于服务端会采用SSE实时回传生成的内容,这里只需要采用对应的方式解析SSE数据项即可。

publicsealedclassA2AClient:IA2AClient,IDisposable{publicA2AClient(UribaseUrl,HttpClient?httpClient=null);...}

如下所示的是采用A2AClient以阻塞方式调用Agent的例子。

usingA2A;usingAzure.AI.Projects;usingDotNetEnv;usingMicrosoft.Agents.AI.Hosting;usingMicrosoft.Extensions.AI;usingOpenAI;usingOpenAI.Responses;usingSystem.ClientModel;Env.Load();varapiKey=Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;varendpoint=Environment.GetEnvironmentVariable("OPENAI_BASE_URL")!;varagent=newOpenAIClient(credential:newApiKeyCredential(key:apiKey),options:newOpenAIClientOptions{Endpoint=newUri(endpoint)}).GetResponsesClient().AsAIAgent(model:"gpt-5.4-mini",name:"a2a-agent",instructions:""" 你是一个深谙中国古代历史的专家,善于根据正史,以公正客观的态度于人交流历史问题。 对于用户提出的问题,请以简介概括性的语言予以答复,字数尽量保持在200字以内。""");varbuidler=WebApplication.CreateBuilder();buidler.Services.AddA2AServer(agent.Name!).AddAIAgent(agent.Name!,(services,anme)=>agent);varurl="http://localhost:3721/";buidler.WebHost.UseUrls(url);varapp=buidler.Build();app.MapA2AJsonRpc(agent,"/");awaitapp.StartAsync();usingvarclient=newA2AClient(newUri(url));varprompt="春秋初霸郑庄公寤生为何没有成为春秋五霸,是因为郑国不够强大吗?";varrequest=newSendMessageRequest{Message=newMessage{Role=Role.User,Parts=[newPart{Text=prompt}]},};varresponse=awaitclient.SendMessageAsync(request);foreach(varpartinresponse.Message!.Parts){Console.WriteLine(part.Text);}

输出:

不完全是。郑庄公在春秋初年确实一度称霸,尤其在“周郑交质”“射王中肩”等事件后,威望很高,但郑国的霸业有明显局限: 一是国土狭小、人口与资源有限,难以长期支撑霸权; 二是地处四战之地,易受周边大国夹击; 三是郑庄公之后继承者能力不足,国力很快衰落。 “春秋五霸”本身也是后世概括,通常重在齐桓公、晋文公等更具持续影响者,所以郑庄公常被视为“春秋初霸”,而不列入五霸。

如果希望通过逐字输出的效果,可以按照如下的方式采用流式调用:

awaitforeach(varresponseinclient.SendStreamingMessageAsync(request)){foreach(varpartinresponse.Message!.Parts){Console.Write(part.Text);}}

3. 针对HTTP-JSON的实现

如果A2A Server是采用HTTP-JSON协议构建,那么就需要使用如下这个对应的客户端类型A2AHttpJsonClient。它与OpenAIClient具有完全一致的构造函数定义。

publicsealedclassA2AHttpJsonClient:IA2AClient,IDisposable{publicA2AHttpJsonClient(UribaseUrl,HttpClient?httpClient=null);...}

我们将上面演示的程序切换成HTTP-JSON协议,并采用A2AHttpJsonClient作为调用客户端。

usingA2A;usingAzure.AI.Projects;usingDotNetEnv;usingMicrosoft.Agents.AI.Hosting;usingMicrosoft.Extensions.AI;usingOpenAI;usingOpenAI.Responses;usingSystem.ClientModel;Env.Load();varapiKey=Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;varendpoint=Environment.GetEnvironmentVariable("OPENAI_BASE_URL")!;varagent=newOpenAIClient(credential:newApiKeyCredential(key:apiKey),options:newOpenAIClientOptions{Endpoint=newUri(endpoint)}).GetResponsesClient().AsAIAgent(model:"gpt-5.4-mini",name:"a2a-agent",instructions:""" 你是一个深谙中国古代历史的专家,善于根据正史,以公正客观的态度于人交流历史问题。 对于用户提出的问题,请以简介概括性的语言予以答复,字数尽量保持在200字以内。""");varbuidler=WebApplication.CreateBuilder();buidler.Services.AddA2AServer(agent.Name!).AddAIAgent(agent.Name!,(services,anme)=>agent);varurl="http://localhost:3721/";buidler.WebHost.UseUrls(url);varapp=buidler.Build();app.MapA2AHttpJson(agent,"/");awaitapp.StartAsync();usingvarclient=newA2AHttpJsonClient(newUri(url));varprompt="春秋初霸郑庄公寤生为何没有成为春秋五霸,是因为郑国不够强大吗?";varrequest=newSendMessageRequest{Message=newMessage{Role=Role.User,Parts=[newPart{Text=prompt}]},};Console.WriteLine($"{newstring('-',20)}SendMessageAsync{newstring('-',20)}");varresponse=awaitclient.SendMessageAsync(request);foreach(varpartinresponse.Message!.Parts){Console.WriteLine(part.Text);}Console.WriteLine($"{newstring('-',20)}SendStreamingMessageAsync{newstring('-',20)}");awaitforeach(varupdateinclient.SendStreamingMessageAsync(request)){foreach(varpartinupdate.Message!.Parts){Console.Write(part.Text);}}Console.ReadLine();

输出:

--------------------SendMessageAsync-------------------- 不是主要因为“郑国不够强大”,而是郑庄公的霸业更偏“春秋初期的权力中心”,难以长期维持。 郑庄公确实曾挟强郑、制诸侯、周旋王室,一度有霸主气象,但郑国地处中原四战之地,国小地狭,战略纵深不足;加之庄公死后国力迅速下滑,未能形成持续稳定的霸权体系。 而后来的“五霸”多是长期扩张、能整合资源并持续主盟的强国君主,所以郑庄公虽有“初霸”之名,终究未列入传统春秋五霸。 --------------------SendStreamingMessageAsync-------------------- 不只是“郑国不够强大”,更关键是郑庄公的霸业具有明显的**短暂性和局部性**。 春秋初年“霸”多指能号令诸侯、主持会盟者,郑庄公虽曾挟王室、败强邻,威震一时,但其影响主要限于中原局部,且未形成长期稳定的盟主地位。 此后郑国国力有限,又屡受宋、楚、齐等国压力,难以延续霸权。后来“五霸”之所以被后世定型,更多是因为其霸业更持久、影响更大、史书叙事也更集中。
http://www.jsqmd.com/news/1273139/

相关文章:

  • 2026绍兴CMA甲醛检测公司怎么选:只测不除的专业第三方实验室——万清测研检测及公共卫生检测 - 创达咨询
  • 金价又飚了上海老乡看过来!淘淇黄金回收领衔 6 家靠谱店不踩坑 - 淘淇黄金回收
  • 2026年身份证加水印用什么小程序安全?亲测好用的免费方法 - 图片处理研究员
  • Zotero中文文献管理的终极解决方案:Jasminum茉莉花插件完全指南
  • 《2026深圳搬家避坑指南:本地人实测5大正规搬家公司口碑精选 透明报价全解析及服务商选型避坑全攻略》 - 深圳家顺兴搬家
  • 变分自编码器(VAE)原理与应用全解析
  • 全新夸父资源社复活,让大家都能找到想要的资源
  • 2023机器学习五大前沿技术解析与应用实践
  • 5分钟快速上手ncmdump:免费解决网易云音乐NCM格式播放限制的终极方案
  • 推荐全国项目改造膜结构住宿篷房生产厂商 - 品牌推广大师
  • 神经网络控制器原理与Simulink实现详解
  • 深入解析OMAP5912 USB OTG控制器:双角色设备与低功耗设计
  • LOAM-Livox技术解析:突破固态激光雷达运动模糊与小视场角限制的SLAM方案
  • Transformer强化学习(TRL)原理与应用实践
  • 抖店采购软件具体能解决哪些问题?货源绑定、自动下单与物流单号回填流程 - 抖掌柜
  • 基于QtPy (PySide6) 的PLC-HMI工程项目(三)PLC上行数据的准备
  • 签证银行流水翻译如何申办?银行流水翻译流程是什么?完整步骤拆解! - 叮咚办真方便
  • QLScriptPublic:企业级自动化任务调度框架的终极指南
  • Linux系统与系统编程(12)——进程间通信
  • OpenClaw开源AI框架:低代码开发与硬件需求解析
  • 2026河池厨房渗水到楼下怎么办?自来水管暗管检测方法,仪器测漏收费标准 - 宅安选房屋修缮
  • 成长型AI智能体的核心技术解析与企业落地实践
  • 终极网盘直链解析工具:告别限速烦恼的完整解决方案
  • 2026 大连黄金回收合规平台盘点:双备案资质 + 权威贵金属检测,线下门店资质均可线上查验 - 日常财经早知道
  • CPLD在DSP评估板中的核心作用:中断、接口与寄存器映射实战解析
  • 深入解析Linux进程管理:从PCB到状态机
  • 2026 年 7 月宁波金价盘点,合扬门店大盘计价实测,市民卖金完整指南 - 好物测评局
  • Trivy忽略配置全解析:从原理到实践,让漏洞扫描精准过滤
  • 内蒙古旅游的真实成本大公开!还有7位靠谱导游联系方式,看完再也不怕被坑! - 纯玩旅游分享
  • 基于YOLOv8和ByteTrack的双向越线计数技术实现