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

大模型关系型数据库智能语音交互

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

picture.image

什么是 Handoff 模式?

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

AutoGen 的回应

picture.image

作为 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)就会出色登场,确保用户的问题得到妥善解决。

picture.image

AutoGen 的实现示例

AutoGen 为了展示这一能力,特地使用了 OpenAI 的客服案例 [2] 进行了实现。不了解AutoGen的朋友可以阅读:一文探秘LLM应用开发(26)-Prompt(架构模式之Agent框架AutoGPT、AutoGen等)

picture.image

一个客户服务场景中,我们可能会有这样的阵容:

  • 客户 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",  
)  
  
# Register the triage agent.  
triage_agent_type = await AIAgent.register(  
    runtime,  
    type=triage_agent_topic_type,  # Using the topic type as the agent type.  
    factory=lambda: AIAgent(  
        description="A triage agent.",  
        system_message=SystemMessage(  
            content="You are a customer service bot for ACME Inc. "  
            "Introduce yourself. Always be very brief. "  
            "Gather information to direct the customer to the right department. "  
            "But make your questions subtle and natural."  
        ),  
        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,  
    ),  
)  
# Add subscriptions for the triage agent: it will receive messages published to its own topic only.  
await runtime.add_subscription(TypeSubscription(topic_type=triage_agent_topic_type, agent_type=triage_agent_type.type))  
  
# Register the sales agent.  
sales_agent_type = await AIAgent.register(  
    runtime,  
    type=sales_agent_topic_type,  # Using the topic type as the agent type.  
    factory=lambda: AIAgent(  
        description="A sales agent.",  
        system_message=SystemMessage(  
            content="You are a sales agent for ACME Inc."  
            "Always answer in a sentence or less."  
            "Follow the following routine with the user:"  
            "1. Ask them about any problems in their life related to catching roadrunners.\n"  
            "2. Casually mention one of ACME's crazy made-up products can help.\n"  
            " - Don't mention price.\n"  
            "3. Once the user is bought in, drop a ridiculous price.\n"  
            "4. Only after everything, and if the user says yes, "  
            "tell them a crazy caveat and execute their order.\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,  
    ),  
)  
# Add subscriptions for the sales agent: it will receive messages published to its own topic only.  
await runtime.add_subscription(TypeSubscription(topic_type=sales_agent_topic_type, agent_type=sales_agent_type.type))  
  
# Register the issues and repairs agent.  
issues_and_repairs_agent_type = await AIAgent.register(  
    runtime,  
    type=issues_and_repairs_agent_topic_type,  # Using the topic type as the agent type.  
    factory=lambda: AIAgent(  
        description="An issues and repairs agent.",  
        system_message=SystemMessage(  
            content="You are a customer support agent for ACME Inc."  
            "Always answer in a sentence or less."  
            "Follow the following routine with the user:"  
            "1. First, ask probing questions and understand the user's problem deeper.\n"  
            " - unless the user has already provided a reason.\n"  
            "2. Propose a fix (make one up).\n"  
            "3. ONLY if not satesfied, offer a refund.\n"  
            "4. If accepted, search for the ID and then execute refund."  
        ),  
        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,  
    ),  
)  
# Add subscriptions for the issues and repairs agent: it will receive messages published to its own topic only.  
await runtime.add_subscription(  
    TypeSubscription(topic_type=issues_and_repairs_agent_topic_type, agent_type=issues_and_repairs_agent_type.type)  
)  
  
# Register the human agent.  
human_agent_type = await HumanAgent.register(  
    runtime,  
    type=human_agent_topic_type,  # Using the topic type as the agent type.  
    factory=lambda: HumanAgent(  
        description="A human agent.",  
        agent_topic_type=human_agent_topic_type,  
        user_topic_type=user_topic_type,  
    ),  
)  
# Add subscriptions for the human agent: it will receive messages published to its own topic only.  
await runtime.add_subscription(TypeSubscription(topic_type=human_agent_topic_type, agent_type=human_agent_type.type))  
  
# Register the user agent.  
user_agent_type = await UserAgent.register(  
    runtime,  
    type=user_topic_type,  
    factory=lambda: UserAgent(  
        description="A user agent.",  
        user_topic_type=user_topic_type,  
        agent_topic_type=triage_agent_topic_type,  # Start with the triage agent.  
    ),  
)  
# Add subscriptions for the user agent: it will receive messages published to its own topic only.  
await runtime.add_subscription(TypeSubscription(topic_type=user_topic_type, agent_type=user_agent_type.type))  
  

    
  • 执行

        
# Start the runtime.  
runtime.start()  
  
# Create a new session for the user.  
session_id = str(uuid.uuid4())  
await runtime.publish_message(UserLogin(), topic_id=TopicId(user_topic_type, source=session_id))  
  
# Run until completion.  
await runtime.stop_when_idle()  
  
# 运行日志:  
--------------------------------------------------------------------------------  
User login, session ID: 7a568cf5-13e7-4e81-8616-8265a01b3f2b.  
--------------------------------------------------------------------------------  
User:  
I want a refund  
--------------------------------------------------------------------------------  
TriageAgent:  
I can help with that! Could I ask what item you're seeking a refund for?  
--------------------------------------------------------------------------------  
User:  
A pair of shoes I bought  
--------------------------------------------------------------------------------  
TriageAgent:  
[FunctionCall(id='call_qPx1DXDL2NLcHs8QNo47egsJ', arguments='{}', name='transfer_to_issues_and_repairs')]  
--------------------------------------------------------------------------------  
TriageAgent:  
Delegating to IssuesAndRepairsAgent  
--------------------------------------------------------------------------------  
IssuesAndRepairsAgent:  
I see you're looking for a refund on a pair of shoes. Can you tell me what the issue is with the shoes?  
--------------------------------------------------------------------------------  
User:  
The shoes are too small  
--------------------------------------------------------------------------------  
IssuesAndRepairsAgent:  
I recommend trying a size up as a fix; would that work for you?  
--------------------------------------------------------------------------------  
User:  
no I want a refund  
--------------------------------------------------------------------------------  
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":"not provided"}', name='execute\_refund')]  
--------------------------------------------------------------------------------  
IssuesAndRepairsAgent:  
[FunctionExecutionResult(content='success', call_id='call\_bPm6EKKBy5GJ65s9OKt9b1uE')]  
--------------------------------------------------------------------------------  
IssuesAndRepairsAgent:  
Your refund has been successfully processed! If you have any other questions, feel free to ask.  
--------------------------------------------------------------------------------  
User:  
I want to talk to your manager  
--------------------------------------------------------------------------------  
IssuesAndRepairsAgent:  
I can help with that, let me transfer you to a supervisor.  
--------------------------------------------------------------------------------  
User:  
Okay  
--------------------------------------------------------------------------------  
IssuesAndRepairsAgent:  
[FunctionCall(id='call\_PpmLZvwNoiDPUH8Tva3eAwHX', arguments='{}', name='transfer\_back\_to\_triage')]  
--------------------------------------------------------------------------------  
IssuesAndRepairsAgent:  
Delegating to TriageAgent  
--------------------------------------------------------------------------------  
TriageAgent:  
[FunctionCall(id='call\_jSL6IBm5537Dr74UbJSxaj6I', arguments='{}', name='escalate\_to\_human')]  
--------------------------------------------------------------------------------  
TriageAgent:  
Delegating to HumanAgent  
--------------------------------------------------------------------------------  
HumanAgent:  
Hello this is manager  
--------------------------------------------------------------------------------  
User:  
Hi! Thanks for your service. I give you a 5 start!  
--------------------------------------------------------------------------------  
HumanAgent:  
Thanks.  
--------------------------------------------------------------------------------  
User:  
exit  
--------------------------------------------------------------------------------  
User session ended, session ID: 7a568cf5-13e7-4e81-8616-8265a01b3f2b.  

    
总结

AutoGen 的 Handoff 实现不仅匹敌 OpenAI 的 Swarm,还在多个方面有所超越。它为开发者提供了一个强大、灵活且可扩展的框架,以构建复杂的多代理 AI 系统。不过,相较于 OpenAI 的 Swarm 实现,AutoGen 明显感觉概念更多,依赖更重,网络上就有人这么评价,“OpenAI 发布了一个示例,大约有 12 行代码,易于阅读,除了 swarm 模块外,没有其他依赖。对于 Autogen,我找不到类似的东西;似乎所有的示例都更复杂。”

这或许也是 AutoGen 之类成熟产品最大软肋吧!

参考资料

[1] 发文: https://microsoft.github.io/autogen/dev/user-guide/core-user-guide/design-patterns/handoffs.html#creating-the-team

[2] OpenAI的客服案例: https://github.com/openai/openai-cookbook/blob/main/examples/Orchestrating\_agents.ipynb

近期原创文章:

后台回复“进群”入群讨论

橱窗有更多精选好书,欢迎光临!

0
0
0
0
关于作者
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论