OpenClaw 意图理解机制解析
一、总体思路:不做分类器,让 LLM 自己判断 OpenClaw 的意图理解与传统 NLU 系统(基于规则或意图分类器)有本质区别。它不在 LLM 之前设置一个独立的意图分类步骤,而是采用「能力驱动架构」: 通过多层前置过滤器处理结构化指令(斜杠命令、内联指令) 将丰富的上下文(工具列表、技能描述、项目文件)组装进系统提示词 让 LLM 自行判断用户意图并选择行动路径 核心逻辑:与其花力气训练一个分类器去猜意图,不如把"能做什么"告诉模型,让模型自己决定"该做什么"。这个选择的代价和边界,我们放到第五章再展开。 二、架构全景:四层管线 用户消息从进入到被理解,经过四层递进的处理管线。前三层是确定性的预处理,第四层才交给 LLM。记忆系统作为横切模块,为第四层的系统提示词组装提供上下文补充。 flowchart TD A[用户发送消息] --> B[第1层 路由层] B -->|选定 Agent| C[第2层 命令检测层] C -->|是控制命令| C1[直接执行,不进 LLM] C -->|都不是| D[第3层 指令解析层] D -->|提取内联指令 + cleaned 文本| IA[Inline Actions 阶段] IA -->|是技能命令| D1[路由到技能处理器] IA -->|不是技能命令| E[第4层 系统提示词组装] M[(记忆系统)] -.->|身份文件/MEMORY.md 注入| E M -.->|memory_search/memory_get 按需拉取| F E --> F[LLM 决策层] F -->|扫描技能索引| F1[read SKILL.md → 按指令执行] F -->|选择工具| F2[调用 exec / web_search / message 等] F -->|复杂任务| F3[spawn 子 Agent] 层 职责 技术手段 是否经过 LLM 第 1 层 决定由哪个 Agent 处理 绑定规则优先级匹配 否 第 2 层 拦截斜杠命令 命令别名表匹配(正则仅用于粗判 token) 否 第 3 层 剥离内联指令,输出 cleaned 文本 正则管线 否 第 4 层 理解用户意图,决定行动 LLM + 系统提示词 + 记忆 是 下面分两章展开:第三章讲 Pre-LLM 层(1-3 层),第四章讲 LLM 层(第 4 层)。 三、Pre-LLM 层:确定性处理(第 1-3 层) 前三层的共同特点:不依赖 LLM,用确定性代码处理确定性的事情。 3.1 路由层 — 消息该发给哪个 Agent 核心文件:src/routing/resolve-route.ts 消息到达后,系统首先决定由哪个 Agent 处理。这不是意图分类,而是身份路由,按优先级匹配: 优先级 匹配方式 含义 1 binding.peer 私聊绑定到特定 Agent 2 binding.peer.parent 线程继承父消息的 Agent 3 binding.guild+roles Discord 服务器 + 角色匹配 4 binding.guild Discord 服务器级别匹配 5 binding.team Teams 团队绑定 6 binding.account 账户级别绑定 7 binding.channel 渠道级别绑定 8 default 兜底,使用默认 Agent 同一个 OpenClaw 实例可以运行多个不同的 Agent,每个 Agent 有自己的人格(SOUL.md)、工具集和技能。路由层确保消息到达正确的 Agent,之后的意图理解才有意义。 3.2 命令检测层 — 拦截结构化指令 核心文件:src/auto-reply/command-detection.ts 系统通过命令别名表(src/auto-reply/commands-registry.ts)做确定性匹配,检测消息是否为已注册的控制命令。正则只用于粗判"是否可能包含命令 token",服务于权限计算,不参与命令识别本身: 1 2 3 4 // 别名表匹配:检测是否为已注册命令 hasControlCommand(text) → boolean // 基于命令别名表 // 正则粗判:仅用于权限计算 hasInlineCommandTokens(text) → boolean // /[a-z] 或 ![a-z] 开头(仅用于粗判) 匹配到的命令不需要 LLM 参与,直接执行: /reset → 清空会话,创建新 session /status → 返回当前会话状态 /model gpt-4 → 切换模型 设计原则:确定性意图用确定性方式处理,不浪费 LLM 的推理能力。 需要注意的是,技能命令(/skillname 或 /skill <name> 格式)虽然也是 Pre-LLM 处理,但不属于命令检测层,也不属于指令解析层。技能命令的解析发生在指令解析之后、进入 LLM 之前的 inline actions 阶段(src/auto-reply/reply/get-reply-inline-actions.ts),系统从多个目录(extra → bundled → managed → agents personal → project → workspace)按优先级合并加载可用技能,匹配后直接路由到对应技能处理器。 3.3 指令解析层 — 提取内联参数 核心文件:src/auto-reply/reply/directive-handling.parse.ts、src/auto-reply/reply/directives.ts 如果消息不是控制命令,系统会检查其中是否夹带了内联指令: 1 2 3 @claude-opus 帮我重构这段代码 → 模型选择指令 /thinking high 分析这个 bug → 思考深度指令 /elevated on 执行部署脚本 → 权限提升指令 与第 2 层的区别:第 2 层判断消息整体是不是命令(是则直接执行,不进 LLM);第 3 层从消息中剥离内联指令,剩余文本继续送给 LLM。 (1)不是槽位抽取,是正则管线剥离 这套机制不是传统 NLU 的槽位模式(先分类意图,再提取参数),而是无意图分类的正则管线——依次扫描、发现就剥离、剩下的送 LLM。 (2)管线实现 parseInlineDirectives 函数依次调用 8 个提取器: flowchart LR A[原始消息] --> B[extractThinkDirective] B --> C[extractVerboseDirective] C --> D[extractReasoningDirective] D --> E[extractElevatedDirective] E --> F[extractExecDirective] F --> G[extractStatusDirective] G --> H[extractModelDirective] H --> I[extractQueueDirective] I --> J[cleaned 文本 → 送给 LLM]每个提取器核心逻辑一样(directives.ts:21-49): 1 2 3 // 正则匹配 /指令名 + 可选级别参数 const match = body.match(/(?:^|\s)\/(?:thinking|think|t)(?=$|\s|:)/i); // 匹配到后:提取参数 → normalize 校验 → 从原文删除 → 返回 cleaned 文本 实际效果: 1 2 3 4 5 6 7 输入: "帮我分析这段代码 /thinking high @claude-opus" ↓ extractThinkDirective → 提取 thinking=high extractModelDirective → 提取 model=claude-opus ↓ 输出: cleaned = "帮我分析这段代码" ← 这才送给 LLM 配置: { thinkLevel: "high", model: "claude-opus" } (3)8 类内联指令 全部硬编码在代码里,不可通过配置扩展。除了这 8 类 directives,系统还会单独识别少量内联简命令(如 /help、/commands、/whoami、/id 等),这些在 reply-inline.ts 中处理,不走 directive 管线: 指令 别名 参数值 作用 /thinking /think, /t high / medium / low / off 控制 LLM 思考深度 /verbose /v on / off 控制工具输出详细程度 /reasoning /reason on / off / stream 控制扩展推理 /elevated /elev on / off / ask / full 控制执行权限级别 /exec - host / security / ask / node 控制命令执行参数 /status - 无参数 查询会话状态(可内联使用) /model @别名 模型名或配置别名 切换模型 /queue - mode / debounce / cap / drop 控制消息队列行为 (4)权限控制 通过 commandAuthorized 标志控制:授权用户所有指令生效;未授权用户的指令-only 消息(只有指令没有正文)会被直接丢弃,含正文时部分指令可能被忽略或持久化(非敏感项),敏感指令不会生效。elevated 在不可用时会给出 unavailable 提示。群组场景中,未 @提及 bot 时 elevated 和 exec 指令也会被忽略(防误触发)。 3.4 Pre-LLM 层小结 三层协同完成一件事:把确定性的控制参数(模型、思考深度、权限)用正则处理掉,只把模糊的用户意图(到底要做什么事)留给 LLM。LLM 不需要浪费推理能力去理解 /thinking high,只需要专注于"帮我分析这段代码"这个真正的用户意图。 四、LLM 层:意图理解的核心阵地(第 4 层) 经过 Pre-LLM 三层处理后,cleaned 文本进入第 4 层。这一层做两件事:组装 LLM 能看到的世界,然后让 LLM 自主决策。 ...