继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

使用Microsoft Semantic Kernel和Google A2A协议构建多代理旅行规划系统的简易指南——比你想象的要简单!

蓝山帝景
关注TA
已关注
手记 482
粉丝 47
获赞 152

作者的图片

学习如何使用语义内核(Semantic Kernel)和谷歌的A2A协议连接和协调代理

让我们创建一个简单的代理系统来管理旅行安排,以展示Google A2A如何连接不同的代理。我们将使用Microsoft Semantic Kernel构建以下这些代理,并通过Google A2A让它们能够互相交流。

  • ✈️ flight-booking-agent:帮助预订航班
  • Travel Planner Agent:这是主要代理,还可以聊天。它帮助规划旅行,需要时会帮忙预订航班。

核心思想是让每个代理保持独立,每个代理都配备有自己的工具集和运行环境,仍可以通过A2A无缝协作。下面简要介绍一下Google的A2A

Google 的“A2A”简介

注:“A2A”指代“Application to Application”

让我们快速了解一下Google A2A。有大量的优秀文档可以参考,如果你对这个感兴趣,我强烈建议阅读官方文档,不过在这篇博客里,我们将重点介绍几个核心概念。

A2A(代理对代理)帮助不同供应商或系统构建的代理使用一个共同的协议进行通信。下面是一些基本组成部分:

  • AgentCard: 想象一下这就像一张名片——它描述了一个代理能做什么,如何与它互动以及它的需求。
  • A2A 服务器: 这个组件托管代理并公开其功能。
  • A2A 客户端: 任何与 A2A 服务器互动的应用程序(或另一个代理)。
  • 任务: 具有一个唯一 ID 和不同生命周期状态(例如,已提交、运行中、需要输入)的工作单元。
  • 部分: 消息或工件中的最小内容单元,例如文本、数据或文件。

这使得A2A非常适合长时间运行的任务或需要协作的任务。

简短概括

第1部分:A2A代理(航班预订代理)

  1. 定义代理类: 创建你的核心代理类及其主要异步方法(例如 book_flight)。
  2. 实现执行器: 构建 AgentExecutor 以将代理的逻辑连接到 A2A 协议并处理请求。
  3. 定义代理卡: 创建一个 JSON AgentCard,详细说明代理的功能及如何与其交互。
  4. 启动服务器: 使用 DefaultRequestHandlerA2AStarletteApplication 启动你的 A2A 服务器,使代理可以被发现和使用。

第二部分:A2A客户端(旅行规划师)

  1. 获取代理凭证: 异步获取你想要与其交流的服务器代理的 AgentCard
  2. 初始化客户端: 初始化客户端,使用获取到的 AgentCard
  3. 准备请求: 准备请求,包括用户输入和上下文信息。
  4. 创建SK工具: 创建一个语义内核工具来封装 A2A 客户端交互。
  5. 集成工具: 将这一由 A2A 支持的工具整合到你的主要 Travel Planner Agent 中。

展示A2A通信流程的流程图。

使用Python一步步创建A2A代理的教程 第1部分

第一步:定义代理程序

我们首先创建一个简单的FlightBookingAgent类,该类有一个异步invoke方法:

    class SemanticKernelFlightBookingAgent:  

        def __init__(self):  
            logger.info("正在初始化SemanticKernelFlightBookingAgent。")  
            self.chat_agent = ChatCompletionAgent(  
                service=AzureChatCompletion(  
                    api_key="<api_key>", # 请用你的Azure OpenAI API密钥替换  
                    endpoint="https://<endpoint>.openai.azure.com",  # 请确认你使用了正确的端点和部署名称  
                    deployment_name="<deployment_name>", # 请用你的部署名称替换  
                    api_version="2024-12-01-preview",  
                ),  
                name="Assistant",  
            )  

            # 上下文ID到聊天历史的映射  
            self.history_store: dict[str, ChatHistory] = {}  

            logger.info("SemanticKernelFlightBookingAgent初始化完成。")  

        async def book_flight(self, user_input: str, context_id: str) -> str:  
            """  
            根据用户输入预订航班票。  
            :param user_input: 用户的航班预订请求。  
            :param context_id: 请求的上下文ID。  
            :return: 航班预订代理的响应。  
            """  
            # 实现在我分享的Git仓库中可以找到  
            return final_response
第二步:实现Agent代理

AgentExecutor充当A2A协议与代理逻辑之间的桥梁,负责处理传入请求并确保任务执行顺利进行。

    class SemanticKernelFlightBookingAgentExecutor(AgentExecutor):  
        """Executor for SemanticKernelFlightBookingAgent."""  

        def __init__(self):  
            logger.info("初始化SemanticKernelFlightBookingAgentExecutor。")  
            self.agent = SemanticKernelFlightBookingAgent()  
            logger.info("SemanticKernelFlightBookingAgentExecutor初始化成功。")  

        async def execute(  
            self,  
            context: RequestContext,  
            event_queue: EventQueue,  
        ) -> None:  
            user_input = context.get_user_input()  
            task = context.current_task  
            context_id = context.context_id  

            logger.info(f"执行航班预订,用户输入为:{user_input},任务ID为:{task.id},上下文ID为:{context_id}")  
            try:  
                result = await self.agent.book_flight(user_input, context_id)  
                event_queue.enqueue_event(new_agent_text_message(result))  
                logger.info("航班预订执行成功。")  
            except Exception as e:  
                logger.error(f"航班预订执行出错:{e}")  
                event_queue.enqueue_event(new_agent_text_message(f"错误:{e}"))  

        async def cancel(  
            self, context: RequestContext, event_queue: EventQueue  
        ) -> None:  
            logger.warning("收到取消操作请求,但不支持。")  
            raise Exception('不支持取消操作。')

AgentExecutor 类中,主要有两个方法。

  • async def execute(self, context: RequestContext, event_queue: EventQueue):处理需要响应或返回事件流的传入请求。
  • async def cancel(self, context: RequestContext, event_queue: EventQueue):处理取消正在进行的任务的请求。
步骤 3:定义角色牌

main.py文件中,你需要按下面的步骤来:

代理卡(Agent 卡)是一个描述代理功能和能力的JSON文档,通常托管在/.well-known/agent.json

        flight_booking_skill = AgentSkill(  
            id='flight_booking',  
            name='航班预订',  
            description='帮助用户根据他们的请求预订航班。',  
            tags=['航班', '预订', '旅行'],  
            examples=[  
                '帮我订一个下周一下午从纽约到伦敦的航班。',  
                '我想订一个明天早上飞往巴黎的航班。',  
            ],  
        )  

        flight_booking_agent_card = AgentCard(  
            name='Semantic Kernel 航班预订代理',  
            description='一个帮助用户使用语义内核功能来预订航班的代理。',  
            capabilities=AgentCapabilities(streaming=True),  
            url='http://localhost:9999/',  
            version='1.0.0',  
            defaultInputModes=['text'],  
            defaultOutputModes=['text'],  
            skills=[flight_booking_skill],  
            supportsAuthenticatedExtendedCard=False  
        )  
步骤 4:定义请求处理器并启动 A2A 服务器。
        # 使用航班预订代理执行器初始化请求处理器  
        request_handler = DefaultRequestHandler(  
            agent_executor=SemanticKernelFlightBookingAgent执行器(),  
            task_store=内存任务存储(),  
        )  

        # 创建并运行服务器应用程序  
        server = A2AStarlette应用程序(  
            agent_card=flight_booking_agent_card,  
            http_handler=request_handler,  
        )  

        logger.info("正在启动Semantic Kernel航班预订代理服务器,监听端口9999.")  
        uvicorn.run(server.build(), host='0.0.0.0', port=9999)
  • 默认请求处理器(DefaultRequestHandler): DefaultRequestHandler 是 SDK 中提供的一种默认请求处理器。它将你的自定义 AgentExecutor(比如 FlightBookingAgentExecutor)与 A2A 协议连接在一起。它还需要一个 TaskStore(如 InMemoryTaskStore)来管理任务——这有助于追踪正在进行的任务、流式响应和重新连接。即使你的代理不需要高级功能,TaskStore 仍然必不可少。
  • A2AStarletteApplication(A2AStarlette 应用程序): 这是运行你代理的 Web 服务器。它使用:代理卡(AgentCard)(用于描述你的代理及其功能)。request_handler(前面提到的 DefaultRequestHandler)。代理卡非常重要,因为它会在 /.well-known/agent.json 端点上共享,从而使其他代理或客户端能够发现你的代理。

最后一步就是启动服务器。

第二部分:一步一步的指南 创建用于行程规划的A2A客户端代理

解释:A2A是指代理与代理之间的通信。

travel-agent.py 文件中,我将创建一个工具,仅在必要时调用航班预订代理。

第一步:取代理卡

# 异步上下文管理器,初始化httpx客户端
async with httpx.AsyncClient() as httpx_client:  
   # 创建A2ACardResolver实例,传入初始化的httpx客户端和基础URL
   resolver = A2ACardResolver(httpx_client=httpx_client, base_url=base_url)  
   # 获取代理卡片
   agent_card = await resolver.get_agent_card()
初始化A2A客户端流程
# 创建一个 A2AClient 实例,传递 httpx 客户端和代理卡信息
# A2AClient 是一个客户端对象
# 初始化 A2AClient 对象
client = A2AClient(httpx_client=httpx_client, agent_card=agent_card)
步骤三:准备请求的数据载荷
                request = SendMessageRequest(  
                    id=str(uuid4()),  
                    params=MessageSendParams(  
                        message={  
                            "messageId": uuid4().hex,  
                            "role": "user",  
                            "parts": [{"text": user_input}],  
                            "contextId": '123', # 请用sessionId替换以支持多轮会话  
                        }  
                    )  
                )  
                response = await client.send_message(request)
步骤 4:将其定义为语义核工具:
    class FlightBookingTool:
        @kernel_function(
            description="使用航班预订代理预订航班",
            name="book_flight"
        )
        async def book_flight(self, user_input: str) -> str:
            async with httpx.AsyncClient() as 客户端:
                resolver = A2ACardResolver(httpx_client=客户端, base_url=base_url)
                agent_card = await resolver.get_agent_card()

                client = A2AClient(httpx_client=客户端, agent_card=agent_card)

                request = SendMessageRequest(
                    id=str(uuid4()),
                    参数=MessageSendParams(
                        消息={
                            "消息ID": uuid4().hex,
                            "角色": "user",
                            "部分": [{"文本": user_input}],
                            "上下文ID": '123',
                        }
                    )
                )
                response = await client.send_message(request)
                result = response.model_dump(mode='json', exclude_none=True)
                日志记录器.info(f"航班预订工具的响应: {result}")

                return result["result"]["部分"][0]["文本"]

第五步:使用该工具定义旅行规划器代理程序

    travel_planning_agent = ChatCompletionAgent(  
        service=AzureChatCompletion(  
            api_key="<your-api-key>",  
            endpoint="https://<your-endpoint>.openai.azure.com",  
            deployment_name="<your-deployment-name>",  
            api_version="2024-12-01-preview",  
        ),  
        name="TravelPlanner",  
        instructions="你是一个乐于助人的旅行规划助手。请使用提供的工具帮助用户制定旅行计划。",  
        plugins=[FlightBookingTool()]
咱们试试看
  • 终端1: 启动Travel Planner Agent(既是A2A客户端也是聊天客户端)。
  • 终端2: 启动Flight Booking Agent(作为A2A服务器端)。

最终结果

你会注意到旅行规划代理会在需要时把任务转交给航班预订代理。这两个代理都有状态,并且使用context_id来维护各自的上下文。我在这儿没有使用事件管理来实现异步任务管理,因为这会让例子更复杂。我想先从一个简单的例子开始。

下面是一些代码参考:

https://github.com/akshaykokane/Implementing-Multi-Agent-With-A2A-SemanticKernel

结束了

这个指南带领你走过了利用Microsoft Semantic Kernel创建代理,并通过Google A2A实现代理间的无缝通信来构建多代理系统的流程。我们展示了如何将Flight Booking Agent设置为A2A服务器,以及将Travel Planner Agent设置为A2A客户端,展示了这些独立实体(如代理)如何有效地协作来管理复杂的任务(如行程规划)。

通过定义清晰的AgentCards和实现强大的AgentExecutors,并利用A2A的异步能力,我们已经为构建高度模块化和可扩展的代理系统奠定了坚实的基础。这种方法允许代理利用其专用工具集和运行时,同时仍从中受益于通用的通信协议。正如你所见,连接不同代理比想象中容易得多,这为更智能和协作的AI应用程序开启了无限可能。

参考

如果你喜欢这篇分步骤指南或觉得它有帮助,可以在Medium关注我,获取更多关于实用AI、自动化和代理工作流的深入探讨。我经常分享动手教程、工具和框架,帮助你构建更智能的系统——无论你的编程背景如何。

📌 关注我LinkedIn链接上的动态,了解更多我在微软及其他地方的AI实际应用案例、产品实验和幕后故事。

💬 有想法、疑问,或者想合作

留言或联系我,我很愿意聊天!

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP