前言

2026 年,腾讯通过 OpenClaw 平台正式开放了微信个人号 Bot API——即 iLink(智联)协议。与之前逆向 iPad 协议、PC Hook 等灰色方案不同,这是微信官方首次合法开放个人号机器人能力,接入域名 ilinkai.weixin.qq.com无封号风险

本文将带你从零开始,用 Java + Spring Boot 搭建一个支持 AI 智能回复的微信机器人。

完整项目代码已开源,文末附 GitHub 地址。


iLink 是腾讯官方的微信个人号 Bot 接入标准,基于纯 HTTP/JSON 协议,核心流程只有三步:

扫码登录 → 长轮询收消息 → 回复消息

核心能力一览:

能力 支持
1v1 私聊
文本/图片/语音/文件/视频
群聊
主动发消息 ❌(只能回复)
Markdown

协议限制:

  • Bot 只能回复用户先发来的消息,不能主动发起对话
  • 用户超 24 小时未发消息,context_token 过期,无法回复
  • iLink Bot 账号无法加入微信群

二、SDK 选型

当前主流的 Java SDK 有两款:

SDK Maven 坐标 特点
wechat-ilink-sdk-java io.github.lith0924:wechat-ilink-sdk:2.3.3 功能全面,Maven 中央仓库,Builder 模式
ilink-wechat-sdk io.github.pig-mesh.ai:ilink-wechat-sdk:1.0.0 零依赖,API 极简

本文选用 wechat-ilink-sdk-java(⭐ 推荐),它自动管理了 context_token 缓存、cursor 游标、心跳保活、重连退避等。

Maven 依赖

<dependency> 
    <groupId>io.github.lith0924</groupId> 
    <artifactId>wechat-ilink-sdk</artifactId> 
    <version>2.3.3</version> 
</dependency>

三、消息类型详解

iLink 定义了 5 种消息类型,通过 MessageItem.type 区分:

type 含义 对应字段
1 文本 item.getText_item().getText()
2 图片 item.getImage_item() → CDN + AES 解密
3 语音 item.getVoice_item() → silk 格式
4 文件 item.getFile_item()
5 视频 item.getVideo_item()
// 消息处理示例
for (MessageItem item : msg.getItem_list()) {
    if (item.getText_item() != null) {
        // 文本消息
        String text = item.getText_item().getText();
    } else if (item.getImage_item() != null) {
        // 图片消息 → 可下载解密
        byte[] image = client.downloadImageFromMessageItem(item);
    }
}

四、建立联系的凭证:QR 码 + Bot Token

iLink 有两层凭证:

凭证 来源 用途 生命周期
QR Code get_bot_qrcode 接口 绑定 Bot-微信账号 一次性,扫码后失效
Bot Token 扫码后微信下发 所有 API 请求鉴权 长期有效

完整鉴权流程:

① GET /ilink/bot/get_bot_qrcode?bot_type=3
   → 返回二维码 URL

② 微信扫描 → 手机确认

③ 轮询 GET /ilink/bot/get_qrcode_status
   → { status: "confirmed", bot_token: "xxx", bot_id: "xxx@im.bot" }

④ 后续所有请求携带:
   Authorization: Bearer <bot_token>

SDK 将这 4 步封装为两句代码:

String qrCode = client.executeLogin(); // 获取二维码 
LoginContext ctx = client.getLoginFuture().get(); // 阻塞等待扫码

五、会话关联的核心:context_token

这是 iLink 协议最重要的概念。

为什么需要 context_token

微信 Bot 不能随意给用户发消息。必须由用户先发起对话,消息中会携带 context_token,Bot 回复时原样回传,微信才知道这条回复应该路由到哪个聊天窗口。

用户发消息 → 消息含 context_token
                ↓
Bot 回复时必须带上同一个 context_token
                ↓
没有 → 消息无法投递到用户窗口

SDK 自动管理

SDK 内部维护了 (botId, userId) → contextToken 的缓存映射:

// SDK 内部逻辑(开发者无需手动处理)
getUpdates() → 提取每个消息的 context_token → 缓存
sendText(userId, text) → 从缓存取 context_token → 带上去请求

WeixinMessage 完整字段

public class WeixinMessage {
    Long getMessage_id();           // 消息唯一 ID
    String getFrom_user_id();       // 发送者: "xxx@im.wechat"
    String getTo_user_id();         // 接收者: "xxx@im.bot"
    String getContext_token();      // ⭐ 会话令牌
    Long getCreate_time_ms();       // 时间戳(毫秒)
    List<MessageItem> getItem_list(); // 消息内容
}

ID 命名规则:

  • xxx@im.wechat → 普通微信用户
  • xxx@im.bot → Bot 账号

六、完整消息收发流程

用户发 "你好"
    │
    ▼
微信服务器缓存消息
    │
    ▼
Bot 长轮询 getUpdates() → 返回消息(含 context_token)
    │
    ▼
Bot 业务逻辑处理 → 生成回复
    │
    ▼
Bot sendMessage(回复内容 + 相同的 context_token)
    │
    ▼
微信服务器路由到正确的聊天窗口
    │
    ▼
用户在微信收到回复

七、项目架构设计

src/main/java/com/example/bot/
├── IlinkApplication.java           # Spring Boot 启动入口
├── config/
│   └── ILinkConfigProperties.java  # 配置类(yaml → Java)
├── service/
│   ├── ILinkBotService.java        # Bot 核心:登录/轮询/回复
│   └── AiChatService.java          # AI API 调用
└── controller/
    └── BotController.java          # REST 管理接口

设计要点:

  • Bot 跑在虚拟线程Thread.startVirtualThread)里,不阻塞主线程
  • 消息轮询用 长轮询模式getUpdates() 最长 hold 35 秒),比定时轮询更实时、更省资源
  • 回复采用 AI 优先 + 固定模板降级 策略,保证可用性
  • AI 接口兼容 OpenAI 格式,可接任意平台(MiMo、SiliconFlow、DeepSeek、OpenAI)

八、核心代码实现

8.1 配置类

@Data
@Component
@ConfigurationProperties(prefix = "ilink.bot")
public class ILinkConfigProperties {
    private int connectTimeoutMs = 35000;
    private boolean aiEnabled = true;
    private String aiApiKey = "";
    private String aiBaseUrl = "https://api.xiaomimimo.com/v1";
    private String aiModel = "mimo-v2.5-pro";
    private String aiSystemPrompt = "你是一个友好的微信助手...";
    private String replyTemplate = "收到你的消息啦!...";
}

8.2 Bot 核心服务(关键代码)

@Slf4j
@Service
public class ILinkBotService {

    private volatile ILinkClient client;
    private final AtomicBoolean running = new AtomicBoolean(false);

    // 启动:虚拟线程中执行,不阻塞主线程
    public void start() {
        running.set(true);
        Thread.startVirtualThread(() -> {
            // 获取二维码
            String qrCode = client.executeLogin();
            log.info("请扫码: {}", qrCode);

            // 等待扫码
            LoginContext ctx = client.getLoginFuture().get();
            log.info("登录成功! botId={}", ctx.getBotId());

            // 消息轮询
            while (running.get()) {
                List<WeixinMessage> msgs = client.getUpdates(); // 35s 长轮询
                for (WeixinMessage msg : msgs) {
                    String reply = buildReply(msg);  // 生成回复
                    client.sendText(msg.getFrom_user_id(), reply);
                }
            }
        });
    }

    // 回复策略:AI 优先,失败降级
    private String buildReply(WeixinMessage msg) {
        String userText = msg.getText();
        if (aiEnabled) {
            String aiReply = aiChatService.chat(userText);
            if (aiReply != null) return aiReply;
        }
        return template.replace("{text}", userText)
                       .replace("{time}", LocalDateTime.now());
    }
}

8.3 AI 服务

@Slf4j
@Service
public class AiChatService {

    private final HttpClient httpClient = HttpClient.newHttpClient();
    private final ObjectMapper mapper = new ObjectMapper();

    public String chat(String userMessage) {
        var body = Map.of(
            "model", config.getAiModel(),
            "messages", List.of(
                Map.of("role", "system", "content", config.getAiSystemPrompt()),
                Map.of("role", "user", "content", userMessage)
            ),
            "max_tokens", 1024
        );

        HttpRequest req = HttpRequest.newBuilder()
            .uri(URI.create(config.getAiBaseUrl() + "/chat/completions"))
            .header("Authorization", "Bearer " + config.getAiApiKey())
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(body)))
            .build();

        var resp = httpClient.send(req, HttpResponse.BodyHandlers.ofString());
        return mapper.readTree(resp.body()).path("choices").get(0)
                     .path("message").path("content").asText();
    }
}

8.4 管理 API

@RestController
@RequestMapping("/bot")
public class BotController {

    @GetMapping("/status")   // 查看运行状态
    public Map<String, Object> status() { ... }

    @GetMapping("/qrcode")   // 获取登录二维码
    public Map<String, Object> qrCode() { ... }

    @PostMapping("/restart") // 重启 Bot
    public Map<String, Object> restart() { ... }
}

8.5 application.yaml

ilink:
  bot:
    connect-timeout-ms: 35000
    reply-template: "收到:「{text}」\n⏰ {time}\n🌤 {weather}"
    weather-city: Beijing
    ai-enabled: true
    ai-api-key: your-api-key
    ai-base-url: https://api.xiaomimimo.com/v1
    ai-model: mimo-v2.5-pro

九、运行效果

启动后控制台输出二维码链接:

📱 QR 码已获取,请使用微信扫描二维码登录 https://liteapp.weixin.qq.com/q/7GiQu1?qrcode=xxx&bot_type=3

微信扫码后,Bot 登录成功。给 Bot 发消息:

用户: 你好 Bot: 你好!我是基于 MiMo-V2.5-Pro 的 AI 助手,有什么可以帮你的吗? 用户: 今天天气怎么样 Bot: 我来帮你查一下...(AI 结合实时数据回复)

如果 AI API 挂了,自动降级:

用户: 你好 Bot: 收到你的消息啦! 你说:「你好」 ⏰ 现在时间:2026-07-16 16:51:15 星期四 🌤 今日天气:晴 +32°C 🤖 这是 iLink Bot 的自动回复~


十、常见问题

Q: 为什么回复重复两条? A: SDK 的 OnMessageListener 回调和 getUpdates() 返回值都会触发消息处理,只保留一个即可。推荐只用 getUpdates() 返回值。

Q: 重启后要重新扫码吗? A: 目前需要。Bot Token 没有持久化,重启后 token 丢失需重新扫码。可以改造 LoginContext 持久化来避免。

Q: 怎么切换 AI 模型? A: 修改 application.yaml 中 ai-base-url 和 ai-model,支持任何 OpenAI 兼容接口。

Q: 支持群聊吗? A: 不支持。iLink Bot 账号被微信限制,无法加入微信群。


十一、总结

iLink 协议让微信个人号机器人开发从灰色地带正式进入合规时代。配合开源 Java SDK,只需几百行代码就能搭建一个支持 AI 智能回复的微信 Bot。

关键要点回顾:

  1. QR 码 + Bot Token 双重鉴权
  2. context_token 是会话关联的核心,SDK 已自动管理
  3. 长轮询比定时轮询更实时高效
  4. AI 优先 + 降级策略保证可用性
  5. 只能 1v1 私聊,不能群聊

本文使用的开源项目:wechat-ilink-sdk-java

作者:Cxx0709 | 日期:2026-07-16

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐