大家好,我是Edison。
最近我一直在跟着圣杰的《.NET+AI智能体开发进阶》课程学习MAF开发多智能体工作流,我强烈推荐你也上车跟我一起出发!
上一篇,我们学习了MAF中常见的多智能体编排模式。本篇,我们来了解下在MAF中如何快速集成A2A (Agent to Agent)。
1 A2A协议介绍
在之前的系列文章中我们其实已经介绍过A2A协议了,这里我们快速温习一下。A2A 即 Agent-to-Agent,翻译过来就是“智能代理之间的协议”,我们可以理解为它就是一个大模型Agent们用来“聊天”的“通用语言”。
A2A定义了一套清晰、标准的沟通方式,让Agent们可以顺畅地交流,让不同平台和框架下的Agent都能够说“同一种话”,实现无障碍的信息交换和协作。
更多关于A2A协议的内容:
- 多Agent协作入门:基于A2A协议的Agent通信(上)
- 多Agent协作入门:基于A2A协议的Agent通信(中)
2 将A2A Agent封装为Tool
在MAF集成A2A Agent,最主要的操作就是:将A2A Agent封装为一个Tool,这个Tool对应到MAF中就是一个AIFunction对象。
前面我们提到可以将MCP服务也封装为一个Tool(AIFunction)让Agent调用,这里A2A Agent也是一样的道理。
这样做的好处是:让MAF中的Agent像调用本地函数一样调用远程A2A Agent 或 MCP Server。
下面的代码展示了在MAF中将A2A Card转换为Agent,然后再将Agent转换为AIFunction:- ......
- var functionTools = new List();
- foreach (var endpoint in agentEndpoints)
- {
- var resolver = new A2ACardResolver(new Uri(endpoint));
- var card = await resolver.GetAgentCardAsync();
- var agent = card.AsAIAgent(); // Convert A2A Agent to AIAgent instance
- functionTools.AddRange(AgentFunctionHelper.CreateFunctionTools(agent, card));
- }
- ......
复制代码 下面是AgentFunctionHelper类的代码实现:- public class AgentFunctionHelper
- {
- public static IEnumerable CreateFunctionTools(AIAgent a2aAgent, AgentCard agentCard)
- {
- foreach (var skill in agentCard.Skills)
- {
- AIFunctionFactoryOptions options = new()
- {
- Name = Sanitize(skill.Id),
- Description = $$"""
- {
- "description": "{{skill.Description}}",
- "tags": "[{{string.Join(", ", skill.Tags ?? [])}}]",
- "examples": "[{{string.Join(", ", skill.Examples ?? [])}}]",
- "inputModes": "[{{string.Join(", ", skill.InputModes ?? [])}}]",
- "outputModes": "[{{string.Join(", ", skill.OutputModes ?? [])}}]"
- }
- """,
- };
- yield return AIFunctionFactory.Create(RunAgentAsync, options);
- }
- async Task<string> RunAgentAsync(string input, CancellationToken cancellationToken)
- {
- var response = await a2aAgent.RunAsync(input, cancellationToken: cancellationToken).ConfigureAwait(false);
- return response.Text;
- }
- }
- private static readonly Regex InvalidNameCharsRegex = new Regex("[^0-9A-Za-z]+", RegexOptions.Compiled);
- public staticstringSanitize(string name)
- {
- return InvalidNameCharsRegex.Replace(name, "_");
- }
- }
复制代码 其中的CreateFunctionTools方法实现了将A2A Agent的所有公开技能转换为AIFunction工具。
而Sanitize方法则实现了函数名称的规范化,因为AIFunction的名称必须符合一定规范(仅限字母、数字和下划线),因此需要主动对技能名称进行规范化。
3 完整集成示例
这次我们还是使用上次文章中的案例,即一个旅游助手,它可以通过A2A协议调用多个Agent的技能。
我们需要创建四个.NET项目,其中:
- 1个.NET控制台项目:主助手
- 3个ASP.NET Web项目:天气智能体、酒店智能体、路线智能体
在VS中的项目结构如下:
本次案例我们希望实现主助手可以回答用户关于不同主题(景点,酒店,天气)的问题,它可以根据问题自主选择需要调用一个或多个Agent去获取必要的信息后进行整合优化后再回复用户。
3.1 天气Agent
添加NuGet包,后续A2A Agent项目都需要安装此包,不再赘述:创建一个 WeatherAgent类,定义其能力 和 AgentCard,这里我们需要公开一个AgentSkill即天气查询的能力:
[code]public class WeatherAgent{ public void Attach(ITaskManager taskManager) { taskManager.OnMessageReceived = QueryWeatherAsync; taskManager.OnAgentCardQuery = GetAgentCardAsync; } private Task QueryWeatherAsync(MessageSendParams messageSendParams, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return Task.FromCanceled(cancellationToken); } // Process the message var messageText = messageSendParams.Message.Parts.OfType().First().Text; // Create and return an artifact var message = new AgentMessage() { Role = MessageRole.Agent, MessageId = Guid.NewGuid().ToString(), ContextId = messageSendParams.Message.ContextId, Parts = [new TextPart() { Text = $"""
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |