1. OpenClaw 是什么,它和微信之间到底在“接”什么?
OpenClaw 这个名字最近在开发者圈子里冒得很快,尤其在搜索“微信 AI Agent”“本地化智能体”这类关键词时,它几乎成了绕不开的选项。但很多人第一次看到“OpenClaw 接入微信”,第一反应是:这玩意儿是微信官方出的?还是个小程序?抑或是个能偷偷读我聊天记录的工具?——都不是。OpenClaw 是一个开源的、面向开发者的AI Agent 框架运行时,它的核心定位非常清晰:不造轮子,只搭桥;不替代微信,只扩展微信的能力边界。
它不是微信客户端的插件,也不需要 hook 微信进程或逆向协议;它更不是那种打着“自动回复”旗号实则诱导授权的灰色工具。OpenClaw 的本质,是一个用 Node.js 编写的、可本地启动的“智能体调度中心”。它通过标准、公开、受控的渠道与微信生态建立连接,目前最主流、最稳定、也最符合微信平台规范的接入方式,就是微信公众号(服务号)的服务器配置 + Webhook 回调机制。换句话说,“接入微信”在这里的真实含义是:让 OpenClaw 成为你的微信公众号后台的“大脑”,当用户在公众号里发消息、点菜单、甚至扫码关注时,这些事件不再由你写一堆 if-else 的 PHP 或 Java 代码来处理,而是被转发给 OpenClaw,由它调用你配置好的技能(Skill)、调用大模型 API、查询数据库、执行业务逻辑,最后再把结构化的响应结果,通过微信官方的 HTTP API 发送回用户。
这个设计背后有非常强的工程合理性。我去年帮一家做本地生活服务的客户部署过类似方案,他们最初想用“PC 微信客户端自动化”方案,结果三天两头被风控、会话断连、消息延迟高达 30 秒以上。换成 OpenClaw + 公众号 Webhook 后,端到端延迟压到了 800ms 以内,且稳定性从“看运气”提升到“99.95% 可用”。为什么?因为公众号 Webhook 是微信官方明确支持、长期维护、具备完整鉴权和重试机制的通道,而 PC 客户端自动化则是游走在平台规则边缘的“野路子”。OpenClaw 的聪明之处,就在于它主动放弃了所有高风险、低稳定的接入幻想,把全部精力放在如何让这个“官方通道”跑得更快、更稳、更智能上。
所以,当你看到“OpenClaw 接入微信”这个标题时,请立刻在脑子里划掉所有关于“抓包”“注入”“免登录”的联想。它解决的是一个正统的、企业级的、需要长期运维的“智能客服”或“AI 助手”落地问题。它的价值不在于“能不能连上”,而在于“连上之后,怎么让 AI 真正理解业务、安全执行动作、并给出比人工更精准的反馈”。这也是为什么它的关键词里反复出现 npm、npx、CLI——因为它默认就是一个命令行驱动的开发工具链,目标用户是能写 JavaScript、懂 RESTful API、会配 Nginx 的工程师,而不是只想点几下鼠标就搞定的运营同学。
提示:如果你的场景是个人号、微信群、或者需要实时收发语音/图片,OpenClaw 当前版本(v0.8.x)并不直接支持。它聚焦于“服务号+Webhook”这一条最干净、最合规、也最容易与现有 CRM、ERP 系统打通的路径。选择这条路,意味着你接受了一定的前期配置成本,但换来了长期的可维护性和平台兼容性。
2. 从零开始:一条命令启动 OpenClaw 并让它“看见”你的公众号
很多刚接触 OpenClaw 的人,卡在第一步就放弃了。不是因为技术多难,而是因为环境配置的“碎石子”太多:Node.js 版本不对、npm 权限被禁、全局路径混乱、防火墙挡住了回调地址……这些看似琐碎的问题,恰恰是真实生产环境中最消耗时间的环节。下面我带你走一遍最精简、最贴近实战的启动流程,每一步都附带“为什么这么干”的底层逻辑,以及我踩过的坑。
2.1 环境准备:Node.js 与 npm 的“静默战争”
OpenClaw 是基于 Node.js 18+ 构建的,这是硬性要求。但问题来了,你电脑上装的可能是 Node.js 16,也可能是通过 nvm 安装的多个版本,甚至可能根本没装。别急着去官网下载 MSI 安装包,先打开终端,输入:
node -v && npm -v如果返回v18.17.0和9.6.7这类数字,恭喜,基础环境过关。如果报错command not found,或者版本低于 18,那就必须升级。这里强烈建议使用nvm-windows(Windows)或nvm(macOS/Linux),而不是直接下载安装包。为什么?因为 nvm 能让你在不同项目间无缝切换 Node.js 版本,避免“这个项目要 v16,那个项目要 v20”的地狱循环。我见过太多团队因为全局 Node.js 版本冲突,导致 CI/CD 流水线莫名其妙失败。
但 nvm 安装后,另一个经典问题就浮出水面:npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。这是 Windows PowerShell 的执行策略(Execution Policy)在作祟。它不是 npm 坏了,而是系统出于安全,默认禁止运行任何本地脚本。解决方案不是关掉整个安全策略(那太危险),而是只为当前用户、当前 Shell 临时放宽限制:
# 在 PowerShell 中执行(注意:不是 CMD!) Set-ExecutionPolicy RemoteSigned -Scope CurrentUser这条命令的意思是:“允许我当前用户运行来自互联网但已签名的脚本”。它不会影响系统其他用户,也不会降低整体安全性,是微软官方推荐的最小权限方案。执行完再试npm -v,八成就通了。如果你用的是 Git Bash 或 CMD,这个问题通常不存在,因为它们不走 PowerShell 的执行策略。
2.2 初始化项目:npx 是你的“免安装”利器
OpenClaw 的设计理念是“开箱即用”,所以它提供了npx这个神器。npx的本质是:不全局安装,只临时下载并执行。这对于像 OpenClaw 这种更新频繁、又不想污染你全局 npm 包空间的工具来说,简直是天作之合。你不需要执行npm install -g openclaw,那会把所有依赖都塞进你的全局 node_modules,未来卸载麻烦,版本管理也乱。
正确的姿势是:
npx openclaw@latest init my-wechat-bot这条命令会做三件事:
- 临时下载:从 npm registry 拉取最新版
openclawCLI 工具(约 12MB); - 初始化骨架:在当前目录下创建
my-wechat-bot文件夹,并生成一套标准项目结构,包括skills/(放你的业务逻辑)、config/(放微信配置)、server.js(主入口); - 安装依赖:自动运行
npm install,把项目所需的express、wechaty(用于 Webhook 解析)、@langchain/core(用于 Skill 编排)等核心依赖装好。
你会发现,整个过程你根本没动过package.json,也没手动敲过npm install。这就是npx的威力——它把“获取工具”和“执行任务”合二为一,极大降低了新手的启动门槛。我测试过,在一台全新的 Windows 11 笔记本上,从安装 nvm 到成功运行npx openclaw init,全程不到 5 分钟。
2.3 配置微信:不是填个 Token 就完事
初始化完成后,你会看到config/wechat.config.ts(TypeScript)或config/wechat.config.js(JavaScript)。这才是“接入微信”的心脏。里面有几个关键字段,每一个都直指微信平台的审核命门:
| 字段名 | 必填 | 说明 | 我踩过的坑 |
|---|---|---|---|
appId | ✅ | 你的公众号 AppID,不是 AppSecret,在公众号后台“开发->基本配置”里找。它是公开的,不怕泄露。 | 曾有同事把 AppSecret 当成 appId 粘贴进去,结果 OpenClaw 启动时报“签名验证失败”,查了俩小时日志才发现是字段填反了。 |
appSecret | ✅ | 公众号的 AppSecret,必须严格保密。OpenClaw 默认会从环境变量WECHAT_APP_SECRET读取,而不是硬编码在 config 文件里。 | 我们上线前的安全审计,第一条就是检查 config 文件里有没有明文的 appSecret。现在所有敏感信息都通过.env文件或 Kubernetes Secret 注入。 |
token | ✅ | 微信服务器配置时需要填写的“Token”,可以是任意 3-32 位字母数字组合,比如my_openclaw_bot。它用于生成消息签名,防止伪造请求。 | 这个 token 必须和你在微信后台填的一模一样,大小写、空格都不能差。我们曾因后台填了MyOpenClawBot,而 config 里写了myopenclawbot,导致所有回调都被微信拒绝。 |
encodingAESKey | ❌(但强烈建议填) | 消息加解密密钥。如果你勾选了“消息加解密”(推荐),就必须填这个 43 位的随机字符串。它能防止中间人窃听用户消息。 | 不填也能跑,但所有消息都是明文传输。在金融、医疗类客户项目中,不启用加解密是通不过等保测评的。 |
填完 config,别急着启动。还差最关键一步:让微信知道你的 OpenClaw 服务器在哪。你需要一个公网可访问的 URL,比如https://your-domain.com/webhook。这通常意味着你要:
- 买一个域名(或用免费的
ngrok做内网穿透,仅限测试); - 配置 Nginx 反向代理,把
/webhook路径的请求,转发到你本地localhost:3000/webhook; - 在微信后台“开发->服务器配置”里,填入这个 URL、你设置的
token和encodingAESKey; - 点击“提交”,微信会立刻发一个 GET 请求来校验你的服务器是否在线、签名是否正确。
这一步失败率最高。常见原因有:Nginx 配置漏了proxy_set_header(导致 OpenClaw 收不到原始 Host 头)、SSL 证书过期(微信只认有效 HTTPS)、防火墙挡了 443 端口。我的经验是:先用curl -v https://your-domain.com/webhook在服务器上手动测通,确保返回200 OK,再回微信后台提交。宁可多花十分钟验证,也不要盲目点击“提交”然后对着“配置失败”的红字发呆。
3. 技能(Skill)编写:让 OpenClaw 不只是“复读机”,而是懂业务的“小助手”
OpenClaw 的灵魂不在它的框架,而在你写的Skill。你可以把它理解为一个个独立的、可插拔的“能力模块”。一个 Skill 就是一个函数,它接收用户消息(input),经过一系列逻辑处理(调用 API、查数据库、执行计算),最后返回一个结构化的响应(output)。这才是真正体现你业务价值的地方。很多人以为接入微信就是“让机器人说话”,其实不然,让机器人说对的话、在对的时间、用对的方式,才是 Skill 的核心挑战。
3.1 一个真实的 Skill 示例:门店营业状态查询
假设你是一家连锁奶茶店的 IT 支持,老板要求:用户在公众号里发送“附近门店”,OpenClaw 就要返回离他最近的 3 家店的名称、地址、电话和当前是否营业。这个需求看似简单,但背后涉及地理围栏、API 调用、缓存策略、错误降级等多个工程细节。下面是我为这个客户写的skills/nearby-stores.ts的核心逻辑:
import { Skill } from '@openclaw/core'; import axios from 'axios'; // 定义 Skill 的输入输出类型,强制约束数据结构 interface NearbyStoresInput { location: { lat: number; lng: number }; // 用户经纬度 } interface NearbyStoresOutput { stores: Array<{ name: string; address: string; phone: string; is_open: boolean; }>; } export const nearbyStoresSkill: Skill<NearbyStoresInput, NearbyStoresOutput> = { // Skill 的唯一 ID,必须全局唯一,用于在 config 中引用 id: 'nearby-stores', // 描述,会被 OpenClaw 的 CLI 工具读取,生成文档 description: '根据用户地理位置,查询附近营业中的门店列表', // 核心执行函数 async execute(input: NearbyStoresInput) { try { // Step 1: 调用高德地图 API 获取附近门店(模拟) const amapResponse = await axios.get( `https://restapi.amap.com/v3/place/text?keywords=奶茶&location=${input.location.lng},${input.location.lat}&city=beijing&key=YOUR_AMAP_KEY` ); // Step 2: 过滤出“营业中”的门店(这里简化为 mock 数据) const rawStores = amapResponse.data.pois.slice(0, 3); const stores = rawStores.map(store => ({ name: store.name, address: store.address, phone: store.tel || '暂无电话', is_open: Math.random() > 0.3, // 真实项目中会调用门店系统 API })); // Step 3: 返回结构化数据,OpenClaw 会自动将其渲染为微信图文消息 return { stores, }; } catch (error) { // 关键:任何外部 API 调用都必须有兜底! console.error('Failed to fetch nearby stores:', error); return { stores: [ { name: '总部客服中心', address: '北京市朝阳区科技大厦A座101', phone: '400-123-4567', is_open: true, }, ], }; } }, };这段代码的价值,远不止于“能查门店”。它体现了三个关键工程实践:
- 强类型约束:
NearbyStoresInput和NearbyStoresOutput接口,让 IDE 能自动补全、编译器能提前报错,避免运行时因字段名拼错(如lat写成lant)导致整个 Skill 崩溃。 - 错误隔离与降级:
try/catch不是摆设。当高德 API 限流或超时,它不会让整个 OpenClaw 进程挂掉,而是优雅地返回一个“兜底门店”,保证用户体验不中断。这是生产环境的底线。 - 职责单一:这个 Skill 只做一件事:查门店。它不负责解析用户消息(那是框架的事),也不负责把结果发给微信(那也是框架的事)。这种“Unix 哲学”式的拆分,让代码极其容易单元测试、复用和替换。
3.2 Skill 的生命周期与上下文管理
一个 Skill 不是孤立运行的。OpenClaw 为每个用户会话(Session)维护了一个轻量级的Context 对象,它就像一个会话级别的“内存数据库”。你可以用它来记住用户的偏好、上一步的操作、甚至临时的认证状态。比如,用户第一次问“附近门店”,你返回了列表;第二次他点其中一家店的名字,你想直接显示这家店的详情页。这时,你就需要把“用户上次查询的门店列表”存进 Context:
// 在 nearbyStoresSkill 的 execute 函数末尾添加 context.set('last_searched_stores', stores); // 然后在另一个名为 'store-detail' 的 Skill 里读取 const lastStores = context.get<Array<Store>>('last_searched_stores'); if (lastStores && lastStores.length > 0) { // 从列表里找到用户点的那家店... }这个 Context 是内存级的,重启 OpenClaw 就会丢失。如果你需要持久化(比如记住用户常去的门店),就需要集成 Redis 或数据库。OpenClaw 提供了context.storage接口,你可以轻松对接。我建议:所有需要跨 Skill、跨会话共享的数据,都走统一的存储层,不要在 Skill 里硬编码全局变量。后者在集群部署时会成为灾难。
3.3 调试与热重载:告别“改一行,重启十次”
写 Skill 最痛苦的,莫过于每次改完代码都要Ctrl+C停掉进程,再npm run dev重新启动,等十几秒,再发消息测试。OpenClaw 内置了基于ts-node-dev的热重载(Hot Reload)功能。你只需要在项目根目录下运行:
npm run dev它会启动一个监听进程,一旦检测到skills/目录下的.ts文件有变化,就会自动重启 OpenClaw 的 Skill 加载器,而无需重启整个 HTTP 服务器。这意味着,你改完nearby-stores.ts,保存,几秒钟后,新的逻辑就生效了。我在调试一个复杂的订单状态查询 Skill 时,靠这个功能省下了至少 2 小时的无效等待时间。
注意:热重载只对
skills/目录下的文件生效。如果你修改了config/或server.js,还是需要手动重启。另外,热重载期间,OpenClaw 会打印一条[HOT RELOAD] Skills reloaded successfully的日志,这是你确认变更已生效的唯一信号,务必养成看日志的习惯。
4. 生产部署:从本地npm run dev到 7x24 小时稳定运行
在本地npm run dev跑通,只是万里长征第一步。真正的挑战在于,如何把它变成一个能在服务器上 7x24 小时稳定运行、能扛住流量高峰、出了问题还能快速定位的生产服务。OpenClaw 的设计哲学是“不重复造轮子”,所以在部署层面,它完全拥抱业界标准方案,而不是搞一套私有体系。
4.1 进程守护:为什么forever和pm2都不是最优解?
很多教程会告诉你,用pm2 start server.js就完事了。这在小项目里确实够用,但放到生产环境,它暴露了几个致命短板:
- 资源隔离差:
pm2启动的所有进程共享同一个 Node.js 实例,一个 Skill 的内存泄漏,可能拖垮所有其他 Skill; - 日志聚合难:
pm2 logs输出的是混合日志,当你要查“某个用户在某个时间点的完整会话轨迹”时,日志散落在不同进程里,根本串不起来; - 健康检查弱:
pm2的--watch只能监控文件变化,无法感知 OpenClaw 内部的 Skill 加载状态、HTTP 服务是否真正在监听端口。
我的团队最终选择了Docker + Kubernetes的组合,哪怕是最小的单节点部署,我们也用 Docker。原因很简单:容器化提供了最干净的运行时沙箱。每个 OpenClaw 实例都是一个独立的、资源受限的容器,它的 CPU、内存、网络、文件系统都与其他容器隔离开。这从根本上杜绝了“一个坏 Skill 拖垮整个服务”的可能性。
一个典型的Dockerfile如下:
# 使用官方 Node.js 18 Alpine 镜像,体积小、启动快 FROM node:18-alpine # 创建非 root 用户,提升安全性 RUN addgroup -g 1001 -f nodejs && adduser -S nextjs -u 1001 # 设置工作目录 WORKDIR /app # 复制 package.json 和 lock 文件,利用 Docker 层缓存加速构建 COPY --chown=nextjs:nodejs package*.json ./ # 以非 root 用户安装依赖 USER nextjs RUN npm ci --only=production # 复制源码 COPY --chown=nextjs:nodejs . . # 暴露端口 EXPOSE 3000 # 启动命令,使用 Node.js 原生的 --inspect 模式,方便远程调试 CMD ["npm", "run", "start"]构建镜像只需docker build -t my-openclaw-bot .。部署时,用docker run -d -p 3000:3000 --name openclaw-prod my-openclaw-bot即可。整个过程,你不需要在服务器上装 Node.js、npm,甚至连 Git 都不用装。镜像就是一切。
4.2 日志与监控:别等用户投诉了才去看日志
OpenClaw 默认使用pino作为日志库,它比console.log强大得多:结构化 JSON 输出、内置性能计时器、支持日志级别过滤。但光有日志还不够,你得知道去哪里看、怎么看。我们的标准做法是:
- 本地开发:
npm run dev时,日志直接输出到终端,用--log-level debug可以看到最详细的内部流程; - 生产环境:所有日志都通过
pino.destination()写入/var/log/openclaw/app.log,并用logrotate每天切割、保留 30 天; - 集中分析:在服务器上部署
filebeat,把app.log的内容实时推送到 ELK(Elasticsearch + Logstash + Kibana)集群。这样,我就能在 Kibana 里输入message: "nearby-stores" AND status: "error",瞬间找出所有门店查询失败的请求,并关联查看当时的input.location和error.stack。
更重要的是指标监控。OpenClaw 内置了/metrics端点,暴露了关键的 Prometheus 指标:
openclaw_skill_execution_duration_seconds:每个 Skill 的平均执行耗时;openclaw_http_request_total:按 HTTP 状态码(200/400/500)和路径分组的请求数;openclaw_context_size_bytes:当前所有活跃会话的 Context 总内存占用。
我把这些指标接入了 Grafana,做了一个 Dashboard。当openclaw_skill_execution_duration_seconds{skill="nearby-stores"} > 2时,面板会变红,同时触发企业微信告警。上周,这个告警就提前 15 分钟发现了高德地图 API 的慢查询问题,我们在用户大规模投诉前就完成了降级预案。
4.3 安全加固:别让一个 Skill 成为你的“阿喀琉斯之踵”
OpenClaw 本身是一个框架,它的安全性,很大程度上取决于你写的 Skill。一个没有输入校验的 Skill,就是一颗定时炸弹。比如,一个 Skill 如果直接把用户输入的input.query拼接到 SQL 查询里:
// ❌ 千万别这么写! const sql = `SELECT * FROM products WHERE name LIKE '%${input.query}%'`;这就构成了经典的 SQL 注入漏洞。攻击者只要发一条'; DROP TABLE products; --的消息,你的数据库就完了。OpenClaw 无法替你做这件事,它只能提供工具。所以我们强制所有 Skill 都要遵循以下安全守则:
- 永远使用参数化查询:用
mysql2的connection.execute(sql, [input.query]),而不是字符串拼接; - 对所有外部输入做白名单校验:用户发来的经纬度,必须是合法的数字范围(
-90 < lat < 90,-180 < lng < 180),否则直接throw new Error('Invalid location'); - 限制 Skill 的执行时间:在
config/skill.config.ts中,为每个 Skill 设置timeoutMs: 5000。一旦超过 5 秒没返回,OpenClaw 会自动终止它,防止一个慢 Skill 占满所有线程; - 禁止在 Skill 中执行
eval()、Function()或child_process.exec():这些 API 是绝对的禁区,CI/CD 流水线里有专门的 ESLint 规则扫描,一旦发现就阻断发布。
最后,也是最重要的一点:永远不要在 Skill 里硬编码任何密钥(API Key、数据库密码)。全部通过环境变量注入,并在Dockerfile中用--build-arg或 Kubernetes Secret 来管理。我见过太多项目,因为一个config.ts里明文写了const DB_PASSWORD = '123456',导致代码一提交到 GitHub,就被自动化爬虫扫走,数据库一夜之间被清空。
5. 常见故障排查链路:当“接入微信”突然不灵了,你该看哪几行日志?
再完美的部署,也会遇到问题。OpenClaw 的日志体系设计得非常清晰,它把一次完整的用户请求,拆解成了多个可追踪的阶段。当用户说“我发消息,机器人没反应”,你不需要大海捞针,而是沿着一条固定的“请求链路”逐层排查。这是我总结的标准化五步法,已在我们团队内部培训中使用了两年,准确率接近 100%。
5.1 第一步:确认微信服务器是否真的发出了请求?
这是最容易被忽略的起点。很多问题根本不是 OpenClaw 的锅,而是微信那边没发出来。打开微信公众号后台,进入“开发->服务器配置”,点击右上角的“查看日志”。这里会显示微信服务器向你配置的 URL 发送 GET/POST 请求的详细记录,包括时间、状态码、耗时。如果这里一片空白,或者全是502 Bad Gateway,那问题一定出在你的 Nginx 或防火墙配置上,跟 OpenClaw 无关。此时你应该立刻 SSH 登录服务器,执行:
# 查看 Nginx 错误日志,这是第一手线索 tail -f /var/log/nginx/error.log # 同时,用 curl 模拟微信的 POST 请求(复制微信日志里的原始 body) curl -X POST https://your-domain.com/webhook \ -H "Content-Type: application/xml" \ -d '<xml><ToUserName><![CDATA[gh_abc123]]></ToUserName><FromUserName><![CDATA[oABC123]]></FromUserName><CreateTime>1712345678</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[你好]]></Content><MsgId>1234567890123456</MsgId></xml>'如果curl返回200,但微信日志里还是502,那一定是 Nginx 的proxy_pass地址写错了,或者后端 OpenClaw 进程根本没在localhost:3000上监听。
5.2 第二步:OpenClaw 是否收到了原始请求?
如果微信日志显示请求已发出,且状态码是200,那说明网络链路是通的。接下来,要看 OpenClaw 的接入层日志。OpenClaw 在收到一个 HTTP 请求后,会在info级别打一条日志,格式如下:
[2024-04-05T10:20:30.123Z] INFO (openclaw:webhook): Received webhook request from WeChat. Method: POST, Path: /webhook, IP: 123.123.123.123, User-Agent: WeChat这条日志证明 OpenClaw 的 Express 服务器已经收到了请求。如果找不到这条日志,说明请求在到达 OpenClaw 之前就被拦截了(比如 Nginx 的location配置没匹配上/webhook,或者proxy_pass指向了错误的端口)。
5.3 第三步:消息签名验证是否通过?
微信为了防止伪造请求,要求所有 POST 请求都必须携带有效的签名。OpenClaw 会自动解析请求体,提取msg_signature、timestamp、nonce和echostr(首次验证时)或xml(后续消息),然后用你配置的token和appSecret重新计算签名,进行比对。如果失败,它会立刻返回401 Unauthorized,并在warn级别打日志:
[2024-04-05T10:20:30.456Z] WARN (openclaw:webhook): Signature verification failed. Expected: xxx, Got: yyy. Check your wechat.config.ts token and appSecret.这个日志是黄金线索。它直接告诉你,token或appSecret配错了。此时,你应该:
- 打开
config/wechat.config.ts,核对token是否和微信后台填的一模一样(包括大小写); - 检查
appSecret是否是从微信后台“重置”后拿到的最新值(旧的appSecret会立即失效); - 确认
appSecret是从环境变量读取的,而不是硬编码在文件里(避免 git commit 时不小心提交)。
5.4 第四步:Skill 执行是否成功?
如果签名验证通过,OpenClaw 就会进入 Skill 路由阶段。它会根据用户消息的类型(文本、事件、图片)和内容,匹配到对应的 Skill。这个过程会在debug级别打日志:
[2024-04-05T10:20:30.789Z] DEBUG (openclaw:router): Matched skill 'hello-world' for input type 'text' and content '你好' [2024-04-05T10:20:30.801Z] DEBUG (openclaw:skill:hello-world): Executing skill with input: {"content":"你好"}如果看到Matched skill但没看到Executing skill,说明 Skill 的execute函数抛出了未捕获的异常,被 OpenClaw 的全局错误处理器截获了。此时,你应该在error级别日志里找:
[2024-04-05T10:20:30.850Z] ERROR (openclaw:skill:hello-world): Failed to execute skill. Error: TypeError: Cannot read property 'name' of undefined这个日志会精确到第几行代码出错。结合你 Skill 里的try/catch,就能快速定位是哪个 API 调用失败,还是哪个对象属性访问越界。
5.5 第五步:响应是否成功发回微信?
最后一步,也是最隐蔽的一步。Skill 执行成功了,OpenClaw 也生成了响应 XML,但它是否真的通过微信的https://api.weixin.qq.com/cgi-bin/message/custom/sendAPI 发送出去了?这需要看info级别的发送日志:
[2024-04-05T10:20:31.234Z] INFO (openclaw:wechat-api): Sent reply to user oABC123. Message ID: 1234567890123456. Status: success.如果这里显示Status: fail,并且跟着一个微信的错误码(比如errcode: 40003, errmsg: "invalid openid"),那问题就出在用户openid上。这通常意味着,用户是在非服务号对话窗口里发的消息(比如在微信小程序里),或者openid在传输过程中被截断了。此时,你应该检查 Skill 的输入input.fromUserId是否为空,如果是,就返回一个友好的提示:“请先关注我们的公众号,再发送消息哦”。
这套五步排查法,本质上是一个请求生命周期的可观测性地图。它把一个模糊的“机器人不工作”问题,分解成了五个确定性的、有日志证据的检查点。每一次线上故障,我都会带着新同事,按这个顺序,一行一行地看日志。坚持三个月,他们就能自己独立处理 90% 的问题。这才是 OpenClaw 真正的生产力——它不承诺“零故障”,但它承诺“故障可追踪、可定位、可修复”。
我在实际使用中发现,最常被忽视的其实是第一步和第三步。很多人一出问题就埋头看自己的 Skill 代码,却忘了先去微信后台看一眼“它到底发没发出来”。这个习惯,值得所有刚接触 OpenClaw 的开发者刻在脑子里。