ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Buzz Agent Observability(NIP-AO)协议解读:基于 Nostr Kind 24200 的加密 Agent 遥测与控制通道

Buzz Agent Observability(NIP-AO)协议解读:基于 Nostr Kind 24200 的加密 Agent 遥测与控制通道 Buzz Agent ObservabilityNIP-AO协议解读基于 Nostr Kind 24200 的加密 Agent 遥测与控制通道【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzz本文以 docs/nips/NIP-AO.md 为主体结合 Buzz 开源仓库中buzz-core、buzz-acp、buzz-relay、buzz-sdk及桌面/移动客户端的真实实现系统讲解 NIP-AO 定义的 Kind 24200Agent Observer Frame事件协议——它如何为 AI Agent 与 Owner 之间提供一条短暂、加密、实时、不经中继持久化的遥测与控制通道。读完本文你将掌握该事件类型的完整线格式、NIP-44 v2 加密与解密流程、中继侧授权与限流机制、客户端订阅与缓冲策略以及基于仓库源码的端到端运行原理。背景为什么 Agent 需要一条独立的可观测性通道AI Agent harness 会执行长时间会话long-running sessions调用工具、向模型发送协议帧、产生中间推理过程。OwnerAgent 所服务的人类或系统需要对这些活动进行实时可见性用于调试、审计和控制。NIP-AO 的动机在于遥测数据必须是实时的而非事后归档遥测数据不应被中继持久化也不应被第三方看到该通道应严格限定在 agent↔owner 关系之内不携带任何持久状态。基于此NIP-AO 定义了Kind 24200Agent Observer Frame一个专用的、加密的、短暂ephemeral事件通道仅用于 Agent 与其 Owner 之间的内部会话遥测与控制。在 Buzz 的 kind 注册表中该类型被正式登记为/// Ephemeral: owner-scoped encrypted agent observer telemetry and control frame. pub const KIND_AGENT_OBSERVER_FRAME: u32 24200;见 crates/buzz-core/src/kind.rs。其归属于 NIP-01 定义的 ephemeral 区间 20000–29999该区间在 Buzz 源码中有显式的边界常量EPHEMERAL_KIND_MIN 20000与EPHEMERAL_KIND_MAX 29999并有配套谓词is_ephemeral(kind)crates/buzz-core/src/kind.rs。核心术语术语含义Agent拥有自己 Nostr 密钥对、代表 Owner 执行会话的 AI 进程OwnerAgent 所归属的人类或系统其 pubkey 是 Agent 的 provision 主体Observer Frame一个携带单条遥测或控制信息的 kind 24200 事件Session由共享的sessionId关联的一次有界 Agent 执行在 crates/buzz-acp/src/observer.rs 中这些概念被直接落地ObserverEvent结构体携带seq、timestamp、kind、agent_index、channel_id、session_id、turn_id、started_at与payload字段与 NIP-AO 定义的解密载荷一一对应ObserverHandle通过进程内broadcast通道向 harness 主循环分发本地事件同时维护一个有界回放缓冲。事件结构一条 Kind 24200 事件的线格式NIP-AO 规定的 wire event加密后结构如下{ kind: 24200, pubkey: sender_pubkey, created_at: unix_timestamp, content: NIP-44 v2 ciphertext, tags: [ [p, recipient_pubkey], [agent, agent_pubkey], [frame, telemetry | control] ] }硬性约束包括事件必须恰好有一个p标签、恰好一个agent标签、恰好一个frame标签frame取值必须是telemetry或control中继对无法识别的frame值应当静默丢弃向发布者返回 OK以保持前向兼容客户端必须忽略无法识别的frame值当会话运行在 NIP-29 群组上下文中时可以包含一个h标签。在 Buzz 源码中agent与frame两个标签名及frame的合法取值被定义为常量crates/buzz-core/src/observer.rspub const OBSERVER_AGENT_TAG: str agent; pub const OBSERVER_FRAME_TAG: str frame; pub const OBSERVER_FRAME_TELEMETRY: str telemetry; pub const OBSERVER_FRAME_CONTROL: str control;方向语义方向签名方pubkeyp 标签agent 标签Telemetryagent → owneragentowneragentControlowner → agentowneragent目标agent目标Buzz 中继在agent_observer_route()中通过event.pubkey、recipient与agent三者关系精确判定方向crates/buzz-relay/src/handlers/event.rsevent.pubkey agent recipient ! agent→ Telemetry期望frame telemetryrecipient agent event.pubkey ! agent→ Control期望frame control其余形态一律拒绝invalid: observer frame must be agent-to-owner telemetry or owner-to-agent control。加密模型NIP-44 v2 端到端加密所有content字段必须使用 NIP-44 v2 加密在 secp256k1 ECDH 共享密钥之上使用 XChaCha20-Poly1305。Telemetry以(agent_privkey, owner_pubkey)加密Control以(owner_privkey, agent_pubkey)加密解密后的明文应在加解密完成后立即从内存中清零zeroize解密后的载荷不得超过 65,535 字节。在 crates/buzz-core/src/observer.rs 中加密与解密被实现为两个可复用函数encrypt_observer_payload::T: Serialize(sender_keys, recipient, payload)先序列化为 JSON校验明文 ≤ 65,535 字节OBSERVER_MAX_PLAINTEXT_LEN随后以 NIP-44 v2 加密加密后使用zeroize立即擦除明文decrypt_observer_payload::T: DeserializeOwned(recipient_keys, event)先校验密文长度落在 NIP-44 v2 的合理包络NIP44_MIN_CONTENT_LEN 132~NIP44_MAX_CONTENT_LEN 87_472之间再解密、反序列化并清零明文。仓库中的单元测试验证了完整往返路径observer_payload_round_trips_with_nip44构造一个turn_started载荷加密后断言content_looks_like_nip44成立再解密比对 JSON 完全一致observer_payload_rejects_short_ciphertext则验证短密文如明文 not encrypted会被以InvalidCiphertextLength拒绝crates/buzz-core/src/observer.rs。解密载荷Telemetry 帧的 ObserverEvent 结构frametelemetry时content解密后是一个ObserverEventJSON 对象{ seq: monotonic_integer, timestamp: rfc3339_string, kind: frame_kind, agentIndex: integer | null, channelId: channel_uuid | null, sessionId: session_id | null, turnId: turn_id | null, payload: { ... } }字段约束与语义REQUIREDseq、timestamp、kind、payloadOPTIONAL可为 nullagentIndex、channelId、sessionId、turnId—— 例如会话建立之前的sessionId可能未知客户端必须优雅处理nullseq按会话单调递增用于丢帧检测timestamp是带亚秒精度的 RFC 3339 字符串如2026-04-29T12:00:41.500ZagentIndex在多 Agent 场景中标识具体 AgentsessionId/turnId用于跨会话、跨轮次关联帧payload与kind相关可为{}未知的kind值必须被忽略。该结构在 crates/buzz-acp/src/observer.rs 中被忠实实现为 Rust 结构体字段名采用 camelCase#[serde(rename_all camelCase)]并额外支持started_at当前轮次开始时间序列化时为空则跳过。ObserverHandle::emit()通过原子自增生成seq用chrono::Utc::now().to_rfc3339()生成时间戳同时写入有界回放缓冲并广播给订阅者。帧类型Frame Kindskind描述acp_read入站 ACP 协议帧model → harnessacp_write出站 ACP 协议帧harness → modelturn_started新的 Agent 轮次开始session_resolved会话完成或终止在 ACP harness 源码中这两个 I/O 帧类型有明确的埋点位置crates/buzz-acp/src/acp.rswrite_ndjson()在向 agent 标准输入写入每条 NDJSON 消息后调用self.observe(acp_write, value.clone())读取模型返回消息的两处路径均调用self.observe(acp_read, msg.clone())。也就是说acp_write/acp_read本质上是对 ACP JSON-RPC 流量进出的逐条镜像Owner 端据此可以在不解密第三方内容的前提下内容仅 Owner 可解密实时观测 Agent 与模型之间到底交换了什么。解密载荷Control 帧的 cancel_turn 指令framecontrol时content解密后为{ type: cancel_turn, channelId: channel_uuid }目前唯一定义的 control 类型是cancel_turn实现必须忽略无法识别的type值。桌面客户端将cancel_turn控制指令的实现集中在 desktop/src/shared/api/agentControl.ts 中它构建{ type: cancel_turn, channelId }载荷并通过sendAgentObserverControl位于 desktop/src/shared/api/observerRelay.ts 附近发布为 kind 24200 控制帧取消结果以异步control_resultobserver 帧的形式返回客户端侧由此跟踪 Agent 何时从 busy 回到 idle见 desktop/src/features/agents/lib/cancelTurnOutcome.ts 及其测试。短暂性契约Ephemerality ContractNIP-AO 对中继提出如下硬性要求与建议中继不得将 kind 24200 事件持久化到任何耐久存储中继不得将 kind 24200 事件纳入搜索索引中继不得将 kind 24200 事件写入审计日志中继应仅通过内存中的 pub/sub 扇出 kind 24200 事件绝不经过数据库写入路径客户端应以sincenow订阅不支持历史回放客户端应在有界内存环形缓冲中暂存收到的帧。Buzz 中继正是这样实现的在 crates/buzz-relay/src/handlers/event.rs 中KIND_AGENT_OBSERVER_FRAME被从普通事件摄入路径提前分流到专门的handle_agent_observer_event()该函数不调用ingest_event()、不写数据库而是经由state.pubsub.publish_event(conn.tenant, EventTopic::Global, event)走全局内存 pub/sub 通道再通过fan_out_event_to_local_subscribers()直接向本地 WS 订阅者扇出crates/buzz-relay/src/handlers/event.rs。这正是 NIP-AO「in-memory pub/subnever via database write path」的源码级印证。订阅侧Buzz 中继为「kind #p全约束」的全局订阅维护专门的global_p_kind_index索引测试用例test_global_p_kind_index_fan_out_targets_matching_p验证了以{kinds:[24200], #p:[owner]}订阅的连接只收到p标签匹配的帧crates/buzz-relay/src/subscription.rs。授权模型双向 agent–owner 关系验证NIP-AO 要求中继在发布路径上做数据库级别的 agent–owner 关系确认仅凭#p标签匹配是不够的Telemetryagent → ownerevent.pubkey必须等于 agent pubkeyp标签必须等于 owner pubkey中继必须通过认证的 ownership 查找验证is_agent_owner(agent, owner)。Controlowner → agentevent.pubkey必须等于 owner pubkeyp标签必须等于 agent pubkey中继必须依据agent标签解析出的 agent 验证is_agent_owner(agent, owner)。未经授权的发布或订阅尝试必须以AUTH required拒绝。Buzz 中继的handle_agent_observer_event()完整落实了这套流程crates/buzz-relay/src/handlers/event.rs先通过spawn_blocking(verify_event)做 NIP-01 签名验证校验created_at是否落在 ±5 分钟新鲜度窗口内详见下文「中继行为」解析路由方向判定授权快路径若该连接通过 NIP-OA 认证且其已核实的 owner 与帧的目标 owner 一致直接跳过数据库查询否则查state.db.is_agent_owner(community, agent, owner)结果缓存在observer_owner_cachecrates/buzz-relay/src/state.rs 附近不匹配则拒绝restricted: observer frame is not authorized for this agent owner。订阅侧同理p_gated_filters_authorized要求 kind 24200 的 REQ 过滤器必须带#p且其值必须等于认证读者的 pubkey测试agent_observer_subscription_requires_matching_p_tag覆盖了缺#p、#p为他人、#p为自身三种情形crates/buzz-relay/src/handlers/req.rs。Kind 24200 也因此被列入P_GATED_KINDScrates/buzz-core/src/kind.rs但因其属于 ephemeral 类型而从不落库存储层的搜索防御对其不适用。中继行为处理流程、限流与新鲜度窗口中继收到 kind 24200 事件后必须依次执行按 NIP-01 校验事件签名按上述规则验证授权通过内存 pub/sub 向匹配订阅者扇出不调用常规的事件摄入或持久化路径。此外中继应强制执行每个 agent pubkey 每秒 100 条事件的限流并且建议拒绝created_at超出 ±5 分钟新鲜度窗口的事件以防止捕获事件的重放。Buzz 中继的实现crates/buzz-relay/src/handlers/event.rs新鲜度窗口(event_ts - now).unsigned_abs() 300即拒绝错误信息为invalid: observer frame timestamp outside ±5 minute freshness window限流滑动窗口计数器observer_rate_limiter按(community_id, agent_key)维度统计同 agent 在不同租户各享独立预算窗口内超过 100 条即返回rate-limited: observer frame rate exceeded (100/sec per agent)一个值得注意的细节限流只针对 Telemetry 帧。Control 帧owner → agent绕过限流器——它们稀少且绝不能被 Agent 突发遥测挤兑饿死。客户端行为订阅、解密与有界缓冲客户端按如下过滤器订阅{kinds: [24200], #p: [own_pubkey], since: now}收到事件后客户端必须校验事件签名使用自己的私钥与event.pubkey解密content解析解密载荷并按kindtelemetry或typecontrol分发忽略未知的kind/type值。同时应在解密前核对agent标签是否指向已知/受信任的 agent pubkey将有界环形缓冲作为接收缓冲建议上限800 条事件不得请求历史 kind 24200 事件不携带过去的since、不使用until、不使用ids查询。仓库中的客户端实现证据ACP harness 端Agent 侧HarnessRelay内置专用订阅OBSERVER_CONTROL_SUB_ID agent-observer-control通过subscribe_observer_controls()订阅发给自己的加密控制帧并提供独立的observer_control_rx接收通道crates/buzz-acp/src/relay.rs桌面端Owner 侧desktop/src/features/agents/useAgentObserverIngestion.ts 在 AppShell 中挂载一次负责接收 kind 24200 帧、解密并维护受信任 agent 集合desktop/src/features/agents/agentWorkingSignal.ts 基于turn_started/session_resolved等帧推算 Agent 是否正在工作移动端mobile/lib/features/channels/agent_activity/observer_models.dart 定义了 kind 24200 解密后的 Observer 帧模型mobile/lib/shared/relay/nostr_models.dart 中有对应的事件类型引用端到端回归desktop/tests/e2e/agent-control-regressions.spec.ts 覆盖了控制帧cancel_turn的端到端场景。安全考量NIP-AO 明确列出六类安全考量Buzz 实现均与之对应威胁说明Buzz 侧应对元数据泄露路由标签p、agent、frame、created_at为明文中继运营者可观察到 agent X 正在以何种速率向 owner Y 流式传输文档建议追求极致元数据隐私的实现在 NIP-59 gift wrap 中包装事件无前向保密NIP-44 不提供前向保密agent 私钥泄露即可解密任何捕获的密文依赖 NIP-44 v2 本身密钥保管是防线重放攻击捕获的已签名事件可在无新鲜度检查时被重放中继强制执行 ±5 分钟created_at新鲜度窗口crates/buzz-relay/src/handlers/event.rs恶意中继短暂性契约是中继策略而非密码学保证NIP-44 加密确保即使事件被存储中继运营者在没有密钥的前提下也无法读取内容尽力投递重连或队列溢出期间控制帧可能被丢弃控制指令应视为 advisory 且具备幂等语义Agent不得依赖控制帧的保证投递操作持久化载体遥测可能短暂存在于进程内存、崩溃转储与应用日志实现应最小化解密载荷的日志记录必须不得在 INFO 及以上级别记录与其他 NIP 的关系NIP-01Kind 24200 位于 ephemeral 区间20000–29999适用标准事件结构与签名规则NIP-42推荐用于中继侧认证门控NIP-44所有content字段的强制加密算法NIP-29当 agent 会话限定在 NIP-29 群组时可包含h标签NIP-XXPR #2226NIP-XX 定义 agent 的输出平面本 NIP 定义可观测性平面内部 agent 活动两者互补且不重叠。在 Buzz 的 NIP 族谱中NIP-AO 还与NIP-AMAgent Turn Metrickind 44200每轮次结束持久化到 Owner 的用量记录形成「实时短帧 耐久用量」的配套关系二者同为P_GATED_KINDS成员crates/buzz-core/src/kind.rs。完整示例示例 1Telemetry 事件acp_write帧线格式加密后{ id: a1b2c3d4..., kind: 24200, pubkey: agent_pubkey_hex, created_at: 1777464041, content: NIP-44 v2 ciphertext, tags: [ [p, owner_pubkey_hex], [agent, agent_pubkey_hex], [frame, telemetry] ], sig: ... }解密后的载荷{ seq: 42, timestamp: 2026-04-29T12:00:41.500Z, kind: acp_write, agentIndex: 0, channelId: 52a85618-0f8f-4542-94ec-599e6e1c6f2e, sessionId: a1b2c3d4, turnId: e5f6g7h8, payload: { jsonrpc: 2.0, method: tools/call, params: { name: shell, arguments: { command: ls -la } } } }这条载荷对应的正是 crates/buzz-acp/src/acp.rs 中write_ndjson()对出站 ACP 消息的observe(acp_write, ...)埋点——Owner 可以实时看到 Agent 向模型发出的tools/call请求及其参数。示例 2Control 事件cancel_turn帧线格式加密后{ id: e5f6a7b8..., kind: 24200, pubkey: owner_pubkey_hex, created_at: 1777464042, content: NIP-44 v2 ciphertext, tags: [ [p, agent_pubkey_hex], [agent, agent_pubkey_hex], [frame, control] ], sig: ... }解密后的载荷{ type: cancel_turn, channelId: 52a85618-0f8f-4542-94ec-599e6e1c6f2e }参考实现与延伸阅读NIP-AO 文档末尾引用了参考实现 block/sprout PR #421。在 Buzz 仓库内可以沿以下路径继续深入Kind 注册与范围断言crates/buzz-core/src/kind.rs24200 常量、P_GATED_KINDS、is_ephemeral加密/解密原语crates/buzz-core/src/observer.rsencrypt_observer_payload/decrypt_observer_payload、65,535 字节上限、zeroizeHarness 侧 observer 总线crates/buzz-acp/src/observer.rsObserverEvent、有界回放缓冲、seq生成Harness 侧中继客户端crates/buzz-acp/src/relay.rssubscribe_observer_controls、OBSERVER_CONTROL_SUB_ID中继侧处理crates/buzz-relay/src/handlers/event.rs签名验证、±5 分钟窗口、授权快路径、100/sec 限流、内存 pub/sub 扇出中继侧订阅门控crates/buzz-relay/src/handlers/req.rs 与 crates/buzz-relay/src/subscription.rsp_gated_filters_authorized、global_p_kind_indexSDK 构造器crates/buzz-sdk/src/builders.rsbuild_agent_observer_frame拒绝非 NIP-44 v2 密文内容Owner 端消费desktop/src/features/agents/useAgentObserverIngestion.ts、desktop/src/shared/api/agentControl.ts、mobile/lib/features/channels/agent_activity/observer_models.dart注NIP-AO 当前状态为draft/optional文中以 MUST/SHOULD/MAY 标注的要求分别对应 RFC 2119 语义Buzz 仓库当前实现已覆盖其中大部分 MUST 与 SHOULD 级行为。【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzz创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表