☰
openclaw-weixin 插件技术原理研究:从 iLink 协议到 OpenClaw Gateway 的完整链路拆解
2026/10/8 18:03:26 网站建设 项目流程

1. openclaw-weixin 插件到底在做什么:微信消息到 Agent 的完整链路

openclaw-weixin 是腾讯官方渠道插件,作用一句话概括:把微信客户端的消息,通过 iLink 协议接进来,再用一套 HTTP JSON 接口转交给 OpenClaw Gateway,让后端的 Agent 或技能能像处理普通请求一样处理微信消息。它适合两类人:一类是想把自建 Agent 接到微信里做客服、通知、自动化回复的开发者;另一类是拿到魔改版 OpenClaw Gateway,想自己实现后端对接的团队。

我先把整条数据流摆出来,后面所有配置和排障都围绕这条链路展开:

微信客户端 ↔ 微信官方服务器 ↔ [iLink 协议] ↔ openclaw-weixin 插件 ↔ [Backend API Protocol] ↔ OpenClaw Gateway ↔ Agent/技能

关键点在于插件是桥接层,它同时扮演两个角色。对微信侧,它用 iLink 协议长轮询拉消息、发消息、传媒体文件;对 Gateway 侧,它暴露一组本地 HTTP JSON 接口,由 Gateway 主动发起请求。也就是说,消息方向是「微信服务器 → 插件 → Gateway」,而 Gateway 不是被动等推送,而是通过长轮询getUpdates主动从插件取新消息。

理解这个方向很重要,因为很多人第一次配的时候会以为插件要主动去连 Gateway,结果把地址填反了。实际上插件本地起一个 HTTP 服务,Gateway 配置里填的是这个本地服务的地址。插件再去连微信官方服务器,用的是登录后拿到的ilink_bot_token。

通用约定这块先记住三条:所有接口都是 POST,请求体和响应体都是 JSON,请求头固定带Content-Type: application/json、AuthorizationType: ilink_bot_token、Authorization: Bearer <token>,以及一个X-WECHAT-UIN,它是随机 uint32 的 base64 编码。这个 UIN 每次会话生成一次即可,不用每条消息都换。

接口一共六个,全部是相对路径,由 Gateway 向插件本地 HTTP 服务发起:

接口路径作用
getupdates长轮询获取新消息,35 秒超时
sendmessage发送文本/图片/视频/文件
getuploadurl获取 CDN 上传预签名 URL
getconfig获取账号配置,含 typing ticket
sendtyping发送/取消输入状态指示

消息结构WeixinMessage里几个字段要重点看:message_type区分 1=USER、2=BOT;message_state区分 0=NEW、1=GENERATING、2=FINISH;item_list是内容列表,type1=TEXT、2=IMAGE、3=VOICE、4=FILE、5=VIDEO;context_token是会话上下文令牌,回复时必须回传,否则消息可能对不上会话。媒体全部走 CDN,用 AES-128-ECB 加密,字段是encrypt_query_param和 base64 的aes_key。

搞清这条链路,后面配 Gateway、验请求、排错才有依据。下一节先解决前置:怎么拿到能用的 token 和 Gateway 地址。

2. 接入前的前置准备:token、Gateway 地址与 openclaw-weixin 插件配置项

在写配置之前,得先把三样东西备齐:iLink 的 bot token、OpenClaw Gateway 的访问地址、以及插件本地 HTTP 服务的监听端口。这三样缺一个,链路都跑不起来。

先说 token。插件登录微信官方服务器后会拿到ilink_bot_token,后续所有请求的Authorization头都用它。这个 token 不是你在 Gateway 侧生成的,而是微信侧登录流程产出的。如果你在排障时看到 401,第一反应应该是 token 是否过期或没带上,而不是 Gateway 地址写错。

再说 Gateway 地址。因为插件是本地 HTTP 服务,Gateway 配置里填的应该是类似http://127.0.0.1:<port>的地址。端口要和插件实际监听的一致,默认值以你安装的版本为准,改过就要同步。这里最容易踩的坑是把公网地址填进去,结果本地服务根本没监听公网,连接直接失败。

第三样是模型和 API 凭证。如果你用的是托管式接入,可以在 TaoToken 控制台创建 API Key,然后按文档把 Base URL 指向https://taotoken.net/api。这一步和插件本身解耦,插件只负责消息桥接,真正调用模型的是 Gateway 后面的 Agent。所以配置要分两层看:插件层管微信消息进出,Gateway 层管模型调用。

下面是一份可直接复制的插件侧配置片段,字段名按常见约定给出,实际以你安装版本的 schema 为准:

{ "openclaw-weixin": { "enabled": true, "listen": { "host": "127.0.0.1", "port": 8787 }, "ilink": { "token": "<你的 ilink_bot_token>", "longpolling_timeout_ms": 35000 }, "gateway": { "base_url": "http://127.0.0.1:9000", "api_key": "<你的 Gateway 访问凭证>" }, "media": { "cdn_encryption": "AES-128-ECB", "upload_retry": 3 } } }

如果你用的是 TOML 风格的配置,等价写法如下:

[openclaw-weixin] enabled = true [openclaw-weixin.listen] host = "127.0.0.1" port = 8787 [openclaw-weixin.ilink] token = "<你的 ilink_bot_token>" longpolling_timeout_ms = 35000 [openclaw-weixin.gateway] base_url = "http://127.0.0.1:9000" api_key = "<你的 Gateway 访问凭证>"

配置里几个参数值得单独说。longpolling_timeout_ms建议和服务端返回的longpolling_timeout_ms保持一致,默认 35000,改小了会频繁空轮询,改大了消息延迟变高。upload_retry是媒体上传重试次数,网络抖动时有用。cdn_encryption固定 AES-128-ECB,不要改。

如果你在 Gateway 侧用的是 Codex 风格的auth.json,那凭证要写全三件套:Base URL、Key、Model ID。缺 Model ID 时有些实现会回退到默认模型,表现就是「能连上但回复不对」。这三件套在 Cline MCP 或 CC Switch 场景里同样适用,配置位置不同但字段含义一致。

前置准备好之后,就可以进入实际对接参数和可复制配置环节了。

3. 可复制的 Gateway 对接参数与 openclaw-weixin 接口配置

这一节把 Gateway 侧和插件侧的对接参数写全,目标是复制粘贴后能直接跑。核心是三件套:Base URL、Key、Model ID,加上插件本地服务的地址和端口。

先给一份 Gateway 侧的settings片段,路径按常见约定放在配置目录下:

{ "gateway": { "listen": { "host": "127.0.0.1", "port": 9000 }, "channels": { "openclaw-weixin": { "type": "http-json", "base_url": "http://127.0.0.1:8787", "endpoints": { "get_updates": "/getupdates", "send_message": "/sendmessage", "get_upload_url": "/getuploadurl", "get_config": "/getconfig", "send_typing": "/sendtyping" }, "auth": { "type": "ilink_bot_token", "token": "<你的 ilink_bot_token>" } } }, "model": { "base_url": "https://taotoken.net/api", "api_key": "<你的 API Key>", "model_id": "<你的 Model ID>" } } }

这份配置里,channels.openclaw-weixin.base_url指向插件本地服务,endpoints把五个接口路径映射清楚。注意getupdates是长轮询,Gateway 侧要有对应的超时设置,建议比 35000ms 略大,比如 40000ms,避免插件还没返回 Gateway 就先超时断开。

如果你用 TOML,等价片段:

[gateway.listen] host = "127.0.0.1" port = 9000 [gateway.channels.openclaw-weixin] type = "http-json" base_url = "http://127.0.0.1:8787" [gateway.channels.openclaw-weixin.auth] type = "ilink_bot_token" token = "<你的 ilink_bot_token>" [gateway.model] base_url = "https://taotoken.net/api" api_key = "<你的 API Key>" model_id = "<你的 Model ID>"

接口层面的请求体也要能对上。getUpdates的请求体最简单:

{ "get_updates_buf": "" }

首次请求传空字符串,之后把上次响应里的get_updates_buf回传。响应里ret为 0 表示成功,msgs是消息列表,get_updates_buf是新游标。errcode为 -14 表示会话超时,这时要重新走登录或刷新 token。

sendMessage的请求体要带to_user_id、context_token和item_list:

{ "msg": { "to_user_id": "<目标用户 ID>", "context_token": "<会话上下文令牌>", "item_list": [ { "type": 1, "text_item": { "text": "你好" } } ] } }

context_token必须来自收到的消息,不能自己编。item_list里type决定内容类型,文本用text_item,图片用image_item,以此类推。

媒体上传要分两步。先调getUploadUrl:

{ "filekey": "<文件标识>", "media_type": 1, "to_user_id": "<目标用户 ID>", "rawsize": 12345, "rawfilemd5": "<明文 MD5>", "filesize": 12352, "thumb_rawsize": 1024, "thumb_rawfilemd5": "<缩略图明文 MD5>", "thumb_filesize": 1040 }

media_type1=IMAGE、2=VIDEO、3=FILE。拿到upload_param和thumb_upload_param后,用 AES-128-ECB 加密文件内容,PUT 上传到 CDN,再用返回的encrypt_query_param构造CDNMedia引用放进MessageItem。

getConfig用来拿 typing ticket:

{ "ilink_user_id": "<用户 ID>", "context_token": "<可选>" }

响应里typing_ticket是 base64 编码,sendTyping时带上它,status1=正在输入、2=取消输入。

配置写完,下一步就是验证请求是否真的通了。

4. 验证消息收发链路:从 getUpdates 到 sendMessage 的成功结果

配置落地后,别急着在微信里发消息,先用 curl 把插件本地服务单独验一遍。这样能把「插件没起来」和「Gateway 没连上」两类问题分开。

先验getUpdates,确认插件能拉到消息:

curl -X POST http://127.0.0.1:8787/getupdates \ -H "Content-Type: application/json" \ -H "AuthorizationType: ilink_bot_token" \ -H "Authorization: Bearer <你的 ilink_bot_token>" \ -H "X-WECHAT-UIN: <随机 uint32 的 base64>" \ -d '{"get_updates_buf": ""}'

成功时你会看到类似这样的响应:

{ "ret": 0, "msgs": [ { "seq": 1, "message_id": 10001, "from_user_id": "user_abc", "to_user_id": "bot_xyz", "create_time_ms": 1774000000000, "session_id": "sess_001", "message_type": 1, "message_state": 0, "item_list": [ { "type": 1, "text_item": { "text": "在吗" } } ], "context_token": "ctx_abc123" } ], "get_updates_buf": "cursor_001", "longpolling_timeout_ms": 35000 }

看到ret: 0且msgs里有内容,说明插件到微信侧的链路通了。把get_updates_buf记下来,下次请求回传它,就能拿到增量消息。

接着验sendMessage,用上一步拿到的to_user_id和context_token:

curl -X POST http://127.0.0.1:8787/sendmessage \ -H "Content-Type: application/json" \ -H "AuthorizationType: ilink_bot_token" \ -H "Authorization: Bearer <你的 ilink_bot_token>" \ -H "X-WECHAT-UIN: <随机 uint32 的 base64>" \ -d '{ "msg": { "to_user_id": "user_abc", "context_token": "ctx_abc123", "item_list": [ { "type": 1, "text_item": { "text": "收到,正在处理" } } ] } }'

如果微信客户端能收到这条消息,说明插件到微信侧的发送链路也通了。这时候再去 Gateway 侧看日志,确认 Gateway 是否成功调用了这两个接口。Gateway 日志里应该能看到对http://127.0.0.1:8787/getupdates和/sendmessage的请求记录。

再验getConfig和sendTyping,这两个是体验优化项,不影响主链路,但能验证账号配置接口是否正常:

curl -X POST http://127.0.0.1:8787/getconfig \ -H "Content-Type: application/json" \ -H "AuthorizationType: ilink_bot_token" \ -H "Authorization: Bearer <你的 ilink_bot_token>" \ -H "X-WECHAT-UIN: <随机 uint32 的 base64>" \ -d '{"ilink_user_id": "user_abc"}'

拿到typing_ticket后调sendTyping:

curl -X POST http://127.0.0.1:8787/sendtyping \ -H "Content-Type: application/json" \ -H "AuthorizationType: ilink_bot_token" \ -H "Authorization: Bearer <你的 ilink_bot_token>" \ -H "X-WECHAT-UIN: <随机 uint32 的 base64>" \ -d '{ "ilink_user_id": "user_abc", "typing_ticket": "<从 getConfig 获取>", "status": 1 }'

微信里能看到「正在输入」状态,就说明这条链路也通了。

媒体链路单独验:先调getUploadUrl拿参数,加密上传后构造CDNMedia引用,再走sendMessage发出去。图片和视频要带缩略图参数,文件不用。上传失败时先看rawsize和filesize是否匹配,AES-128-ECB 加密后密文大小会变,填错会导致 CDN 拒绝。

到这里,主链路和媒体链路都验证过了。下一节把常见报错集中排一遍。

5. 常见报错排查:401、local proxy failed、reading choices 与 OAuth

排障时先定位问题在哪一层:插件本地服务、微信侧 iLink、还是 Gateway 到模型的调用。下面按真实报错逐个拆。

401 Unauthorized。这个最常见,出现在插件本地接口或 Gateway 调用模型时。如果是插件接口返回 401,检查Authorization头是不是Bearer <token>格式,AuthorizationType是不是ilink_bot_token,token 有没有过期。如果是 Gateway 调模型返回 401,检查base_url是不是https://taotoken.net/api,api_key有没有写错或失效。两种情况都别急着改端口,先看是哪个 URL 返回的 401。

local proxy failed。这个报错通常出现在 Gateway 尝试连插件本地服务时。原因一般是插件没启动、端口不对、或者base_url写成了公网地址。排查顺序:先curl http://127.0.0.1:8787/getupdates看插件是否响应,再核对 Gateway 配置里的base_url和插件listen.port是否一致。如果插件监听的是127.0.0.1,Gateway 也在同一台机器上,那就用127.0.0.1,不要用localhost,有些环境解析会出问题。

reading choices 相关报错。这类报错一般出现在 Gateway 解析模型响应时,说明请求发出去了但响应结构不符合预期。常见原因是model_id没填或填错,导致返回的不是标准 chat completion 结构。检查三件套是否齐全:Base URL、Key、Model ID。如果用的是 Codex 风格auth.json,确认字段名和层级没写错。Cline MCP 场景下同样要确认 Model ID 和实际可用模型一致。

OAuth 相关报错。如果 Gateway 侧配置了 OAuth 流程,报错通常和 token 刷新有关。检查刷新端点、client_id、client_secret 是否匹配,以及回调地址是否和注册时一致。OAuth 和 iLink token 是两套东西,别混在一起排查。iLink token 管微信侧,OAuth 管 Gateway 到模型的授权。

errcode -14 会话超时。这是 iLink 侧返回的,说明长轮询会话过期。处理方式是重新登录刷新 token,或者检查longpolling_timeout_ms是否和服务端建议值差太多。如果频繁出现,把超时调到 35000 附近。

消息发出但微信收不到。先确认context_token是不是来自最近一条收到的消息,过期 token 会导致发送失败。再确认to_user_id和from_user_id没写反。媒体消息还要确认encrypt_query_param和aes_key都带上了。

媒体上传失败。检查rawsize、rawfilemd5、filesize三个值是否自洽。filesize是 AES-128-ECB 加密后的密文大小,不是原文件大小。图片和视频要带缩略图三件套,文件不用。上传重试次数可以调大,但根因通常是参数算错。

排障时建议开两个终端,一个盯插件日志,一个盯 Gateway 日志,对照时间戳看请求在哪一层断掉。这样比盲猜快得多。

6. 后续接入与长期运行建议

链路跑通之后,接下来要考虑的是长期运行。插件本地服务建议用进程守护工具托管,崩了能自动拉起。长轮询接口要保持连接稳定,网络抖动时upload_retry能兜住媒体上传,但消息拉取断了要靠重连逻辑。

如果你打算长期跑 Agent 编码或自动化任务,可以了解下 Coding Plan 这类方案,把模型调用和消息桥接分开管理,插件层保持轻量。需要创建 API Key 或查看接入文档时,可以从控制台和文档入口进:

  • 模型对话:https://taotoken.net/api?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=model_chat
  • Coding Plan:https://taotoken.net/api?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding_plan
  • 控制台:https://taotoken.net/api?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=console
  • API Keys:https://taotoken.net/api?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api_keys
  • 接入文档:https://taotoken.net/api?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc

最后提醒一句:插件源码里的src/api/types.ts和src/api/api.ts是最准的参考,字段有疑问直接看类型定义,比翻文档快。配置改完记得重启插件和 Gateway,两边都生效了再验一遍getUpdates,确认游标能正常推进。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询