资讯详情

资讯详情

openclaw-weixin 插件技术原理研究:从 iLink 协议到 OpenClaw Gateway 的完整链路拆解

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 上传预签名 URLgetconfig获取账号配置含 typing ticketsendtyping发送/取消输入状态指示消息结构WeixinMessage里几个字段要重点看message_type区分 1USER、2BOTmessage_state区分 0NEW、1GENERATING、2FINISHitem_list是内容列表type1TEXT、2IMAGE、3VOICE、4FILE、5VIDEOcontext_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_type1IMAGE、2VIDEO、3FILE。拿到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_tokencurl -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后调sendTypingcurl -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_tokentoken 有没有过期。如果是 Gateway 调模型返回 401检查base_url是不是https://taotoken.net/apiapi_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.1Gateway 也在同一台机器上那就用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_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodel_chatCoding Planhttps://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcoding_plan控制台https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentconsoleAPI Keyshttps://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi_keys接入文档https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdoc最后提醒一句插件源码里的src/api/types.ts和src/api/api.ts是最准的参考字段有疑问直接看类型定义比翻文档快。配置改完记得重启插件和 Gateway两边都生效了再验一遍getUpdates确认游标能正常推进。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →