生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~250,000 tokens,输出 ~18,000 tokens(本章合计)
一条消息从通道到达 Gateway 时,系统需要回答两个问题:交给哪个 Agent? 和 放入哪个会话? 这就是会话路由的核心职责。本节逐文件分析路由系统的源码实现。
13.2.1 路由绑定(Bindings)
路由绑定(Binding)是用户在配置文件中定义的规则,用于将特定的通道/账户/对等方映射到特定的 Agent。src/routing/bindings.ts 提供了绑定查询的基础设施。
// src/routing/bindings.ts
import type { OpenClawConfig } from "../config/config.js";
import type { AgentBinding } from "../config/types.agents.js";
export function listBindings(cfg: OpenClawConfig): AgentBinding[] {
return Array.isArray(cfg.bindings) ? cfg.bindings : [];
}
一个典型的绑定配置如下:
// config.json5
{
"bindings": [
{
"agentId": "work-assistant",
"match": {
"channel": "slack",
"accountId": "company-workspace"
}
},
{
"agentId": "personal",
"match": {
"channel": "telegram",
"peer": { "kind": "dm", "id": "12345" }
}
}
]
}
这表示:来自 Slack 公司工作区的消息交给 work-assistant Agent,来自 Telegram 用户 12345 的私聊交给 personal Agent。
listBoundAccountIds() 函数提取某个通道下所有被绑定的账户 ID:
buildChannelAccountBindings() 构建一个嵌套的 Map<channel, Map<agentId, accountId[]>> 结构,方便后续快速查找:
13.2.2 路由解析(Resolve Route)
src/routing/resolve-route.ts 是路由系统的核心——resolveAgentRoute() 函数接收消息的来源信息,返回应该使用的 Agent ID 和会话键。
matchedBy 字段记录了路由匹配的原因,调试时很有用。
resolveAgentRoute() 按照从具体到宽泛的优先级尝试匹配:
衍生解释:这种从具体到宽泛的匹配优先级在路由系统中很常见。类似于 nginx 的 location 匹配规则——精确匹配 > 前缀匹配 > 正则匹配 > 默认。OpenClaw 的路由也遵循同样的原则:peer 绑定 > guild 绑定 > account 绑定 > channel 绑定 > 默认。
路由解析的最终产物是会话键。buildAgentSessionKey() 函数根据路由结果生成适当的会话键:
对于 Slack 线程、Discord 帖子等场景,resolveThreadSessionKeys() 在基础会话键后追加 :thread:<threadId>:
用具体示例总结不同消息类型产生的会话键:
群组消息不受 dmScope 影响,始终包含通道和群组 ID:
定时任务使用特殊的键格式:
线程在基础键上追加线程标识:
会话路由是 OpenClaw 消息处理流水线中的关键一环:
绑定系统:通过配置文件将通道/账户/对等方映射到特定的 Agent
优先级匹配:从具体(peer)到宽泛(default)的 7 级匹配优先级
灵活的键生成:根据 dmScope、identityLinks 和消息类型生成唯一的会话键
线程继承:线程消息继承父消息的路由绑定,保证同一线程的所有消息路由到同一个 Agent
路由系统的设计使得 OpenClaw 能够在一个 Gateway 实例中同时服务多个 Agent、多个通道、多种消息类型,而每条消息都能被准确地路由到正确的位置。