主题与订阅#
运行时有两种消息传递方式:直接消息传递或广播。直接消息传递是一对一的:发送方必须提供接收方的 agent ID。而广播则是一对多的,发送方无需提供接收方的 agent ID。
许多场景适合使用广播。例如,在事件驱动的工作流中,agents 并不总是知道谁会处理它们的消息,而且工作流可以由相互无依赖的 agents 组成。本节重点介绍广播中的核心概念:主题和订阅。
主题#
主题定义了广播消息的作用范围。本质上,agent运行时通过其广播API实现了一种发布-订阅模型:当发布消息时,必须指定主题。这是对agent ID的一种间接抽象。
主题由两个组成部分构成:主题类型和主题来源。
备注
主题 = (主题类型, 主题来源)
类似于agent ID(同样包含两个组成部分),主题类型通常由应用程序代码定义,用于标记该主题所针对的消息类型。例如,GitHub agent在发布关于新issue的消息时,可能会使用"GitHub_Issues"
作为主题类型。
主题来源是主题在特定主题类型下的唯一标识符。它通常由应用程序数据定义。例如,GitHub agent可能会使用"github.com/{repo_name}/issues/{issue_number}"
作为主题来源,以唯一标识该主题。主题来源允许发布者限制消息范围并创建隔离区。
主题ID可以与字符串相互转换。该字符串的格式为:
备注
主题类型/主题来源
如果类型满足UTF8编码且仅包含字母数字(a-z和0-9)或下划线(_),则被视为有效。有效标识符不能以数字开头,也不能包含任何空格。如果来源满足UTF8编码且仅包含ASCII码32(空格)至126(~)之间的字符(含),则被视为有效。
订阅机制#
订阅机制实现了主题与agent ID之间的映射关系。
上图展示了主题与订阅之间的关系。agent运行时会维护订阅信息,并据此将消息分发给对应的agents。
若某主题未被订阅,发布到该主题的消息将不会被递送给任何agent。若某主题存在多个订阅,消息将遵循所有订阅规则仅向每个接收agent投递一次。应用程序可通过agent运行时的API动态添加或移除订阅。
基于类型的订阅#
基于类型的订阅实现了主题类型与agent类型之间的映射(参见agent标识)。这种机制声明了从主题到agent ID的无限映射关系,无需预先知晓具体的主题来源和agent密钥。其原理简明:任何匹配订阅规则中主题类型的主题,都会被映射为具有对应agent类型的agent ID,且agent密钥会被赋值为主题来源的值。Python API中请使用TypeSubscription
。
备注
基于类型的订阅 = 主题类型 --> Agent类型
通常而言,基于类型的订阅是声明订阅关系的首选方式。它具有可移植性和数据独立性:开发者无需编写依赖特定agent ID的应用程序代码。
适用场景#
当具体主题或agent ID与数据相关时,基于类型的订阅可应用于多种场景。这些场景可通过两个维度划分:(1) 单租户或多租户架构;(2) 每个租户对应单个主题或多个主题。此处租户通常指代处理特定用户会话或特定请求的一组agents。
单租户单主题场景#
在此场景中,整个应用只有一个租户和一个主题。这是最简单的场景,适用于许多用例,例如命令行工具或单用户应用程序。
要为这种场景实现基于类型的订阅,需要为每种agent类型创建一个基于类型的订阅,并为所有订阅使用相同的主题类型。发布消息时,始终使用相同的主题(即相同的主题类型和主题来源)。
例如,假设有三种agent类型:"triage_agent"
、"coder_agent"
和"reviewer_agent"
,主题类型为"default"
,则创建以下基于类型的订阅:
# 单租户单主题场景下的基于类型订阅
TypeSubscription(topic_type="default", agent_type="triage_agent")
TypeSubscription(topic_type="default", agent_type="coder_agent")
TypeSubscription(topic_type="default", agent_type="reviewer_agent")
使用上述基于类型的订阅时,所有消息都采用相同的主题来源"default"
。因此主题始终是("default", "default")
。发布到此主题的消息将传递给所有上述类型的agents。具体来说,消息将发送到以下agent ID:
# 基于主题来源生成的agent ID
AgentID("triage_agent", "default")
AgentID("coder_agent", "default")
AgentID("reviewer_agent", "default")
下图展示了此示例中基于类型订阅的工作机制。
如果对应ID的agent不存在,运行时将自动创建它。
单租户多主题场景#
在此场景中,只有一个租户,但您需要控制不同agent处理不同主题。当您希望创建信息隔离区,并让不同agent专门处理不同主题时,这种配置非常有用。
要实现基于类型的订阅,请为每种agent类型创建不同的订阅配置,但使用不同的主题类型。如果希望多个agent类型共享同一主题,可以将相同主题类型映射到多个agent类型。发布消息时,所有消息仍使用相同的主题源值。
沿用前文示例中的agent类型,创建以下基于类型的订阅配置:
# 单租户多主题场景的基于类型订阅配置
TypeSubscription(topic_type="triage", agent_type="triage_agent")
TypeSubscription(topic_type="coding", agent_type="coder_agent")
TypeSubscription(topic_type="coding", agent_type="reviewer_agent")
通过上述订阅配置,发布到主题("triage", "default")
的所有消息将被递送给类型为"triage_agent"
的agent,而发布到主题("coding", "default")
的消息将同时递送给类型为"coder_agent"
和"reviewer_agent"
的agents。
下图展示了此示例中基于类型订阅的工作机制:
多租户场景#
在单租户场景中,主题来源始终相同(例如 "default"
),它被硬编码在应用程序代码中。而在多租户场景中,主题来源则变为数据依赖型。
备注
判断是否处于多租户场景的一个明显标志是:你需要创建同一agent类型的多个实例。例如,你可能需要不同的agent实例来处理不同用户会话以保持数据隔离,或者你可能希望将繁重的工作负载分配给同一agent类型的多个实例并行处理。
延续上述示例,如果你希望使用专用agent实例来处理特定的GitHub问题,就需要将主题来源设置为该问题的唯一标识符。
例如,假设为agent类型 "triage_agent"
设置了以下基于类型的订阅:
TypeSubscription(topic_type="github_issues", agent_type="triage_agent")
当消息发布到主题 ("github_issues", "github.com/microsoft/autogen/issues/1")
时,运行时会将消息传递给ID为 ("triage_agent", "github.com/microsoft/autogen/issues/1")
的agent。同理,发布到主题 ("github_issues", "github.com/microsoft/autogen/issues/9")
的消息会被传递给ID为 ("triage_agent", "github.com/microsoft/autogen/issues/9")
的agent。
下图展示了此示例中基于类型订阅的工作原理:
请注意agent ID是数据依赖型的,如果对应实例不存在,运行时将会创建新的agent实例。
要支持每个租户的多个主题,可以像单租户多主题场景那样使用不同的主题类型。