Agent Relay事件驱动实战:5个addListener技巧,让Agent在idle瞬间被唤醒
【免费下载链接】relayReal time communication for agents. Wake on message, channels, DMs and actions. Useful for orchestrating agents.项目地址: https://gitcode.com/gh_mirrors/relay35/relay
Agent Relay 是一个面向 AI Agent 的实时通信编排工具,提供频道(Channels)、私信(DMs)和动作(Actions),并支持"消息即唤醒"(Wake on Message)机制。本文用 5 个addListener事件监听技巧,教你以事件驱动方式编排多 Agent 协作,让 Agent 在 idle 空闲的瞬间被精准唤醒,彻底告别轮询与忙等 🎯
上图是 Agent Relay 的一个真实演示:planner、reviewer、adversarial 三个 Agent 围绕同一个 broker 实时辩论,所有消息收发与状态流转都由事件驱动完成。这种"消息到达 → 立即唤醒 → 继续工作"的体验,正是addListener要解决的问题。
为什么是事件驱动?先认识 addListener 这个单一入口
轮询(每隔几秒问一次"有新消息吗")是最常见的反面模式:浪费 token、响应延迟高,还可能漏掉消息。Agent Relay 的答案是把所有事件收敛到一个入口:
const unsubscribe = relay.addListener('message.created', (event) => { console.log(`${event.envelope.from.handle}: ${event.message.text}`); }); unsubscribe(); // 随时干净离场addListener(selector, handler)的 selector 支持三种写法,处理器永远收到一个可判别的事件对象:
| 写法 | 示例 | 适用场景 |
|---|---|---|
| 点分事件名 | 'message.created' | 监听某类具体事件 |
| 前缀通配符 | 'action.*'、'*' | 监听一整族事件 |
| 流式谓词(Predicate) | agent.status.becomes('idle') | 按 Agent、频道、@提及精准过滤 |
三种 selector 的分发与通配匹配逻辑都在 listeners.ts 中实现,SDK 主入口见 agent-relay.ts。
💡上手技巧:先跑一句relay.addListener('*', (e) => console.log(e.type)),给整个系统"照一次 X 光",看清正在发生哪些事件,再决定精确订阅什么。
技巧1:用点分事件名订阅,快速接管消息事件流
Agent Relay 把事件按前缀分成四大族,用通配符一次订阅一族,是搭建观测面(observer plane)最快的方式:
relay.addListener('message.*', (event) => console.log(event.type)); // 所有消息事件 relay.addListener('action.*', (event) => console.log(event.type)); // 所有动作事件| 事件族 | 事件名 | 何时触发 |
|---|---|---|
| 消息 | message.created/message.updated/thread.reply | 频道新消息、更新、话题回复 |
| 私信 | dm.received/group_dm.received | 收到一对一或群组私信 |
| 回执 | message.read/message.reacted | 对方已读、添加或移除表情回应 |
| 动作 | action.invoked/action.completed/action.failed/action.denied | 动作被调用、完成、失败或被拒绝 |
| 状态 | agent.status.idle/active/blocked/waiting/offline | Agent 会话状态变化 |
| 活动 | agent.activity.changed | Agent 正在做什么(思考、调工具等) |
完整的 selector 到事件类型的映射表定义在 listeners.ts 的 RelayEventMap,它同时为 TypeScript 处理器提供了精确的类型推导。
技巧2:监听 idle 状态,让空闲 Agent 在瞬间被唤醒
这是标题承诺的核心技巧。Agent Relay 的唤醒机制分两层:
- Broker 层:消息被持久化排队,投递模式支持
immediate、next-tool-call和on-idle。Agent 忙的时候消息不会丢,而是等到它 idle 的那一刻自动注入——这就是"在 idle 瞬间被唤醒"的底层保障,投递逻辑见 delivery.rs。 - SDK 层:订阅 Agent 的状态谓词,在它变 idle 的瞬间接手下一步工作:
// 流式谓词:只关心 reviewer 这一个 Agent 变 idle 的时刻 relay.addListener(reviewer.status.becomes('idle'), () => { assignNextReview(); // 立刻派发下一个任务,零延迟接力 }); // 等价的点分写法:监听任意 Agent 的 idle relay.addListener('agent.status.idle', (event) => { console.log(event.agentId, '已空闲,可以派活了'); });状态谓词的匹配实现见 listeners.ts 的 StatusPredicate。相比"发送后 sleep 30 秒再问一次",状态事件让编排者的响应时间从秒级降到事件到达即触发 ⚡
技巧3:频道 + @提及双重过滤,避免 Agent 被无效唤醒
在大群里,"所有消息都唤醒我"会导致 Agent 被无关噪音反复打断。Agent Relay 的message.created()谓词支持链式过滤,只有目标频道里的、@ 了我的消息才触发处理器:
relay.addListener( relay.events.message.created().in('#general').mentions(me), (event) => respond(event.message) // 只有真正 @ 我时才动手 );该谓词会先比对频道名,再检查mentions列表和正文中的@名字,两层过滤的实现见 listeners.ts 的 MessageCreatedPredicate。搭配dm.received事件,你还能区分"群聊里被点名"与"私聊直接找我"两种唤醒路径。
🎯经验法则:编排者只订阅 @提及 + 关键状态事件;普通 Worker 只订阅自己的 DM。唤醒次数少一个量级,token 成本同步下降。
技巧4:用 Typed Action 事件,串联多 Agent 协作流水线
Agent 之间除了聊天还能互相调用"动作"(Actions)。动作是 fire-and-forget 的:调用方立刻拿到确认,结果稍后以事件形式广播。registerAction返回的句柄自带带类型的谓词构建器,处理器里的event.output直接是注册时 schema 推导出的类型,无需任何断言:
const handle = relay.registerAction({ name: 'github.open_pr', description: '为准备好的分支创建 PR', input: z.object({ repository: z.string(), branch: z.string() }), handler: async ({ input }) => openPR(input), }); relay.addListener(handle.completed(), (event) => { console.log(event.output.url); // 类型完整,零断言 });由此可以搭出"接力棒"流水线:Agent A 的动作完成 → 事件触发编排者 → 编排者立刻给 Agent B 发消息 → B 被唤醒继续。四个阶段事件invoked / completed / failed / denied让失败路径同样可编排——监听handle.failed()就能实现自动重试。完整示例见 SDK README 的 Actions 一节。
技巧5:once() 一次性订阅 + 错误隔离,防止监听器泄漏
长时运行的编排程序里,两类事故最伤:忘了退订的监听器越积越多;某个处理器抛异常把整条事件流搞崩。Agent Relay 对两者都有内建答案:
// 一次性监听:首个匹配事件到达后自动退订 relay.once('agent.status.idle', (event) => { console.log(`${event.agentId} 就绪,开始第一轮`); });once()在首次命中后自动解除订阅,实现见 listeners.ts 的 once,特别适合"等第一个信号"的启动握手场景。- 常规订阅务必保留返回的
unsubscribe函数,在 Agent 释放、流水线结束时调用。 - 每个处理器都在 try/catch 中执行,异常通过
onError钩子上报(默认打印警告),不会影响其他监听器和事件源——事件流的"熔断"是内建的。
总结:把 5 个技巧装进你的编排蓝图
| 技巧 | 一句话口诀 | 关键 API |
|---|---|---|
| 1. 点分事件名 + 通配符 | 先全景,后聚焦 | addListener('message.*', ...) |
| 2. idle 状态唤醒 | 空闲瞬间即派活 | agent.status.becomes('idle') |
| 3. 频道 + @提及过滤 | 不关我事不唤醒 | .in('#ch').mentions(me) |
| 4. Typed Action 事件 | 完成即接力 | handle.completed() |
| 5. once() + 错误隔离 | 一次性、可熔断 | relay.once(...)/unsubscribe() |
想继续深入,这些文件是事件驱动路径上的"路标":
- 监听器核心实现:packages/sdk/src/listeners.ts
- SDK 主入口(含 addListener 定义):packages/sdk/src/agent-relay.ts
- SDK 官方文档与示例:packages/sdk/README.md
- 观测平面设计规格:specs/observer-plane.md
- 事件总线(harness-driver):packages/harness-driver/src/event-bus.ts
- 多 Agent 演示脚本:scripts/demos/sprint-planning.sh、scripts/demos/server-capacity.sh
掌握这 5 个技巧后,你的编排代码将从"不停地问"变成"被事件推着走"——Agent 在该醒的时候醒,在无关时保持安静,这正是事件驱动多 Agent 系统的全部精髓 🚀
【免费下载链接】relayReal time communication for agents. Wake on message, channels, DMs and actions. Useful for orchestrating agents.项目地址: https://gitcode.com/gh_mirrors/relay35/relay
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考