# 03 — 消息与媒体处理 > 本文档覆盖:五种消息类型的结构、媒体文件的 CDN 传输、AES-128-ECB 加解密、语音的特殊性。 > 媒体部分的字段级细节来自官方包逆向与第三方适配器实现,标注 ⚠️ 处建议对照官方包源码或实测确认。 ## 1. 消息类型速览 | `item.type` | 类型 | 入站 | 出站 | 关键字段 | |---|---|---|---|---| | 1 | 文本 | ✅ | ✅ | `text_item.text` | | 2 | 图片 | ✅ | ✅ | CDN 引用 + aes_key | | 3 | 语音 | ✅(附转写) | ⚠️ 存疑 | silk 编码,`voice_item.text` 为 ASR 文本 | | 4 | 文件 | ✅ | ✅ | CDN 引用 + aes_key | | 5 | 视频 | ✅ | ⚠️ | CDN 引用 + aes_key | > 关于出站语音/视频:早期协议解析称「仅文本」或「bot 暂不能主动发语音」,但 OpenAkita 等适配器后续实现了图片/文件/语音的 CDN+AES 出站。说明协议能力在逐步开放或官方未完整公开,**以你的账号实测为准**。 ## 2. 文本消息 ### 2.1 入站 ```json { "item_list": [ { "type": 1, "text_item": { "text": "你好" } } ] } ``` 一条消息的 `item_list` 可能含多个 item(图文混排等场景),处理时应遍历而不是只取 `[0]`。 ### 2.2 出站 ```json { "msg": { "to_user_id": "...@im.wechat", "client_id": "uuid", "message_type": 2, "message_state": 2, "context_token": "...", "item_list": [ { "type": 1, "text_item": { "text": "回复内容" } } ] } } ``` 注意: - **微信侧不渲染 Markdown**。如果你的 AI 后端输出 Markdown,发送前应转纯文本(OpenAkita 的做法),或至少把 `**`、`` ` ``、标题符号等剥掉 - 超长文本考虑分片发送(多条 `sendmessage`)。Java SDK 提供 `sendTextStream(...)` 做分片——注意这只是「把长文本切成多条消息」,不是 LLM 流式输出 - 每条消息带唯一 `client_id` 防重 ## 3. 媒体传输总流程 微信侧所有媒体文件不直接走 iLink API 的 JSON body,而是走独立 CDN: ``` CDN 域名: https://novac2c.cdn.weixin.qq.com/c2c 加密方式: AES-128-ECB ``` ### 3.1 出站(Bot → 用户)完整流程 ``` 1. 生成随机 AES-128 key(16 字节) 2. plaintext = 原始文件字节 3. encrypted = AES-128-ECB-Encrypt(plaintext, key) 4. POST /ilink/bot/getuploadurl → 拿到 CDN 预签名上传 URL 5. PUT encrypted 到 CDN URL 6. POST /ilink/bot/sendmessage,item 中携带: - CDN 引用参数(上传后返回/约定的 key) - aes_key(base64 编码的 16 字节 key),供接收方解密 ``` ### 3.2 入站(用户 → Bot)完整流程 ``` 1. getupdates 收到媒体类 item(含 CDN 引用与密钥信息) 2. 从 CDN 下载 encrypted 字节 3. plaintext = AES-128-ECB-Decrypt(encrypted, key) 4. 交给业务层(存盘 / 送多模态模型 / ASR 等) ``` ### 3.3 关于解密密钥的来源 ⚠️ - **出站**:key 由发送方(你)随机生成,随消息的 `aes_key` 字段(base64)带给接收方——这部分明确。 - **入站**:OpenAkita 的实现笔记记载「加密密钥从 Token 中提取(base64 解码后取后 16 字节)」。即入站媒体解密密钥与 `bot_token` 派生相关。⚠️ 此细节来源单一,实现时若解密失败,请对照 `@tencent-weixin/openclaw-weixin` 官方包 `src/cdn/` 目录的源码确认 key 的实际派生方式。 ### 3.4 AES-128-ECB 实现要点 - ECB 模式无 IV,块大小 16 字节,需要 PKCS#7 padding(具体 padding 方案以官方包源码为准) - 各语言实现: - Node.js:`crypto.createCipheriv('aes-128-ecb', key, null)` - Python:`Crypto.Cipher.AES.new(key, AES.MODE_ECB)`(pycryptodome) - Java:`Cipher.getInstance("AES/ECB/PKCS5Padding")` ## 4. 语音消息的特殊性 - 入站语音是 **silk 编码**(微信语音专用格式) - 好消息:`voice_item.text` 直接附带微信侧的 **ASR 转写文字**——如果你的场景只需要文本,直接用转写结果,不必自己解码 silk - 如果需要原始音频做二次处理(自己的 ASR、声纹等),需 silk 解码。社区方案: - `pilk`(Python silk 解码绑定) - 或 silk → wav → ffmpeg 转任意格式 - 出站语音:⚠️ 开放状态存疑(见第 1 节) ## 5. 图片消息 - 入站:CDN 下载 + AES 解密得到原图(jpg/png 等),可直接送多模态模型 - 出站:按 3.1 流程加密上传 - OpenAkita 的实践经验:图片入站后由消息网关自动下载预处理;文件和视频**不自动下载**,由 Agent 按需主动拉取(节省带宽和存储)——这个策略值得借鉴 ## 6. 文件与视频 - item type 4(文件)、5(视频),链路同为 CDN + AES - 建议默认不自动下载大文件,在消息里记录元信息(文件名、大小、CDN 引用),业务层需要时再拉 - 注意给用户反馈:大文件处理慢时先发一条文本「收到文件 xxx,处理中」 ## 7. 消息规范化建议(Bridge 内部模型) 不管后端是什么 AI 项目,建议在 Bridge 层把 iLink 消息规范化成统一内部模型,例如: ```json { "channel": "wechat-ilink", "msg_id": "", "direction": "inbound", "peer_id": "o9cq809L...@im.wechat", "context_token": "CK3E...", "received_at": "2026-08-19T10:00:00Z", "parts": [ { "kind": "text", "text": "看这个图" }, { "kind": "image", "cdn_ref": "...", "local_path": "/tmp/xxx.jpg", "mime": "image/jpeg" }, { "kind": "voice", "transcript": "语音转写文字", "duration_ms": 3200 } ] } ``` 好处: - AI 后端不感知 iLink 协议细节,以后加别的 IM 通道(Telegram/飞书等)复用同一模型 - 多 item(图文混排)天然支持 - 媒体下载策略(立即/惰性)在 Bridge 层统一控制 ## 8. 常见坑 1. **只取 `item_list[0]`** → 图文混排丢内容。遍历整个 list。 2. **Markdown 直接发** → 用户看到一堆 `*` 和 `#`。发送前转纯文本。 3. **长文本一条发** → 可能被截断或体验差。按字数/段落分片,带不同 `client_id`。 4. **入站媒体密钥搞错** → 解密出一堆乱码还以为是 bug。先确认 key 派生方式(见 3.3)。 5. **语音自己跑 ASR** → 浪费算力,`voice_item.text` 已有微信转写。 6. **大文件自动下载** → 用户发个 100MB 视频你的磁盘/带宽就炸了。惰性下载 + 大小上限。 ## 参考资料 - [微信 Bot API 技术解析 — 3.6 媒体文件 AES-128-ECB](https://github.com/hao-ji-xing/openclaw-weixin/blob/main/weixin-bot-api.md) - [OpenAkita IM 通道指南 — 微信媒体处理与收发矩阵](https://github.com/openakita/openakita/blob/main/docs/im-channels.md) - [openclaw-weixin-sdk (Java) — MediaUploadService / CdnUploader / CdnMediaDownloader](https://github.com/openclaw-java/openclaw-weixin-sdk) - 腾讯官方协议包 `src/cdn/` 目录(字段细节的最终依据):`npm pack @tencent-weixin/openclaw-weixin` 下载查看