路由与处理层 (Routing & Processing Layer)
文档版本:2026.3.4 最后更新:2026-03-04
openclaw版本:v2026.2.25
1. 层概述
职责: 对渠道层传入的消息进行安全检查、授权验证、账号解析及代理路由分发
定位: 渠道接入层与 AI 代理层之间的"守门人"与"调度员"
核心特性:
- 6 级路由绑定(全局 → 频道 → 账号 → 角色 → 群组 → 用户)
- 白名单(AllowFrom)安全模型
- 配对(Pairing)一次性授权
- DM 群组访问策略决策
- 全链路安全审计日志
2. 主要组件
2.1 路由解析器 (Route Resolver)
路径: src/routing/resolve-route.ts
职责: 根据消息来源(渠道 + 账号)和配置文件中的绑定规则,解析出对应的目标 Agent 实例及其 Session Key。
关键类型与函数:
| 符号 | 说明 |
|---|---|
resolveAgentRoute(input) | 核心路由解析入口,返回 ResolvedAgentRoute |
ResolveAgentRouteInput | 路由解析输入:channelId, accountId, guildId, roleIds 等 |
ResolvedAgentRoute | 解析结果:agentId, sessionKey, bindingScope |
buildEvaluatedBindingsIndex | 构建已求值绑定索引(带 LRU 缓存) |
BindingScope | 绑定作用域枚举:global / channel / account / role / group / user |
RoutePeerKind | 路由对等方类型:dm / group / guild |
绑定层级(从低优先级到高优先级):
global → channel → account → role → group → user
匹配越具体优先级越高;命中最高优先级绑定,路由到对应 Agent。
缓存策略:
resolvedRouteCacheByCfg— 按配置哈希缓存路由结果(上限MAX_RESOLVED_ROUTE_CACHE_KEYS)evaluatedBindingsCacheByCfg— 缓存已求值绑定索引
2.2 账号查找 (Account Lookup)
路径: src/routing/account-lookup.ts, src/routing/account-id.ts
职责: 将平台原始账号标识(如WhatsApp JID)规范化为系统内部 accountId,并查找 AllowFrom 条目。
核心函数:
| 函数 | 说明 |
|---|---|
resolveAccountEntry | 解析账号条目,处理遗留格式兼容 |
normalizeId | 规范化账号 ID(去除多余前缀/后缀) |
2.3 安全配对系统 (Pairing System)
路径: src/pairing/
职责: 通过一次性配对码实现陌生用户的安全授权入驻,避免将凭证硬编码到配置中。
关键文件:
| 文件 | 说明 |
|---|---|
pairing-store.ts | AllowFrom 状态读写、配对请求管理 |
pairing-challenge.ts | 配对挑战/验证逻辑 |
pairing-messages.ts | 配对流程的用户提示消息 |
setup-code.ts | 一次性设置码生成与验证 |
配对流程:
用户发送 /pair <code>
↓
pairing-challenge 验证 code 有效性及未过期
↓
approveChannelPairingCode() 写入 AllowFrom 状态
↓
用户加入白名单,后续消息正常路由
关键常量:
PAIRING_CODE_LENGTH= 6 位PAIRING_PENDING_TTL_MS— 请求过期时限PAIRING_PENDING_MAX— 同时待确认请求上限
2.4 白名单管理 (AllowFrom / Allowlist)
路径: src/pairing/pairing-store.ts, src/security/dm-policy-shared.ts
职责: 维护每个渠道的"允许接入"账号列表(AllowFrom),决定哪些账号的消息会被处理。
数据结构:
interface AllowFromStore {
allowFrom: AllowFromEntry[] // 白名单条目列表
pairingRequests: PairingRequest[]
}
interface PairingChannel {
id: string // 渠道 ID
allowFrom: string[] // 允许的账号列表
}
AllowFrom 状态文件: ~/.openclaw/credentials/<channelId>/allow-from.json
关键操作:
| 函数 | 说明 |
|---|---|
readChannelAllowFromStore | 异步读取渠道白名单 |
readChannelAllowFromStoreSync | 同步读取(启动时使用) |
updateChannelAllowFromStore | 更新渠道白名单(带文件锁) |
addChannelAllowFromStoreEntry | 新增白名单条目 |
removeChannelAllowFromStoreEntry | 移除白名单条目 |
2.5 DM 访问策略 (DM Policy)
路径: src/security/dm-policy-shared.ts
职责: 决定群组(group/guild)中的私信(DM)消息是否允许访问 AI Agent。
决策流程:
resolveDmGroupAccessDecision(params)
↓
resolveDmGroupAccessWithCommandGate → 检查是否已发送过指令消息
↓
resolveDmGroupAccessWithLists → 检查 AllowFrom 白名单
↓
DmGroupAccessDecision { allowed: boolean; reason: DmGroupAccessReasonCode }
DmGroupAccessReasonCode 枚举值(部分):
PINNED_MAIN_DM_OWNER— 固定主账号持有人ALLOW_FROM_MATCH— 白名单命中COMMAND_SENT— 已发送命令NOT_ALLOWED— 未授权
2.6 安全审计 (Security Audit)
路径: src/security/audit.ts, src/security/audit-channel.ts
职责: 对所有安全相关事件(消息接入、配对、工具调用等)进行结构化审计日志记录。
关键函数:
| 函数 | 说明 |
|---|---|
auditChannelAccess | 审计渠道消息接入事件 |
auditToolPolicy | 审计工具策略决策 |
auditFs | 审计文件系统访问 |
审计级别: 继承主日志系统(trace/debug/info/warn/error)
2.7 Session Key 管理
路径: src/routing/session-key.ts, src/sessions/session-key-utils.ts
职责: 为每次路由结果生成稳定、唯一的 Session Key,用于后续 Agent 会话查找与续接。
Session Key 构成:
{agentId}:{channelId}:{accountId}[:{threadId}]
- 同一 (agent, channel, account) 三元组复用同一 Session
- 可选
threadId支持多线程隔离(如 Discord 线程)
3. 对外提供的接口
路由层作为内部模块,不直接暴露 HTTP/WebSocket 接口。对上层(Agent 层)提供以下编程接口:
| 接口 | 说明 |
|---|---|
resolveAgentRoute(input) | 核心路由解析,返回 agentId + sessionKey |
readChannelAllowFromStore(channelId) | 读取白名单状态 |
resolveDmGroupAccessDecision(params) | DM 访问决策 |
approveChannelPairingCode(channelId, code) | 审批配对码 |
upsertChannelPairingRequest(channelId, req) | 提交配对申请 |
4. 与其他层的交互
4.1 上游(渠道接入层 → 路由层)
ChannelLayer 接收消息
↓
提取 { channelId, accountId, guildId, roleIds, text }
↓
调用 resolveAgentRoute() 获取目标 agentId 和 sessionKey
4.2 下游(路由层 → Agent 层)
路由层输出 { agentId, sessionKey, bindingScope }
↓
Agent 层使用 sessionKey 查找/建立对话上下文
↓
将消息派发到对应的 Pi Agent 实例
4.3 与 Gateway 控制平面的交互
- 路由层读取 Gateway 的配置(
agents[].bindings)构建绑定索引 - 配置热重载时自动清除绑定缓存
- 审计日志写入 Gateway 事件总线
5. 关键代码路径
src/routing/
├─ resolve-route.ts # 核心路由解析(6级绑定 + LRU缓存)
├─ account-lookup.ts # 账号条目查找
├─ account-id.ts # 账号 ID 规范化
├─ session-key.ts # Session Key 生成规则
├─ bindings.ts # 绑定配置类型定义
└─ default-account-warnings.ts # 默认账号配置警告
src/pairing/
├─ pairing-store.ts # AllowFrom 状态持久化(文件锁)
├─ pairing-challenge.ts # 配对码验证逻辑
├─ pairing-messages.ts # 用户提示文本
└─ setup-code.ts # 一次性设置码生成
src/security/
├─ audit.ts # 安全审计主模块
├─ audit-channel.ts # 渠道访问审计
├─ dm-policy-shared.ts # DM 群组访问策略决策
├─ dangerous-config-flags.ts # 危险配置项检测
└─ external-content.ts # 外部内容安全过滤
6. 技术实现
6.1 核心技术
- 语言: TypeScript (ESM)
- 文件锁:
proper-lockfile— 确保并发写入安全 - 缓存: 基于 Map 的 LRU 缓存(按配置哈希分区)
- ID 规范化: 正则归一化各平台账号标识
6.2 设计模式
- 策略模式:
DmGroupAccessDecision封装多条件决策逻辑 - 缓存优先: 路由解析结果缓存,避免每条消息重新计算绑定索引
- 不可变决策: 路由解析为纯函数,输入相同配置必定输出相同结果
6.3 安全设计
- 默认拒绝: 未在 AllowFrom 中的账号,消息静默丢弃(不回复)
- 过期清理: 配对请求自动按 TTL 过期,防止配对码滥用
- 文件锁: AllowFrom 状态写入使用文件锁,防止并发写入损坏
6.4 配置示例
# openclaw.config.json5 中的绑定配置
agents:
- id: "my-agent"
bindings:
- channel: "feishu" # 渠道级绑定
- channel: "discord"
account: "123456789" # 账号级绑定
- channel: "slack"
guild: "T0XXXXXXX"
roles: ["admin", "member"] # 角色级绑定