OpenClaw 接入 Zalo 渠道:Bot API 插件安装、配置与 Webhook 实战指南

原创2026-10-14 23:54:451,335 阅读
文章标签:人工智能AI Agent即时通讯后端本地部署语音

OpenClaw 接入 Zalo 渠道:Bot API 插件安装、配置与 Webhook 实战指南

导读

Zalo 是越南主流的即时通讯平台,其 Bot API 允许开发者创建机器人并进行一对一的私聊对话。OpenClaw(本仓库以 openclaw-cn 中文社区版形式维护)将 Zalo 以独立插件(@clawdbot/zalo)的方式提供,通过 gateway 承载 Zalo 频道,实现消息的收发、配对授权与确定性路由。读完本文,你将掌握:如何从本地源码或 npm 安装 Zalo 插件、如何配置 bot token 与访问策略、如何启用 Webhook 模式并理解网关端的安全校验机制,以及长轮询与 Webhook 两种接收模式各自的适用场景。

一、插件是什么:Zalo 频道的定位与能力边界

Zalo 频道插件位于仓库 extensions/zalo/ 目录,其 package.json 中声明渠道元信息:渠道 ID 为 zalo,别名为 zl,在渠道选择列表中显示为 "Zalo (Bot API)",简介为 "Vietnam-focused messaging platform with Bot API"(extensions/zalo/package.json)。

从插件入口 extensions/zalo/index.ts 可以看到,插件在注册时会执行三件事:

  1. 保存插件运行时句柄(setZaloRuntime);
  2. 向核心注册频道插件与频道停靠点(registerChannel);
  3. 注册 HTTP 处理器,用于接管 gateway HTTP 服务器上的 Webhook 请求(registerHttpHandler)。

插件声明的能力集(位于 extensions/zalo/src/channel.ts)明确界定了其边界:

能力 支持情况
私聊(DM) ✅ 支持
群聊 ❌ 暂不支持(等待 Zalo Bot API 开放)
媒体(图片) ✅ 支持
Reactions / Threads / Polls / 原生命令 ❌ 均不支持
流式输出(streaming) ⚠️ 默认屏蔽(受 2000 字符限制影响)

关键行为特性包括:

  • 确定性路由:所有回复都回到发起对话的同一个 Zalo 会话,模型不会自行选择渠道;
  • 共享会话:Zalo 私聊复用 agent 的主会话,不额外创建独立会话;
  • 长文本分块:出站文本按 2000 字符切块发送(Zalo API 限制);
  • 配对模式:私聊访问默认走 pairing(配对)授权流程。

二、安装插件:本地 checkout 与 npm 两种方式

2.1 从本地源码 checkout 安装

在本仓库源码目录下执行:

openclaw-cn plugins install ./extensions/zalo

这种方式的优点是直接使用仓库内的最新实现,适合二次开发、调试或离线环境。

2.2 从 npm 安装

openclaw-cn plugins install @clawdbot/zalo

插件元数据中声明了安装来源:npm 包名为 @clawdbot/zalo,本地路径为 extensions/zalo,默认安装选择为 npm(见 extensions/zalo/package.json)。

2.3 通过 Onboarding 交互式安装

在 onboarding 流程中选择 Zalo,并在安装确认提示中确认,即可自动拉取插件。这适合首次安装时使用向导快速完成渠道接入。

三、获取 Bot Token:Zalo Bot Platform

接入 Zalo Bot API 前,需要先在 Zalo 官方机器人平台创建机器人并获取 token:

  1. 打开 https://bot.zaloplatforms.com 并登录;
  2. 创建新的 Bot 并完成基础设置;
  3. 复制生成的 Bot Token(格式形如 12345689:abc-xyz)。

插件源码中的提示逻辑(extensions/zalo/src/onboarding.ts)会在引导时展示上述步骤,并提醒也可以使用环境变量 ZALO_BOT_TOKEN 注入 token。

四、最小配置:启用频道与设置 token

4.1 基础配置示例

在配置文件(JSON5 格式)中写入:

{
  channels: {
    zalo: {
      enabled: true,
      botToken: "12345689:abc-xyz",
      dmPolicy: "pairing",
      proxy: "http://proxy.local:8080"
    }
  }
}

各字段含义:

  • enabled:是否在启动时拉起该频道;
  • botToken:从 Zalo Bot Platform 获取的机器人 token;
  • dmPolicy:私聊访问策略,默认 pairing(详见下文"访问控制");
  • proxy:访问 Zalo API 时使用的代理地址,适用于国内网络环境等需要代理的场景。

4.2 Token 的三种注入来源

插件的 token 解析逻辑位于 extensions/zalo/src/token.ts,解析优先级(针对默认账户)为:

  1. 配置文件:channels.zalo.botToken;
  2. Token 文件:channels.zalo.tokenFile 指向的文件内容(自动 trim());
  3. 环境变量:ZALO_BOT_TOKEN(仅对默认账户生效)。

如果启用多账户,resolveZaloToken 会优先读取 channels.zalo.accounts.<id>.botToken 或对应的 tokenFile,再回退到顶层配置。token 解析结果会标记来源(env / config / configFile / none),用于 openclaw-cn channels status 等诊断命令展示。

4.3 多账户支持

在默认账户之外,可通过 channels.zalo.accounts 配置多个 Zalo 机器人账户,每个账户拥有独立的 token、访问策略、Webhook 与代理配置:

{
  channels: {
    zalo: {
      enabled: true,
      defaultAccount: "support-bot",
      accounts: {
        "support-bot": {
          name: "Support Bot",
          enabled: true,
          botToken: "123456789:aaa-bbb",
          dmPolicy: "allowlist",
          allowFrom: ["100010001", "100020002"]
        },
        "news-bot": {
          name: "News Bot",
          botToken: "987654321:ccc-ddd"
        }
      }
    }
  }
}

账户解析逻辑(extensions/zalo/src/accounts.ts)会先将账户配置与顶层基础配置合并(账户级字段优先),再判断 enabled、解析 token 与 defaultAccount。

五、访问控制:私聊的四种策略

Zalo 插件的配置模式(extensions/zalo/src/config-schema.ts)中,dmPolicy 支持四种取值:

取值 行为
pairing(默认) 未知发送者会收到一个配对码,消息被忽略直到配对被批准;配对码 1 小时后过期
allowlist 仅接受 allowFrom 列表中已批准的用户 ID
open 接受任意用户消息(要求 allowFrom 中包含 "*")
disabled 完全拒绝私聊消息

allowFrom 接受数字形式的 Zalo 用户 ID(插件没有用户名查询能力)。该字段支持 zalo: 与 zl: 前缀,插件会在比较时自动归一化去除前缀(见 extensions/zalo/src/monitor.ts)。

5.1 批准配对

默认策略下,当陌生用户首次给机器人发消息时,机器人会回复一条包含配对码与用户 ID 的提示。管理员可通过 CLI 批准:

openclaw-cn pairing list zalo
openclaw-cn pairing approve zalo <CODE>

5.2 安全提示:避免使用 open 策略

插件的状态诊断模块(extensions/zalo/src/status-issues.ts)会在 dmPolicy 为 open 时向 openclaw-cn channels status 报告一条配置类告警,提示"任何用户都可以不经配对直接给机器人发消息",并建议改为 pairing 或 allowlist。这属于内置的主动安全审计,值得在部署时留意。

六、消息收发机制:长轮询与 Webhook

Zalo 插件支持两种接收更新的模式,二者互斥(Zalo API 文档明确二者不可同时使用)。启动时 monitorZaloProvider 会根据是否配置 webhookUrl 自动选择模式(extensions/zalo/src/monitor.ts)。

6.1 长轮询模式(默认)

不配置 webhookUrl 时,插件调用 Zalo Bot API 的 getUpdates 接口进行长轮询:

  • 单次轮询超时 30 秒,接口调用内部超时设为 30 + 5 秒;
  • 轮询返回单个更新(与 Telegram 返回数组不同,源码注释已注明此差异);
  • 收到 408 错误码视为正常超时(无新消息),不报错;
  • 适合无需公网 URL 的场景,是默认推荐方式。

6.2 Webhook 模式

在需要低延迟推送或无法长时间占用轮询连接时,可启用 Webhook:

{
  channels: {
    zalo: {
      webhookUrl: "https://example.com/zalo-webhook",
      webhookSecret: "your-secret-8-plus-chars",
      webhookPath: "/zalo-webhook"
    }
  }
}

Webhook 模式启动时会做如下校验与动作(见 extensions/zalo/src/monitor.ts):

  1. webhookUrl 与 webhookSecret 必填;
  2. webhookUrl 必须为 https:// 开头;
  3. webhookSecret 长度必须在 8~256 字符之间;
  4. 调用 setWebhook 将回调地址与 secret 注册到 Zalo;
  5. 在 gateway 的 HTTP 服务器上注册请求处理器,路径解析规则为:
    • 若配置了 webhookPath,则使用该路径(自动补全前导 /、去除尾部 /);
    • 若省略 webhookPath,则从 webhookUrl 中提取 URL 路径作为监听路径;
  6. 在 gateway 停止(abort 信号触发)时调用 deleteWebhook 清理注册。

配置变更后需重启 gateway 才会生效。

6.3 Webhook 请求的安全校验

Webhook 请求处理器(extensions/zalo/src/monitor.ts)在把事件交给 agent 之前做了多层防护,这些细节对线上安全至关重要:

  • 方法限制:仅接受 POST,其他方法返回 405 Method Not Allowed;
  • 恒定时间比较:通过请求头 X-Bot-Api-Secret-Token 与配置的 webhookSecret 做 timingSafeEqual 校验,长度不匹配时也会填充后执行比较,避免通过时序推断 secret(返回 401 unauthorized);
  • 限流:按"路径 + 来源 IP"维度限流,窗口为 60 秒,最多 120 次请求,超限返回 429 Too Many Requests;
  • Content-Type 校验:非 application/json(或 +json)返回 415 Unsupported Media Type;
  • 体积限制:请求体最大 1 MB,超限返回 413;
  • 重放去重:按 event_name + message_id 在 5 分钟内去重,重复事件直接返回 200 ok 但不再进入消息处理管线。

上述防护均有对应单元测试覆盖(extensions/zalo/src/monitor.webhook.test.ts),例如非 JSON content-type 返回 415、重复事件只触发一次入站、超限请求返回 429 等,可直接运行验证。

七、入站消息处理与回复路由

7.1 支持的消息类型

消息类型 处理方式
文本(message.text.received) 完整支持,进入 agent 对话管线
图片(message.image.received) 下载图片并作为媒体附件进入管线(caption 作为文本)
贴纸(message.sticker.received) 仅记录日志,不触发 agent 回复
其他不支持类型(message.unsupported.received) 仅记录日志

图片入站处理(extensions/zalo/src/monitor.ts)会先下载远程图片,再通过核心的媒体存储机制按 mediaMaxMb(默认 5 MB)上限保存,之后连同 caption 一起进入标准入站管线。

7.2 入站消息的标准管线

文本与图片消息最终都进入 processMessageWithPipeline(extensions/zalo/src/monitor.ts),完成以下工作:

  1. 依据 dmPolicy 与 allowFrom 做访问控制(配对/白名单判断);
  2. 依据群聊/私聊与访问策略计算命令授权(CommandAuthorized);
  3. 通过 resolveAgentRoute 确定消息应路由到的 agent 与会话;
  4. 将消息归一化为核心标准入站信封(channel envelope),携带 From、To、SessionKey、Provider: "zalo"、Surface: "zalo" 等上下文;
  5. 记录入站会话并调用 dispatchReplyWithBufferedBlockDispatcher 分发到 agent 处理。

7.3 出站回复:分块与媒体

出站回复由 deliverZaloReply 完成(extensions/zalo/src/monitor.ts):

  • 文本按 2000 字符分块发送(支持按换行/空格优先断行的智能分块);
  • 若回复包含媒体 URL,则通过 sendPhoto 发送图片,并把文本作为首张图片的 caption;
  • Markdown 表格会被转换为更兼容的表格模式后发送;
  • 每条消息发送成功后更新 lastOutboundAt 状态,供渠道状态页展示。

底层 API 封装位于 extensions/zalo/src/api.ts:统一 POST 到 https://bot-api.zaloplatforms.com/bot<token>/<method>,提供 getMe、sendMessage、sendPhoto、getUpdates、setWebhook、deleteWebhook、getWebhookInfo 等接口,并在 ok: false 时抛出携带 error_code 的 ZaloApiError。

八、CLI 投递目标与运维命令

8.1 直接发送消息(CLI / cron)

可以使用 chat id 作为目标,通过消息命令直接投递:

openclaw-cn message send --channel zalo --target 123456789 --message "hi"

目标解析规则支持 zalo: 与 zl: 前缀,且纯数字 ID(3 位及以上)会被识别为 Zalo chat id(见 extensions/zalo/src/channel.ts)。

8.2 状态诊断

# 探测 token 有效性并展示渠道状态
openclaw-cn channels status --probe

# 查看 gateway 日志
openclaw-cn logs --follow

插件通过 probeZalo(调用 getMe)验证 token 并获取机器人昵称与头像(extensions/zalo/src/probe.ts),状态页会展示 token 来源、运行模式(webhook / polling)、最近入站/出站时间与 DM 策略等信息。

8.3 代理支持

proxy 配置通过 undici 的 ProxyAgent 实现,代理 fetcher 会按代理 URL 缓存复用(extensions/zalo/src/proxy.ts)。API 调用、探针与 Webhook 注册均会使用该 fetcher,适用于需要代理访问 Zalo API 的网络环境。

九、常见问题排查

9.1 机器人不回复

  1. 用 openclaw-cn channels status --probe 确认 token 有效;
  2. 确认发送者已通过配对或 allowFrom 白名单授权;
  3. 检查 gateway 日志:openclaw-cn logs --follow。

9.2 Webhook 收不到事件

  1. 确认 webhookUrl 使用 HTTPS;
  2. 确认 webhookSecret 长度在 8~256 字符之间;
  3. 确认 gateway HTTP 服务器在 webhookPath(或 webhook URL 路径)上可达;
  4. 确认长轮询未在运行(二者互斥)。

9.3 性能与限制提示

  • 出站文本 2000 字符分块;
  • 入站媒体默认上限 5 MB(mediaMaxMb 可调);
  • 流式输出默认屏蔽,长文本以分块形式发送。

十、关联文档与深入阅读

提示:修改 channels.zalo 相关配置后,务必重启 gateway 使配置生效;如配置了 webhookUrl,请确认 getUpdates 轮询已停止,以避免两种模式冲突。

登录后查看全文
openclaw-cn