返回顶部
热门问答 更多热门问答
技术文章 更多技术文章

AutoGen: 我也能实现OpenAI Swarm中的handoff

[复制链接]
链载Ai 显示全部楼层 发表于 3 小时前 |阅读模式 打印 上一主题 下一主题

最近,OpenAI 推出的 Swarm 框架引发了业界对 MultiAgent框架的热议。特别是,Swarm 中的核心原语抽象——handoff(交接), 允许代理之间高效转移任务,以其简单直观的设计,受到了好评。

什么是 Handoff 模式?

如果想象一下四人接力赛,运动员们一棒接一棒,顺畅无比。换到 AI 的世界里,“交接”就像是代理之间互相传递工作任务。OpenAI 推出的 Swarm 框架十分灵活,这种交接模式允许一个 AI 代理把任务无缝转交给其他代理,如同在聊天中把话筒递给下一个人。

AutoGen 的回应

作为 MultiAgent 框架领域的代表 AutoGen 坐不住了,发文[1]表示,利用 AutoGen 的灵活和可扩展的系统设计,同样可以实现 Handoffs,并且还具备以下优势:

  1. 可扩展性:AutoGen 可以轻松扩展到分布式环境,支持更大规模的代理协作。

  2. 灵活性:开发者可以自定义代理的实现,根据需求打造专属的 AI 团队。

  3. 集成便利性:原生异步 API 可以轻松与 UI 和其他系统集成,适应各种应用场景。

  4. 开放性:作为开源项目,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 的实现示例
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,或者在必要时直接转给人类客服,确保你能得到及时的帮助。这种“交接”就像是办公室里的团队协作,确保没有人被落下。

下面是一些具体实现:

  • 定义不同角色的 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 之类成熟产品最大软肋吧!


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

链载AI是专业的生成式人工智能教程平台。提供Stable Diffusion、Midjourney AI绘画教程,Suno AI音乐生成指南,以及Runway、Pika等AI视频制作与动画生成实战案例。从提示词编写到参数调整,手把手助您从入门到精通。
  • 官方手机版

  • 微信公众号

  • 商务合作

  • Powered by Discuz! X3.5 | Copyright © 2025-2025. | 链载Ai
  • 桂ICP备2024021734号 | 营业执照 | |广西笔趣文化传媒有限公司|| QQ