|
最近,OpenAI 推出的 Swarm 框架引发了业界对 MultiAgent框架的热议。特别是,Swarm 中的核心原语抽象——handoff(交接), 允许代理之间高效转移任务,以其简单直观的设计,受到了好评。 
什么是 Handoff 模式?如果想象一下四人接力赛,运动员们一棒接一棒,顺畅无比。换到 AI 的世界里,“交接”就像是代理之间互相传递工作任务。OpenAI 推出的 Swarm 框架十分灵活,这种交接模式允许一个 AI 代理把任务无缝转交给其他代理,如同在聊天中把话筒递给下一个人。 AutoGen 的回应
作为 MultiAgent 框架领域的代表 AutoGen 坐不住了,发文[1]表示,利用 AutoGen 的灵活和可扩展的系统设计,同样可以实现 Handoffs,并且还具备以下优势: 可扩展性:AutoGen 可以轻松扩展到分布式环境,支持更大规模的代理协作。 灵活性:开发者可以自定义代理的实现,根据需求打造专属的 AI 团队。 集成便利性:原生异步 API 可以轻松与 UI 和其他系统集成,适应各种应用场景。 开放性:作为开源项目,AutoGen 一样允许开发者自由扩展和优化系统。 在技术层面上,“交接”模式通过一些消息协议来实现,比如 UserLogin、UserTask 和 AgentResponse 等。这些协议确保了代理之间的信息传递顺畅,类似于聊天中的对话指南。在 AutoGen 中,AI 代理使用 AIAgent 类来生成回复,利用 delegate_tools 可以轻松地将任务交给其他代理。当 AI 代理遇到无法处理的问题时,人类代理(Human Agent)就会出色登场,确保用户的问题得到妥善解决。ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin-bottom: 16px;">
AutoGen 为了展示这一能力,特地使用了OpenAI 的客服案例ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0px;line-height: 0;color: rgb(30, 107, 184);font-weight: bold;">[2]进行了实现。不了解AutoGen的朋友可以阅读:一文探秘LLM应用开发(26)-Prompt(架构模式之Agent框架AutoGPT、AutoGen等) 一个客户服务场景中,我们可能会有这样的阵容: - 客户 Agent(UserAgent)处理用户登录和 Agent 响应,并启动与聊天机器人的新会话。
- 分流Agent(Triage Agent):负责初步评估客户问题
- 维修Agent(Issue and Repair Agent):处理维修相关事务
- 销售Agent(Sales Agent):负责产品推荐和销售
- 人类Agent(Human Agent):处理复杂情况或需要人工干预的问题,确保系统的鲁棒性。
每个 AI Agent都由 AIAgent 类来处理,它们可以: 使用 ChatCompletionClient 生成回复 通过 delegate_tools 将任务委派给其他代理 订阅特定的主题类型,并向用户发送消息,每个 Agent 都有自己的主题类型,如 sales_agent_topic_type、issues_and_repairs_agent_topic_type 等,便于消息的精准投递。
当你发问时,初步分流 Agent 会首先接手。如果问题超出了它的处理能力,它会把任务“交接”给维修 Agent 或者销售 Agent,或者在必要时直接转给人类客服,确保你能得到及时的帮助。这种“交接”就像是办公室里的团队协作,确保没有人被落下。 下面是一些具体实现: runtime=SingleThreadedAgentRuntime()
model_client=OpenAIChatCompletionClient( model="gpt-4o-mini", #api_key="YOUR_API_KEY", )
#Registerthetriageagent. triage_agent_type=awaitAIAgent.register( runtime, type=triage_agent_topic_type,#Usingthetopictypeastheagenttype. factory=lambda:AIAgent( description="Atriageagent.", system_message=SystemMessage( content="YouareacustomerservicebotforACMEInc." "Introduceyourself.Alwaysbeverybrief." "Gatherinformationtodirectthecustomertotherightdepartment." "Butmakeyourquestionssubtleandnatural." ), model_client=model_client, tools=[], delegate_tools=[ transfer_to_issues_and_repairs_tool, transfer_to_sales_agent_tool, escalate_to_human_tool, ], agent_topic_type=triage_agent_topic_type, user_topic_type=user_topic_type, ), ) #Addsubscriptionsforthetriageagent:itwillreceivemessagespublishedtoitsowntopiconly. awaitruntime.add_subscription(TypeSubscription(topic_type=triage_agent_topic_type,agent_type=triage_agent_type.type))
#Registerthesalesagent. sales_agent_type=awaitAIAgent.register( runtime, type=sales_agent_topic_type,#Usingthetopictypeastheagenttype. factory=lambda:AIAgent( description="Asalesagent.", system_message=SystemMessage( content="YouareasalesagentforACMEInc." "Alwaysanswerinasentenceorless." "Followthefollowingroutinewiththeuser:" "1.Askthemaboutanyproblemsintheirliferelatedtocatchingroadrunners.\n" "2.CasuallymentiononeofACME'scrazymade-upproductscanhelp.\n" "-Don'tmentionprice.\n" "3.Oncetheuserisboughtin,droparidiculousprice.\n" "4.Onlyaftereverything,andiftheusersaysyes," "tellthemacrazycaveatandexecutetheirorder.\n" "" ), model_client=model_client, tools=[execute_order_tool], delegate_tools=[transfer_back_to_triage_tool], agent_topic_type=sales_agent_topic_type, user_topic_type=user_topic_type, ), ) #Addsubscriptionsforthesalesagent:itwillreceivemessagespublishedtoitsowntopiconly. awaitruntime.add_subscription(TypeSubscription(topic_type=sales_agent_topic_type,agent_type=sales_agent_type.type))
#Registertheissuesandrepairsagent. issues_and_repairs_agent_type=awaitAIAgent.register( runtime, type=issues_and_repairs_agent_topic_type,#Usingthetopictypeastheagenttype. factory=lambda:AIAgent( description="Anissuesandrepairsagent.", system_message=SystemMessage( content="YouareacustomersupportagentforACMEInc." "Alwaysanswerinasentenceorless." "Followthefollowingroutinewiththeuser:" "1.First,askprobingquestionsandunderstandtheuser'sproblemdeeper.\n" "-unlesstheuserhasalreadyprovidedareason.\n" "2.Proposeafix(makeoneup).\n" "3.ONLYifnotsatesfied,offerarefund.\n" "4.Ifaccepted,searchfortheIDandthenexecuterefund." ), model_client=model_client, tools=[ execute_refund_tool, look_up_item_tool, ], delegate_tools=[transfer_back_to_triage_tool], agent_topic_type=issues_and_repairs_agent_topic_type, user_topic_type=user_topic_type, ), ) #Addsubscriptionsfortheissuesandrepairsagent:itwillreceivemessagespublishedtoitsowntopiconly. awaitruntime.add_subscription( TypeSubscription(topic_type=issues_and_repairs_agent_topic_type,agent_type=issues_and_repairs_agent_type.type) )
#Registerthehumanagent. human_agent_type=awaitHumanAgent.register( runtime, type=human_agent_topic_type,#Usingthetopictypeastheagenttype. factory=lambda:HumanAgent( description="Ahumanagent.", agent_topic_type=human_agent_topic_type, user_topic_type=user_topic_type, ), ) #Addsubscriptionsforthehumanagent:itwillreceivemessagespublishedtoitsowntopiconly. awaitruntime.add_subscription(TypeSubscription(topic_type=human_agent_topic_type,agent_type=human_agent_type.type))
#Registertheuseragent. user_agent_type=awaitUserAgent.register( runtime, type=user_topic_type, factory=lambda:UserAgent( description="Auseragent.", user_topic_type=user_topic_type, agent_topic_type=triage_agent_topic_type,#Startwiththetriageagent. ), ) #Addsubscriptionsfortheuseragent:itwillreceivemessagespublishedtoitsowntopiconly. awaitruntime.add_subscription(TypeSubscription(topic_type=user_topic_type,agent_type=user_agent_type.type))
#Starttheruntime. runtime.start()
#Createanewsessionfortheuser. session_id=str(uuid.uuid4()) awaitruntime.publish_message(UserLogin(),topic_id=TopicId(user_topic_type,source=session_id))
#Rununtilcompletion. awaitruntime.stop_when_idle()
#运行日志: -------------------------------------------------------------------------------- Userlogin,sessionID:7a568cf5-13e7-4e81-8616-8265a01b3f2b. -------------------------------------------------------------------------------- User: Iwantarefund -------------------------------------------------------------------------------- TriageAgent: Icanhelpwiththat!CouldIaskwhatitemyou'reseekingarefundfor? -------------------------------------------------------------------------------- User: ApairofshoesIbought -------------------------------------------------------------------------------- TriageAgent: [FunctionCall(id='call_qPx1DXDL2NLcHs8QNo47egsJ',arguments='{}',name='transfer_to_issues_and_repairs')] -------------------------------------------------------------------------------- TriageAgent: DelegatingtoIssuesAndRepairsAgent -------------------------------------------------------------------------------- IssuesAndRepairsAgent: Iseeyou'relookingforarefundonapairofshoes.Canyoutellmewhattheissueiswiththeshoes? -------------------------------------------------------------------------------- User: Theshoesaretoosmall -------------------------------------------------------------------------------- IssuesAndRepairsAgent: Irecommendtryingasizeupasafix;wouldthatworkforyou? -------------------------------------------------------------------------------- User: noIwantarefund -------------------------------------------------------------------------------- IssuesAndRepairsAgent: [FunctionCall(id='call_Ytp8VUQRyKFNEU36mLE6Dkrp',arguments='{"search_query":"shoes"}',name='look_up_item')] -------------------------------------------------------------------------------- IssuesAndRepairsAgent: [FunctionExecutionResult(content='item_132612938',call_id='call_Ytp8VUQRyKFNEU36mLE6Dkrp')] -------------------------------------------------------------------------------- IssuesAndRepairsAgent: [FunctionCall(id='call_bPm6EKKBy5GJ65s9OKt9b1uE',arguments='{"item_id":"item_132612938","reason":"notprovided"}',name='execute_refund')] -------------------------------------------------------------------------------- IssuesAndRepairsAgent: [FunctionExecutionResult(content='success',call_id='call_bPm6EKKBy5GJ65s9OKt9b1uE')] -------------------------------------------------------------------------------- IssuesAndRepairsAgent: Yourrefundhasbeensuccessfullyprocessed!Ifyouhaveanyotherquestions,feelfreetoask. -------------------------------------------------------------------------------- User: Iwanttotalktoyourmanager -------------------------------------------------------------------------------- IssuesAndRepairsAgent: Icanhelpwiththat,letmetransferyoutoasupervisor. -------------------------------------------------------------------------------- User: Okay -------------------------------------------------------------------------------- IssuesAndRepairsAgent: [FunctionCall(id='call_PpmLZvwNoiDPUH8Tva3eAwHX',arguments='{}',name='transfer_back_to_triage')] -------------------------------------------------------------------------------- IssuesAndRepairsAgent: DelegatingtoTriageAgent -------------------------------------------------------------------------------- TriageAgent: [FunctionCall(id='call_jSL6IBm5537Dr74UbJSxaj6I',arguments='{}',name='escalate_to_human')] -------------------------------------------------------------------------------- TriageAgent: DelegatingtoHumanAgent -------------------------------------------------------------------------------- HumanAgent: Hellothisismanager -------------------------------------------------------------------------------- User: Hi!Thanksforyourservice.Igiveyoua5start! -------------------------------------------------------------------------------- HumanAgent: Thanks. -------------------------------------------------------------------------------- User: exit -------------------------------------------------------------------------------- Usersessionended,sessionID:7a568cf5-13e7-4e81-8616-8265a01b3f2b.
总结AutoGen 的 Handoff 实现不仅匹敌 OpenAI 的 Swarm,还在多个方面有所超越。它为开发者提供了一个强大、灵活且可扩展的框架,以构建复杂的多代理 AI 系统。不过,相较于 OpenAI 的 Swarm 实现,AutoGen 明显感觉概念更多,依赖更重,网络上就有人这么评价,“OpenAI 发布了一个示例,大约有 12 行代码,易于阅读,除了 swarm 模块外,没有其他依赖。对于 Autogen,我找不到类似的东西;似乎所有的示例都更复杂。” 这或许也是 AutoGen 之类成熟产品最大软肋吧!
|