深度解析:Buzz 多 Agent 协作中的会话边界、共享状态与线程作用域)
buzz-acp 会话模型Session Model深度解析Buzz 多 Agent 协作中的会话边界、共享状态与线程作用域【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzz导读本文以crates/buzz-acp的会话模型文档为核心系统讲解 Buzz 平台中 AI Agent通过 ACP 协议接入的 goose、Codex、Claude Code 等在多渠道并行场景下的会话隔离机制同一个 Agent 身份如何在不同渠道、不同线程中并存为独立会话会话之间共享什么、隔离什么以及当人类在 A 渠道提及你在 B 渠道的工作时你应该如何响应。读完本文你将掌握--session-policyBUZZ_ACP_SESSION_POLICY的 Channel/Thread 两种作用域策略、SessionScope的推导规则以及支撑这一模型的服务端源码实现与测试验证。背景Buzz 中的 Agent 接入架构buzz-acp 是连接 AI Agent 与 Buzz 平台的 ACPAgent Client Protocolharness。它监听 relay 上的mention事件将消息组装为提示词prompt交给 AgentAgent 再通过 Buzz CLI 回复。其数据流如下见 crates/buzz-acp/README.mdBuzz Relay ──WS──→ buzz-acp ──stdio──→ Your Agent │ Buzz CLI (send_message, etc.)Buzz 是一个基于 Nostr 的人机协作消息平台围绕渠道channel、**会话conversation与共享工作shared work**组织协作。当多个渠道同时有人 同一个 Agent 时harness 需要在同一个 Agent 身份下并发处理多个对话——这正是会话模型要解决的核心问题。会话模型核心语义一个身份多个并存会话crates/buzz-acp/src/session_model_channel.md 开宗明义You are one per-channel session of your agent identity — not the only copy.在默认的渠道级per-channel模型下Agent 在每个渠道拥有一个独立会话同一个 Agent 身份可能同时在多个渠道中活跃。会话模型的核心边界可以概括为一句话每个渠道拥有独立的对话上下文conversation contextA 渠道的对话不会污染 B 渠道的上下文窗口。同一渠道内的线程thread共享该渠道的会话渠道内的子线程不单独隔离上下文。私信DM始终保持单一会话DM 的整个对话就是一次会话不按线程拆分。而真正体现分布式身份设计的是共享与隔离的边界划分跨会话共享SHARE跨会话隔离DO NOT SHARE核心记忆core memory对话上下文conversation context磁盘工作区workspace on disk进行中的推理in-progress reasoningrelay 访问权限relay access上下文内任务状态in-context task state渠道授权channel authorization—这组边界意味着Agent 的记忆、文件系统与网络能力是全局持久的属于身份而非会话而当前正在聊什么、正在想什么、手上进行到哪一步是会话局部的。从源码看核心记忆与工作区约定都定义在基础提示词 crates/buzz-acp/src/base_prompt.md 中core记忆每个回合自动注入上下文工作区采用RESEARCH/、PLANS/、GUIDES/、WORK_LOGS/、OUTBOX/、REPOS/、.scratch/的目录布局——这些都属于身份级持久状态因此跨会话共享。会话作用域的实现SessionScope 与推导规则会话模型的工程落地是 crates/buzz-acp/src/scope.rs 中的SessionScope枚举——它是标识 ACP provider 会话及其对话上下文边界的唯一可哈希键也是 provider 会话、队列分区queue partition、在途任务跟踪与上下文收集context gathering的规范键pub enum SessionScope { /// 整个渠道是一个会话。DM 恒为 ConversationChannel 策略下所有渠道事件也是它。 Conversation { channel_id: Uuid }, /// 渠道内的单一规范线程以根事件 id64 位小写十六进制为键。 Thread { channel_id: Uuid, root_event_id: String, }, }SessionScope::derive按如下优先级推导见 scope.rs 中derive的文档注释与实现DM 恒为Conversation——无论策略如何私信始终保持对话级作用域Channel策略下渠道内所有事件全部折叠为Conversation(channel_id)完整保留旧有的按渠道键控行为Thread策略下带 NIP-10 root 标签的事件归入该规范根事件无线程标签的顶层 mention 则以触发事件自身 id开启新线程。值得注意的是渠道channel始终是授权与协作边界而作用域scope只是默认的执行边界。SessionScope::channel_id()在任何变体下都可用——无论作用域如何划分渠道授权不会因会话拆分而失效。策略矩阵scope.rs 顶部注释给出了完整的策略矩阵事件面Surface作用域Scope新顶层渠道 mentionThread(channel_id, triggering_event)渠道线程内的回复Thread(channel_id, canonical_root)同一线程内的重复 mention复用该线程作用域私信DMConversation(channel_id)在Channel策略下当前默认/回滚路径所有事件面都塌缩为Conversation(channel_id)行为与今日渠道键控完全一致。根事件解析的细节规则线程根的解析复用parse_thread_tags即 Buzz 共享的 buzz-core 的 NIP-10 规范根规则格式非法的 marker id 被忽略事件按顶层处理只有rootmarker 而没有replymarker 视为顶层与 relay 摄取ingest规则一致根 id 统一规范化为小写后再作为作用域键。原因是共享 NIP-10 解析器接受并保留大写 ASCII 十六进制但 relay 在摄取时将事件 id 解码为字节因此AB…与ab…指向同一条线程——若不规范化两种等价拼写会哈希到不同的Thread键把同一条 relay 线程拆成两个 ACP 会话队列状态、provider 会话、亲和性、投递账本全部分裂。nostr::EventId::to_hex()本身输出小写所以顶层路径不受影响。策略配置--session-policy 与 BUZZ_ACP_SESSION_POLICY会话模型是可配置的。SessionPolicy枚举定义于 scope.rs#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, clap::ValueEnum)] pub enum SessionPolicy { /// 旧行为每渠道一个 provider 会话所有事件共享 Conversation(channel_id)。 #[default] Channel, /// 线程作用域每个规范渠道线程获得隔离的 provider 会话DM 保持对话级。 Thread, }配置入口见 crates/buzz-acp/src/config.rs#[arg( long, env BUZZ_ACP_SESSION_POLICY, default_value channel, value_enum )] pub session_policy: crate::scope::SessionPolicy,参数说明项值CLI 标志--session-policy环境变量BUZZ_ACP_SESSION_POLICY默认值channel可选值channel每渠道一个会话旧行为thread每规范线程一个会话DM 仍为对话级config.rs 中注释明确了设计意图默认channel是为了让线程作用域功能暗线发布ships dark可以在不改代码的情况下灰度canary、切换、回滚。 对应测试test_session_policy_default_is_channel、test_session_policy_thread_flag_parses、test_session_policy_env_var_parses验证了默认值与两种解析路径的一致性。启动时harness 在任何 Agent 进程启动之前一次性构建 standing contextconfig.session_policy.append_session_model(...)将对应会话模型文档追加到基础提示词尾部见 crates/buzz-acp/src/lib.rsconfig.session_policy.append_session_model( base_prompt_content .as_deref() .unwrap_or(include_str!(base_prompt.md)), )append_session_modelscope.rs按策略选择注入哪个文档let session_model match self { Self::Channel include_str!(session_model_channel.md), Self::Thread include_str!(session_model_thread.md), }; format!({}\n\n{}, base_prompt.trim_end(), session_model.trim_end())也就是说session_model_channel.md 与 session_model_thread.md 这两份文档本身就是运行时提示词的一部分——它们是给 Agent 读的行为规范而 scope.rs 是给 harness 读的工程实现。Pi 通过原生--system-prompt消费这份 base其他 ACP Agent 则通过session/new或旧版首轮 framing 消费同样的字节见 lib.rs 注释。两种会话模型的差异channel 与 thread将两份会话模型文档对照可以清晰看到策略切换带来的行为变化维度Channel 策略默认Thread 策略会话划分单位每渠道一个会话每线程一个会话渠道内线程线程共享渠道会话每个线程独立会话顶层 mention 开启新线程DM单一会话单一会话不变并发不同渠道可并行不同渠道或同渠道不同线程可并行对应 scope.rs 中的session_model_is_appended_once_and_matches_policy测试Channel 策略的提示词必须包含one per-channel session且不包含each thread gets its ownThread 策略则相反——两个文档通过这一断言被锁定为互斥、恰好一次注入。跨会话协作准则被引用时如何响应会话模型文档中有一整段行为准则这是给 Agent 的跨会话边界纪律也是全文最关键的实操指引When a human references work you are doing in another channel, that work belongs to a different session of you. Unless the human asks you to take it over or coordinate it from this channel, leave execution with the owning session — answer from what you can verify (core memory, workspace files, relay messages) and assume the owning session has it handled.翻译成实操规则识别归属当人类在 A 渠道引用你在 B 渠道做的工作时那份工作属于你的另一个会话不是当前会话的上下文默认不接管除非人类明确要求你从当前渠道接管take over或协调coordinate否则把执行权留给归属会话owning session基于可验证信息作答只依据你能核实的东西回答——核心记忆core memory、工作区文件workspace files、relay 消息relay messages——这三者正是上一节表格中跨会话共享的资产默认信任归属会话假设归属会话已经处理妥当不要越权重复执行或抢答。Thread 策略下的文档session_model_thread.md把这一准则扩展到兄弟线程引用范围从另一渠道扩大到另一渠道或同渠道的兄弟线程。这条准则与基础提示词中的工程纪律一脉相承如果这一轮产出了值得知道的东西你必须发布它buzz messages send你的推理和工具调用对人是不可见的——正因为执行过程不可见跨会话的事实同步只能依赖共享的持久状态memory、workspace、relay这反过来解释了为什么会话模型要如此严格地区分共享与隔离。会话作用域的运行时影响所有者控制命令随作用域变化READMEcrates/buzz-acp/README.md说明了!cancel/!rotate/!shutdown与作用域的关系Channel 策略下一个会话作用域是整个渠道因此这些命令保留渠道级行为Thread 策略下需要把命令作为目标线程内的回复发布!cancel/!rotate才只影响该线程DM始终是一个会话作用域。其中!rotate使该作用域的会话失效下一个排队/到达的事件会在该作用域开启全新会话!cancel在作用域空闲时是空操作no-op。遥测标签为避免把完整 id 泄漏进高基数字段SessionScope::telemetry_label()生成紧凑、利于日志聚合的标签scope.rsConversation→conversationThread→thread:root8根 id 前 8 个字符。对应测试断言thread:abcdef01这样的输出格式。源码级验证scope.rs 测试套件会话模型的正确性由 scope.rs 内嵌的测试严格守护以下测试直接印证了文档中的每一条边界dm_is_always_conversation_scoped_under_thread_policy—— 即使 DM 带 reply 标签Thread 策略下仍保持对话级作用域channel_policy_collapses_everything_to_conversation—— Channel 策略下线程回复与顶层 mention 均塌缩为对话级top_level_mention_opens_thread_rooted_at_trigger—— 无线程标签的顶层 mention 以触发事件 id 为根开启新线程direct_reply_to_root_scopes_to_that_root—— 仅有root无reply的标签按摄取规则视为顶层nested_reply_scopes_to_canonical_root_not_parent—— 嵌套回复键控规范根而非直接父事件repeated_replies_in_same_thread_share_scope—— 同根回复复用同一线程作用域对应线程内共享会话语义different_top_level_mentions_get_distinct_scopes—— 两个独立顶层 mention 必须分属不同会话mixed_case_root_spellings_share_one_thread_scope——AB…与ab…等价拼写收敛到同一Thread键大小写规范化malformed_thread_tag_falls_back_to_top_level—— 非法 marker id 被忽略、回退为顶层scope_is_hashable_and_usable_as_map_key——SessionScope可哈希、可作 HashMap 键支撑队列分区与在途跟踪。实践建议如何在自己的部署中观察会话模型默认部署channel 策略buzz-acp直接运行即为每渠道单会话。想要在保持旧行为的前提下验证线程作用域设置BUZZ_ACP_SESSION_POLICYthread或--session-policy thread即可无需改代码可随时切回。并行扩展配合--agents N1–32可让不同渠道Thread 策略下还包括不同线程被不同 Agent 子进程并发处理所有 N 个进程共享同一 Nostr bot 身份用户看到的是一个 bot详见 README 的 Shared Identity。跨会话协作观察当 Agent 在多个渠道活跃时留意其回复是否从可验证信息作答——如果 Agent 试图凭记忆复述另一渠道的进行中任务细节说明它可能越过了会话边界正确行为是依赖 core memory、workspace 文件与 relay 消息核实。小结Buzz 的会话模型用一套清晰且工程化的边界解决了一个身份多路并发的核心难题身份级状态记忆、工作区、授权全局共享对话级状态上下文、推理、任务状态严格隔离。SessionPolicy/SessionScope将这一模型落为可配置、可灰度、可回滚的运行时机制并通过 scope.rs 的完整测试套件锁定了每一条推导规则。理解这份模型是正确部署多 Agent 协作、排查跨渠道上下文串扰、以及设计 Agent 行为准则的前提。延伸阅读会话模型文档crates/buzz-acp/src/session_model_channel.mdChannel 策略默认crates/buzz-acp/src/session_model_thread.mdThread 策略作用域实现与全部测试crates/buzz-acp/src/scope.rs配置项定义--session-policy/BUZZ_ACP_SESSION_POLICYcrates/buzz-acp/src/config.rs基础提示词含核心记忆、工作区布局、发布纪律crates/buzz-acp/src/base_prompt.mdharness 接入与配置总览crates/buzz-acp/README.md【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzz创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考