← 听不懂

OpenClaw 新旧飞书插件共存冲突:从死锁到流式输出统一

2026-03-18 运维 OpenClawopenclaw-lark飞书插件冲突

问题描述

安装了飞书官方出品的 openclaw-lark 插件后,系统里同时存在两套飞书插件:

两套插件互相打架,形成死锁:

更烦的是,两套插件都在抢 feishu 这个 channel id,导致不同 Agent 的回复路径不一样:热巴和敖丙走 openclaw-lark 的流式卡片(打字机效果),拖鞋走内置插件的静态路径(等很久一次蹦出来)。

根因分析

坑一:openclaw-lark 有一个硬编码的旧版插件检查

src/core/tool-client.js 第 111-119 行:

const feishuEntry = this.config.plugins?.entries?.feishu;

if (feishuEntry && feishuEntry.enabled !== false) {

throw new Error('❌ 检测到旧版插件未禁用...');

}

只要内置插件没被显式禁用,openclaw-lark 的所有工具调用直接抛异常拒绝执行。本意是强制迁移,但没考虑到内置插件还承担着其他功能。

坑二:openclaw-lark 对 default 账号的特殊处理

src/core/accounts.jsgetLarkAccount() 里有一个隐藏假设:default 账号的凭证必须放在 channels.feishu 顶层,而不是 accounts.default 下。

const accountOverride = accountMap && requestedId !== DEFAULT_ACCOUNT_ID

? accountMap[requestedId]

: undefined; // default 账号不读 accounts.default!

其他账号(media、aobing)走 accountMap[requestedId],正常读取。但 default 账号永远走顶层。

所以当 feishu.enabled = false 时,内置插件停了,openclaw-lark 接管,但因为 appId/appSecret 放在 accounts.default 里而不是顶层,default 账号 configured = false,被跳过,WebSocket 不启动。

整个过程没有报错,就是静默不连接。

修复方案

两步搞定:

第一步:禁用内置插件

cat ~/.openclaw/openclaw.json | \

jq '.plugins.entries.feishu.enabled = false' \

> /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json

第二步:把 default 账号凭证提升到顶层

cat ~/.openclaw/openclaw.json | jq '

.channels.feishu.appId = .channels.feishu.accounts.default.appId |

.channels.feishu.appSecret = .channels.feishu.accounts.default.appSecret |

.channels.feishu.dmPolicy = "open" |

.channels.feishu.groupPolicy = "open" |

.channels.feishu.allowFrom = ["*"]

' > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json

重启 Gateway,搞定。

修复后的效果

事后提的三个 GitHub Issue

最重要的教训

框架级配置的「隐式约定」很难靠文档发现。 这两个坑都是通过读源码才搞清楚的。遇到「配置看起来没问题但就是不工作」的情况,先查源码,不要一直试参数。

另一个教训:两个插件争同一个 channel id 时,谁在前谁赢,结果不确定。 多账号场景下,不同 Agent 可能走不同路径,表现完全不一样,很难调试。