主要技术:Node.js、OpenClaw、WebSocket
项目目录
项目简介
OpenClaw 是一套基于 TypeScript 和 Node.js 的智能体网关,把运行在自有设备上的助手接入聊天渠道、终端和控制台。用户可以从 Telegram、Slack、Discord 等入口提出任务,由配置选定的 Agent 调用模型和工具,再把回复发回对应对话。
例如,同一 Gateway 可以将个人私聊和项目频道分别交给不同 Agent,维护各自工作区与会话;用户也可以直接在 Control UI 中与助手交互。渠道连接、会话划分、工具策略及插件扩展由宿主管理,具体可执行任务取决于启用的工具与运行环境。
项目亮点
- 确定的多渠道路由: 根据聊天对象、父对象、组织、账号和渠道等绑定选 Agent,按固定优先级处理冲突;模型不负责猜测消息该交给谁。
- 会话范围与回复路线分开:
SessionKey决定使用哪段上下文,渠道、账号、目标及线程决定回复投递位置。私聊默认可以进入主会话,也可配置按对象、渠道或账号划分。 - 工具策略逐层收窄: 工具配置、全局、Agent、群组和发送者等策略共同过滤工具;当轮身份约束还可拦截实际调用,工具定义可见不等于获准执行。
- 插件声明与运行契约: 清单负责身份和能力声明,同步注册入口接入工具、渠道、Hook 与服务;生命周期契约管理启动和清理,插件能力仍受宿主策略约束。
技术架构
消息接入与投递: 渠道适配器提供消息及可信来源信息,Gateway 选择 Agent 和会话;运行结果通过保留的投递坐标返回,控制台与 CLI 使用同一控制平面。
Agent 执行与扩展: Agent 加载工作区、模型与工具,经策略管道形成可用工具范围;插件注册表提供渠道、工具和服务实现,具体动作再由工具与配置的执行环境处理。
| 代码位置 | 主要职责 |
|---|---|
src/gateway/、src/channels/ |
网关服务与渠道公共接入能力 |
src/routing/resolve-route.ts、src/routing/session-key.ts |
绑定优先级与会话标识 |
src/agents/tool-policy-pipeline.ts、src/agents/agent-tools.turn-authority.ts |
工具过滤与当轮调用准入 |
src/plugins/ |
插件发现、注册和生命周期 |
extensions/、ui/ |
具体扩展实现与控制台界面 |
如何写进简历
商聊通 · 跨渠道商品咨询助手 | 跨境电商场景示例
项目描述:面向跨境电商客服的跨渠道商品咨询助手,接入多个聊天渠道,结合商品资料与业务工具整理回复,保留客户上下文并将结果送回来源会话。
技术栈:TypeScript、Node.js、OpenClaw、WebSocket
主要工作:
- 多渠道接入与确定性路由:基于渠道、账号、聊天对象及团队绑定选择商品咨询
Agent,按既定优先级处理精确匹配与兜底;通过Gateway和渠道插件承接消息收发,使不同入口进入对应咨询流程。 - 客户会话作用域与回复坐标:使用
per-account-channel-peer区分接入账号与客户会话,按SessionKey组织历史;另行传递来源渠道、账号、目标和线程,区分上下文标识与实际回复地址。 - 工具策略与当轮执行约束:按全局、
Agent、群组和发送者策略逐层收窄工具范围,分别维护会话可见定义与当轮callableTools;对当前发送者无权使用的调用在执行入口明确拒绝,约束客户聊天入口的工具能力。 - 商品工具与可信业务上下文:通过插件工具工厂读取可信账号、发送者和会话上下文,接入型号、规格及政策资料查询;返回适用条件与来源,支持多轮补充问题后继续答复。
值班通 · 研发告警协作助手 | 软件服务场景示例
项目描述:面向软件团队的研发告警协作助手,将告警频道消息交给对应服务助手,结合运行手册与只读工具整理排查要点,在原讨论线程持续反馈进展。
技术栈:TypeScript、Node.js、OpenClaw、WebSocket
主要工作:
- 服务绑定与排查会话路由:通过聊天对象、群组、团队和账号绑定的优先级选择服务
Agent,沿会话或线程保留后续排查背景;以SessionKey管理历史,使用宿主投递上下文把进展送回来源讨论。 - 工具可见性与执行授权分离:结合全局、
Agent、群组及发送者策略构造工具清单,以当轮授权包装检查真正可执行的callableTools;对会话中仍可见但当前无权使用的工具返回拒绝,收窄告警入口的操作范围。 - 排查工具与服务证据收集:利用插件工具接口接入服务目录、运行手册与只读日志查询,按告警服务和时间窗组织证据;将接口错误、无匹配记录和有效结果分开反馈,供模型继续查询或整理排查要点。
- 告警实例与延迟通知衔接:以服务、规则和关键标签归并同类告警,再按平台事件标识或触发批次区分故障实例;恢复消息只更新已确认的实例,无法确认归属的延迟通知保留待核项,避免覆盖同指纹的新故障。
面试题与回答
3 题多渠道多 Agent 系统如何设计消息路由,OpenClaw 的匹配优先级是什么?
展开收起
核心回答
多渠道多 Agent 系统需要分开解决三件事:谁处理、使用哪段会话、回复发到哪里。渠道适配器先提供渠道、接入账号、聊天对象、组织和线程等身份信息;路由层按确定的优先级选 Agent;会话层生成上下文标识;投递层保留回复的渠道、账号、目标和线程。入口身份应来自可信的渠道上下文,不能让模型生成的参数决定用户身份。
OpenClaw使用TypeScript和Node.js构建Gateway,连接消息渠道与 Agent 执行层。普通入站路由由配置规则决定,选出一个 Agent,再确定其工作区和会话。它的匹配顺序是:精确聊天对象 → 父聊天对象 → 聊天对象通配 → Guild 与角色 → Guild → Team → 账号 → 渠道 → 可确定的兜底 Agent。同一级按配置顺序选第一个满足条件的规则。这类规则路由与按问题内容选择专家可以同时存在:渠道绑定先确定负责这段对话的 Agent,选中的 Agent 内部再决定是否委派任务。普通渠道路由本身不要求模型判断,也不意味着把消息广播给所有 Agent。
实际匹配优先级
解析前先规范化渠道名和
accountId,只取当前渠道、当前账号及账号通配规则作为候选。这里的账号是接入平台的机器人或账号实例,发送消息的人则属于聊天对象身份,两者不能混用。当前共享路由解析器按以下顺序检查:
- 精确聊天对象:匹配
peer.kind与peer.id,例如指定某个私聊用户、群或频道。 - 父聊天对象:当前对象未命中时,使用渠道提供的
parentPeer查找绑定,让线程可以继承父频道的 Agent。 - 聊天对象通配:匹配指定对象类型的
peer.id: "*",例如该账号下所有私聊。 - Guild 与角色:匹配
guildId,并要求发送者的角色 ID 与配置的roles至少有一个相同,常用于Discord。 - Guild:匹配所在服务器的
guildId。 - Team:匹配
teamId,例如Slack工作区。 - 账号:当前渠道下的具体
accountId绑定。 - 渠道:该渠道中
accountId: "*"的绑定,覆盖任意账号。 - 兜底 Agent:使用调用方明确给出的所属 Agent,或配置中可以唯一确定的所属 Agent;多 Agent 场景无法确定时,需要补绑定或指定 Agent,不会任取名册第一项。
优先级先于配置顺序,配置顺序解决同级冲突。 一个精确对象规则即使排在账号规则后面,也仍先检查;两个同级规则都能命中时,则由先出现的规则获胜,而不是按字段数量临时计算“更具体”。
复合条件仍然全部有效。绑定同时写了
peer、guildId、teamId或roles,不能只满足其中一个就命中;父对象继承阶段也继续检查组织与角色条件。角色匹配使用平台提供的角色 ID,不是看到消息里提到某个角色就转发。还有一个容易配错的地方:省略
accountId表示默认账号,显式写"*"才覆盖任意账号。入站账号和配置账号使用同一套归一化规则,例如" WORK "会按work参与匹配。Session key 决定上下文范围
选定 Agent 后,还要确定消息进入哪段历史。
SessionKey用于持久化上下文和控制会话并发,不能简单固定为“渠道加用户”。OpenClaw的私聊作用域由session.dmScope或命中绑定中的覆盖配置决定:main:默认值,进入该 Agent 的主会话,形如agent:<agentId>:main。per-peer:按聊天对象区分,可跨渠道共享同一对象的会话。per-channel-peer:按渠道与聊天对象区分。per-account-channel-peer:进一步包含接入账号,适合同一渠道存在多个账号的情况。
session.identityLinks可以把已配置的跨渠道身份映射为统一对象标识,在非main的私聊模式中参与生成会话标识。是否最终合并,还取决于所选作用域是否继续包含渠道与账号;它不是自动识别人,也不是授权机制。群或频道默认使用
per-group范围,线程或话题由渠道继续补充标识;配置也可以将选定群组并入主会话。因此私聊默认并不按用户隔离,多人接入时需要明确选择合适的范围。会话划分解决上下文共享问题,入口授权和工具执行权限还要分别控制。路由目标与回复投递目标分开
agentId和SessionKey决定在哪里执行、读写哪段上下文;回复的channel、accountId、to和threadId决定发给谁。同一个主会话可能承接多个渠道的输入,但本轮回复仍应使用对应来源的投递坐标,不能从共享主会话推导出唯一收件人。OpenClaw会结合当前OriginatingChannel、OriginatingTo、账号和线程解析回复路由;内部事件或符合条件的sessions_send交接可以继承已保存的外部投递信息。普通交互不能任意借用旧的外部目标,当前显式路线与已保存路线不同,也不应继承旧房间的描述信息。选中 Agent、获得执行准入、生成回复和确认投递,是不同阶段。用冲突场景验证路由
例如在同一个
Discord账号work下,分别配置:频道C17交给reviewer,服务器G1交给support,整个账号兜底交给general。G1中来自C17的消息命中精确对象,交给reviewer。C17的子线程没有自己的绑定时,渠道提供父对象信息,可继承reviewer;线程自身有精确绑定时,精确绑定优先。G1的其他频道交给support,其他服务器中未命中的消息再落到账号规则。- 另一账号的消息不能误用仅属于
work的规则;两条同级规则重叠时,应检查配置顺序。
还应覆盖跨账号相同聊天对象、角色不符、私聊作用域切换,以及当前回复来源与历史投递路线不同的情况。检查路由结果中的
matchedBy、agentId和SessionKey,再单独核对投递坐标,可以区分“选错 Agent”和“回复发错地方”。- 精确聊天对象:匹配
同一工具如何按场景控制权限,OpenClaw 的工具策略管道如何分层?
展开收起
核心回答
同一工具的权限应由可信的身份和场景决定:先限制这次任务允许使用哪些工具,再在执行时检查具体参数、资源和调用者权限。 模型可以提出调用,但不能通过填写“我是管理员”给自己授权。
OpenClaw把工具策略分成基础工具集、全局与 Agent 配置、渠道会话与发送者、沙箱与子 Agent 等层,逐层过滤候选工具。普通策略中deny优先,各层允许范围共同约束结果;后层写了allow,不会恢复前层已经移除的工具。owner 权限还会作用于当轮执行,模型看见工具定义,不等于本轮能够调用。例如,本地开发者可以用
exec调试,群聊助手则可通过群组策略禁止exec、process以及文件修改工具。这里解决的是工具准入;命令在哪运行、能写哪些目录,以及业务接口能操作哪个对象,仍分别由执行环境和具体工具检查。工具策略管道怎样分层?
固定版本的
buildDefaultToolPolicyPipelineSteps()按以下顺序使用已经解析好的策略:- 基础工具集:
profilePolicy、providerProfilePolicy,分别对应通用和模型供应方的工具 profile。 - 全局与 Agent:
globalPolicy、globalProviderPolicy、agentPolicy、agentProviderPolicy。 - 当前会话与发送者:
groupPolicy、senderPolicy。同一个 Agent 在不同群组、不同发送者的请求下,可以得到不同工具范围。
会话管道随后追加
sandboxPolicy、subagentPolicy、按需要纳入的runtimeToolPolicy,以及inheritedToolPolicy。未配置的层跳过;已配置的层继续收窄当前候选。沙箱层只在相应沙箱场景生效,子 Agent 层与继承限制也不是每次普通聊天都凭空产生。默认层次、会话附加层。applyToolPolicyPipeline()保存当前工具数组,每经过一层,就对上层结果执行filterToolsByPolicy()。匹配器先检查拒绝规则,再检查允许规则,支持工具组和通配模式。alsoAllow是向相应层已有允许集合补充条目,不是跨层的授权通行证。逐层过滤、名称匹配。渠道、插件与子 Agent 各影响什么?
渠道策略约束请求所处的对话。 群组、账号与发送者信息应由宿主解析,不能信任模型自报的身份。当前实现通过请求者策略解析群组和发送者范围;子 Agent 还会携带持久化的继承限制,不能换一个会话就丢掉来源约束。请求者策略解析。
插件扩展工具来源,不自动扩大权限。 管道按插件元数据把插件 ID、
group:plugins展开成具体工具名,再应用策略。已加载插件的工具仍可能被全局、发送者或沙箱层排除;配置了MCP服务,也不代表当前沙箱会话可以调用它。插件工具组展开。子 Agent 另受子任务限制与继承范围约束。 例如控制平面、直接跨会话投递等工具存在额外限制。显式的跨 Agent 工具委派是运维配置授予的能力,不能由模型在
sessions_spawn参数里自行声明;普通allow也不能消除其它来源的拒绝。子 Agent 工具策略。owner 权限为什么不能只靠隐藏工具?
这个版本会区分提供给模型的工具定义与当轮真正可调用的工具。
resolveTurnToolSurface()对未获 owner 权限或超出当轮请求者权限的工具,保留定义并包装执行入口;调用会被拒绝,同时从本轮callableTools和后代继承的exportedTools中排除。这既保持会话工具前缀稳定,也避免把“定义仍在”当成有效授权。具体工具仍可以拥有动作级和对象级检查。当轮工具权限处理。工具策略能保证什么,不能替代什么?
工具策略回答“允许调用哪个工具”,沙箱回答“工具在哪里运行、能接触什么”。允许
exec后,即使拒绝write、edit,命令仍可能修改文件,因此不能据此宣称整个 Agent 只读。elevated也不增加工具集合,不能绕过已经拒绝的exec。对同一个被允许的工具,执行层仍应依据真实身份检查目标、参数和当前状态。例如允许调用发消息工具,不等于可以向任意群组投递;允许执行命令,也不等于获得所有主机或目录的访问权。实际系统需要把工具准入、具体动作授权与执行隔离分别落实。沙箱、工具策略与 elevated 的区别。
- 基础工具集:
Agent 插件系统如何设计,OpenClaw 的插件 API 提供哪些扩展契约?
展开收起
核心回答
Agent 插件系统需要把能力声明、加载策略、运行时注册和资源生命周期分开:宿主定义渠道、工具和事件的接口,插件提供实现,再由配置选择启用哪些提供者。注册表保存能力及所属插件,宿主统一负责调用、诊断和卸载,避免每增加一种能力就修改主循环。
OpenClaw使用openclaw.plugin.json声明身份、配置结构和能力,再向插件的同步register(api)入口注入OpenClawPluginApi。插件通过registerTool、registerChannel、api.on(...)和registerService等契约贡献行为;宿主将它们登记为可调用的运行时能力。设计时还应明确接口版本、同名冲突、调用上下文、失败处理和资源释放。清单合法与注册成功只代表接入满足契约,不意味着第三方代码已获得进程隔离或业务操作授权。
清单、配置与加载怎样配合
该版先发现插件根目录并读取清单与包元数据,检查路径安全,再依据
plugins.enabled、allow、deny、entries、槽位和激活条件决定加载范围。清单中的configSchema用于校验该插件的配置,静态能力声明允许宿主在不导入运行时代码时完成发现和归属判断。选中的运行时模块才进入加载与注册。例如工具须出现在
contracts.tools中,registerTool会核对运行时工具名称与声明;导出身份与清单身份不一致也会产生加载错误。这样能区分“目录里存在一个包”“配置允许它参与”和“其运行时能力已注册”三个状态。register(api)必须同步完成注册,该版会拒绝返回Promise的注册函数。需要连接外部系统或执行长期后台任务时,应先登记服务,把异步工作交给服务的启动阶段;不能在注册结束后继续补注册。主要扩展契约是什么
- 工具:
api.registerTool(...)接受工具对象或按上下文创建工具的工厂,定义名称、描述、参数和执行结果。工具进入模型可见集合后,实际调用仍受宿主工具策略和执行层约束;参数结构也不能替代业务字段与权限校验。 - 渠道:
api.registerChannel(...)提交渠道插件,配置适配器负责账号解析,按能力提供认证、收发、状态、线程或消息转换等适配器。渠道的运行和投递通过统一接口接入 Gateway,而不把平台细节散布到 Agent 主循环里。 - 事件 Hook:
api.on("before_tool_call", ...)、api.on("agent_end", ...)等注册有类型的执行阶段回调,参数与返回值由具体事件契约决定。api.registerHook(...)则属于内部事件 Hook 路径,两者不能按名称互换;将before_tool_call注册到后一条路径并不会获得同样的调用。 - 后台服务与清理:
api.registerService(...)提供id、start与可选stop,由宿主安排服务运行和停止。受宿主管理的插件实例还可通过api.lifecycle接入取消信号、销毁回调与registerRuntimeLifecycle,把插件持有的后台工作和状态纳入清理。
插件还可以扩展模型提供者、HTTP 路由、CLI 命令等,但每个扩展点都要使用对应的身份、输入输出与所有权契约,而不是拿到一个宿主内部对象后任意修改共享状态。
在多渠道故障工单平台的场景化接入中,可将查询与进度记录做成两个插件工具:前者接收工单号,后者再接收进度文本;渠道、账号与线程由宿主上下文传入,返回工单号、办理状态与回执,供来源会话答复。写入超时应先保留“待确认”状态并查询工单结果,再决定是否重试,避免把网络超时当作未写入。工单接口及这项处置属于业务适配设计,不是
OpenClaw已内置工单系统或业务幂等。怎样处理兼容、失败和卸载
兼容性需要固定宿主与 SDK 版本,核对包声明及实际使用的 API,并验证发现、注册、调用、停用这条完整路径。该版
OpenClawPluginApi仍标为实验性接口,不能仅因为TypeScript类型检查通过,就认为后续宿主升级一定兼容。加载或注册抛错时,宿主记录插件归属与失败阶段,并回收已登记的宿主侧贡献;插件停用时,也要停止连接、定时任务和事件订阅,避免旧实例继续处理请求。对状态变更类 Hook 和纯观测 Hook,应分别定义失败后停止还是继续,不能把所有异常统一吞掉。
原生插件在宿主进程中运行。清单校验、配置允许名单和注册回收有助于管理能力,但不能撤销插件代码任意产生的文件或网络副作用。若设计要求运行不可信代码,需要额外的进程、容器或远程服务边界,不能把内存注册表当成安全沙箱。
- 工具: