尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Openclaw源码深潜之六——消息路由完全指南:从 Session Key 到 Agent 分发

发布时间:2026/9/26 16:02:13

资讯中心
01
ARTICLE

Openclaw源码深潜之六——消息路由完全指南:从 Session Key 到 Agent 分发

Openclaw源码深潜之六——消息路由完全指南:从 Session Key 到 Agent 分发
1. 一条消息为什么会被送错 Agent本地部署 Openclaw 之后最容易踩的坑不是模型接不上而是消息路由错位。你明明给用户 A 配了助手 Agent结果他发一句话回复风格却像客服或者群里所有人共用一份上下文张三问完李四接着问Agent 把两个人的信息串在一起。这类问题表面看是Agent 不听话根子几乎都在消息路由这一层。Openclaw 的消息路由系统负责把来自不同渠道QQ、飞书、微信等的消息按预设规则分发给正确的 Agent 处理。它要解决三件事这条消息属于谁、应该交给哪个 Agent、上下文要不要隔离。核心链路可以概括成一句话——路由决定 AgentSession Key 决定上下文。前者回答谁来处理后者回答记不记得住。这篇面向本地部署 Openclaw 的开发者把一条消息从入口到 Agent 的完整路径拆开讲清楚。你会看到 Session Key 是怎么拼出来的、9 级优先级匹配是怎么逐层往下找的、分发策略怎么配才符合预期。文末给出可复制的路由配置片段和验证动作构造多 Session 请求观察日志里的路由命中结果确认分发符合预期。如果你还没拿到可用的模型调用凭证可以先用 TaoToken 的 API Key 把链路跑通再回来调路由。2. 前置准备把模型调用链路先打通路由调通之前得先保证 Agent 能真正调用到模型。Openclaw 本身只负责消息分发和会话管理模型能力需要外部 API 提供。我习惯用 TaoToken 作为统一入口它的接口兼容主流协议配置成本低本地调试时不用来回换 SDK。先到官网注册并创建 API Key地址是 https://taotoken.net/api-keys 登录后在控制台生成密钥。拿到 Key 之后在 Openclaw 的模型配置里填上 base URL 和密钥即可。base URL 用 https://taotoken.net/api 注意这个地址不带任何查询参数直接填就行。配置片段大致长这样放在~/.openclaw/openclaw.yaml的模型段里model: provider: openai-compatible baseUrl: https://taotoken.net/api apiKey: sk-你的密钥 model: claude-sonnet-4-5 timeout: 60000这里有个细节值得说provider选openai-compatible是因为 TaoToken 的接口遵循 OpenAI 兼容格式Openclaw 内置的适配器可以直接识别不需要额外写转换层。timeout建议给到 60 秒本地网络波动时不容易误判超时。如果你打算长期跑编码类 Agent或者要接多个 Agent 做分发可以考虑 Coding Plan额度更划算地址是 https://taotoken.net/coding-plan 。单纯验证路由逻辑的话按量付费的 Key 就够了。配好之后先别急着调路由用一次最简单的对话确认模型链路是通的。打开模型对话页面 https://taotoken.net/model-chat 发一句你好能正常返回就说明 Key 和网络都没问题。这一步跳过的话后面路由报错你分不清是路由配错了还是模型根本没连上。3. Session Key 生成上下文隔离的纽带Session Key 是连接路由 → Session → Agent的纽带它保证同一个用户总是路由到同一个 Session从而维持上下文连续。格式是agent:{agentId}:{scope}其中 scope 部分由 DM Session Scope 决定。Openclaw 支持四种 DM Scope对应不同的隔离粒度scope 值说明适用场景main所有私聊合并到主会话默认个人助手、简单场景per-peer每个用户独立会话需要区分不同用户上下文per-channel-peer每个渠道用户独立会话多渠道部署、用户 ID 可能重复per-account-channel-peer每个账户渠道用户独立会话复杂多租户场景对应的 Session Key 示例# 主会话所有私聊合并 agent:main:main # 按用户独立会话per-peer agent:main:direct:4D6A3F5D3023823E09A3B6EA0BFF8C15 # 按渠道用户独立会话per-channel-peer agent:main:qqbot:direct:4D6A3F5D3023823E09A3B6EA0BFF8C15 # 按账户渠道用户独立会话per-account-channel-peer agent:main:qqbot:default:direct:4D6A3F5D3023823E09A3B6EA0BFF8C15配置方式是在session段里指定dmScopesession: dmScope: per-peer选哪个 scope 取决于你的业务。个人助手用main最省事所有对话共享一份上下文。但如果你做的是多用户客服main会让所有人的历史混在一起Agent 分不清谁是谁这时候必须上per-peer。多渠道部署时同一个用户在不同渠道的 ID 可能不一样用per-channel-peer才能正确隔离。源码里 Session Key 的生成入口是buildAgentPeerSessionKey位于src/routing/session-key.ts整个文件 238 行逻辑不复杂值得通读一遍。它会根据dmScope的值决定拼接哪些字段最终产出唯一的 Key。4. 9 级优先级匹配Agent 分发的核心逻辑路由匹配用的是 9 级优先级从高到低依次检查找到第一个匹配的绑定就立即返回对应的 agentId。如果全部不匹配返回默认 Agent。优先级顺序如下binding.peer— 直接匹配用户/群 ID最高优先级binding.peer.parent— 线程继承父级绑定binding.peer.wildcard— 通配符匹配如group:*binding.guildroles— 服务器 角色匹配binding.guild— 服务器级别binding.team— 团队级别binding.account— 账户级别binding.channel— 渠道级别default— 默认 Agent最低优先级匹配逻辑是从具体到模糊先看有没有精确指定某个用户没有再看通配符再没有就看渠道最后兜底到默认。这个设计的好处是你可以只配几条精确规则剩下的走默认不用为每个用户都写一条。基础配置示例bindings: # 1. 直接匹配用户 ID优先级最高 - match: peer: kind: direct id: 4D6A3F5D3023823E09A3B6EA0BFF8C15 agentId: main # 2. 通配符匹配所有群聊 - match: peer: kind: group id: * agentId: group-handler # 3. 按渠道匹配 - match: channel: qqbot agentId: qqbot-agent # 4. 默认 Agent最低优先级无需显式配置 # 系统自动使用 defaultAgentId高级配置里可以叠加服务器和角色条件bindings: # 服务器级别 角色匹配 - match: guildId: 123456789 roles: [admin, moderator] agentId: admin-agent # 服务器级别无角色限制 - match: guildId: 123456789 agentId: guild-agent注意binding.guildroles需要遍历角色列表性能比纯 guild 匹配低只在必要时用。绑定列表越长匹配越慢高频用户或渠道的绑定建议放前面减少遍历次数。路由核心逻辑在src/routing/resolve-route.ts381 行入口函数是resolveAgentRoute。绑定列表的读取在src/routing/bindings.ts只有 81 行负责把 YAML 配置解析成内存里的绑定数组。5. 验证请求构造多 Session 观察路由命中配置写完不代表生效得实际发消息看日志。验证分三步确认配置加载、观察路由命中、检查 Session Key。第一步确认当前配置被正确读取cat ~/.openclaw/openclaw.yaml | grep -A 20 bindings:第二步在路由核心函数里加日志。打开src/routing/resolve-route.ts在resolveAgentRoute里插入调试输出export function resolveAgentRoute(input: ResolveAgentRouteInput): ResolvedAgentRoute { // ... 现有代码 ... // 添加日志 logDebug([routing] 输入channel${channel}, peer${formatPeer(peer)}, guildId${guildId || none}); for (const tier of tiers) { // ... 匹配逻辑 ... if (matched) { logDebug([routing] 匹配成功matchedBy${tier.matchedBy}, agentId${matched.binding.agentId}); return choose(matched.binding.agentId, tier.matchedBy); } } logDebug([routing] 未匹配使用默认 Agent${resolveDefaultAgentId(input.cfg)}); return choose(resolveDefaultAgentId(input.cfg), default); }第三步在 Agent 处理前打印 Session Keyconsole.log([agent] sessionKey${sessionKey}, mainSessionKey${mainSessionKey});然后构造多 Session 请求。用两个不同的用户账号分别发消息观察日志输出。预期结果是用户 A 的消息命中binding.peer路由到assistant用户 B 的消息命中另一条绑定路由到support。如果两条消息都落到默认 Agent说明绑定配置没生效回去检查 YAML 格式。再验证 Session 隔离。把dmScope设为per-peer用户 A 和用户 B 各发一条消息日志里应该看到两个不同的 sessionKey[agent] sessionKeyagent:main:direct:用户A_OpenID [agent] sessionKeyagent:main:direct:用户B_OpenID两者上下文完全隔离A 的历史不会污染 B。如果 sessionKey 相同说明dmScope没生效检查配置是否被正确加载。6. 常见错误排查路由问题大多集中在几个固定位置对照下表排查能省不少时间现象原因解决方案消息总是到默认 Agent绑定配置错误或未生效检查config.bindings格式是否正确同一用户每次路由到不同 SessiondmScope 配置错误确认session.dmScope配置为per-peer群聊消息被当成私聊处理peer.kind 识别错误检查 Channel 插件是否正确传递kind角色匹配不生效roles 字段格式不对确认 roles 是数组且与平台角色名一致修改配置后行为没变缓存未失效重启 Openclaw 进程或确认 config 对象引用已更新关于缓存Openclaw 用了两级缓存提升路由性能。第一级是绑定列表缓存用 WeakMap 按 config 引用缓存避免每次重新解析 YAML第二级是路由结果缓存同样按 config 引用缓存最多 4000 条key 由channel、accountId、peer、parentPeer、guildId、teamId、roles、dmScope拼接而成。超过 4000 条时自动清空。这意味着如果你在运行时修改了 config 对象但引用没变缓存不会失效路由结果还是旧的。调试时如果发现改了配置没反应先重启进程。生产环境里 config 通常是启动时加载一次不存在这个问题。还有一个容易忽略的点binding.peer.wildcard的通配符匹配优先级高于渠道匹配。如果你同时配了group:*和channel:qqbot群聊消息会先命中通配符规则走group-handler而不是qqbot-agent。理解优先级顺序才能预测实际命中结果。7. 把路由链路固化下来路由调通之后建议把验证动作固化成脚本每次改配置跑一遍。构造几个固定用户 ID 的测试请求断言日志里的matchedBy和agentId符合预期比人工看日志可靠得多。模型调用这块如果 Agent 数量多、调用频繁按量付费的成本会上去可以评估 Coding Plan 是否更合适。接入文档在 https://taotoken.net/doc 里面有完整的接口说明和示例代码路由调完之后对着文档把 Agent 的模型参数再核对一遍避免因为参数不匹配导致 Agent 虽然被正确路由、但调用模型时失败。整条链路的核心就两点Session Key 管上下文隔离9 级优先级管 Agent 分发。把这两个机制吃透再复杂的多 Agent 场景也能拆解成一条条绑定规则。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。