首页
/ AutoGen 消息路由设计解析:TopicId、订阅模型与 Well-Known Topic 类型

AutoGen 消息路由设计解析:TopicId、订阅模型与 Well-Known Topic 类型

2026-09-05 18:42:47作者:董灵辛Dennis

本文基于 AutoGen 仓库的设计文档 [02 - Topics](https://gitcode.com/GitHub_Trending/au/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/docs/design/02 - Topics.md?utm_source=gitcode_repo_files),系统讲解其发布/订阅消息模型的核心抽象:Topic 作为消息路由原语的定位、TopicId 与 AgentId 双标识符的命名规范、订阅(Subscription)的 matcher/mapper 双函数设计、按需实例化 Agent 的运行时行为,以及用于实现点对点消息与 RPC 的 Well-Known Topic 类型。读完本文,你将能够理解 AutoGen 分布式运行时中“一条广播消息如何被投递给正确的 Agent 实例”的完整机制,并能对照 Python 与 .NET 两侧的源码实现加以印证。

Topic 的定位:管理“谁收到这条消息”的原语

AutoGen 运行时采用发布/订阅(publish-subscribe)模型来传递消息。设计文档明确指出:

  • Topic 是用于管理哪些 Agent 会收到某条已发布消息的原语(primitive);
  • Agent 订阅 Topic,Topic 到 Agent 实例的映射关系由应用代码定义(application defined mapping from topic to agent instance);
  • 这些概念刻意映射到 CloudEvents 规范,以便与现有系统和工具无缝集成。

仓库中确实保留了 CloudEvents 的 Protobuf 定义:cloudevent.proto 定义了 CloudEvent 消息体,包含必需的上下文字段 idsourcespec_versiontype,以及 attributes 扩展属性和 binary_data/text_data/proto_data 三选一的数据负载,并声明 csharp_namespace = "Microsoft.AutoGen.Contracts",说明 .NET 侧的契约类型直接生成自该规范文件。这与文档中“intentionally map to the CloudEvents specification”的表述相互印证。

文档同时声明了一个明确的非目标(Non-goals):该文档本身不规定 RPC/直接消息(direct messaging)的具体协议。值得注意的是,文档最后一节的 Well-Known Topic 类型实际上给出了一组用于在广播语义上“搭出”RPC 通道的约定(下文详述),属于约定层面的补充而非完整 RPC 规范。

标识符:TopicId 与 AgentId

TopicId:type + source

一个 Topic 由两个组件唯一标识,合称 TopicId

组件 语义 约束
type 事件类型,静态,在代码中定义 SHOULD 使用反向域名记法(reverse domain name notation)避免命名冲突,例如 com.example.my-topic;取值 MUST 匹配正则 ^[\w\-\.\:\=]+\Z;与 Agent type 相比额外允许 =: 两个字符
source 事件来源,动态,由消息本身决定 SHOULD 是一个 URI

Python 侧的实现与文档约束完全一致。TopicId 定义 中:

  • is_valid_topic_type 使用正则 ^[\w\-\.\:\=]+\Z 校验 type(见 校验函数);
  • TopicId.__post_init__ 在构造时即抛出 ValueError 拒绝非法 type(见 构造校验);
  • TopicIdtype/source 字符串互转,from_str 按第一个 / 切分解析(见 字符串解析)。

type 之所以比 Agent type 多出 =:,正是为了支撑 Well-Known Topic 中 {AgentType}:rpc_request={RequesterAgentType} 这类带参数的 topic type 写法。

AgentId:type + key

Agent 实例由两个组件唯一标识,合称 AgentId

  • type — 表示 Agent 类型,静态、在代码中定义,取值 MUST 匹配正则 ^[\w\-\.]+\Z
  • key — 表示该类型下的具体实例,SHOULD 是一个 URI;
  • 文档给出的示例:GraphicDesigner:1234

AgentId 实现 中,is_valid_agent_type 使用正则 ^[\w\-\.]+\Z 校验 type(见 校验函数),类 docstring 说明它是分布式运行时中 Agent 实例的“地址”。字符串形式同为 type/key,可通过 AgentId.from_str 解析。

关于 type 的进一步语义,设计文档 [04 - Agent and Topic ID Specs](https://gitcode.com/GitHub_Trending/au/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/docs/design/04 - Agent and Topic ID Specs.md?utm_source=gitcode_repo_files) 给出了更严格的约束说明:agent type 不是 Agent 类本身,而是关联 Agent 与其工厂函数——不同的工厂函数可以用不同构造参数产生同一 Agent 类但不同 type 的实例;type 仅允许字母、数字与下划线,不能以数字开头、不能含空格;key 与 topic source 则允许 ASCII 32(空格)到 126(~)之间的可见字符。

在 .NET 侧,AgentId 同样是一等公民:AgentIdSurrogate.cs 中定义了 AgentIdSurrogate(含 TypeKey 两个字段)及对应的 Orleans 序列化转换器 AgentIdSurrogateConverter。从源码结构看,AgentId 需要在 gRPC/Orleans 分布式网关层被序列化和反序列化,说明双标识符体系贯穿了整个跨语言运行时,而非仅存在于 Python 端。

订阅(Subscription):matcher 与 mapper 两个函数

订阅决定了发布到某个 Topic 上的消息会投递给哪些 Agent。文档要点:

  • 订阅是动态的,可以在任何时候添加或移除;
  • 每个订阅定义两个函数:
    • Matcher 函数,签名 TopicId -> bool,回答“该订阅是否匹配这个 topic”;
    • Mapper 函数,签名 TopicId -> AgentId,回答“该订阅匹配此 topic 时,应映射到哪个 Agent”。

文档对这两个函数提出了一个关键工程约束:它们 MUST 是无副作用(free of side effects)的,从而使得匹配求值结果可以被缓存。

Python 运行时把这个契约固化成了一个协议。Subscription 协议定义 是一个 runtime_checkable 的 Protocol,要求实现者提供:

  • id 属性——订阅的唯一 ID(文档注释建议通常使用 UUID,见 id 属性);
  • is_match(topic_id: TopicId) -> bool——即文档中的 matcher 函数(见 is_match);
  • map_to_agent(topic_id: TopicId) -> AgentId——即文档中的 mapper 函数,且明确“只在 is_match 返回 True 时才可调用”(见 map_to_agent)。

文件末尾还定义了 UnboundSubscription = Callable[[], list[Subscription] | Awaitable[list[Subscription]](见 行 65),说明订阅支持在 Agent 注册时以“工厂”方式惰性提供,天然契合“订阅可动态增删”的设计。

内置订阅实现:TypePrefixSubscription

仓库提供了文档所述“prefix subscription”思想的直接实现:TypePrefixSubscription。其类文档说明行为如下:

from autogen_core import TypePrefixSubscription

subscription = TypePrefixSubscription(topic_type_prefix="t1", agent_type="a1")
  • topic type 为 t1、source 为 s1 的 TopicId 将由 type 为 a1、key 为 s1 的 Agent 处理;
  • source 为 s2 时则由 key 为 s2a1 Agent 处理;
  • 即使 topic type 带后缀(如 t1SUFFIX)也能前缀匹配成功。

也就是说,每个 source 会拥有自己独立的 Agent 实例。这一实现精确对应了文档中“对于 {AgentType}: 这个前缀订阅,source 应直接映射为 agent key”的规则。此外,_default_topic.py_type_subscription.py 等模块提供了默认 Topic 与按 type 精确匹配的订阅变体,与文档中“type 为静态约定、source 为动态实例区分”的语义一致。

按需实例化:消息先到、Agent 后建

文档的 “Agent instance creation” 一节规定:

如果一条消息到达某个 topic,而该 topic 映射到的 Agent 尚不存在,运行时(runtime)会实例化一个 Agent 来履行(fullfil)该请求。

这为分布式部署带来了重要的运维语义:Agent 实例是**懒创建(lazy instantiation)**的,无需预先拉起所有 Agent 进程,只要订阅关系声明了“这个 topic 应交给什么 type 的 Agent 处理”,运行时就能在第一条消息到达时自动完成实例化。结合上一节 UnboundSubscription 的工厂式定义方式,可以推断订阅与实例化是同一套生命周期机制的两面:订阅告诉运行时“去哪找/怎么建 Agent”,而运行时负责按 topic 命中时机触发创建。

消息类型与广播语义:所有 Agent 都收到,各自过滤

文档 “Message types” 一节描述了当前的投递语义:

  • Agent 能够处理某些特定类型的消息,这是 Agent 实现的内部细节
  • 通道(channel)内所有 Agent 都会收到所有消息,但会忽略自己无法处理的消息

文档还附有一条设计备注(原文以 NOTE 形式标注):这一“全量广播 + 接收端过滤”的机制可能基于扩展性与性能的考虑而被重新审视。也就是说,当前实现优先保证简单性与正确性,过滤式投递是否演进出更精细的按类型路由,文档保留了开放空间。

Well-Known Topic 类型:在广播语义上约定出 RPC 通道

这是文档最具实操价值的一节。约定如下:

Agent 应通过前缀订阅订阅 {AgentType}: 这个 topic,将其作为该 Agent 类型的直接消息(direct message)通道。对于该订阅,source 应直接映射为 agent key。

据此,该前缀订阅将收到以下四个 well-known topic 上的所有事件:

Well-Known Topic 用途 路由要求
{AgentType}: 通用直接消息 应路由到对应的消息处理器(message handler)
{AgentType}:rpc_request={RequesterAgentType} RPC 请求消息 应路由到对应的 RPC 处理器;使用 RequesterAgentType 来发布响应
{AgentType}:rpc_response={RequestId} RPC 响应消息 应路由回调用方的响应 future
{AgentType}:error={RequestId} 对应指定请求的错误消息 与请求 ID 关联的错误投递

这组约定巧妙地利用了 TopicId type 字段允许 := 的规则:把“请求方是谁”“关联哪个请求 ID”编码进 topic type 本身,从而让 matcher/mapper 这些无副作用函数仅凭 TopicId 就能完成路由决策——这正是前文“函数必须无副作用、可缓存”约束的落地场景。例如请求方 WebSurferCodeReviewer 发起 RPC,就是向 type 为 CodeReviewer:rpc_request=WebSurfer 的 topic 发布消息;响应则发布到 WebSurfer:rpc_response={RequestId}

从源码结构看,这条约定在 .NET 运行时中已有对应支撑:Core.Grpc 的 Constants.cs 中包含 rpc_request / rpc_response 相关常量,且 gRPC 网关测试(如 GrpcGatewayServiceTests.cs)覆盖了对应的消息分发场景。跨语言场景下,同一套 topic/agent 标识约定通过 agent_worker.proto 等协议文件在 Python 与 .NET 运行时之间传递,使“Python 端发布、.NET 端接收”成为可能。

小结与延伸阅读

回顾整个设计,AutoGen 的 Topic 模型可以概括为三句话:

  1. 路由靠 TopicId(type + source)与订阅(matcher + mapper)的纯函数组合,无副作用约束保证求值可缓存;
  2. 实例生命周期交给运行时:消息到达而 Agent 不存在时自动实例化,配合前缀订阅实现“每个 source 一个实例”;
  3. 点对点与 RPC 不依赖新的传输机制,而是通过 {AgentType}: 前缀家族的四类 well-known topic 约定在广播语义上构建出来,并与 CloudEvents 规范对齐以打通外部生态。

若要进一步深入,可按以下路径在当前仓库中继续探索:

  • [03 - Agent Worker Protocol](https://gitcode.com/GitHub_Trending/au/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/docs/design/03 - Agent Worker Protocol.md?utm_source=gitcode_repo_files):描述 Agent 与运行时网关之间的通信协议,与本文的 topic 路由约定互补;
  • [01 - Programming Model](https://gitcode.com/GitHub_Trending/au/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/docs/design/01 - Programming Model.md?utm_source=gitcode_repo_files) 与 [05 - Services](https://gitcode.com/GitHub_Trending/au/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/docs/design/05 - Services.md?utm_source=gitcode_repo_files):理解 Topic 机制所在的更大编程模型;
  • Python 核心实现:_topic.py_agent_id.py_subscription.py
  • 用户指南中的专题文档:topic_and_subscription 相关章节 对 Topic 与订阅的 API 用法有更细粒度的示例;
  • .NET 侧:Microsoft.AutoGen 下的 CoreCore.GrpcRuntimeGateway.Grpc 项目,覆盖标识符序列化、gRPC 常量与网关服务实现。

适用前提说明:本文基于当前仓库快照中的设计文档与源码,其中 Message types 一节的广播式投递语义被文档明确标注“可能基于扩展性与性能考虑而重新审视”,阅读时请注意该机制在未来版本中可能演进。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384