对虾:虾哥小智AI和OpenClaw合体

OpenClaw的热度还是没有下去,看来我还能蹭一波,不过今天还是带来一点有意思的东西,那就是把OpenClaw接入到虾哥的小智AI。
不同于手机APP和电脑程序接入OpenClaw,运行在开发板上的小智AI有它自己的特点。它自身的产品形态就适合自然语言对话,倾向于更为自然的交流,我们都有过这样的经历,当你和朋友聊天聊到了一些精彩的内容,你滔滔不绝妙语连珠,但是回头想把它用文字记录下来的时候你会发现怎么写怎么别扭,只能在文字上添油加醋,最后还是会留下许多遗憾,甚至你笔下的自己都不像自己。所以更为自然的交流包含了真实的自己。
现在流行“养龙虾”也就是调教OpenClaw,希望OpenClaw更懂你,那么最重要的一点就是你把最真实的自己交给龙虾,为此,小智AI这种对话盒子的形态可能更适合帮助你养龙虾。所以这次使用小智AI对接OpenClaw其实还是挺有意思的。

那么这件有意思的事情需要我们准备什么东西呢:一个ESP32开发板及配件(网上有现成的可以直接购买)、一台电脑,还有就是你用起来顺手的vibe coding工具。
这个事情涉及到固件编写及烧录、小智服务端程序编写、OpenClaw的channel插件编写。看上去是不是很复杂,不用担心,其实固件、小智服务端程序、channel插件我都已经编写完毕上传到了GitHub上,你要做的只是下载安装,把它们配置起来就好了。
不过这里还是要说明下整个软件系统的工作流程,以便大家能够很好的理解它的原理,一旦出了问题大家也能自行解决。

整条链路可以理解成一个接力赛:

  1. ESP32 小智终端 负责采集语音,发给服务端。
  2. xiaozhi-server 负责把语音变成文字,再把文字转交给 OpenClaw。
  3. myapp-channel 插件负责把 OpenClaw 和 xiaozhi-server 连起来。
  4. OpenClaw 负责真正的智能体处理,也就是“理解问题、思考、生成回答”。
  5. 回答再一路返回给 xiaozhi-server,由它转成语音。
  6. 最终语音再发回 ESP32 小智终端 播放出来。

说白了:

小智负责听和说,xiaozhi-server 负责搬运和转换,OpenClaw 负责思考。


一张图先看懂

如果把它拟人化一点:

  • 小智终端像一个“麦克风 + 音箱”
  • xiaozhi-server 像一个“翻译官 + 调度员”
  • OpenClaw 像一个“大脑”
  • myapp-channel 像一根“专线电话”

我们一步一步来实现。


第一部分 先从终端开始 完成固件修改和烧录

终端硬件可以从淘宝购买,我买到硬件如下图所示,是一个组装好的小智AI硬件形态。

虾哥小智AI固件是开源的,为此我们可以随意修改固件,不过不用担心,这种修改很简单,就是把小智AI连接虾哥服务器的地址改成我们自己服务器的地址,这一步仅仅需要修改几行代码。

接下来就是下载固件源码–修改源码–编译–烧录,整个过程虾哥有文档说明很详细,大家可以参考这个链接(Windows搭建 ESP IDF 5.5.3开发环境以及编译小智 – 飞书云文档),这里我只把关键步骤描述下:


1.下载固件

我使用git命令,将源码克隆到本地目录(建议目录路径中不要有中文和空格)

   git clone https://github.com/78/xiaozhi-esp32.git

2.下载编译环境ESP-IDF

地址:https://dl.espressif.com/dl/esp-idf/,下载完成后双击安装包,一路下一步即可。

3.进入IDF环境

双击桌面上的PowerShell会自动导入IDF环境,电脑安装了Windows Terminal(win11自带,win10可以搜索store打开商店安装)的可以直接打开终端,终端的+号可以直接运行IDF环境

4.在IDF环境中进入工作目录

在刚才打开的PowerShell中使用cd命令进入到刚才GitHub克隆下来的项目的目录里。

5.修改固件源码

先修改固件源码。由于虾哥的文档中有提到“最新的1.6.2版本已经取消了从menuconfig配置websocket接口的源码,最新源码是从OTA接口接收websocket的api接口,无法自己设置,需要切换到1.6.0或者以下才可以”,所以这里我们也不切换到1.6.0了,直接修改固件源码里负责和小智AI后台服务通讯的模块,屏蔽OTA的代码,将链接方式默认为WebSocket,并且将WebSocket连接地址改为你的服务器地址,我这里用的是内网服务器,所以我改成了192.168.2.3。

一共修改了两个文件:

第一个文件是 application.cc

找到以下代码,将这段代码改为一行:

   if (ota_->HasMqttConfig()) {
       protocol_ = std::make_unique<MqttProtocol>();
   } else if (ota_->HasWebsocketConfig()) {
       protocol_ = std::make_unique<WebsocketProtocol>();
   } else {
       ESP_LOGW(TAG, "No protocol specified in the OTA config, using MQTT");
       protocol_ = std::make_unique<MqttProtocol>();
   }

修改为:

   protocol_ = std::make_unique<WebsocketProtocol>();

第二个文件是 protocols/websocket_protocol.cc

将以下代码:

   std::string url = settings.GetString("url");

改为自己的服务器地址,这里要写自己实际的地址:

   std::string url = "ws://192.168.2.3:8080";

6. 编译准备及编译

确认在PowerShell中已经进入了项目根目录,确认自己板子的型号,默认的编译芯片是ESP32的,所以自己的板子是S3的话一定要输入以下命令把芯片设置为S3

   idf.py set-target esp32s3

开始编译,再次输入 idf.py build 进行编译:

   idf.py build

7. 烧录到设备中

确认你的ESP32设备已经连接到了计算机,编译完成后输入 idf.py build flash monitor 进行下载和显示日志。

   idf.py build flash monitor

至此硬件部分的操作就完成了,现在可以打开开发板,唤醒小智,如果显示“链接中….”,而且一直连不上,那么恭喜你,刷机成功了。接下来就是完成小智后台服务的搭建。

第二部分 开发和部署小智后台服务端

前文已经说了,小智后台服务类似一个桥,将小智和OpenClaw连接起来,而且完成语音到文字和文字到语音的转换。

理论上这里需要你自己开发属于自己的小智后台服务端,你可能有各种各样的想法,想让小智变得更智能,响应速度更快,因为并非所有的请求都要发送到OpenClaw,这个“桥”上你可以增加各种逻辑。

但是我们现在的目的是把项目跑通,最主要的就是完成小智和OpenClaw的连接,在本文中提供了一个最小的但是开箱可用小智后台服务端程序。

在虾哥的GitHub上当然也介绍了一个优秀的第三方小智后台服务,如果你有时间,并且想让小智获得更多的能力,你可以基于这些第三方的小智后台服务进行二次开发。

但是如果你仅仅是想将小智连接到OpenClaw而且不想编写任何代码,那么你可以尝试下我的这个轻量级的小智后台服务。我已经把它放到了GitHub上,地址是:

https://github.com/frogchou/xiaozhi-openclaw

这里还是要说明下这个小智后台服务的原理和结构,如果后期你想修改它,这个说明可以帮你少走弯路。当然前期你可以选择直接用它而不进行任何修改。

如果把整个系统比作一条路,那么 xiaozhi-server 就是中间那座桥。

它前面连接的是 ESP32 小智终端,后面连接的是 OpenClaw。小智终端负责“听”和“说”,OpenClaw 负责“思考”,而 xiaozhi-server 负责把两边顺畅地接起来。

通俗一点说,它主要做四件事:

  1. 接收小智终端上传的语音音频流
  2. 把语音转成文字
  3. 把文字转交给 OpenClaw 获取回复
  4. 把 OpenClaw 返回的文字再转成语音,发回小智终端播放

所以它不是“大脑”,更像一个语音交互的“调度中心”。

也可以顺手补一句更口语化的总结:
小智终端负责采集和播放,OpenClaw 负责生成答案,xiaozhi-server 负责把这整套流程真正跑起来。


xiaozhi-server 的目录结构

xiaozhi-server 的目录不复杂,核心主要分成 4 部分:

  • core/
    放核心流程,比如 WebSocket 服务入口、设备会话管理、消息处理流程。
  • services/
    放具体服务逻辑,比如语音识别、文字转语音、OpenClaw bridge 通信。
  • utils/
    放工具代码,比如音频转换、日志处理。
  • config.py / .env
    放运行配置,比如端口、OpenAI 参数、OpenClaw bridge 参数。

大致结构如下:

xiaozhi-server/
├── main.py                 # 程序启动入口
├── config.py               # 配置读取
├── .env / .env.example     # 环境变量配置
├── requirements.txt        # Python 依赖
├── core/
│   ├── server.py           # WebSocket 服务入口
│   ├── session.py          # 设备会话和一轮对话处理
│   └── protocol.py         # 小智终端通信协议编解码
├── services/
│   ├── asr.py              # ASR / LLM / TTS 相关逻辑
│   ├── openclaw_bridge.py  # 与 OpenClaw 的桥接通信
│   └── openclaw_channel.py # 旧方案残留文件
└── utils/
    ├── audio_converter.py  # 音频格式转换
    └── logger.py           # 日志工具

xiaozhi-server 的主要功能

从功能上看,xiaozhi-server 主要承担了下面这些角色:

1. 设备接入层

它通过 WebSocket 和小智终端保持连接,接收终端上传的音频帧,并把最终语音结果再推回终端。

2. 语音处理层

它会先把终端发来的音频帧整理成标准音频,再做 ASR,把“声音”变成“文字”。

3. AI 调度层

拿到文字以后,它不会自己生成回答,而是通过 myapp-channel 对应的桥接协议,把请求发给 OpenClaw。

4. 语音返回层

OpenClaw 返回文本回答后,它会再做 TTS,把文字重新变成语音音频包,再发回小智终端播放。

运行方式可以这样写:


xiaozhi-server 是怎么运行的

xiaozhi-server 是一个 Python 项目,启动方式比较直接。

1. 安装依赖

pip install -r requirements.txt

2. 配置环境变量

主要配置写在 .env 里,例如:

  • 服务监听地址和端口
  • OpenAI 的 ASR / TTS 配置
  • OpenClaw bridge 的路径和 token

其他的配置可以保持默认。

3. 启动服务

python main.py

启动后,它会监听一个 WebSocket 服务端口,等待两类连接:

  1. 小智终端的设备连接
  2. OpenClaw myapp-channel 插件建立的 bridge 长连接

如果你想在博文里再更顺一点,可以加一小段“项目定位”:

以上就是 xiaozhi-server 也就是小智后台服务的整个介绍,如果你按照以上的步骤操作完毕了,那么小智后台服务已经可以正常的运行了,测试方法也很简单,那就是用你的开发板,这时你唤醒小智,那么它应该显示“链接中…”,这里只需稍等,就会进入“聆听中…”,如果出现这个提示,那么就证明小智后台服务运行正常。

第三部分 开发并安装自己的OpenClaw channel

那么接下来,就要开发自己的channel,这方面我属实不是专家,只是翻阅了下官方文档,大致了解了一下它的原理,然后使用vibe coding让AI帮我写了一个channel,这个channel和小智后台服务之间使用WebSocket维持了一个长连接,channel内部的实现完全是AI生成的,当然它目前是可用的,这部分代码我也上传到了GitHub,如果你和我一样不想折腾,那么你可以尝试下我的这个channel插件,它的安装和配置也很简单。GitHub的地址如下:

https://github.com/frogchou/xiaozhi-openclaw

但是在开始之前,你最好还是先了解下什么是channel,为此我还是进行了一下说明。看完说明后可能更有助于你安装我开发的这个channel插件。

在 OpenClaw 里,channel 可以理解成“消息入口”和“消息出口”。

它的作用,就是把外部世界的消息,接进 OpenClaw;再把 OpenClaw 生成的回复,送回外部世界。

如果把 OpenClaw 想成一个 AI 大脑,那 channel 就像它的“耳朵”和“嘴巴”。

比如常见的 Telegram、Slack、Discord 这类接入方式,本质上都是不同的 channel。
它们虽然面对的平台不同,但做的事情其实类似:

  1. 接收外部消息
  2. 把消息转换成 OpenClaw 能理解的格式
  3. 交给 OpenClaw 的 agent 处理
  4. 再把处理结果发送回原来的平台

所以,channel 的本质其实就是一层“适配器”。

它把外部平台的协议、身份、会话、消息结构,翻译成 OpenClaw 内部统一的处理方式。这样 OpenClaw 不需要关心消息到底来自 Telegram、Slack,还是你自己写的系统。


为什么我要自己开发一个 myapp-channel

我这里的场景并不是 Telegram 或 Slack,而是一套自己的语音对话系统:

  • 前端是 ESP32 小智终端
  • 中间是 xiaozhi-server
  • 后面是 OpenClaw

这时候就有一个现实问题:

xiaozhi-server 发来的消息,OpenClaw 默认并不认识。

OpenClaw 能处理的是“标准 channel 消息”,而不是任意一个外部服务随便发过来的 JSON。所以,要想让 xiaozhi-server 和 OpenClaw 正式打通,就需要自己做一个自定义 channel。

这就是 myapp-channel 的由来。


myapp-channel 的作用是什么

myapp-channel 的作用可以概括成一句话:

xiaozhi-server 发来的桥接消息,翻译成 OpenClaw 能处理的标准消息,再把 OpenClaw 的回复翻译回去。

它在整条链路里,承担的是“桥接适配器”的角色。

具体来说,它做了几件事:

1. 主动连接 xiaozhi-server

因为 OpenClaw 运行在容器里,外部不方便直接访问它,所以最终采用的是反向思路:

不是让 xiaozhi-server 主动调用 OpenClaw,而是让 myapp-channel 主动连到 xiaozhi-server 暴露出来的 WebSocket bridge。

这样一来,OpenClaw 就像主动拉了一根长期在线的通信线出去。

2. 接收 reply.request

xiaozhi-server 拿到用户语音识别后的文本时,会通过 bridge 发来一条 reply.request 消息。

myapp-channel 收到后,会把这条消息解析出来。

3. 转换成 OpenClaw 内部消息

这一步很关键。

外部消息和 OpenClaw 内部消息不是一回事。
myapp-channel 会把诸如:

  • 用户是谁
  • 当前会话是谁
  • 消息正文是什么
  • 这是哪个 channel
  • 该归属哪个 SessionKey

这些信息整理好,转成 OpenClaw 内部标准上下文。

4. 交给 OpenClaw 的 agent 处理

整理完成后,myapp-channel 会把消息真正送进 OpenClaw,让 agent 去完成理解、推理和回复生成。

5. 把结果回传给 xiaozhi-server

等 OpenClaw 生成回复后,myapp-channel 再把它包装成 reply.response,通过同一条 WebSocket 长连接发回 xiaozhi-server

于是,xiaozhi-server 就能继续做 TTS,把文字转成语音,再播放给小智终端。


myapp-channel 在整个系统里的位置

整条链路可以这样理解:

ESP32 小智终端
  ↓
xiaozhi-server
  ↓
myapp-channel
  ↓
OpenClaw
  ↓
myapp-channel
  ↓
xiaozhi-server
  ↓
ESP32 小智终端

如果说 xiaozhi-server 是连接硬件和 AI 的那座桥,那么 myapp-channel 就是这座桥和 OpenClaw 之间的“桥头转换器”。它不负责语音识别,不负责语音合成,也不负责真正的 AI 推理。
它只做一件事:
让 OpenClaw 能以“原生 channel”的方式接收并处理来自这套语音系统的消息。

myapp-channel 的安装和配置方式

myapp-channel 本质上是一个 OpenClaw 自定义 channel 插件。安装方式并不复杂,核心分成两步:

  1. 把插件目录放到 OpenClaw 的扩展目录里
  2. openclaw.json 里配置 channels.myapp-channel

1. 安装插件

先把插件复制到 OpenClaw 的扩展目录:

mkdir -p ~/.openclaw/extensions
cp -R myapp-channel ~/.openclaw/extensions/

安装完成后,目录结构大致如下:

~/.openclaw/extensions/myapp-channel/
├── index.ts
├── openclaw.plugin.json
└── README.md

如果我是通过打包好的压缩包分发,也可以先解压:

tar -xzf myapp-channel-0.1.0.tar.gz
cp -R myapp-channel-0.1.0/myapp-channel ~/.openclaw/extensions/

2. 配置 OpenClaw

然后在 OpenClaw 的配置文件 openclaw.json 中加入 myapp-channel 这一段:

{
  "channels": {
    "myapp-channel": {
      "enabled": true,
      "bridgeUrl": "ws://192.168.2.3:8080/openclaw-bridge",
      "bridgeToken": "replace-with-random-token",
      "botName": "OpenClaw",
      "timeoutMs": 120000,
      "reconnectMs": 3000
    }
  }
}

这里需要注意 bridgeUrlbridgeToken

bridgeUrlOpenClaw 要主动连接的 WebSocket bridge 地址。比如这里的:ws://192.168.2.3:8080/openclaw-bridge 意思就是:让 OpenClaw 插件主动去连接部署在这台机器上的 xiaozhi-server。

bridgeToken 桥接认证 token。插件连接 xiaozhi-server 时,会把这个 token 带过去。xiaozhi-server 也会校验这个 token,只有一致才允许建立连接。所以这个值必须和 xiaozhi-server 里的配置保持一致。

3. xiaozhi-server 这一侧也要同步配置

因为 myapp-channel 走的是 WebSocket bridge,所以 xiaozhi-server 这一侧也要配对应参数,找到 xiaozhi-server 服务的 .env 文件,修改里面的配置,例如:

OPENCLAW_BRIDGE_PATH=/openclaw-bridge
OPENCLAW_BRIDGE_TOKEN=replace-with-random-token
OPENCLAW_BRIDGE_REQUEST_TIMEOUT_SECONDS=120

这里最重要的是:

  • OPENCLAW_BRIDGE_PATH
  • OPENCLAW_BRIDGE_TOKEN

它们必须和 OpenClaw 侧配置对应起来。


4. 配置完成后怎么生效

改完插件文件或者 openclaw.json 之后,需要重启 OpenClaw gateway。也就是说,myapp-channel 不是“热更新立即生效”的那种模式,通常需要重启 OpenClaw 才会重新加载插件和配置。


5. 启动后怎么判断有没有配置成功

如果配置正确,OpenClaw 启动日志里通常会出现类似信息:

[myapp-channel] connecting bridge to ws://192.168.2.3:8080/openclaw-bridge?token=...
[myapp-channel] bridge connected

这表示:

  1. 插件已经被 OpenClaw 成功加载
  2. 插件已经开始主动连接 bridge
  3. 和 xiaozhi-server 的长连接已经建立成功

如果你看到这两行,那么恭喜你,基本就说明安装和配置已经通了。

第四部分 整体测试

这是最开心的部分了,就是完成整体测试。

下面按“启动顺序 + 检查点”的方式来跑一遍,基本能把问题定位在具体环节。

启动前检查

  • 终端固件里的 WebSocket 地址已经改成你的 ws://...:8080(跟 xiaozhi-server 对外地址一致)。
  • xiaozhi-server.env 里已经配置好 ASR / TTS(以及 bridge 的 path/token)。
  • OpenClaw 已经配置并启用 myapp-channelbridgeUrl / bridgeToken 与 xiaozhi-server 保持一致。

启动顺序

  1. 启动 OpenClaw(gateway),确认日志里 myapp-channel 能正常加载(至少没有报错)。
  2. 启动 xiaozhi-server,确认它监听的端口正常,并且 bridge 路径已经挂起来(例如 /openclaw-bridge)。
  3. 给 ESP32 上电,观察屏幕:一般会从“链接中…”进入“聆听中…”。

端到端测试

  1. 唤醒小智,说一句简单的话,比如“你好,你是谁?”。
  2. xiaozhi-server 侧看日志:应该能看到 ASR 的文本结果,以及发往 bridge 的 reply.request
  3. 在 OpenClaw 侧看日志:应该能看到 myapp-channel 收到请求并返回回复。
  4. 回到设备端:应该能听到 TTS 播放的回答。

常见问题排查

  • 设备一直“链接中…”:优先检查固件里的 ws:// 地址、端口、防火墙/局域网可达性。
  • myapp-channel 连不上 bridge:检查 bridgeUrl 是否能从 OpenClaw 容器访问到 xiaozhi-server(尤其是内网 IP、容器网络),以及 bridgeToken 是否一致。
  • 能识别文字但不说话:检查 TTS 配置、音频设备、以及 xiaozhi-server 的 TTS 返回是否报错。
  • 延迟很大:把 OpenClaw / ASR / TTS 的日志打开,看卡在 ASR、LLM 还是 TTS。

以上就是这是整个小智AI接入Openclaw的过程。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注