首页
/ OpenClaw Zalo 个人号插件(zalouser)实战指南:基于 zca-js 的进程内自动化接入

OpenClaw Zalo 个人号插件(zalouser)实战指南:基于 zca-js 的进程内自动化接入

2026-09-09 13:31:07作者:咎岭娴Homer

本篇技术指南围绕 OpenClaw 中的 zalouser 插件展开,讲解如何通过该插件以进程内(in-process)原生 zca-js 方式自动化一个普通的 Zalo 个人账号(非官方 Bot API),实现二维码登录、收发消息、媒体发送、群组策略与多账号管理。读完本文,你将掌握从插件安装、Gateway 配置、CLI 登录/运维到 Agent 工具调用的完整实操链路,并理解其访问控制、入站消息持久化与底层实现原理。

风险提示:Zalo 个人账号自动化属于非官方集成,可能导致账号被限制或封禁,请自行评估风险后再使用。

插件定位与命名:zalouser 与 zalo 的区别

在 OpenClaw 的渠道体系中,zalouserzalo 是两个语义明确区分的渠道 ID:

  • zalouser:本插件对应的渠道 ID,明确标识其自动化的是 Zalo 个人用户账号(unofficial),基于 zca-js 库在进程内运行,不需要任何外部 zca / openzca CLI 二进制
  • zalo:官方 Zalo Bot / webhook 集成渠道(见 docs/channels/zalo.md)。

从插件的 manifest(extensions/zalouser/openclaw.plugin.json)可以看到,插件声明 "id": "zalouser""name": "Zalo Personal""channels": ["zalouser"],并向 Agent 暴露 "tools": ["zalouser"] 工具契约;此外它还注册了 zalouser-credentials-json-to-plugin-statezalouser-direct-session-keys 两个状态迁移,用于 openclaw doctor --fix 自动修复历史凭证格式。

运行位置:进程内运行于 Gateway

zalouser 插件运行在 Gateway 进程内部。这意味着:

  • 若你的 Gateway 部署在远程主机,必须在该主机上安装并配置插件,然后重启 Gateway 生效;
  • 插件不依赖外部守护进程或 CLI 二进制,zca-js 的 socket 监听器、登录凭证、消息收发全部在本进程内完成。

从源码结构看,extensions/zalouser/src/channel.ts 通过 createChatChannelPlugin 组装了完整的渠道能力:目录查询(self / peers / groups / group members)、认证(loginWithQrStart / loginWithQrWait / logoutAccount)、消息收发、状态探测(probeZalouser)以及设置向导(setup wizard),并将 zca-js 相关逻辑通过惰性加载(createLazyRuntimeModule)延迟到运行时再导入。

安装插件

从 npm 安装

openclaw plugins install @openclaw/zalouser

建议使用裸包名以跟随当前官方发布标签;仅在需要可复现安装时才固定精确版本:

openclaw plugins install @openclaw/zalouser@<version>

安装完成后重启 Gateway

从本地源码目录安装(开发模式)

PLUGIN_SRC=./path/to/local/zalouser-plugin
openclaw plugins install "$PLUGIN_SRC"
cd "$PLUGIN_SRC" && pnpm install

同样需要重启 Gateway。仓库中的插件源码位于 extensions/zalouser,可作为本地开发参考。更完整的插件安装说明见 docs/tools/plugin.md

快速上手:配置与二维码登录

1. 登录(QR 扫码)

登录需要在 Gateway 所在机器上执行:

openclaw channels login --channel zalouser

执行后用 Zalo 手机 App 扫描终端输出的二维码完成授权。登录凭证(cookie、imei、userAgent 等)会被持久化到 OpenClaw 状态中;从源码看(extensions/zalouser/src/zalo-js.ts),QR 登录 TTL 为 3 分钟,等待超时为 120 秒,凭证写入时会计算签名以判断是否有变化,避免无意义的重复落盘。

2. 启用渠道

渠道配置位于 channels.zalouser 下(不是 plugins.entries.*):

{
  channels: {
    zalouser: {
      enabled: true,
      dmPolicy: "pairing",
    },
  },
}

3. 重启并首次配对

重启 Gateway(或完成设置向导)后,私聊访问默认采用 pairing 策略,首次收到陌生联系人消息时需要批准配对码(详见下文“访问控制”)。

4. 发送第一条消息

openclaw message send --channel zalouser --target <threadId> --message "Hello from OpenClaw"

<threadId> 可通过下文 directory 系列命令查询。

CLI 命令速查

插件注册的完整 CLI 操作如下:

# 登录 / 登出 / 状态
openclaw channels login --channel zalouser
openclaw channels login --channel zalouser --account <name>
openclaw channels logout --channel zalouser
openclaw channels status --probe

# 发消息
openclaw message send --channel zalouser --target <threadId> --message "Hello from OpenClaw"

# 目录查询(用于解析 ID)
openclaw directory self --channel zalouser
openclaw directory peers list --channel zalouser --query "name"
openclaw directory groups list --channel zalouser --query "name"
openclaw directory groups members --channel zalouser --group-id <id>

# 私聊配对审批
openclaw pairing list zalouser
openclaw pairing approve zalouser <code>

其中 directory 系列命令在源码中的实现位于 extensions/zalouser/src/channel.tsdirectory 适配器:self 调用 getZaloUserInfo 返回当前账号信息;listPeers 调用 listZaloFriendsMatching 按名字/ID 检索好友;listGroups 返回群列表(群 ID 以 group: 前缀标记);listGroupMembers 返回指定群成员。

配置详解

基础配置与账户级字段

extensions/zalouser/src/config-schema.tsZalouserConfigSchema 可以看出,channels.zalouser 支持以下账户级配置字段:

字段 类型 说明
enabled boolean 是否启用渠道(根级与账户级均可设置)
dmPolicy pairing | allowlist | open | disabled 私聊访问策略,默认 pairing
allowFrom string[] 私聊放行名单,应使用稳定的 Zalo 用户 ID
groupPolicy allowlist | open | disabled 群访问策略,默认 allowlist
groups object 群级配置表(见下文)
groupAllowFrom string[] 允许群内哪些发送者触发机器人
defaultAccount string 默认账号 ID
accounts object 多账号配置表
profile string 凭证 Profile 名(选择已保存的登录会话)
mediaMaxMb number 单条出站附件大小上限(MiB)
markdown object Markdown 解析配置
historyLimit number 群历史消息保留条数
messagePrefix / responsePrefix string 消息前缀 / 响应前缀
dangerouslyAllowNameMatching boolean 危险模式:开启启动期名称解析与运行时群名称匹配(见下文)

注意:分组策略默认值在 extensions/zalouser/src/accounts.ts 中被显式收敛为 "allowlist"(源码注释表明这是为了与 Telegram 渠道的默认安全策略保持一致,除非显式开放,否则群组默认保持白名单模式)。

私聊访问控制(DMs)

channels.zalouser.dmPolicy 支持四种取值:pairing | allowlist | open | disabled,默认 pairing

  • pairing:陌生联系人需通过配对码审批,命令为 openclaw pairing list zalouseropenclaw pairing approve zalouser <code>
  • allowlist:仅 channels.zalouser.allowFrom 中列出的发送者可访问;
  • open:向所有私聊开放;
  • disabled:禁用私聊入口。

allowFrom 中的条目应当使用稳定的 Zalo 用户 ID,也可以引用静态发送者访问组(accessGroup:<name>)。交互式配置向导中,可以直接输入联系人名字,插件会通过进程内联系人查询解析为 ID 写入配置。若配置中残留了原始名称,则仅当 channels.zalouser.dangerouslyAllowNameMatching: true 时,启动阶段才会尝试解析该名称;未开启该选项时,运行时发送者校验只认 ID,原始名称会被忽略(不参与授权判定)。

群组访问策略(可选)

默认行为是 channels.zalouser.groupPolicy = "allowlist",即群组必须显式加入白名单才能触发机器人:

  • groupPolicy = "open":开放所有群组;
  • groupPolicy = "disabled":屏蔽所有群组;
  • groupPolicy = "allowlist" 时:
    • channels.zalouser.groups 的键应为稳定的群 ID;名称仅在 dangerouslyAllowNameMatching: true 时于启动期解析为 ID;
    • channels.zalouser.groupAllowFrom 控制白名单群内哪些发送者可以触发机器人,同样支持 accessGroup:<name> 静态组引用。

一个完整示例:

{
  channels: {
    zalouser: {
      groupPolicy: "allowlist",
      groupAllowFrom: ["1471383327500481391"],
      groups: {
        "123456789": { enabled: true },
        "Work Chat": { enabled: true },
      },
    },
  },
}

关于群匹配的几个要点:

  • 群白名单匹配默认仅按 ID;未解析的名称不参与授权,除非开启 dangerouslyAllowNameMatching
  • dangerouslyAllowNameMatching: true 是一个“应急兼容模式”(break-glass),会重新启用可变的启动期名称解析与运行期群名称匹配;
  • groupAllowFrom 在普通群消息场景下不会回退到 allowFrom:白名单群若留空 groupAllowFrom,则向任意发送者开放该群。唯一例外是受控命令(如 /new),其发送者校验在 groupAllowFrom 为空时会回退到 allowFrom
  • 历史遗留字段 channels.zalouser.groups.<id>.allow 已被 enabled 取代,openclaw doctor --fix 会自动将 allow 迁移为 enabled(对应 manifest 中声明的 doctorContract 状态迁移能力)。

从源码角度,extensions/zalouser/src/group-policy.ts 实现了群条目的解析顺序与通配逻辑:候选依次为群 ID → group:<id> 别名 → 群名/slug(仅名称匹配开启时生效)→ 通配 *isZalouserGroupEntryAllowed 同时兼容旧字段 allow !== false 与新字段 enabled !== false

群消息提及门控(requireMention)

channels.zalouser.groups.<group>.requireMention 控制群内回复是否必须提及(@)机器人。解析顺序为:群 ID → group:<id> 别名 → 群名/slug(仅 dangerouslyAllowNameMatching: true 时应用名称候选)→ * → 默认值 true

  • 该门控同时作用于白名单群与 open 模式群;
  • 引用(quote)机器人的消息视作隐式提及,可触发群激活;
  • 受控命令(如 /new)可绕过提及门控;
  • 因需要提及而被跳过的群消息,会被 OpenClaw 记录为待处理群历史,并在下一条被处理的群消息中一并携带;
  • 群历史条数上限依次取 channels.zalouser.historyLimitmessages.groupChat.historyLimit,最后回退为 50

配置示例:

{
  channels: {
    zalouser: {
      groupPolicy: "allowlist",
      groups: {
        "*": { enabled: true, requireMention: true },
        "Work Chat": { enabled: true, requireMention: false },
      },
    },
  },
}

多账号与 Profile

zalouser 支持多账号:每个账号映射到 OpenClaw 状态中的一个 zalouser 凭证 Profile。示例:

{
  channels: {
    zalouser: {
      enabled: true,
      groupPolicy: "allowlist",
      defaultAccount: "work",
      accounts: {
        work: { enabled: true, profile: "work", groupPolicy: "allowlist" },
      },
    },
  },
}

多账号登录使用:

openclaw channels login --channel zalouser --account <name>

Profile 解析优先级

凭证 Profile 的选择顺序为(见 extensions/zalouser/src/accounts.tsresolveProfile):

  1. 配置中的显式 profile 字段;
  2. 环境变量 ZALOUSER_PROFILE
  3. 环境变量 ZCA_PROFILE(旧版回退,仅在 ZALOUSER_PROFILE 未设置时生效);
  4. 非默认账号使用其 account id;默认账号使用 default

多账号场景下,建议在配置中为每个账号显式设置 profile,避免单一环境变量导致多个账号共享同一登录会话。

环境变量

变量 作用
ZALOUSER_PROFILE 当渠道/账号配置中未设置 profile 时,指定要使用的 Profile 名称
ZCA_PROFILE 旧版回退,仅当 ZALOUSER_PROFILE 未设置时使用

Profile 名称对应 OpenClaw 状态中保存的 Zalo 登录凭证(cookie、imei、userAgent、language 等)。

功能限制与行为边界

  • 出站文本分块:单条文本被截断/分块为 2000 字符(Zalo 客户端限制)。源码中 extensions/zalouser/src/send.ts 定义 ZALO_TEXT_LIMIT = 2000,通过 chunkTextRangesnewline(优先换行处)或 hard 模式切分,分块发送时每次投递结果都会先持久化再发送下一块;Markdown 模式下还会将文本样式(加粗、斜体、缩进等)同步切分到各分块。
  • 附件大小channels.zalouser.mediaMaxMb 限制单条出站附件大小(MiB)。生效优先级为:所选渠道账号的 mediaMaxMb → 渠道根级 mediaMaxMbagents.defaults.mediaMaxMb 兜底。图片可能被自动优化压缩;未设置时沿用共享加载器默认值。Agent 工具的 image 动作仅在当前投递账号使用了所选 Profile 时才采用该账号的容量上限,否则使用渠道根级与 Agent 兜底值(extensions/zalouser/src/tool.tsresolveToolMediaMaxBytes)。
  • 不支持流式输出(Streaming is not supported)。
  • 入站去重:已完成处理的入站消息 ID 保留 30 天,且每个账号最多保留最近 1000 条

入站消息持久化

OpenClaw 会在处理每条原始 zca-js 消息回调之前先将其持久化。Gateway 重启后,待处理消息会从账号队列恢复继续处理,且每个私聊会话/群的处理保持串行化(serialized)。

需要理解的能力边界:zca-js 的 socket 监听器不提供投递确认,重连后也不会自动重放旧消息。因此持久化队列只能保护“回调已到达 OpenClaw 之后”的本地崩溃窗口,无法恢复 socket 从未投递过的消息;去重墓碑(replay tombstones)主要用来防范相同 Zalo 消息 ID 的重复回调。

打字、反应与回执

  • 回复派发前,OpenClaw 会尽力发送 typing(正在输入)事件
  • 渠道消息动作支持 react 反应(Agent 工具动作中不包含 react,仅渠道消息动作支持):
    • 使用 remove: true 可从某条消息上移除指定的反应 emoji;
    • 反应语义参见 docs/tools/reactions.md
  • 对携带事件元数据的入站消息,OpenClaw 会尽力回送 delivered + seen 确认(对应源码 extensions/zalouser/src/send.ts 中的 sendDeliveredZalouser / sendSeenZalouser)。

Agent 工具:zalouser

插件为 AI Agent 注册了名为 zalouser 的工具,动作包括:sendimagelinkfriendsgroupsmestatus

extensions/zalouser/src/tool.ts 可见其完整参数契约:

参数 类型 用途
action 枚举 要执行的动作(上述 7 个之一)
threadId string 消息目标线程 ID(send/image/link 必需)
message string 消息文本(send 必需;image/link 中作为 caption)
isGroup boolean 目标是否为群聊
profile string 凭证 Profile 名称
query string friends/groups 动作的搜索关键字
url string image/link 动作的媒体/链接 URL

各动作行为:

  • send:发送文本消息,要求 threadIdmessage,成功返回 { success: true, messageId }
  • image:发送图片 URL,要求 threadIdurl,可带 caption,并遵循上文 mediaMaxMb 容量解析;
  • link:发送链接,要求 threadIdurl
  • friends / groups:按 query 搜索好友/群列表;
  • me:返回当前账号资料(未认证时返回 { error: "Not authenticated" });
  • status:返回认证状态 { authenticated: boolean }

该工具还能从投递上下文(delivery context)中推断“环境目标”:当回复某条 Zalo 消息时,若未显式传 threadId,工具会自动沿用当前会话的线程与群属性(resolveAmbientZalouserTarget),让 Agent 的回复无需重复指定目标。

故障排查

登录不持久 / 掉线:

openclaw channels status --probe
openclaw channels logout --channel zalouser && openclaw channels login --channel zalouser

白名单/群名称未解析:

  • allowFrom / groupAllowFrom 中使用数字 ID,在 groups 中使用稳定的群 ID;
  • 若确实需要精确的好友名/群名,才开启 channels.zalouser.dangerouslyAllowNameMatching: true

从旧的外部 zca / CLI 方案升级:

  • 移除任何外部 zca 进程假设:当前渠道完全通过 zca-js 在进程内运行,无外部 CLI 二进制;
  • 凭证若来自旧格式,可运行 openclaw doctor --fix 触发 manifest 中声明的状态迁移。

相关文档

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
docsdocs
暂无描述
Markdown
899
5.83 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.03 K
525
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395