事件驱动 Agent 架构
事件驱动 Agent 架构
学习目标
读完本章后,你将能够:
- 理解基于有向图的 Agent 事件传播模型
- 设计 Event/Link/Agent 三元组架构
- 掌握即时传播与定时传播的双模式策略
- 了解事件生命周期管理与过期淘汰策略
核心概念
事件驱动 Agent 的本质
事件驱动 Agent 架构的核心思想是:Agent 之间不直接通信,而是通过事件作为中介进行异步交互。
与直接调用的 Agent 协作模式不同,事件驱动架构有三个关键特征:
- 解耦:发送方不知道也不关心谁会接收事件
- 异步:事件的创建与处理不需要在同一时间发生
- 可回溯:事件持久化存储,支持事后分析和重放
Event/Link/Agent 三元组
事件驱动 Agent 系统由三个核心实体构成:
| 实体 | 职责 | 核心属性 |
|---|---|---|
| Agent | 事件的创建者和消费者 | check(主动获取)、receive(被动处理)、create_event(创建事件) |
| Event | Agent 之间的通信载体 | payload(JSON 数据)、expires_at(过期时间)、lat/lng(可选位置信息) |
| Link | Agent 之间的有向连接 | source(事件源 Agent)、receiver(事件接收 Agent)、event_id_at_creation(创建时的最新事件 ID) |
有向图传播算法
传播流程的关键细节:
- 水位线追踪:每个 Agent 维护
last_checked_event_id,只处理 ID 大于水位线的新事件,避免重复处理 - 创建时快照:Link 创建时记录
event_id_at_creation,忽略 Agent 连接之前的历史事件 - 批量传播:传播器按分钟级别批量扫描新事件,一次性推送给所有下游 Agent
- 即时传播:支持
propagate_immediately标志,事件创建后立即触发下游传播,无需等待下一个传播周期
设计模式
模式一:事件过滤器
使用条件判断 Agent(如 TriggerAgent)在事件流中间插入过滤层,只允许匹配条件的事件继续传播:
模式二:事件聚合器
将多个来源的事件汇聚到一个 Agent 进行统一处理:
模式三:事件分支
一个 Agent 的事件同时分发给多个下游 Agent,各自独立处理:
模式四:事件去重
在事件流中插入去重层,避免下游 Agent 重复处理相同事件:
事件生命周期管理
事件过期与清理
事件不是永久存在的——每个事件都有 expires_at 字段,由创建者 Agent 的 keep_events_for 设置决定:
| 保留策略 | 适用场景 |
|---|---|
永久保留(expires_at = nil) | 审计日志、历史分析 |
| 短期保留(1 小时 ~ 1 天) | 实时告警、临时状态 |
| 中期保留(2 ~ 30 天) | 日报周报、趋势分析 |
| 长期保留(45 ~ 365 天) | 合规要求、年度对比 |
清理策略的实现要点:
- 定时任务(默认每 6 小时)扫描
expires_at < NOW()的事件并删除 - MySQL InnoDB 需排除最新事件(避免 AUTO_INCREMENT 计数器回退)
- 清理后更新受影响 Agent 的
events_count缓存列
反压机制
当事件产生速度超过消费速度时:
- 丢弃策略:Agent 可通过
set_last_checked_event_id跳过积压事件,从最新水位线开始消费 - 批量消费:
receive!方法一次性收集所有待消费事件,避免逐条查询
陷阱与对策
陷阱一:事件循环
当 Agent A → Agent B → Agent A 形成环时,事件会无限循环传播。
对策:在 Link 层面不做自动环检测,而是依靠 expires_at 自然终止。设计上应避免环,或在环中插入 TTL 限制的 Agent。
陷阱二:事件风暴
一个 Agent 短时间内产生大量事件,导致下游 Agent 队列积压。
对策:
- 限制 Agent 的
events_count上限 - 使用 DeDuplicationAgent 去重
- 配置合理的
keep_events_for避免存储膨胀
陷阱三:传播延迟
定时传播模式下(默认每分钟),从事件创建到下游 Agent 接收可能有最多 1 分钟的延迟。
对策:对低延迟场景使用 propagate_immediately 标志,事件创建后立刻触发传播。
设计取舍
数据库存储 vs 消息队列
| 维度 | 数据库存储(如 Huginn) | 消息队列(如 RabbitMQ/Kafka) |
|---|---|---|
| 持久性 | 天然持久化,可回溯 | 需额外配置持久化 |
| 延迟 | 较高(轮询,分钟级) | 极低(推送,毫秒级) |
| 复杂度 | 低(复用已有数据库) | 高(需额外基础设施) |
| 回溯 | 天然支持 SQL 查询 | 需保留策略支持 |
| 吞吐 | 中等(受限于数据库写入) | 极高(百万级 TPS) |
选择数据库驱动的原因:简单部署、天然回溯、中等规模场景足够。如果追求极低延迟或极高吞吐,应引入消息队列。
有向图 vs 工作流引擎
| 维度 | 有向图(Link 连接) | 工作流引擎(如 LangGraph) |
|---|---|---|
| 灵活性 | 高(运行时可修改连接) | 低(图结构通常是预定义的) |
| 可视化 | 自动生成拓扑图 | 需要显式定义 |
| 状态管理 | 分散(每个 Agent 独立内存) | 集中(统一状态对象) |
| 适用场景 | 用户自定义自动化 | 复杂的条件分支与循环 |
参考来源
- Flow-based Programming — J. Paul Morrison 提出的数据流编程范式
- Node-RED — 基于有向图的 IoT 事件编排工具
- Apache NiFi — 企业级数据流管理系统