PicoClaw WeCom(企业微信)渠道实战指南:WebSocket 接入、扫码绑定与配置详解
【免费下载链接】picoclawTiny, Fast, and Deployable anywhere — automate the mundane, unleash your creativity项目地址: https://gitcode.com/gh_mirrors/pi/picoclaw
PicoClaw 通过官方的 WeCom AI Bot WebSocket API,将企业微信(WeCom)暴露为单一的channels.wecom渠道,替代了早期wecom、wecom_app、wecom_aibot三套分裂的配置模型。本文围绕该渠道的接入方式(Web 界面扫码 / CLI 扫码 / 手动配置)、完整配置参数、运行时行为以及从旧配置的迁移方法展开,并对照开源仓库源码,解释流式回复、路由过期、去重缓冲等关键机制的实际实现依据,帮助你在内网环境下把 WeCom 机器人完整跑起来。
渠道概览:单一渠道与纯出站连接
PicoClaw 把 WeCom 收敛为一个统一渠道channels.wecom,构建在 WeCom 官方 AI Bot 的 WebSocket API 之上。与传统的 webhook 回调模式不同,它不需要任何公网回调 URL——PicoClaw 主动向 WeCom 建立一条出站 WebSocket 连接即可收发消息,这对部署在内网、NAT 之后或没有固定公网入口的主机非常友好。
该渠道支持的能力包括:
- 单聊(direct chat)与群聊(group chat)投递;
- 基于 WeCom AI Bot 协议的渠道侧流式回复(streaming replies);
- 入站消息:文本、语音、图片、文件、视频以及混合(mixed)消息;
- 出站回复:文本与媒体消息(
image、file、voice、video); - 基于二维码(QR)的扫码接入,支持 Web UI 和 CLI 两种方式;
- 共享的发送者白名单(
allow_from)与reasoning_channel_id推理输出路由。
渠道在启动阶段通过工厂注册到渠道管理器,见 pkg/channels/wecom/init.go:
func init() { channels.RegisterFactory( config.ChannelWeCom, func(channelName, channelType string, cfg *config.Config, b *bus.MessageBus) (channels.Channel, error) { bc := cfg.Channels[channelName] decoded, err := bc.GetDecoded() ... return NewChannel(bc, c, b) }, ) }构造函数NewChannel会强制校验凭据——bot_id与secret缺一不可,且未显式指定websocket_url时自动落到默认端点,见 pkg/channels/wecom/wecom.go。
快速接入:三种上线路径
方式一:Web UI 扫码绑定(推荐)
打开 PicoClaw 的 Web 界面,进入Channels → WeCom,点击 QR 绑定按钮。用 WeCom 扫描二维码并在 App 中确认后,bot_id与secret会被自动写入配置。
方式二:CLI 扫码登录
在服务器上执行:
picoclaw auth wecom该命令的完整流程为:
- 向 WeCom 申请一个二维码并在终端中打印;
- 同时打印一个QR Code Link(网页链接),当终端二维码不方便扫描时,可在浏览器中打开该链接完成扫码;
- 轮询等待确认——注意:扫码之后还必须进入 WeCom App 点击"确认",仅扫码不会完成登录;
- 成功后将
bot_id与secret写入channels.wecom并保存配置。
默认等待超时为5 分钟,可用--timeout延长:
picoclaw auth wecom --timeout 10m扫码并不等于登录完成——必须在 WeCom App 中点击"确认",否则命令会一直等到超时。
从源码看,这条命令的轮询细节集中在 cmd/picoclaw/internal/auth/wecom.go:默认轮询间隔为 3 秒(wecomQRPollInterval)、默认超时 5 分钟(wecomQRPollTimeout),HTTP 请求超时 15 秒。轮询状态中,scanned状态会提示 "QR code scanned. Confirm the login in WeCom.",只有success状态才会取回botid与secret;expired状态则直接报错要求重扫。登录成功后由 applyWeComAuthResult 把凭据落到cfg.Channels["wecom"]、置Enabled = true,并补上默认 WebSocket 端点,最后统一SaveConfig。
方式三:手动配置
如果你已经从 WeCom AI Bot 平台拿到了bot_id和secret,可以直接在配置中写死:
{ "channel_list": { "wecom": { "enabled": true, "type": "wecom", "bot_id": "YOUR_BOT_ID", "secret": "YOUR_SECRET", "websocket_url": "wss://openws.work.weixin.qq.com", "send_thinking_message": true, "allow_from": [], "reasoning_channel_id": "" } } }配置参数全解
完整字段如下表(对应配置路径channels.wecom):
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled | bool | false | 是否启用 WeCom 渠道。 |
bot_id | string | — | WeCom AI Bot 标识。启用渠道时必填。 |
secret | string | — | WeCom AI Bot 密钥。加密存储在.security.yml中。启用渠道时必填。 |
websocket_url | string | wss://openws.work.weixin.qq.com | WeCom WebSocket 端点。 |
send_thinking_message | bool | true | 在流式回复开始前,先发送一条Processing...提示消息。 |
allow_from | array | [] | 发送者白名单。为空表示允许所有发送者。 |
reasoning_channel_id | string | "" | 可选的会话 ID,用于把推理/思考过程输出路由到独立的对话中。 |
对应源码中的结构体定义见 pkg/config/config.go:
type WeComSettings struct { BotID string `json:"bot_id" ...` Secret SecureString `json:"secret,omitzero" yaml:"secret,omitempty" ...` WebSocketURL string `json:"websocket_url,omitempty" yaml:"-" ...` SendThinkingMessage bool `json:"send_thinking_message" yaml:"-" ...` Streaming StreamingConfig `json:"streaming,omitzero" yaml:"-"` }可以看到secret的类型是SecureString,即文档中所说的"加密存储在.security.yml"——明文 secret 不会直接留在常规配置文件里。此外该结构体还内置了一个Streaming配置块,控制流式回复是否开启(渠道侧BeginStream会检查config.Streaming.Enabled,未启用时直接返回 "streaming disabled in config")。
环境变量覆盖
所有字段都可以通过PICOCLAW_CHANNELS_WECOM_前缀的环境变量覆盖:
| 环境变量 | 对应字段 |
|---|---|
PICOCLAW_CHANNELS_WECOM_ENABLED | enabled |
PICOCLAW_CHANNELS_WECOM_BOT_ID | bot_id |
PICOCLAW_CHANNELS_WECOM_SECRET | secret |
PICOCLAW_CHANNELS_WECOM_WEBSOCKET_URL | websocket_url |
PICOCLAW_CHANNELS_WECOM_SEND_THINKING_MESSAGE | send_thinking_message |
PICOCLAW_CHANNELS_WECOM_ALLOW_FROM | allow_from |
PICOCLAW_CHANNELS_WECOM_REASONING_CHANNEL_ID | reasoning_channel_id |
在容器化部署或 CI 环境中,用环境变量注入bot_id/secret可以避免把凭据写进配置文件。
运行时行为与关键参数来源
文档中列出的运行时行为,几乎都能在渠道实现的常量与主循环中找到一一对应的出处:
- 维护活动回合(active turn):每条入站消息会建立一个
wecomTurn(含ReqID、ChatID、StreamID),流式回复在该回合的同一 stream 上继续;回合按会话排队,流式结束或过期时被消费。见 pkg/channels/wecom/wecom.go 中的wecomTurn结构与BeginStream逻辑。 - 流式回复最长 5.5 分钟、最小发送间隔 500ms:对应常量
wecomStreamMaxDuration = 5*time.Minute + 30*time.Second与wecomStreamMinInterval = 500 * time.Millisecond(wecom.go)。wecomStreamer.Update每次发 chunk 前都会等待距上次发送至少 500ms;回合创建超过 5.5 分钟后validateActiveTurn判定过期,流式不可用。 - 流式不可用时回退到主动推送:
Send方法先尝试在有效回合上发 stream 回复;失败或回合过期后,退化为通过sendActivePush(Cmd: send_msg,markdown 类型)主动推送消息。 - 路由 30 分钟过期:入站消息会把
req_id写入路由表(reqIDStore,支持持久化),TTL 为wecomRouteTTL = 30 * time.Minute,过期后主动推送只能按原始 chat_id 投递。 - 入站媒体先落地本地媒体库:图片/文件/视频(含混合消息中的每一项)都会经
storeRemoteMedia下载到本地媒体存储(默认带 AES 解密),生成 media ref 后再交给 agent,见 pkg/channels/wecom/wecom.go。 - 出站媒体先上传为临时文件:出站媒体在 pkg/channels/wecom/media.go 中有明确的体积约束——文件 20MB、图片 2MB、语音 2MB、视频 10MB,采用 512KB 分块上传(最多 100 块);上传成功后作为
media_id媒体消息发送。上传失败时渠道会回退为占位文本回复,而不是让整条消息丢失。 - 重复消息抑制(环形缓冲 1000 条):
recentMessageSet用容量 1000(wecomRecentMessageMax)的 ring buffer 记录最近的消息 ID,Mark返回 false 的回调消息会被直接丢弃,防止 WeCom 侧重复投递造成 agent 重复处理。
除此之外,连接管理也有一些值得了解的隐含参数:WebSocket 拨号超时 15 秒、命令等待 ACK 超时 10 秒、心跳间隔 30 秒(wecomCmdPing);断线后connectLoop按指数退避重连,退避从 1 秒翻倍、上限 1 分钟。这些行为均由 wecom.go 中的connectLoop/runConnection/heartbeatLoop实现,并由 wecom_test.go、media_test.go 等测试覆盖。
从旧版 WeCom 配置迁移
旧版本中 WeCom 相关配置分散在多个渠道名下,迁移规则如下:
| 旧配置 | 迁移方式 |
|---|---|
channels.wecom(webhook 机器人) | 替换为使用bot_id+secret的新channels.wecom。 |
channels.wecom_app | 删除,改用统一的channels.wecom。 |
channels.wecom_aibot | 把其中的bot_id与secret迁移到channels.wecom。 |
token、encoding_aes_key、webhook_url、webhook_path | 不再使用,从配置中删除。 |
corp_id、corp_secret、agent_id | 不再使用,从配置中删除。 |
welcome_message、processing_message、max_steps | 已不属于 WeCom 渠道配置。 |
迁移后只需保留上表"配置参数全解"一节中的字段;原先为 webhook 回调服务的企业微信应用凭据(corp 系列)和加解密参数都可以整体移除,因为新的 WebSocket 模式仅依赖 AI Bot 的bot_id/secret对。
故障排查
扫码绑定超时
- 扫码之后还必须在 WeCom App 内确认登录,仅扫码不够;
- 用更长的超时重跑:
picoclaw auth wecom --timeout 10m; - 如果终端里的二维码不好扫,使用打印在二维码下方的QR Code Link,在浏览器中打开完成扫码。
二维码已过期
- 二维码有效期有限。重新执行
picoclaw auth wecom获取新的二维码即可(源码中过期状态会直接返回 "WeCom QR code expired, please retry")。
WebSocket 连接失败
- 检查
bot_id与secret是否正确; - 确认主机能访问
wss://openws.work.weixin.qq.com(这是出站 WebSocket 连接,无需开放任何入站端口)。
收不到回复
- 检查
allow_from是否把发送者挡在了白名单外; - 确认
channels.wecom.bot_id与channels.wecom.secret均已设置且非空(渠道构造函数在凭据缺失时会直接拒绝启动,并记录 "wecom bot_id and secret are required")。
小结
WeCom 渠道的接入路径可以概括为:扫码拿凭据(Web UI / CLI)→ 统一写入channels.wecom→ 渠道进程主动拨号wss://openws.work.weixin.qq.com并保持心跳。配置层只关心 7 个字段,运行时则依靠"活动回合 + 5.5 分钟流式窗口 + 30 分钟路由 TTL + 1000 条消息去重环"这套机制保证回复的时效与幂等。相关实现集中在 pkg/channels/wecom/、扫码流程在 cmd/picoclaw/internal/auth/wecom.go、配置模型在 pkg/config/config.go,如需进一步理解协议细节,可直接阅读这些源文件及其测试用例。
【免费下载链接】picoclawTiny, Fast, and Deployable anywhere — automate the mundane, unleash your creativity项目地址: https://gitcode.com/gh_mirrors/pi/picoclaw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考