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

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

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

什么是 Handoff 模式?

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

AutoGen 的回应

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

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

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

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

  • 客户 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 之类成熟产品最大软肋吧!

前沿技术新闻资讯

惊艳!Phi-4 14B如何击败GPT-4o与o1,实现数学推理新突破?

2025-2-11 0:38:31

前沿技术新闻资讯

一文彻底搞懂Transformer - 注意力机制

2025-2-11 0:53:20

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
购物车
优惠劵
搜索