基于MetaBot将Claude Code接入飞书实战-Win版
一、写在前面
最近我在 Windows 11 本地部署 MetaBot,希望把它接入飞书机器人,做一个可以直接在飞书里对话调用的大模型助手。
不过在真正上手之后我发现,MetaBot 其实并不只是"把一个机器人接到飞书上"这么简单。
根据官方仓库的介绍,MetaBot 本质上是一个用于构建 受监督、可自我改进的 agent 组织 的基础设施。它把 Claude Code 从本地终端里"释放出来",通过 Feishu / Telegram 作为入口,把 Claude Code 的能力、共享记忆、任务调度、Agent Bus、Agent Factory 等能力整合到一起。
换句话说,MetaBot 的定位不是一个普通聊天机器人,而是:
- 让每个 bot 都拥有 Claude Code 级别的执行能力
- 让多个 agent 可以共享记忆、彼此协作
- 让任务可以被调度、分发、追踪
- 让人类通过 Feishu / Telegram 对 agent 进行监督和控制
对于个人开发者来说,你可以把它理解成:
把 Claude Code 接到 飞书 / Telegram 上,让你在手机上也能调度一个真正可执行任务的 AI agent。
而对于更复杂的团队场景,它又可以进一步扩展成:
- 多 bot 分工协作
- 共享记忆库
- 文档 / Wiki 同步
- 定时任务自动执行
- agent 间任务委派
也正因为它的能力边界比普通 IM 机器人更大,所以部署时涉及的内容也更多:
- 本地 Node / PM2 运行
- Claude Code / provider 接入
- 飞书后台权限与事件订阅
- 配置文件
.env与bots.json - 长连接模式
- MetaMemory 与 API 服务
一开始我以为这件事会很顺利:
- 执行安装脚本
- 填入模型配置
- 配置飞书应用
- PM2 托管
- 完成
结果实际上并没有这么简单。
整个过程中,我先后遇到了:
- PM2 显示 online,但机器人实际上不可用
pid = N/A、mem = 0bmetabot status触发 WSL 相关报错node dist/index.js启动时报 JSON 解析错误bots.json路径写法与编码问题- 手工启动能跑,但 PM2 无法正确托管
- 中文路径 / 中文消息一度出现乱码
最终,经过完整排查,还是把:
- MetaBot 本体
- Feishu 机器人
- 模型调用
- PM2 托管
- 中文日志
全部跑通了。
这篇文章就是对整个过程的一次完整复盘,希望帮你少踩一些坑。
二、我的环境信息
本文对应的实战环境如下:
- 操作系统:Windows 11
- Shell:PowerShell 7.5.4
- Node.js:v23.10.0(最终建议换成 Node 22 LTS)
- 进程管理:PM2
- IM 平台:Feishu / Lark
- MetaBot:官方 GitHub 仓库安装
- 模型接入:第三方 provider + 自定义 API Base URL
三、MetaBot 安装
项目地址:
- GitHub:
- 官方文档:
- 中文文档:
如果你准备在 Windows 11 本地部署 MetaBot,最直接的方式就是使用官方 PowerShell 安装脚本。
1. 执行安装脚本
我当时在 PowerShell 7.5.4 下执行的命令如下:
PS A:\study\AI\LLM\MetaBot> irm https://raw.githubusercontent.com/xvirobotics/metabot/main/install.ps1 | iex
安装器启动后,会先输出 MetaBot Installer 欢迎界面,然后依次进入多个阶段。
2. Phase 1:检查基础环境
安装器会先检查本机环境是否满足要求,典型输出如下:
[INFO] PowerShell version: 7.5.4
[INFO] OS: Microsoft Windows NT 10.0.22631.0
==> Phase 1: Checking prerequisites
[OK] Git found: A:\Git\Git\bin\git.exe
[OK] Node.js found: v23.10.0
[OK] npm found: A:\nodejs\npm.ps1
这一阶段的意义非常直接:
- 确认 Git 可用
- 确认 Node.js 可用
- 确认 npm 可用
如果这里没有通过,后续步骤不建议继续。
3. Phase 2:拉取或更新 MetaBot 代码
安装器会把项目部署到用户目录下,例如:
==> Phase 2: Setting up MetaBot at C:\Users\你的用户名\metabot
[INFO] Existing installation found, pulling latest...
Already up to date.
[OK] MetaBot code ready at C:\Users\你的用户名\metabot
如果是首次安装,这里通常是 clone;如果目录已存在,则会尝试 pull 最新代码。
4. Phase 3:安装依赖
随后安装器会执行 npm install。这一阶段最值得注意的,并不是"安装成功"本身,而是中间出现了大量 EBADENGINE 警告,例如:
npm warn EBADENGINE Unsupported engine {
package: '@eslint/config-array@0.23.2',
required: { node: '^20.19.0 || ^22.13.0 || >=24' },
current: { node: 'v23.10.0', npm: '10.9.2' }
}
类似提示会出现在多个依赖上,例如:
@eslint/config-array@eslint/config-helpers@eslint/coreeslintespreeeslint-scopeeslint-visitor-keys
这说明:
- 当前安装并未中断
- 但 Node 23 并不是项目依赖声明最理想的版本
这也是为什么我最终建议:
长期运行最好切换到 Node 22 LTS。
安装结束后还会看到类似:
up to date, audited 268 packages in 2s
74 packages are looking for funding
1 high severity vulnerability
这里的重点在于:依赖已经装完,但后续稳定性仍需结合实际运行来判断。
5. Phase 4:交互式配置
这是整个安装过程中最关键的一步之一,因为后续是否能正常运行,很大程度取决于这里填写的内容。
(1)工作目录
安装器会要求输入 Claude 工作目录,例如:
Working Directory:
Project directory for Claude to work in [C:\Users\你的用户名\metabot-workspace]:
这个目录会直接写入配置文件,因此:
- 路径要真实存在
- Windows 路径写法要规范
- 中文路径与编码问题要特别小心
本次排障里,defaultWorkingDirectory 后来正是关键问题之一。
(2)模型提供方配置
安装器接着会让你选择模型接入方式,例如:
Claude AI Authentication:
1) Claude Code Subscription
2) Anthropic API Key
3) Third-party provider
我当时选择的是第三方 provider,并进一步选择:
4) Custom URL
然后填写:
- API Base URL
- API Key
- Model name
- Small/Fast model
这一部分决定了 MetaBot 后续具体调用哪个模型。
(3)IM 平台选择
接着会询问要接入哪个 IM 平台:
IM Bot Platform:
1) Feishu/Lark
2) Telegram
3) Both
这次实战里我选择的是:
Feishu/Lark
(4)飞书应用信息
随后继续填写:
- Feishu App ID
- Feishu App Secret
- Bot Name
这一步要特别注意:
- 不要在公开场景泄露 Secret
- 若 Secret 已在聊天、截图、文档中暴露,建议后续立即重置
6. Phase 5:生成配置文件
交互配置完成后,安装器会生成:
.envbots.json
典型输出:
[OK] .env generated
[OK] bots.json generated
这一阶段当时看起来很平常,但后来排障证明:
bots.json 正是本次部署中最关键的风险点之一。
7. Phase 6:安装 skills 并部署到工作区
安装器会自动安装一批与 MetaBot 配套的 skill,例如:
- metaskill
- metamemory
- metabot
- feishu-doc
典型输出类似:
[OK] metaskill skill installed
[OK] metamemory skill installed
[OK] metabot skill installed
[OK] feishu-doc skill installed
并且这些 skill 会同步部署到工作目录下的 .claude/skills 中。
这一阶段意味着:
- 不只是主程序被安装
- 连同工作区能力和相关工具链也一起被初始化了
8. Phase 7:MetaMemory
安装器会提示:
MetaMemory is embedded in MetaBot (no separate server needed)
MetaMemory will start automatically with MetaBot on port 8100
也就是说,MetaMemory 并不是独立外部服务,而是由 MetaBot 一起启动。
9. Phase 8:构建并尝试启动
最后,安装器会执行构建:
> metabot@1.0.0 build
> tsc && cp -r src/memory/static dist/memory/static
构建完成后,安装器会继续尝试通过 PM2 启动 MetaBot。
而真正的坑,也在这里第一次显现出来:
[PM2] App [metabot] launched (1 instances)
...
│ 0 │ metabot │ default │ 1.0.0 │ fork │ N/A │ 0s │ 0 │ online │ 0% │ 0b │
看到这里时,如果经验不足,很容易误判为:
安装已经成功,服务已经正常启动。
但实际上:
pid = N/Amem = 0b
这两个信号已经说明:
这个 PM2 进程很可能根本没有真正健康运行。
这也是后续整条排障链路的起点。
10. 安装阶段的小结
这一步最重要的经验,不是"安装脚本跑完了",而是:
- 安装器可以完成初始化,但不等于最终链路已经打通
- Node 23 虽然能安装,但并非最推荐版本
.env和bots.json是后续最关键的配置文件- PM2 的
online不能单独作为成功依据 - 一旦看到
pid = N/A、mem = 0b,应立即进入手工验证阶段
也正是从这里开始,我后续才转向:
- 直接运行
node dist/index.js - 定位
bots.json问题 - 最终修复 PM2 假在线
四、飞书机器人配置
如果说 MetaBot 安装解决的是"本地程序能不能跑起来",那么飞书后台配置解决的就是"消息能不能真正进到 MetaBot"。
很多人会把注意力全部放在本地命令和 PM2 上,但实际部署时,飞书后台配置同样是完整链路里不可缺的一环。
1. 创建企业自建应用
首先需要在飞书开发者后台创建一个 企业自建应用。
这里建议:
- 应用名称尽量清晰
- 图标可以先用默认
- 创建完成后第一时间记录 App ID
这是后续配置机器人的基础。

创建企业自建应用
2. 添加机器人能力
创建应用后,还需要为应用添加"机器人"能力。
如果没有这一步,即便应用存在,也无法在飞书中以机器人身份对话。
加完之后,你应该能在应用能力相关页面中看到机器人配置项。

添加机器人
3. 配置权限
这是飞书配置里非常重要的一步,而且是最容易"表面看起来配了,实际还差一点"的环节。
在本次部署中,我使用了批量导入权限的方式,把 MetaBot 所需的 tenant / user 权限一次性导入。
这些权限覆盖的能力范围比较广,主要包括:
- 通讯录与用户基础信息
- 文档 / DocX
- IM 消息读写
- 消息资源下载
- 搜索
- 日历
- 任务
- Wiki
- 多维表格
- 云空间文件
为什么要配这么多权限?
因为 MetaBot 不是一个只会"收发文字消息"的简单机器人,它后续可能涉及:
- 读取飞书文档
- 同步 Wiki
- 搜索消息
- 下载消息资源
- 操作日历与任务
- 处理多维表格与云空间文件
如果权限配得过少,最常见的问题是:
- 机器人能收消息,但部分能力报权限不足
- 文档 / Wiki 能力不可用
- 资源下载失败
- 某些 API 只能部分成功


批量导入权限
{
"scopes": {
"tenant": [
"contact:contact.base:readonly",
"docx:document:readonly",
"im:chat:read",
"im:chat:update",
"im:message.group_at_msg:readonly",
"im:message.p2p_msg:readonly",
"im:message.pins:read",
"im:message.pins:write_only",
"im:message.reactions:read",
"im:message.reactions:write_only",
"im:message:readonly",
"im:message:recall",
"im:message:send_as_bot",
"im:message:send_multi_users",
"im:message:send_sys_msg",
"im:message:update",
"im:resource",
"application:application:self_manage",
"cardkit:card:write",
"cardkit:card:read",
"contact:user.basic_profile:readonly"
],
"user": [
"contact:user.employee_id:readonly",
"offline_access","base:app:copy",
"base:field:create",
"base:field:delete",
"base:field:read",
"base:field:update",
"base:record:create",
"base:record:delete",
"base:record:retrieve",
"base:record:update",
"base:table:create",
"base:table:delete",
"base:table:read",
"base:table:update",
"base:view:read",
"base:view:write_only",
"base:app:create",
"base:app:update",
"base:app:read",
"sheets:spreadsheet.meta:read",
"sheets:spreadsheet:read",
"sheets:spreadsheet:create",
"sheets:spreadsheet:write_only",
"docs:document:export",
"docs:document.media:upload",
"board:whiteboard:node:create",
"board:whiteboard:node:read",
"calendar:calendar:read",
"calendar:calendar.event:create",
"calendar:calendar.event:delete",
"calendar:calendar.event:read",
"calendar:calendar.event:reply",
"calendar:calendar.event:update",
"calendar:calendar.free_busy:read",
"contact:contact.base:readonly",
"contact:user.base:readonly",
"contact:user:search",
"docs:document.comment:create",
"docs:document.comment:read",
"docs:document.comment:update",
"docs:document.media:download",
"docs:document:copy",
"docx:document:create",
"docx:document:readonly",
"docx:document:write_only",
"drive:drive.metadata:readonly",
"drive:file:download",
"drive:file:upload",
"im:chat.members:read",
"im:chat:read",
"im:message",
"im:message.group_msg:get_as_user",
"im:message.p2p_msg:get_as_user",
"im:message:readonly",
"search:docs:read",
"search:message",
"space:document:delete",
"space:document:move",
"space:document:retrieve",
"task:comment:read",
"task:comment:write",
"task:task:read",
"task:task:write",
"task:task:writeonly",
"task:tasklist:read",
"task:tasklist:write",
"wiki:node:copy",
"wiki:node:create",
"wiki:node:move",
"wiki:node:read",
"wiki:node:retrieve",
"wiki:space:read",
"wiki:space:retrieve",
"wiki:space:write_only",
"contact:user.basic_profile:readonly"
]
}
}
4. 关于"应用身份权限可访问的数据范围"
在权限导入后,飞书后台通常还会要求确认:
"应用身份权限"可访问的数据范围
本次配置中,保持默认即可:
- 与应用的可用范围一致
这个设置很容易被忽略,但如果这里设置得太窄,可能出现:
- 机器人在某些用户侧不可见
- 应用对某些群、成员、文档、资源的访问范围受限

"应用身份权限"可访问的数据范围的设置保持默认 "与应用的可用范围一致 " ,点击 确认 完成操作。

5. 事件与回调:开启长连接模式
这是飞书机器人真正把消息送进 MetaBot 的关键设置。
在飞书开发者后台中,需要进入:
- 事件与回调
- 订阅方式
- 选择 使用长连接接收事件/回调
MetaBot 在运行日志中也会明确提示这一点,类似:
receive events or callbacks through persistent connection
如果这一步没开,即使机器人已经创建完成、权限也配置好了,MetaBot 依然可能接收不到消息事件。







6. 勾选 im.message.receive_v1
在长连接模式开启后,还必须勾选实际需要订阅的事件。
对于 MetaBot 这类聊天机器人来说,最关键的事件之一就是:
im.message.receive_v1
如果没有勾选这项,最典型的现象就是:
- 飞书里能看到机器人
- 本地 MetaBot 服务也在运行
- 但无论怎么发消息,日志里都没有
Received message
这是典型的"看起来都对,但业务完全不通"的问题。



7. 发布应用版本
这是飞书配置里另一个极容易漏掉的步骤。
很多人会完成以下所有动作:
- 创建应用
- 添加机器人
- 配权限
- 开长连接
- 勾事件
然后就直接去测试。
但如果没有 发布应用版本,这些修改并不会真正对外生效。
也就是说:
后台"看上去已经配置好",并不等于"线上已经生效"。
这是实际联调中非常常见的坑。



8. 配置完成后,正确的 MetaBot 日志应该是什么样
当飞书后台配置正确,且本地 MetaBot 也已成功启动后,日志通常会出现类似内容:
[info]: [ 'client ready' ]
[info]: [ 'event-dispatch is ready' ]
[info]: [ '[ws]', 'ws client ready' ]
INFO: Starting Feishu bot...
INFO: Bot info fetched
INFO: Feishu bot is running
这些日志分别意味着:
- Feishu 客户端初始化成功
- 事件分发器 ready
- WebSocket 长连接建立成功
- 机器人身份拉取成功
- Feishu Bot 已进入运行状态
这时候就可以开始在飞书里给机器人发测试消息了。
9. 飞书测试消息发送后,正确日志应长什么样
在飞书里私聊机器人发送一条最简单的消息,例如:
测试
如果整个链路正常,MetaBot 日志里应依次出现:
INFO: Received message
INFO: Starting Claude execution (multi-turn)
INFO: audit:task_complete
这三行对应的意义分别是:
Received message:飞书消息事件已成功到达 MetaBotStarting Claude execution:MetaBot 已开始调用模型task_complete:模型执行完毕,任务完成
这是判断飞书配置是否真正生效、机器人是否真正打通的最可靠方法。
10. 飞书配置最容易犯的几个错误
根据这次实战,我总结出几类高频错误:
错误 1:创建了应用,但没加机器人能力
结果:应用存在,但不能作为机器人对话。
错误 2:加了机器人,但没开事件订阅
结果:机器人看得见,但消息进不来。
错误 3:开了长连接,但没勾 im.message.receive_v1
结果:WebSocket 建立了,但消息事件仍然进不来。
错误 4:权限配置不完整
结果:收消息可能正常,但文档、消息资源、搜索等能力报权限不足。
错误 5:修改了配置,但没发布应用版本
结果:后台看起来都配好了,实际上还没生效。
错误 6:误以为问题一定在飞书后台
本次实战最开始的主因其实并不在飞书,而是本地 bots.json 配置问题,程序根本没启动起来。
所以排查时一定要同时看:
- 飞书后台配置是否完整
- 本地 MetaBot 是否真的健康运行
11. 飞书机器人配置阶段的小结
这一节最值得记住的结论有几点:
- 飞书机器人配置不是"建个应用就结束",而是完整链路
- 权限、长连接、事件订阅、发布缺一不可
im.message.receive_v1是最关键的消息事件之一- 配完后台后,必须回到 MetaBot 日志里验证链路是否真的打通
- 如果日志里没有
Received message,就说明链路仍未成功 - 排障时不能只盯开发者后台,也要同时看本地运行状态
五、最开始的异常现象
安装完成后,我第一反应是:
pm2 status
pm2 logs metabot
结果发现一个很奇怪的现象:
- PM2 里显示
metabot是online - 但
pid = N/A mem = 0bpm2 logs metabot也没什么有效日志
这其实是一个非常重要的信号:
PM2 并不一定真的把服务正常拉起来了,它可能只是"看起来在线"。
后来再执行:
metabot status
还出现了 WSL 相关提示。
这说明 Windows 下某些 CLI wrapper 可能并不适合作为核心排查入口。
六、真正有效的第一步:直接运行主程序
排查这类问题时,最有效的方式不是继续盯着 PM2,而是直接运行 Node 主入口:
cd C:\Users\你的用户名\metabot
node dist/index.js
这一步直接把问题暴露出来了:
Fatal error: SyntaxError: Bad escaped character in JSON at position ...
看到这里,结论就非常明确了:
- 问题不是飞书后台先出错
- 也不是模型 provider 先出错
- 而是 本地配置文件 JSON 解析失败,程序根本没启动起来
七、根因定位:bots.json 的 Windows 路径问题
继续检查后,发现核心问题出在 bots.json。
在 Windows 上,路径如果写得不规范,很容易导致 JSON 解析失败。
例如这种写法就有风险:
"defaultWorkingDirectory": "C:\Users\你的用户名\metabot-workspace"
更稳妥的方式是统一写成正斜杠:
"defaultWorkingDirectory": "C:/Users/你的用户名/metabot-workspace"
我这次还遇到过一个更坑的问题:
- 用户名路径在文件或日志里出现乱码
- 路径虽然看上去像是 Windows 路径,但已经不是实际存在的目录了
所以 bots.json 这一步非常关键。
最终可用的配置类似这样:
{
"feishuBots": [
{
"name": "MetaBot-Win",
"feishuAppId": "你的 Feishu App ID",
"feishuAppSecret": "你的 Feishu App Secret",
"defaultWorkingDirectory": "C:/Users/你的用户名/metabot-workspace"
}
]
}
修正后再次执行:
node dist/index.js
终于看到了正常启动日志。
八、服务终于启动成功
当我修好 bots.json 后,MetaBot 的启动日志开始出现:
Starting MetaBot bridge...Starting Feishu bot...Bot info fetchedFeishu bot is runningMetaMemory server startedAPI server started
这说明:
- MetaBot 主程序启动成功
- Feishu 长连接建立成功
- 本地 API 与 MetaMemory 正常监听
这时候再去飞书里给机器人发消息,日志里开始出现:
Received messageStarting Claude execution (multi-turn)audit:task_complete
也就是说,真正的消息链路终于通了。
九、第二个大坑:手工能跑,PM2 还是不行
虽然手工运行已经成功,但还有一个现实问题:
只要我把当前 PowerShell 窗口关掉,MetaBot 服务就会退出。
这说明手工运行只能用于验证,不能作为长期托管方式。
但是旧的 PM2 任务依旧是假在线:
pid = N/Amem = 0b
这时候不能再继续:
pm2 restart metabot
因为这个旧任务本身就已经坏了。
正确思路是:
删除旧 PM2 任务,直接按正确方式重建。
十、Win11 下最终正确的 PM2 启动方式
我最终验证通过、可稳定运行的方式如下:
cd C:\Users\你的用户名\metabot
pm2 delete all
pm2 start dist/index.js --name metabot --interpreter node
pm2 status
pm2 logs metabot --lines 100
pm2 save
这一步之后,状态终于变成了真正健康的样子:
- 只有 1 个
metabot version = 1.0.0pid是真实数字mem是正常值status = online
并且飞书里的消息也可以稳定触发模型执行。
十一、如何判断是否真正部署成功
我最后总结出来,不能只看"安装脚本跑完了",也不能只看"PM2 显示 online"。
真正部署成功至少要满足以下几点:
1. 主程序能直接启动
node dist/index.js
没有配置报错。
2. PM2 状态健康
pm2 status
必须满足:
- 单实例
pid正常mem正常status = online
3. 飞书消息能进来
日志中出现:
Received message
4. 模型能执行
日志中出现:
Starting Claude execution (multi-turn)
5. 任务能完成
日志中出现:
audit:task_complete
只要这几个链路完整出现,才能认定"整个系统真的跑通了"。
十二、这次部署里最关键的经验总结
这次踩坑下来,我觉得最重要的经验有下面几条:
1. 安装脚本只是起点,不是终点
安装成功不代表服务真的可用。
2. 排障一定优先看主程序
最有价值的命令是:
node dist/index.js
3. Windows 下要特别注意 JSON 路径写法
建议统一用正斜杠:
C:/Users/你的用户名/metabot-workspace
4. PM2 的 online 可能是假象
如果出现:
pid = N/Amem = 0b
那就基本可以判定这个实例是坏的。
5. PM2 坏任务不要 restart,要 delete 后重建
这是我这次排障中最关键的修复动作之一。
6. 最终稳定命令要记住
pm2 start dist/index.js --name metabot --interpreter node
十三、安全提醒
还有一点必须强调。
在部署和排障过程中,下面这些信息都属于敏感信息:
- Feishu App Secret
- 模型 API Key
- MetaBot API Secret
.env内容bots.json中的真实密钥
如果你曾经:
- 发到聊天里
- 放进截图里
- 写进共享文档里
- 提交到仓库里
那么都应该视为有泄露风险,建议及时轮换。
十四、推荐的最终运维命令
查看状态
pm2 status
查看日志
pm2 logs metabot --lines 100
重启
pm2 restart metabot
停止
pm2 stop metabot
删除并重建
cd C:\Users\你的用户名\metabot
pm2 delete all
pm2 start dist/index.js --name metabot --interpreter node
pm2 save
十五、写在最后
如果你也打算在 Windows 11 本地部署 MetaBot,并接入飞书机器人,我的建议是:
- 不要过度依赖安装脚本的最终提示
- 不要迷信 PM2 里显示的
online - 一旦有异常,优先跑
node dist/index.js - 一旦 PM2 假在线,直接 delete 后按正确命令重建
我这次最终跑通之后,整个链路已经可以稳定工作:
- 飞书机器人收消息
- MetaBot 处理任务
- 模型返回结果
- PM2 单实例托管
如果你正在做类似部署,希望这篇文章能帮你少踩一些坑。
十六、适合收藏的一页式最终命令
cd C:\Users\你的用户名\metabot
pm2 delete all
node dist/index.js
# 如果手工启动正常,再切回 PM2
pm2 start dist/index.js --name metabot --interpreter node
pm2 status
pm2 logs metabot --lines 100
pm2 save
如果这套流程跑通,基本就说明你的 Win11 + PM2 + MetaBot + Feishu 链路已经打通。