mcpField
A
ag2-network-quickstart

ag2-network-quickstart

github.com/ag2aiAgent 工作流1261 次安装13 周前更新
代码仓库

关于 ag2-network-quickstart

介绍如何通过中心 Hub 使用 AG2 Network 协调已注册的不同 Agent。内容涵盖双人咨询和自由对话频道、人工参与者,以及由 Hub 管理的身份和交互记录。

主要功能

  1. 01通过 Hub 协调已注册的 Agent
  2. 02支持咨询与对话频道
  3. 03提供 Agent 注册与身份管理
  4. 04支持人工网络参与者
  5. 05将消息记录到预写日志

适用场景

  1. 01设置双 Agent 咨询
  2. 02构建 Agent 间自由交流
  3. 03让人工参与 Agent 对话
  4. 04通过共享网络路由消息

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ag2ai/ag2-skills --skill ag2-network-quickstart

安装后在 Claude Code 中输入/ag2-network-quickstart确认已加载。

详细介绍

AG2 Network — 快速入门

该网络可将一组 Agent 实例组成一个协调的多 Agent 系统。中央 Hub 保存权威状态(注册表、审计日志、每个通道的预写日志);每个 Agent 都运行在精简的 AgentClient 后面,并通过 HubClient 连接。每条消息都会经过 Hub,因此每次交互都可重放且可观察。

该网络为可选启用。裸 Agent 仍可独立运行——只有从 ag2.network 导入时,网络才会启用。

适用场景

当用户希望两个或更多 Agent 进行交互时,加载此技能。明确的触发语句包括:

  • “让两个 Agent 互相交谈”
  • “设置多 Agent 系统/多 Agent 聊天/Agent 网络”
  • “让 Agent 能够互相调用”
  • “替换经典的 GroupChat/ConversableAgent.handoffs”
  • “为我的 Agent 添加注册表/审计跟踪/共享收件箱”

**非网络任务:**如果用户要求一个 Agent生成自己的子任务(递归任务分发、并行执行子任务),请改用 ag2-subagent-delegation。网络适用于彼此独立且已注册的 Agent 协作。

概念模型

                        ┌────────────────┐
                        │      Hub       │  ←── audit log, registry, channels,
                        │ ── adapters ── │       WAL, sweepers, expectation
                        │ ── channels ── │       evaluators
                        │ ── audit log ──│
                        └────────┬───────┘
                                 │  in-process duplex (LocalLink)
              ┌──────────────────┼──────────────────┐
              ▼                  ▼                  ▼
        ┌──────────┐       ┌──────────┐       ┌──────────┐
        │AgentClient│      │AgentClient│      │AgentClient│
        │  alice    │      │   bob     │      │   carol   │
        │  Agent    │      │  Agent    │      │  Agent    │
        └──────────┘       └──────────┘       └──────────┘
概念所在位置用途
Hub每个网络一个权威状态——注册表、审计日志、通道表、WAL、清理器
PassportHub 注册表稳定身份(name、由 Hub 分配的 agent_id、可选的 owner、model)
ResumeHub 注册表能力声明,以及由 Hub 更新的 observed 记录
HubClient每个进程一个每个进程的代理;管理注册
AgentClient每个已注册 Agent 一个包装 Agent;发送信封并运行通知处理程序
Envelope线上格式Hub 标记的单个通道中单个事件的记录
Channel由 agent_client.open(...) 创建由适配器管理的有界多方交互

Hub 在注册时分配 agent_id。路由时请使用该 ID(alice.agent_id),而非易读的名称。

最小网络示例

单进程 Hub、两个 Agent、一个 consulting 通道(严格 1Q1R,回复后自动关闭):

import asyncio

from ag2 import Agent
from ag2.config import AnthropicConfig
from ag2.knowledge import MemoryKnowledgeStore
from ag2.network import (
    EV_CHANNEL_CLOSED,
    EV_TEXT,
    Hub,
    HubClient,
    LocalLink,
    Passport,
    Resume,
)


async def main() -> None:
    config = AnthropicConfig(model="claude-sonnet-4-6")

    # 1. Boot the hub. MemoryKnowledgeStore for in-process; DiskKnowledgeStore(path)
    #    for durability across restarts.
    hub = await Hub.open(MemoryKnowledgeStore(), ttl_sweep_interval=0)
    link = LocalLink(hub)  # in-process duplex transport

    # 2. One HubClient per process boundary; here we use two for clarity.
    alice_hc = HubClient(link, hub=hub)
    bob_hc = HubClient(link, hub=hub)

    # 3. Register each Agent. The hub stamps the agent_id and returns an AgentClient.
    #    attach_plugin=False gives a bare agent (no peers/channels/tasks/context/
    #    delegate tools) — fine here since alice & bob just send/reply. The `say`
    #    tool is offered per-turn by the adapter, not the plugin (see below).
    alice = await alice_hc.register(
        Agent("alice", prompt="Ask one focused question and stop.", config=config),
        Passport(name="alice"),
        Resume(),
        attach_plugin=False,
    )
    bob = await bob_hc.register(
        Agent("bob", prompt="Answer in one short sentence.", config=config),
        Passport(name="bob"),
        Resume(),
        attach_plugin=False,
    )

    # 4. Open a consulting channel. The adapter posts EV_CHANNEL_INVITE to bob,
    #    bob's default handler auto-acks, channel goes ACTIVE.
    channel = await alice.open(type="consulting", target="bob")
    await channel.send(
        "What's the single most important property of a distributed system?",
        audience=[bob.agent_id],
    )

    # 5. Bob's default handler probes can_send, runs Agent.ask on the inbound
    #    text, sends the reply. ConsultingAdapter sees both flags set and
    #    auto-closes with reason "consulting_complete".
    close_env = await alice.wait_for_channel_event(
        channel_id=channel.channel_id,
        predicate=lambda e: e.event_type == EV_CHANNEL_CLOSED,
        timeout=60.0,
    )
    print(f"closed: {close_env.event_data.get('reason')!r}")

    # 6. Replay the conversation from the hub's WAL.
    wal = await hub.read_wal(channel.channel_id)
    for env in wal:
        if env.event_type == EV_TEXT:
            speaker = "alice" if env.sender_id == alice.agent_id else "bob"
            print(f"{speaker}: {env.event_data['text']}")

    await alice_hc.close()
    await bob_hc.close()
    await hub.close()


asyncio.run(main())

必需内容就这么多。以下内容都是变体。

选择通道适配器

每个通道都由一个适配器管理,用于定义参与者、轮次顺序和终止条件。系统提供四种适配器;调用 agent_client.open(type=..., target=...) 时选择一种。

适配器参与者轮次顺序终止条件默认视图
consulting恰好 2 个严格 1Q1R(发起方 → 响应方)响应方回复后自动关闭FullTranscript()
conversation恰好 2 个自由形式(任一方均可随时发言)显式调用 channel.close() 或 TTL 到期WindowedSummary(recent_n=10)
discussion2 个或更多通过 ordering="round_robin" 进行轮询显式关闭或 TTL 到期WindowedSummary(recent_n=N*2)
workflow2 个或更多声明式 TransitionGraph图终止(TerminateTarget/max_turns)WindowedSummary(recent_n=N*2)

**此技能涵盖 consulting 和 conversation(两方适配器)。**其他适配器请参阅:

  • N 方轮询 → 加载 ag2-network-discussion。
  • 使用 TransitionGraph 进行声明式编排、条件移交,或从经典 GroupChat 迁移 → 加载 ag2-network-workflow。
插件工具与适配器工具 — attach_plugin 和 say

HubClient.register(...) 默认会附加 NetworkPlugin。该插件提供身份级别的横切工具 — peers / channels / tasks / context / delegate — 不包含任何特定于频道的工具。特定于频道的工具(尤其是 say,用于向频道发布文本信封)由频道适配器通过 adapter.tools_for(...) 在每轮中提供,与 attach_plugin 无关:

适配器是否提供 say?
consulting仅提供给在 1Q1R 中轮到发言的参与者
conversation始终提供(无轮次顺序)
discussion仅提供给 expected_next_speaker
workflow从不提供 — 路由由你的 @tool 交接函数完成

因此,attach_plugin=False 不再意味着“没有 say” — 而是意味着“没有 delegate / peers / channels / tasks / context”。对于纯 Agent(测试、纯流水线工作进程),请传入此参数;如果 Agent 需要这些横切动词,则保留默认值。

通常完全不需要考虑 say:默认处理程序总是会根据 Agent 的普通回复发布轮次结束信封,因此只需回答即可。say 用于少数情况,例如在一轮中发布额外消息,或发布到 Agent 也参与的其他频道。(需要避免的边缘情况:在 consulting 频道上的 Agent 调用 say(...) 并且返回非空回复,会发送两次 — 第二个信封会在严格的 1Q1R 适配器上触发 channel is closed。如果不希望 Agent 调用 say,只需不要在提示词中要求它这样做。)完整详情:ag2-network-tools-and-views →“适配器拥有的工具(tools_for)”。

consulting — 严格的 1Q1R

即上面的示例。发起方恰好发送一个实质性信封;响应方恰好发送一条回复;适配器会自动关闭,并将 event_data["reason"] 设为 "consulting_complete"。

Hub 端的状态:

@dataclass(slots=True)
class ConsultingState:
    initiator_sent: bool = False
    respondent_replied: bool = False

ConsultingAdapter.validate_send 会拒绝:

  • 顺序错误的发送(响应方在发起方发送第一个信封前发言)。
  • 两个标志均已设置后发送的任何内容 — 会引发 ProtocolError,并传播回调用方的 channel.send(...)。

默认预期严格:acks_within(30s, auto_close) 和 reply_within(600s, auto_close)。如果响应方未在 30s 内确认邀请,或未在 10 分钟内回复,Hub 会自动关闭,并使用 "expectation_violated:acks_within" 或 "expectation_violated:reply_within"。可通过 ag2-network-governance 调整这些设置。

conversation — 自由形式的双方对话

任何一方都可以随时以任意顺序发送消息。适配器绝不会自动关闭;你可以通过 channel.close() 停止,也可以依赖 TTL。

channel = await alice.open(type="conversation", target="bob")
await channel.send("Hi bob, what's a good first ML concept to learn?")

两个默认处理程序都会对每个入站 EV_TEXT 运行 Agent.ask,因此对话启动后会自动持续进行。两种停止模式:

  1. 应用端限制 — 轮询 WAL,直到看到 N 个文本信封,然后执行 await channel.close()。
  2. 空回复作为停止信号 — 默认处理程序会将空正文视为“不发送”,因此回复 "" 的 LLM 会结束链条。可搭配类似 "reply with empty string when you have nothing useful to add" 的提示词。

ConversationAdapter.validate_send 只会检查“发送方是否为参与者?” — 允许同一方连续发送,因为适配器不会建模轮次顺序。

默认预期较宽松:max_silence(3600s, audit)(会将日志写入审计类型 AUDIT_KIND_EXPECTATION_VIOLATED,但不会关闭)。

适用场景: 两个专业 Agent 在没有固定顺序的情况下进行实际对话(分析师 ↔ 评论者);由应用控制停止信号的聊天 UI。

不适用场景: 严格的 1Q1R(使用 consulting);多参与者聊天(使用 discussion 或 workflow)。

非大模型参与者 — HumanClient

并非所有参与者都是 Agent。HumanClient 是网络成员,不使用大模型、没有 NetworkPlugin,也没有组装策略——它可以是 UI 上的用户、连接到其他系统的桥梁,或用于向频道填入初始内容的脚本化“用户”。使用 register_human 注册它(而不是 register——现在这条路径会拒绝 kind="human" 并引导你使用此方法):

from ag2.network import HumanClient, Passport

user_hc = HubClient(link, hub=hub)
user = await user_hc.register_human(Passport(name="user", kind="human"))   # resume=, rule=, auto_ack_invites= optional

它在出站方面实现了与 AgentClient 相同的 NetworkClient 接口——user.open(type=..., target=...)、user.send(channel_id, text, audience=...)、user.post_envelope(env)(用于发送类似工作流 EV_PACKET 这类适配器格式信封的备用方法)——并提供两种方式来使用入站信封:

  • 推送 — user.on_envelope(callback);每收到一个入站信封,协程就会触发一次。多个回调可以组合;若回调抛出异常,异常会被记录,但不会传播。
  • 拉取 — await user.next_envelope(predicate=..., timeout=...) 会等待下一个匹配项;async for env in user.envelopes(): ... 会持续传输所有信封,直到调用 user.disconnect()。

它会自动确认频道邀请(默认 auto_ack_invites=True),使 hub 的加入握手无需 UI 往返即可完成;传入 auto_ack_invites=False,即可自行控制加入流程。使用 hub.list_agents(kind="human") 查找人类参与者。

常见用途:为 workflow 频道填入初始内容的启动者(FromSpeaker(user) → AgentTarget(first_agent)——参见 ag2-network-workflow)、consulting 问答中的人类参与者,或 discussion 轮流发言中的参与者。Agent 端的接口(自定义处理器、无头工作进程、网关)见 ag2-network-tools-and-views。

身份 — Passport 和 Resume

三个数据类用于描述网络中的 Agent。租户提供大多数字段;其余字段由 hub 填入。

from ag2.network import Passport, Resume, ResumeExample

passport = Passport(
    name="alice",          # required, unique within the hub
    owner="acme",          # optional, tenant id for multi-tenant deployments
    model="claude-sonnet-4-6",  # optional, surfaces on peer-lookup results
    kind="agent",          # optional: "agent" (default / None) | "human" | "remote_agent"
)

resume = Resume(
    claimed_capabilities=["analysis", "policy"],
    domains=["finance"],
    summary="Senior policy analyst — scenario synthesis and rebuttal review.",
    examples=[ResumeExample(title="Q3 risk brief", note="…")],
)

hub 会在注册时填入 Passport.agent_id 和 Passport.created_at。Passport.kind(类型别名 PassportKind)用于区分参与者类型——常规的、由大模型驱动的 AgentClient 使用 None/"agent",HumanClient 使用 "human"(请使用 register_human,而不是 register),"remote_agent" 保留给 A2A/联邦场景。hub.list_agents(kind=...) 会按此字段筛选。Agent 执行带有能力标签的任务时,hub 会更新 Resume.observed 字段(按能力统计的 ObservedStat 计数)——如何进行配置,请参见 ag2-network-governance。

最简单的情况下,你可以传入 Passport(name="alice") 和 Resume(),即可完成设置。

频道生命周期

agent_client.open(type=..., target=...)
    │
    ▼
PENDING ──┬─ all targets ack ──→ ACTIVE ──┬─ adapter terminates ──→ CLOSED
          │                                │
          └─ ack timeout ──→ CLOSED       └─ explicit channel.close() ──→ CLOSING ──→ CLOSED
                  (invite_timeout)               or TTL expired

Hub.open(...) 上 invite_ack_timeout 的默认值为 30s;如果受邀目标中有任何一个未在此时间窗口内确认,create_channel 就会引发 ProtocolError,并将频道直接关闭,状态变为 CLOSED,原因是 "invite_timeout"。(另一条独立的期望检查器路径——acks_within 期望——会改为自动关闭频道,原因是 "expectation_violated:acks_within";参见下文的 consulting 部分。)

发送信封

await channel.send(text, audience=[bob.agent_id])

audience 控制哪些人可以看到该信封(默认:所有参与者)。hub 会填入 Envelope.envelope_id、sender_id 和 created_at,并将信封写入 WAL。

对于自定义事件类型,请通过 agent_client.send_envelope(envelope) 发送原始信封。Envelope 的完整结构和 EV_* 事件常量见 ag2-network-tools-and-views。

五种通道关闭路径

每个通道都会以 EV_CHANNEL_CLOSED 信封终止。有五种路径可以到达该状态;根据由谁决定来选择:

模式决定者最适合
channel.close(reason=...)你的编排代码自定义上限(轮数、时间、谓词)
Agent 侧工具(ChannelInject)大模型“由 Agent 决定何时结束”
适配器哨兵(子类)框架基于内容的停止(“TERMINATE”关键字)
工作流 TerminateTarget声明式图多步骤编排
TTL / 预期Hub 的扫描器基于时间或预期的安全网

适配器兼容性:

自动关闭应用关闭Agent 工具哨兵工作流图
consulting是(回复后)是(提前退出)是子类不适用
conversation从不是(典型用法)是规范实现不适用
discussion从不是(典型用法)是子类不适用
workflow是(图)是(覆盖)是(通过 ToolCalled)不适用规范实现
模式:Agent 侧关闭工具

由大模型决定何时停止。将活动的 Channel 注入工具:

from ag2.network.client.inject import ChannelInject


async def end_conversation(reason: str, channel: ChannelInject) -> str:
    """Close the active channel. The reason flows on EV_CHANNEL_CLOSED."""
    if channel is None:
        return "no active channel"
    await channel.close(reason=f"agent_close:{reason}")
    return f"closed: {reason}"


alice_agent.tool(end_conversation)
bob_agent.tool(end_conversation)

默认处理程序会在每轮大模型调用前将活动的 Channel 写入 context.dependencies,因此 ChannelInject 会自动解析。在网络轮次之外,它会解析为 None —— 上述保护逻辑可确保该工具在非网络上下文中安全运行。

优先使用工具调用模式,而非适配器哨兵(“TERMINATE”关键字)——工具调用有类型、可在 WAL 中追踪、支持多语言,且能抵御提示词注入。

监听关闭

这五种路径都会生成相同的 EV_CHANNEL_CLOSED 信封,因此观察者只需一个谓词:

close_env = await alice.wait_for_channel_event(
    channel_id=channel.channel_id,
    predicate=lambda e: e.event_type == EV_CHANNEL_CLOSED,
    timeout=180.0,
)
print(f"reason: {close_env.event_data.get('reason')!r}")

ChannelMetadata.close_reason 也会存储在通道记录中——await hub.get_channel(channel_id) 无需重新读取 WAL 即可返回原因。

重放与检查

Hub 的 WAL 是记录“此通道中发生了什么”的唯一真实来源:

wal = await hub.read_wal(channel.channel_id)
for env in wal:
    print(env.created_at, env.event_type, env.sender_id, env.event_data)

每个信封都会由 Hub 写入戳记(envelope_id、created_at、sender_id、audience、event_type、event_data)。WAL 以通道 ID 为键;对于此进程能够访问的任何通道,都可以读取其 WAL。

如需查看审计日志(Hub 级事件:Agent 已注册、通道已创建/关闭、预期未满足),请参阅 ag2-network-governance。

关闭

await alice_hc.close()
await bob_hc.close()
await hub.close()

始终将 Hub.open(...) 与 hub.close() 配对使用(通常放在 try/finally 中)。hub.close() 会取消扫描器任务、关闭底层存储并清空待处理的 I/O。HubClient.close() 会取消链接的监听任务,并取消订阅客户端。

接下来加载什么

用户目标技能
N 方轮询 / 固定轮次顺序ag2-network-discussion
声明式编排 / TransitionGraph / GroupChat 迁移ag2-network-workflow
速率限制、访问策略、预期、审计、能力追踪、可替换仲裁器 / Hub 监听器ag2-network-governance
适配器拥有的工具(say / tools_for)、插件工具(delegate / peers / …)、自定义处理程序、HumanClient 内部实现、视图、对等方发现ag2-network-tools-and-views

快速参考 — 导入

from ag2.network import (
    # Hub + transport
    Hub,
    HubClient,
    LocalLink,
    # Participants
    HumanClient,           # register via HubClient.register_human(...)
    # Identity
    Passport,
    PassportKind,          # Literal["agent", "human", "remote_agent"] | None
    Resume,
    ResumeExample,
    # Envelopes + events
    Envelope,
    EV_TEXT,
    EV_CHANNEL_INVITE,
    EV_CHANNEL_INVITE_ACK,
    EV_CHANNEL_OPENED,
    EV_CHANNEL_CLOSED,
    EV_CHANNEL_EXPIRED,
    Priority,
    # Errors
    AccessDeniedError,
    InboxFull,
    ProtocolError,
)
from ag2.knowledge import MemoryKnowledgeStore  # or DiskKnowledgeStore

评论

支持 Markdown