芥末
发布于 2026-03-22 / 0 阅读
0
0

用 ClawBot 协议把 Claude Code 接入微信:本地长轮询实现思路

Claude Code 通常运行在电脑终端里,适合处理代码阅读、文件修改、命令执行、项目重构这类开发任务。问题是,人不一定一直坐在电脑前。如果能在手机微信里给 Claude Code 发消息,电脑上的 Claude Code 负责执行任务,微信负责收发指令,就能把手机变成一个远程开发入口。

关键点不在于“把 Claude Code 塞进微信”,而是写一个桥接进程:

  1. 本地 Node.js 进程通过 ClawBot 协议连接微信。
  2. 微信消息通过 HTTP(超文本传输协议)长轮询进入本地进程。
  3. 本地进程解密消息,交给 Claude Agent SDK(Software Development Kit,软件开发工具包)。
  4. Claude Code 处理完成后,把回复再发回微信。

开源实现地址:

https://github.com/Wechat-ggGitHub/wechat-claude-code

整体架构

ClawBot 相关包里已经包含一套微信 Bot 协议能力,包括消息接收、AES(Advanced Encryption Standard,高级加密标准)加解密、二维码认证、CDN(内容分发网络)媒体上传下载等。把这些能力单独抽出来,就可以绕开 OpenClaw 的业务处理逻辑,改成对接 Claude Code。

flowchart LR
    A[手机微信] --> B[微信 ClawBot 服务]
    B -->|HTTP 长轮询| C[本地 Node.js 桥接进程]

    C --> D[微信协议层]
    D --> D1[AES 解密]
    D --> D2[消息解析]
    D --> D3[媒体文件处理]

    D --> E[会话与命令路由]
    E --> F[Claude Agent SDK]
    F --> G[Claude Code]

    G --> F
    F --> E
    E --> D
    D -->|发送文本或媒体| B
    B --> A

这里最重要的设计是:微信协议层和 Agent 执行层要解耦。

微信协议层只负责“怎么和微信通信”,包括登录、收消息、发消息、加解密、媒体文件处理;Claude 适配层只负责“怎么把用户消息变成 Claude Code 能处理的请求”。这样做的好处是,Claude Code 不是唯一选择,后续换成其他 Agent,也只需要替换适配层。

为什么不需要公网地址和域名

很多机器人系统使用 Webhook,也就是平台主动请求开发者提供的服务器地址。这种方式通常要求公网 IP(Internet Protocol,互联网协议)地址、域名和可访问的 HTTPS 服务。

ClawBot 这套思路不一样。它使用的是长轮询:本地进程主动向微信侧发起请求,请求会挂起一段时间;如果期间有新消息,微信侧直接返回;如果超时没有消息,本地进程马上发起下一次请求。

sequenceDiagram
    participant Local as 本地 Node.js 进程
    participant WeChat as 微信 ClawBot 服务
    participant Claude as Claude Code

    Local->>WeChat: 发起长轮询请求
    WeChat-->>Local: 返回微信消息或超时
    Local->>Local: 解密并解析消息
    Local->>Claude: 调用 query() 处理任务
    Claude-->>Local: 流式返回结果
    Local->>WeChat: 发送回复
    WeChat-->>Local: 发送成功
    Local->>WeChat: 继续下一轮长轮询

因为连接是本地进程主动发起的,所以电脑只要能访问外网就行,不需要让外部访问你的电脑。这也是它适合个人开发环境的原因。

核心模块拆分

一个可维护的微信 Claude Code 桥接项目,至少需要拆成这些模块:

模块责任关键点
微信协议客户端负责登录、长轮询、发消息处理超时、重连、消息确认
加解密模块处理 AES 加密消息密钥不能写死,不能泄露到日志
媒体模块上传和下载图片、文件、语音等媒体需要接入 CDN 上传下载流程
消息解析器把微信消息转换成统一格式文本、图片、文件要区分处理
会话管理维护微信用户和 Claude 会话的关系避免不同用户上下文串在一起
Claude 适配器调用 Claude Agent SDK 的 query()支持流式返回、错误处理
命令路由处理斜杠命令、管理命令、普通对话例如 /help/reset/status
权限审批处理 Claude Code 的敏感操作确认用户可以在微信里回复 yes/no
守护进程保证本地进程长期运行macOS 可以用 launchd 托管

这种拆分方式能让协议、会话、Agent 调用互不干扰。微信协议变了,只改协议客户端;Claude SDK 变了,只改 Claude 适配器。

消息处理流程

一条微信消息进入本地进程后,不应该直接丢给 Claude Code。更稳妥的做法是先经过标准化处理,再判断它属于普通对话、命令还是审批回复。

flowchart TD
    A[收到微信消息] --> B{能否解密}
    B -->|不能| B1[记录错误并丢弃]
    B -->|可以| C[解析消息类型]

    C --> D{是否为审批回复}
    D -->|是| D1[恢复等待中的 Claude 操作]
    D -->|否| E{是否为斜杠命令}

    E -->|是| E1[执行本地命令路由]
    E -->|否| F[写入会话上下文]

    F --> G[调用 Claude Agent SDK query()]
    G --> H[接收流式输出]
    H --> I[合并或分段回复微信]

核心循环可以抽象成这样:

for await (const packet of wechatClient.poll()) {
  const message = cryptoBox.decrypt(packet)

  if (approvalGate.resolveIfNeeded(message)) {
    continue
  }

  if (commandRouter.isCommand(message.text)) {
    const result = await commandRouter.handle(message)
    await wechatClient.sendText(message.from, result)
    continue
  }

  const session = sessionStore.getOrCreate(message.from)

  let reply = ""

  const stream = claudeAdapter.query({
    sessionId: session.claudeSessionId,
    prompt: message.text,
  })

  for await (const event of stream) {
    if (event.type === "text_delta") {
      reply += event.text
    }
  }

  await wechatClient.sendText(message.from, reply)
}

代码里的 poll()decrypt()query() 只是表达核心逻辑,真实项目还要补上异常处理、消息去重、重试、限流和日志。

Claude Agent SDK 的接入方式

Claude Agent SDK 提供的 query() 可以把用户输入交给 Claude Code。桥接进程要做的事情,是把微信里的自然语言消息转换成一次 Agent 请求。

普通对话很简单:

await claudeAdapter.query({
  sessionId: "wechat-user-xxx",
  prompt: "帮我检查这个项目里的 TypeScript 类型错误",
})

真正复杂的是多轮任务。比如 Claude Code 可能需要读取文件、修改代码、执行命令,某些操作需要用户确认。这时微信端必须能承接“审批”这个状态。

一个可行的状态模型如下:

stateDiagram-v2
    [*] --> Idle
    Idle --> Running: 收到普通任务
    Running --> WaitingApproval: Claude 请求执行敏感操作
    WaitingApproval --> Running: 用户回复 yes
    WaitingApproval --> Idle: 用户回复 no
    Running --> Idle: 任务完成
    Running --> Failed: 执行失败
    Failed --> Idle: 返回错误信息

如果没有审批状态管理,Claude Code 一旦要求用户确认,整个会话就会卡住。本地桥接进程需要保存“哪一个微信用户、哪一个 Claude 会话、正在等待哪个审批请求”。

用 Superpowers 组织开发流程

Superpowers 是一个面向 Claude Code 等工具的 Skill 框架。它的价值不是让 AI 随便生成代码,而是把开发流程拆成更稳定的几个阶段:先明确方案,再写计划,再并行实现。

适合这类桥接项目的流程可以这样组织:

flowchart LR
    A[Brainstorming] --> B[明确协议边界和功能范围]
    B --> C[Writing Plans]
    C --> D[拆模块、定接口、排依赖]
    D --> E[Dispatching Parallel Agents]
    E --> F[多个 Agent 并行实现独立模块]
    F --> G[集成、编译、测试]

三个阶段各自解决不同问题:

阶段目标产物
Brainstorming明确能不能做、怎么做、边界在哪里协议分析、架构选择、功能取舍
Writing Plans把方案拆成可执行任务Markdown 计划、模块接口、依赖关系
Dispatching Parallel Agents让多个 Agent 同时处理独立模块协议层、SDK 接入、会话管理、命令路由等代码

Brainstorming 阶段要重点确认几个问题:

  • 是否复用 OpenClaw 相关包里的协议层,还是完全重写协议。
  • 是否需要 OpenClaw Gateway(网关)。
  • 是否支持斜杠命令。
  • Claude Code 请求执行敏感操作时,微信端如何确认。
  • 文本、图片、文件等不同消息类型是否都要支持。
  • 多个微信会话同时使用时,如何隔离上下文。

Writing Plans 阶段要把这些问题落到接口上。例如微信协议层只暴露 poll()sendText()sendMedia(),Claude 适配层只暴露 query(),这样并行开发时不会互相踩代码。

适合和不适合的场景

场景是否适合原因
个人在手机上给 Claude Code 分配开发任务适合本地电脑执行任务,微信负责收发指令
没有公网地址、没有域名的个人机器适合长轮询由本地进程主动发起
临时查看项目状态、让 Claude Code 跑检查适合微信消息足够表达轻量任务
面向大量用户的客服机器人不适合会话隔离、稳定性、风控要求更高
严格企业合规环境不一定适合需要额外审计、权限、数据隔离
电脑不能长期在线不适合本地进程停止后,微信入口也会失效

它更像个人开发者的“移动控制台”,不是直接面向生产环境的大规模机器人平台。

上手流程

项目基于 Node.js,本地需要先准备好 Node.js 环境和 Claude Code 相关认证。

常见启动流程类似这样:

git clone https://github.com/Wechat-ggGitHub/wechat-claude-code.git
cd wechat-claude-code

npm install

# 按仓库里的示例配置 Claude 与微信会话参数
# 如果存在 .env.example,可以复制后再填写
# cp .env.example .env

npm run dev

如果脚本名不同,以 package.json 里的 scripts 为准。第一次启动时,本地进程会进入二维码认证流程。认证完成后,手机微信发来的消息就能进入本地 Node.js 进程,再由 Claude Code 处理。

在 macOS 上长期运行时,可以交给 launchd 管理。核心思路是让系统启动后自动拉起 Node.js 进程,进程退出后再重启。

<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>local.wechat-claude-code</string>

    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/bin/node</string>
      <string>/path/to/wechat-claude-code/dist/index.js</string>
    </array>

    <key>WorkingDirectory</key>
    <string>/path/to/wechat-claude-code</string>

    <key>RunAtLoad</key>
    <true/>

    <key>KeepAlive</key>
    <true/>
  </dict>
</plist>

路径要替换成本机真实路径。如果使用 TypeScript 开发模式,也可以让 launchd 执行项目提供的启动脚本,但生产运行更建议先构建再启动。

容易踩的坑

1. 长轮询超时不是异常

长轮询经常会“等一段时间后没有消息返回”,这属于正常情况。处理逻辑应该是:超时后立刻发起下一轮请求,而不是把它当成错误疯狂打印日志。

while (true) {
  try {
    const messages = await wechatClient.poll({ timeoutMs: 30000 })
    await handleMessages(messages)
  } catch (error) {
    logger.warn(error)
    await sleep(1000)
  }
}

2. 消息必须去重

网络重试、确认失败、进程重启都可能导致同一条消息被处理多次。每条微信消息最好根据消息 ID 做去重,已经处理过的消息不要再次交给 Claude Code。

3. 流式输出不要每个 token 都发微信

Claude Code 的返回通常是流式的。如果每来一小段就发一次微信,会造成刷屏,也容易触发频率限制。更合理的方式是先缓冲,再按句子、段落或时间窗口合并发送。

4. 授权确认要有明确状态

Claude Code 执行命令、修改文件时,可能需要确认。微信里回复 yesno 时,桥接进程要知道它对应哪一次请求,不能把普通聊天误判成授权。

5. 会话上下文要隔离

同一个桥接进程可能收到多个微信会话的消息。每个用户都应该有独立的 Claude 会话 ID、任务状态和审批状态,否则上下文会混在一起。

6. 密钥和会话文件不能进仓库

微信会话 token、AES 密钥、Claude 认证信息都属于敏感数据。它们应该放在本地配置或受保护的凭据存储里,并加入 .gitignore

.env
*.token
sessions/
credentials/

关键结论

ClawBot 协议层解决的是微信通信问题,Claude Code 解决的是 Agent 执行问题。把两者用本地 Node.js 进程连接起来,就能得到一个不依赖公网回调的微信入口。

这套结构的核心不是某一个具体实现,而是协议层与 Agent 层的解耦:

flowchart LR
    A[微信协议层] --> B[统一消息模型]
    B --> C[Agent 适配层]
    C --> D[Claude Code]

    C -.可替换.-> E[其他 Agent]

只要能处理微信认证、长轮询、AES 加解密和消息发送,后面的 Agent 可以是 Claude Code,也可以是其他代码助手。微信负责输入输出,本地电脑负责执行任务,这就是整个方案最实用的地方。


评论