OpenClaw zalouser 插件实战:用 zca-js 进程内集成驱动 Zalo 个人账户消息通道
本篇基于 extensions/zalouser/README.md 展开,讲清 OpenClaw 的 Zalo 个人账号(Zalo Personal Account)通道插件 @openclaw/zalouser 的安装、QR 扫码登录、多账号配置、访问策略与 Agent 工具集成。读完你可以独立完成该插件的部署与日常运维,并理解其"无外部 CLI、进程内 zca-js 集成"的架构选型在多账号场景下是如何落地的。
风险提示(原文档警告): 对 Zalo 个人账号做自动化可能导致账号被停用或封禁。这是非官方集成,风险自担。
一、插件定位:为什么叫 zalouser
zalouser 通道的命名刻意强调它自动化的是个人 Zalo 用户账号(非官方途径),与潜在的官方 Zalo Bot API 集成(保留给 zalo 通道)区分开。从 extensions/zalouser/package.json 可以看到插件以 @openclaw/zalouser 发布,核心依赖只有 zca-js、typebox 和 zod,并且声明 openclaw 为可选的 peer 依赖(>=2026.8.1)。
它解决的核心问题是:在 Zalo Bot API 不可用的场景下,让 OpenClaw 的 AI Agent 通过个人账户收发 Zalo 消息。README 给出的特性清单如下:
- 通道插件集成,带配置向导(setup wizard)+ QR 扫码登录;
- 通过
zca-js在进程内实现监听器/发送器,无需外部zca、openzca或zca-cli二进制; - 多账号支持;
- Agent 工具集成(工具名
zalouser); - 支持 DM/群组策略(pairing、allowlist 等)。
前置要求仅有两项:一个运行中的 OpenClaw Gateway,以及手机上的 Zalo App(用于扫码登录)。
从 extensions/zalouser/openclaw.plugin.json 的插件元数据可以进一步确认其契约:声明了 channels: ["zalouser"]、工具契约 contracts.tools: ["zalouser"],并启用 doctor 契约(configRepair 与 stateMigrations 均为 true),意味着 openclaw doctor --fix 会参与该插件的配置修复与状态迁移。此外 package.json 中通道别名包含 zlu,频道排序 order: 85,文档路径为 /channels/zalouser(对应 docs/channels/zalouser.md)。
二、安装:npm 与本地源码两种方式
方式 A:npm 安装(默认)
openclaw plugins install @openclaw/zalouser
方式 B:本地源码检出
PLUGIN_SRC=./path/to/local/zalouser-plugin
openclaw plugins install "$PLUGIN_SRC"
cd "$PLUGIN_SRC" && pnpm install
两种方式安装后都需重启 Gateway 生效。
从源码结构看,插件通过 createLazyRuntimeModule 懒加载运行时模块(见 extensions/zalouser/src/channel.ts 第 32 行的 loadZalouserChannelRuntime),即 zca-js 相关的重模块只在真正需要监听、登录或探测时才被 import,这解释了 openclaw.plugin.json 中 activation.onStartup: false 的设计——插件不会在 Gateway 启动时立即拉起完整运行时。
三、快速上手:QR 登录、启用通道、发送消息
3.1 QR 扫码登录
openclaw channels login --channel zalouser
用手机上 Zalo App 扫描终端输出的二维码完成登录。多账号场景下可以指定账号:
openclaw channels login --channel zalouser --account work
QR 登录的底层由 Gateway 侧的 loginWithQrStart / loginWithQrWait 两个回调实现(extensions/zalouser/src/channel.ts 第 165-181 行):先按账号解析 credential profile(resolveZalouserQrProfile),再调用运行时中的 startZaloQrLogin 发起登录并等待扫码结果。凭证以"profile"为单位保存在 OpenClaw 状态中,而不是外部进程的文件里。
3.2 启用通道
在 OpenClaw 配置中开启通道并设定 DM 策略:
channels:
zalouser:
enabled: true
dmPolicy: pairing # pairing | allowlist | open | disabled
dmPolicy 默认值为 pairing(配对码模式):首次 DM 收到配对请求后,在 Gateway 侧批准配对码即可。从 extensions/zalouser/src/channel.ts 第 130 行的状态适配器可以看到,状态快照中展示的 dmPolicy 在缺省时即回退为 "pairing",与文档一致。
3.3 发送一条消息
openclaw message send --channel zalouser --target <threadId> --message "Hello from OpenClaw"
从实现细节看,出站文本在发送前会经过 Markdown 分块处理:extensions/zalouser/src/channel.adapters.ts 中定义了 ZALOUSER_TEXT_CHUNK_LIMIT = 2000,并以 chunkTextForOutbound(markdown 模式)作为 chunker——即出站长文本会被按 2000 字符的 Zalo 客户端限制切分。测试用例 extensions/zalouser/src/channel.sendpayload.test.ts 验证了"先做 Markdown 格式化、再分块"的顺序以及内部分块进度会透传给出站适配器。
四、配置详解
4.1 基础配置
channels:
zalouser:
enabled: true
dmPolicy: pairing
4.2 多账号配置
channels:
zalouser:
enabled: true
defaultAccount: default
accounts:
default:
enabled: true
profile: default
work:
enabled: true
profile: work
这里的关键概念是 account 与 profile 的分离:
- account 是 OpenClaw 通道侧的逻辑账号(决定路由、策略、状态归属);
- profile 是
zca-js侧的凭证档案名,决定实际用哪一套已登录的 Zalo 会话。
账号解析逻辑在 extensions/zalouser/src/accounts.ts 中,profile 的解析优先级为(resolveProfile,第 36-50 行):
- 配置中显式声明的
profile; - 环境变量
ZALOUSER_PROFILE; - 环境变量
ZCA_PROFILE(遗留兼容); - 非默认账号回退到账号 id 本身;默认账号回退到
"default"。
因此官方建议:多账号场景下务必在每个 account 上显式写 profile,避免一个环境变量让多个账号共享同一登录会话。ZALOUSER_PROFILE / ZCA_PROFILE 同时也是该通道"已配置"状态的探测依据(package.json 中 channel.configuredState.env.anyOf)。
另外两个值得注意的默认行为(均可在 accounts.ts 中找到实现):
groupPolicy缺省为"allowlist"(第 32 行注释明确"与 Telegram 的安全默认保持一致")——群组默认需要显式 allowlist 条目才会被处理;- 账号
enabled是通道级enabled与账号级enabled的"与"关系,任一层关闭都会禁用该账号。
官方文档 docs/channels/zalouser.md 对群组侧有更完整的说明,包括 groups.<id>.requireMention 的 @提及门控、groupAllowFrom 的发送者限制、dangerouslyAllowNameMatching 这一"破玻璃"兼容模式(重新启用启动期名称解析与运行时群名匹配),以及 mediaMaxMb 的账号级 → 通道根级 → agents.defaults.mediaMaxMb 的三级回退,可延伸阅读。
五、常用运维命令
# 登录 / 登出 / 状态探测
openclaw channels login --channel zalouser
openclaw channels login --channel zalouser --account work
openclaw channels status --probe
openclaw channels logout --channel zalouser
# 目录查询:查自己、搜好友、查群组、查群成员
openclaw directory self --channel zalouser
openclaw directory peers list --channel zalouser --query "name"
openclaw directory groups list --channel zalouser --query "work"
openclaw directory groups members --channel zalouser --group-id <id>
这些命令并非空壳:channel.ts 中的 directory 适配器(第 60-114 行)实现了 self / listPeers / listGroups / listGroupMembers 四个目录接口,底层调用 getZaloUserInfo、listZaloFriendsMatching、listZaloGroupsMatching、listZaloGroupMembers。群组 id 会以 group:<groupId> 前缀规范化,供会话路由使用。channels status --probe 则走 probeAccount(第 122-123 行)调用 probeZalouser 对凭证 profile 做连通性探测,用于判断登录态是否有效。
六、Agent 工具 zalouser
该插件为 AI Agent 注册了名为 zalouser 的工具(在 openclaw.plugin.json 中以 contracts.tools 声明)。可用动作共 7 个:
| action | 作用 | 关键参数 |
|---|---|---|
send |
发送文本消息 | threadId、message、isGroup |
image |
发送图片 | threadId、url(图片 URL) |
link |
发送链接 | threadId、url |
friends |
列出/搜索好友 | query、profile |
groups |
列出群组 | query、profile |
me |
获取当前登录资料 | profile |
status |
检查认证状态 | profile |
从 extensions/zalouser/src/tool.ts 的 Tool Schema(第 22-33 行)可以确认全部参数集:action、threadId、message、isGroup、profile、query、url,且 additionalProperties: false(不接收未声明参数)。实现上有两个值得了解的细节:
- 环境上下文回退:
resolveZalouserSendTarget(第 100-107 行)表明threadId/isGroup可以省略——当投递上下文(deliveryContext)本身就在zalouser通道上时,工具会自动从当前会话解析目标线程,Agent 不必重复传入;显式参数永远优先。 profile选的是凭证档案,不是通道账号:resolveToolMediaMaxBytes(第 50-68 行)注释明确"Profiles are credentials, not account IDs"。只有当当前投递路由所在账号使用的 profile 与工具传入的 profile 一致时,才会套用该账号的mediaMaxMb上限;否则回退到通道根级/代理级媒体上限,且不会去搜索其他恰好共享该 profile 的账号。
七、故障排查
README 给出的三条排查路径:
- 登录态未持久化:先登出再重新登录——
登出会调用运行时的openclaw channels logout --channel zalouser && openclaw channels login --channel zalouserlogoutZaloProfile清理对应 profile 的会话(channel.ts 第 182-185 行logoutAccount)。 - 状态探测:
openclaw channels status --probe,确认凭证 profile 是否仍处于认证态。 - 名称解析问题(allowlist/群组):优先使用数字型 Zalo ID 或精确的 Zalo 名称,避免依赖可变的群名/昵称做匹配。
官方文档还补充了两类问题(见 docs/channels/zalouser.md):allowlist/群名未解析时改用数字 ID 或显式开启 dangerouslyAllowNameMatching;从旧的外部 zca/CLI 方案升级后需移除对外部 zca 进程的一切假设,因为新通道完全进程内运行。
八、小结
@openclaw/zalouser 是 OpenClaw 面向 Zalo 个人账户的通道插件:它以 zca-js 为唯一运行时依赖,把监听、发送、QR 登录全部收敛到 Gateway 进程内,通过 account/profile 双层模型支持多账号,并以 zalouser 工具向 Agent 暴露 send、image、link、friends、groups、me、status 七类动作。对需要在无官方 Bot API 条件下接入 Zalo 的团队,它的配置面(dmPolicy、groupPolicy、accounts、profile)与运维命令(login/logout/status/directory)都已按 OpenClaw 通道插件的标准契约实现,可直接套用上述安装与配置流程;同时请牢记其非官方属性与账号风控风险。
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 StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00