OpenClaw Zalo 渠道插件:Bot API 凭证配置、Webhook 模式与源码级解析
OpenClaw 的 Zalo 渠道插件(@openclaw/zalo)基于 Zalo Bot API 接入越南主流即时通讯平台 Zalo,支持私聊与群聊两种会话形态。本文以插件自身的说明文档 README 为核心骨架,完整覆盖安装方式、Bot 凭证与代理配置、Webhook 模式接入三类关键配置,并结合仓库源码补充凭证解析顺序、长轮询 API 细节与群组访问控制策略,帮助你在生产环境正确落地该渠道并完成排障。
插件定位与安装方式
Zalo 插件在 OpenClaw 中以渠道插件(channel plugin)形式提供。其插件清单 openclaw.plugin.json 声明了渠道 id 为 zalo,activation.onStartup 为 false(不随网关无条件自启动,需要配置后才启用),channels 字段登记为 ["zalo"]。
README 给出了两种安装途径:
本地检出(local checkout)安装:
openclaw plugins install ./path/to/local/zalo-plugin
npm 安装:
openclaw plugins install @openclaw/zalo
此外,OpenClaw 的引导流程(Onboarding)中也内置了 Zalo 选项:在选择渠道时勾选 Zalo 并确认安装提示,即可自动拉取该插件。官方渠道文档 docs/channels/zalo.md 补充说明:当前版本的 OpenClaw 已将 Zalo 作为捆绑插件随发行版一起提供,打包构建无需单独安装;只有在旧版本构建或自定义安装中排除了 Zalo 时,才需要通过上述 npm 包方式显式安装。
基础配置:Bot 凭证、DM 策略与代理
README 给出的最小可用配置如下,这是轮询(long-polling)模式的典型写法:
{
channels: {
zalo: {
enabled: true,
botToken: "12345689:abc-xyz",
dmPolicy: "pairing",
proxy: "http://proxy.local:8080",
},
},
}
各字段含义:
| 配置项 | 说明 |
|---|---|
enabled |
是否启用 Zalo 渠道启动 |
botToken |
Zalo Bot Platform 签发的 Bot Token,格式为 numeric_id:secret |
dmPolicy |
私聊访问策略,默认 pairing(配对码模式) |
proxy |
API 请求走代的代理 URL |
代理(proxy)的源码实现
proxy 字段并非简单透传,而是在 proxy.ts 中通过 resolveZaloProxyFetch 实现(L7-L19):对传入的代理 URL 做 trim 与去空格处理后,调用 openclaw/plugin-sdk/fetch-runtime 的 makeProxyFetch 构造一个带代理的 fetch 实现,并按 URL 字符串做进程内缓存(proxyCache)避免重复创建。这个带代理的 fetcher 会被注入到所有 Bot API 调用中,未配置时直接返回 undefined,走默认 fetch。
Bot Token 的解析顺序
Zalo Token 的解析逻辑集中在 token.ts 的 resolveZaloToken(L34-L93),其优先级链条值得明确掌握:
- 账户级
accounts.<id>.botToken(多账户配置下优先生效); - 账户级
accounts.<id>.tokenFile(从文件读取,且明确拒绝符号链接,见readTokenFromFile中rejectSymlink: true); - 顶层
channels.zalo.botToken(扁平写法); - 顶层
channels.zalo.tokenFile; - 环境变量
ZALO_BOT_TOKEN——仅对默认账户(default account)生效,非默认账户不会回落到该环境变量。
解析结果携带 source(env/config/configFile/none)与 status(available/configured_unavailable/missing)诊断信息,会展示在渠道状态快照中,便于排查凭证缺失问题。
Webhook 模式
当部署环境拥有公网可达的 HTTPS 端点时,可以改用 Webhook 推送替代长轮询。README 给出的配置为:
{
channels: {
zalo: {
webhookUrl: "https://example.com/zalo-webhook",
webhookSecret: "your-secret-8-plus-chars",
webhookPath: "/zalo-webhook",
},
},
}
README 特别指出:如果省略 webhookPath,插件会直接使用 Webhook URL 自身的路径作为网关 HTTP 服务上的监听路径。并且任何配置变更后都需要重启网关(Restart the gateway after config changes)。
Webhook 注册与验证的源码链路
Webhook 的注册走 Zalo Bot API 的 setWebhook 方法,见 api.ts(L270-L299):setWebhook(token, { url, secret_token }) 将 URL 与密钥一同提交给 Zalo 平台;配套的 getWebhookInfo 可查询当前 Webhook 状态(含 updated_at、has_custom_certificate),deleteWebhook 用于撤销。插件启动时根据 webhookUrl 是否存在决定运行模式——channel.ts 的账户快照中即以 account.config.webhookUrl ? "webhook" : "polling" 标记当前模式(L225)。
Webhook 模式的关键约束
结合仓库内官方渠道文档 docs/channels/zalo.md 的记载,Webhook 模式有以下必须满足的前提与行为细节:
- Webhook URL 必须使用 HTTPS;密钥(
webhookSecret)长度要求 8-256 字符; - Zalo 推送事件携带
X-Bot-Api-Secret-Token请求头,网关侧使用常量时间比较校验密钥,防止时序侧信道; - 请求体上限 1 MB,读取超时 30 秒;速率限制为 每路径+客户端 IP 120 次/60 秒,超限返回 HTTP 429;
- 请求必须使用
Content-Type: application/json(或+json媒体类型); - 只有原始事件被持久化落盘成功后才返回 HTTP 200,落盘失败返回 HTTP 500;持久化成功对应的
200响应头带有x-openclaw-delivery-accepted: durable,反向代理可据此区分 OpenClaw 真实受理与通用 200; - 事件按消息 id 维护重放墓碑(tombstones):30 天、每账户最多 20,000 条已完成事件,用于幂等去重;
- 按 Zalo API 文档约定,
getUpdates长轮询与 Webhook 二选一,互斥。
长轮询模式与 Zalo Bot API 细节
未配置 webhookUrl 时,插件默认使用长轮询接收消息。API 客户端的核心封装在 api.ts:
- API 基地址默认为
https://bot-api.zaloplatforms.com(L14),可通过环境变量ZALO_API_URL覆盖;resolveZaloApiUrl(L112-L131)要求覆盖值必须是合法的 http/https URL,且不允许携带 query 或 fragment,尾部斜杠会被归一化去除; - 所有方法统一走
callZaloApi(L136-L176):请求形如POST {apiBase}/bot{token}/{method},带默认请求超时控制(AbortController),响应体{ ok, result, error_code, description }中ok为假时抛出携带errorCode的ZaloApiError; getUpdates(L256-L265):timeout参数以秒为单位、以字符串形式传给 API,默认 30 秒;客户端超时会额外放宽 5 秒((timeout + 5) * 1000ms)避免误判。源码注释特别指出:Zalo 每次调用只返回单条 update,而非像 Telegram 那样返回数组,这是接入时最容易踩的差异点;- 轮询超时的识别:
ZaloApiError.isPollingTimeout(L106-L109)以error_code === 408判定"长时间等待无更新",监控循环据此将其视为正常的空转而非错误; - 消息类型:入站事件名包含
message.text.received、message.image.received、message.sticker.received、message.unsupported.received(ZaloUpdate定义,L55-L62); - 出站媒体:
sendPhoto(L203-L235)要求照片参数必须是绝对 HTTP(S) URL,并先经 SSRF 策略(resolvePinnedHostnameWithPolicy)固定主机名解析校验;其请求超时使用更长的ZALO_SEND_PHOTO_REQUEST_TIMEOUT_MS,因为 Zalo 侧会先自行拉取该 URL 再回复。
访问控制:DM 配对与群组策略
私聊(DM)
dmPolicy可选pairing(默认,见 channel.ts 快照中dmPolicy ?? "pairing")、allowlist、open、disabled;- 配对模式下,陌生发送者会收到配对码,批准前其消息被忽略,配对码 1 小时过期。常用命令:
openclaw pairing list zaloopenclaw pairing approve zalo <CODE>
allowFrom接受数字 Zalo 用户 ID(不做用户名解析);dmPolicy: "open"时必须显式写"*"。
群聊
群聊能力在插件元数据中显式声明:channel.ts 的 capabilities.chatTypes 为 ["direct", "group"](L207),且 resolveRequireMention: () => true(L238)意味着群内必须 @提及才会触发,且不可关闭。群组访问控制由两级配置构成:
groupPolicy:open|allowlist|disabled;groupAllowFrom:限制群内哪些发送者 ID 可以触发机器人,未设置时回落到 DM 的allowFrom;- 解析规则:只要
channels.zalo有配置而未显式设置groupPolicy,就解析为open;若channels.zalo整体缺失,则运行期按allowlist失败关闭(fail closed)。
源码中还有对应的安全告警收集器 collectZaloSecurityWarnings(channel.ts L158-L197):当群策略为 open 且没有任何 groupAllowFrom/allowFrom 白名单时,会输出"任意群成员(提及门控)均可触发"的严重级别告警,并提示通过 groupPolicy="allowlist" + groupAllowFrom 收敛。
媒体与出站能力边界
插件的能力声明(channel.ts L206-L214)与实际行为:
| 能力 | 状态 |
|---|---|
| 私聊 / 群聊 | 均支持(群聊需 @提及) |
| 媒体(入站/出站) | 支持,受 mediaMaxMb 限制(默认 5 MB) |
| 表情回应(reactions) | 不支持 |
| 话题(threads) | 不支持 |
| 投票(polls) | 不支持 |
| 原生命令 | 不支持 |
| 引用回复(reply-to) | 不使用,固定关闭(replyToMode 固定 off) |
| 流式输出 | 声明 block-streaming,但 Zalo 无专用出站队列/合并文本调优项 |
出站文本按 2000 字符分块(zaloTextChunkLimit = 2000,channel.ts L94,为 Zalo API 的文本长度上限),发送前还会经过 sanitizeAssistantVisibleText 清理模型/工具 XML 痕迹。主动发送消息(CLI/cron 场景)使用聊天 ID 作为目标:
openclaw message send --channel zalo --target 123456789 --message "hi"
目标前缀 zalo: 与 zl: 会被自动剥离(normalizeZaloMessagingTarget,L77-L83),group: 前缀的群目标可被推断为群组会话(L244-L247)。
故障排查
机器人不响应:
- 用
openclaw channels status --probe探测 Token 与账户状态(快照会显示tokenSource、tokenStatus与mode); - 确认发送者已通过配对或
allowFrom白名单; - 查看网关日志:
openclaw logs --follow。
Webhook 收不到事件:
- 确认 URL 为 HTTPS、密钥长度 8-256 字符;
- 确认网关 HTTP 端点在
webhookPath上可达; - 确认没有同时运行
getUpdates轮询(二者互斥); - 瞬时突发可能被 429 限速(120 次/60s/路径+IP),需退避重试。
注意:部分 Marketplace bot 存在平台侧限制导致无法被拉入群聊,这属于 Zalo 平台约束而非 OpenClaw 策略,需要在 Bot Platform 侧核实。
完整配置参考
以下为 docs/channels/zalo.md 给出的完整配置项(以 channels.zalo.accounts.<id>.* 为准;README 中的扁平顶层写法 channels.zalo.botToken 等属于遗留单账户简写,两种形式均受支持):
| 配置项 | 说明 | 默认值 |
|---|---|---|
channels.zalo.enabled |
启用/禁用渠道启动 | true |
channels.zalo.accounts.<id>.botToken |
Zalo Bot Platform 签发的 Bot Token | - |
channels.zalo.accounts.<id>.tokenFile |
从文件读取 Token(拒绝符号链接) | - |
channels.zalo.accounts.<id>.name |
展示名称 | - |
channels.zalo.accounts.<id>.enabled |
启用/禁用该账户 | true |
channels.zalo.accounts.<id>.dmPolicy |
账户级私聊策略 | pairing |
channels.zalo.accounts.<id>.allowFrom |
私聊白名单(数字用户 ID) | - |
channels.zalo.accounts.<id>.groupPolicy |
账户级群组策略 | 见上文群组规则 |
channels.zalo.accounts.<id>.groupAllowFrom |
群内发送者白名单,回落 allowFrom |
- |
channels.zalo.accounts.<id>.mediaMaxMb |
入站/出站媒体上限(MB) | 5 |
channels.zalo.accounts.<id>.webhookUrl |
启用 Webhook 模式(必须 HTTPS) | - |
channels.zalo.accounts.<id>.webhookSecret |
Webhook 密钥(8-256 字符) | - |
channels.zalo.accounts.<id>.webhookPath |
网关 HTTP 上的 Webhook 路径 | Webhook URL 的路径 |
channels.zalo.accounts.<id>.proxy |
API 请求代理 URL | - |
channels.zalo.accounts.<id>.responsePrefix |
出站回复前缀覆盖 | - |
channels.zalo.defaultAccount |
多账户时的默认账户 | default |
环境变量 ZALO_BOT_TOKEN=... 仅解析默认账户的 Token。配置变更生效的最后一步始终是重启网关;多账户场景下,在 accounts.<id> 下为每个 Bot 各自配置独立的 botToken/name 即可。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00