多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

ZeroClaw SOP Fan-In:用 AMQP 投递触发标准作业流程

ZeroClaw SOP Fan-In:用 AMQP 投递触发标准作业流程 ZeroClaw SOP Fan-In用 AMQP 投递触发标准作业流程【免费下载链接】zeroclawFast, small, and fully autonomous AI personal assistant infrastructure, any OS, any platform — deploy anywhere, swap anything 项目地址: https://gitcode.com/gh_mirrors/ze/zeroclaw导读本文讲解 ZeroClaw 中将 AMQP 0-9-1RabbitMQ 及其兼容 broker消息投递转换为 SOPStandard Operating Procedure标准作业流程运行触发器的完整链路从[channels.amqp.alias]的 broker 连接配置、dispatch路由模式、routing key 通配匹配与condition表达式到投递被提升为 SOP 事件后的引擎分发、背压重投递与审批观察。读完本文你将能够把任意 AMQP 主题上的业务事件发布监控、CI 通知、告警流等接入 ZeroClaw SOP 引擎让事件自动驱动需要人工审批的作业流程。一、AMQP 在 SOP Fan-In 中的角色ZeroClaw 的fan-in是指外部事件源启动 SOP 运行的机制每个事件源通过dispatch_sop_event将事件交给 SOP 引擎引擎把事件与所有已加载 SOP 的触发器逐一匹配命中即启动运行。一个实例可以同时绑定多个 fan-in——MQTT 主题、文件系统路径、AMQP routing key 可以同时喂给同一个引擎无需独立进程见 fan-in 总览。AMQP 是其中一类事件源当某个 alias 以 SOP 派发模式运行时AMQP 消费者会把每条投递提升为一个 SOP 事件——routing key 成为事件 topic消息体成为事件 payload——然后交给引擎匹配。也就是说传输侧broker 连接、队列、交换器、TLS由 AMQP channel 负责触发侧routing key 匹配、condition 求值由本文对应的 SOP 触发器负责决定一条投递驱动 agent 循环、SOP 引擎还是两者兼顾的是 channel 的dispatch字段。从源码看这一职责划分非常清晰crates/zeroclaw-channels/src/amqp.rs中AmqpChannel持有dispatch: SopDispatch、engine: OptionArcMutexSopEngine与audit: OptionArcSopAuditLogger三组状态route_deliveryamqp.rs 第 142 行根据dispatch的值分别把投递送入 agent 循环ChannelMessage或 SOP 引擎dispatch_untrusted_fan_in。安全前置条件dispatch为sop或sop_and_agent_loop时若构造 channel 时没有提供 SOP engine/audit 句柄AmqpChannel::new会直接bail拒绝启动amqp.rs 第 86-95 行避免出现确认了投递却没人派发的静默丢消息。测试new_rejects_sop_dispatch_without_handles专门守护了这一 fail-closed 行为。二、传输侧配置[channels.amqp.alias]要接入 SOP 触发先要有一个可用的 AMQP channel。完整的字段清单来自运行时 schemaschema.rs 第 17734 行起字段默认值作用enabledfalse是否启用该 channel。运行时只加载enabled true的 channel默认关闭避免粘贴半截配置就意外上线amqp_url无broker 地址。明文用amqp://TLS 用amqps://如amqps://fedora:rabbitmq.fedoraproject.org/%2Fpublic_pubsub属于 secret 字段exchange无消费者队列要绑定的交换器如amq.topic必填routing_keys[]要绑定的 routing key 列表。建议收窄到感兴趣的主题绑定#会消费整个交换器几乎永远不是你想要的必填至少一个queue无队列名。留空则使用服务端生成的临时独占队列仅在需要跨重连持久投递时才设置稳定名称推荐 UUIDca_cert无amqps://连接用的 CA 证书 bundle 路径client_cert/client_key无双向 TLSmTLS的客户端证书与私钥必须成对出现Fedora Messaging 就要求客户端证书sender_labelamqp写入每条投递ChannelMessage.sender的标识如anitya供编排器自环防护与按 channel 路由识别来源content_template空入站消息内容模板{field}占位符从 JSON 投递体顶层键插值为空时原样使用投递体thread_id_field空指向 JSON 投递体的点分路径其值作为消息thread_ts用于关联回复如message.project.name空则关闭线程关联durable_acktrue确认模式true时投递只在消息被可靠移交给 agent 循环后才 ack至少一次语义崩溃会重投false时 broker 派发即确认至多一次仅适合无副作用、可丢弃的消费者dispatchagent_loop投递路由去向驱动 agent 回合默认、派发到 SOP 引擎sop、或两者同时sop_and_agent_loopexcluded_tools[]不向该 channel 的工具规格暴露的工具列表配置校验AmqpConfig::validateschema.rs 第 17826 行会强制以下规则amqp_url必须以amqp://或amqps://开头使用amqps://时ca_cert必须提供否则报错 amqps:// requires ca_cert to verify the brokerclient_cert与client_key必须同时设置或同时缺省mTLS 成对校验exchange不能为空至少配置一个 routing key。一个最小化的 SOP 触发用配置示例[channels.amqp.release] enabled true amqp_url amqps://fedora:rabbitmq.example.org/%2Fpublic_pubsub exchange amq.topic routing_keys [org.release-monitoring.prod.anitya.project.version.update] ca_cert /etc/zeroclaw/certs/ca.pem # 将投递交给 SOP 引擎而不是 agent 循环 dispatch sopDispatch 三种模式dispatch字段决定一条投递做什么channels/amqp.mdagent_loop默认投递作为一条消息交给 agent 循环保持原有行为存量消费者不受影响sop投递被提升为 SOP 事件routing key → 事件 topic消息体 → payload并派发到 SOP 引擎sop_and_agent_loop每条投递同时执行上述两者。TLS 与 mTLSTLSamqp_url指向amqps://端点并配置ca_cert双向 TLS额外设置client_cert与client_key。不配置这些就是明文连接不要把明文消费者暴露在不可信网络上。底层实现上AmqpChannel::connectamqp.rs 第 255 行会把 PEM 格式的客户端证书与私钥转换为内存中的 PKCS#12 bundlepem_to_pkcs12_deramqp.rs 第 373 行交给 rustls 客户端认证路径client_cert/client_key只设置其一会在构造期直接报错。三、触发侧AMQP 触发器与 routing key 匹配SOP 的 AMQP 触发器在SOP.toml的[[triggers]]中声明。从测试代码可见其结构amqp.rs 第 912 行SopTrigger::Amqp { routing_key: anitya.update.into(), condition: None, }对应到SOP.toml[[triggers]] type amqp routing_key anitya.update # condition $.value 85 # 可选routing_key采用AMQP topic-exchange 语义key 以.分隔为多个词word*精确匹配一个词#匹配零个或多个词。例如org.release-monitoring.prod.anitya.project.version.update这类多点 key 可直接作为触发器模式发布方的 routing key 与触发器模式匹配即视为命中候选。匹配时消息体被原样转发进 SOP 事件 payload供可选的触发器condition求值而进入 step 上下文的则是经过截断、清洗、框架化的受限形式详见下文安全默认。一个 JSON-path 的condition如$.value 85要求发布方发送 JSON 消息体。四、Condition 条件表达式触发器的condition与 step 的when:守卫共用同一套表达式语法sop/syntax.md触发条件针对事件 payload 求值。求值失败即关闭非法条件、缺失 payload、无法解析的 JSON path、以及两侧不是数字的直接数值比较一律判为不匹配空条件无条件匹配。JSON Path 形式以$开头比较 JSON payload 内的某个值$.path.to.field op value。常用示例来自 syntax 参考的官方匹配表表达式Payload是否匹配$.value 85{value:90}是$.status critical{status:critical}是$.data.sensor.value 85{data:{sensor:{value:87.3}}}是$.readings.1 20{readings:[10,20,30]}是$.nonexistent 0{value:90}否路径规则使用点分隔的段数组元素用数字段如$.readings.1不支持方括号语法缺失键、越界索引、非法 JSON、空 payload 一律失败关闭没有通配符、过滤器、递归下降或内置变量。直接数值形式无前导$的条件把整个 payload 当作数值比较适合标量事件 payload如 0、 5、 42、 3.14。若任何一侧解析不出数字则无匹配。运算符与注意事项支持的运算符、!、、、、解析器按最长优先匹配运算符 tokenJSON path 比较先尝试数值比较——两侧都能解析为数字则按数值比较否则按字符串比较比较值两侧的英文双引号会被剥离所以字符串字面量要加引号$.status criticalJSON 布尔值会被转换为字符串true/false因此用引号字符串比较$.active true一个条件只允许单个比较不支持AND/OR/NOT逻辑组合。五、开火把事件送入 SOP 引擎端到端触发一条 AMQP 驱动的 SOP 运行步骤为确认sops_dir已配置。SOP 定义从sops_dir下的子目录加载该字段默认未设置运行时 SOP 关闭需要显式开启相对路径相对于安装根目录config.toml所在目录解析文档化值为shared/sops即install/shared/sops也可用绝对路径或~前缀路径。设置 channel 的dispatch为 SOP 模式sop或sop_and_agent_loop。加载 SOP在sops_dir/name/下放置SOP.toml含[[triggers]] type amqp与可选的SOP.md用zeroclaw sop validate name验证。发布消息向配置的 exchange 发布一条 routing key 与触发器匹配的消息。消费者把投递提升为事件routing key → topicbody → payload并派发。每个已加载且 routing key 模式匹配、condition若有对 body 成立的 SOP 都会启动一个运行。如果什么都不启动按顺序排查也见 fan-in 总览的故障排查表dispatch是否是 SOP 模式sop或sop_and_agent_loop而非默认的agent_loop队列是否正确绑定使 routing key 真正到达消费者检查exchange、routing_keys与发布方实际发射值是否一致condition是否对 payload 成立可用$.value 85这类带 JSON body 的发布做快速验证。底层派发链路消费者循环AmqpChannel::listenamqp.rs 第 444 行逐条取出投递后调用route_delivery当routes_sop为真时调用dispatch_untrusted_fan_indispatch.rs 第 1209 行——这是一个兼容包装内部走SopIngress统一入口执行用cap_untrusted对 topic 与 payload 做长度截断上限由sop.untrusted_payload_max_bytes控制默认8192字节按 UTF-8 字符边界截断0表示不设上限规范化、prompt-guard 筛查、加不可信内容框framing再进入匹配与上下文每个事件对所有已加载 SOP 的触发器求值命中即启动运行并经由SopAuditLogger持久化启动审计。六、背压与重投递Deferred 的两种命运SOP 引擎有并发准入控制SOP.toml中的max_concurrent、admission_policy、max_pending_approvals。当触发器到达但执行槽位或待审批池已满时投递被标记为Deferred背压其恢复方式依赖传输本版本引擎内没有持久化待触发队列见 sop/syntax.md 的准入小节AMQP SOP-only 派发dispatch sop且durable_ack true投递被nackrequeue truebroker 会在有空位后重投——不会把触发器 ack 掉丢失。这正是DeliveryOutcome::Deferred分支amqp.rs 第 477-494 行的行为由results_need_redeliverydispatch.rs 第 1196 行判定结果集中存在 Deferred 且没有任何Started 时才要求重投。若想延迟重试可在 broker 侧配置带 TTL 的死信交换器。AMQP 组合模式sop_and_agent_loopagent 侧已经消费了这条投递若再 requeue 会向 agent 循环重复投递同一条消息、双重执行其副作用。因此 SOP 侧溢出时大声记录日志后直接 ACK不重投避免 agent 侧被跑两遍。源码中该分支会发出WARN级日志amqp.rs 第 219-242 行测试combined_mode_acks_sop_overflow_and_agent_gets_exactly_one_message专门守护agent 恰好收到一次这一回归点。准入策略admission_policysnake_case包括parallel默认无法准入则延迟永不静默丢弃、hold串行化仅当该 SOP 无运行进行中或停靠时准入、coalesce把并发触发器折叠到已在飞的运行上、drop显式选择的历史 fire-and-forget。恰好一次的语义message_id 去重AMQP 投递的message_id被用作每消息幂等键按 channel alias 加命名空间amqp:alias:id且只有 broker 标记为redelivered的确认重投才会被折叠全新投递即使复用 message_id 也总是会派发amqp.rs 第 206-216 行。因此发布方应为每条逻辑消息设置唯一且稳定的message_id以获得恰好一次语义没有或空白 message_id 的投递完全不参与去重每条都启动自己的运行绝不猜测性 ACK复用 message_id违反约定时重投仍可能把不同触发器折叠——这是文档化的至多一次边界。对应测试覆盖了route_delivery_coalesces_only_a_redelivery_of_the_same_message_id与route_delivery_fresh_deliveries_reusing_a_message_id_both_start两个方向。七、安全默认不可信输入处理AMQP 事件源属于活的外部输入默认安全机制fan-in 总览安全表关注点机制不可信触发输入topic 与 payload 文本在进入模型上下文前截断、规范化、prompt-guard 筛查并加框framing 始终开启可隐藏提示文字但绝不把外部原始文本直接插值进模型上下文不安全触发块sop.untrusted_input_guard block直接拒绝不安全的不可信事件BlockedUnsafe默认warn是审计并放行头部受限上下文无 agent 循环时process_headless_results将ExecuteStep动作记为 pending 而不是静默执行[sop]下与不可信输入相关的字段还包括untrusted_guard_sensitivity默认0.7prompt-guard 筛查灵敏度、untrusted_frame_warning默认true不可信内容框中的警告文字、untrusted_outbound_redact默认trueSOP 内容安全消费者的出站脱敏。八、审批与观察checkpoint 停靠后的处理AMQP 触发的运行一旦到达 checkpointkind: checkpoint/requires_confirmation: true即暂停为WaitingApproval待审批。审批与观察有两种途径CLI 命令zeroclaw sop list # 列出运行含停靠在审批处的运行 zeroclaw sop approve # 批准停靠的运行Gateway APIout-of-band通过 gateway APIGET /admin/sop/pending— 查看待审批运行POST /admin/sop/approve— 批准POST /admin/sop/deny— 拒绝。审批门可以绑定策略SOP.mdstep 上的- policy: prod策略定义在[sop.approval.policies.*]包含required_group、quorum法定人数、escalation_route等需要跨渠道通知时还可以配置request_route如discord.ops:123456789012345678把审批请求路由到 Discord 等渠道仅 daemon 路径生效。运行持久化sop.persist_runs默认true停靠在 HITL 审批或确定性 checkpoint 的运行会跨 daemon 重启存活后端sqlite写入runs.db如希望引擎为纯内存、非持久化可显式设false。九、故障排查速查表症状可能原因修复没有消息被消费exchange 或 routing keys 与发布方不匹配核对exchange与routing_keys和发布方实际发射值一致TLS 握手失败amqps://未配ca_cert或证书与密钥不匹配提供ca_certmTLS 校验client_cert/client_key配对投递到达但无 SOP 启动dispatch还是agent_loop或 SOP 触发器不匹配将dispatch设为sop或sop_and_agent_loop检查触发器的 routing key 模式与conditionSOP 启动了但某步未执行无活跃 agent 循环的 headless 触发为ExecuteStep运行 agent 循环或把运行设计为停靠在审批处进一步资料AMQP channel 传输侧细节见 channels/amqp.mdfan-in 各事件源统一机制见 fan-in 总览SOP.toml/SOP.md完整格式、准入控制与条件语法见 SOP 语法参考。【免费下载链接】zeroclawFast, small, and fully autonomous AI personal assistant infrastructure, any OS, any platform — deploy anywhere, swap anything 项目地址: https://gitcode.com/gh_mirrors/ze/zeroclaw创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表