ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

微信 ClawBot 直连 Claude — 独立桥接方案完整实现(TaoToken 统一 Key 接入)

微信 ClawBot 直连 Claude — 独立桥接方案完整实现(TaoToken 统一 Key 接入) 1. 微信 ClawBot 直连 Claude 的桥接场景与核心难点微信 ClawBot 直连 Claude 这件事本质上是在解决一个很具体的需求你希望在自己的微信里像跟朋友聊天一样把问题丢给 Claude然后拿到回复而不是每次打开网页、复制粘贴、再切回来。这个方案适合三类人一是日常在微信里处理大量文字、需要随手调用大模型的人二是想研究微信 ilink API 与 CLI 工具如何对接的开发者三是希望把 Claude 的代码能力接进自己工作流、但又不想依赖官方 Channels 功能的人。我试过几条路最后落到「独立桥接」这条线上。原因很直接Claude Code Channels 功能对账号有开放限制不是所有人都有直接走 Anthropic API Key 又需要额外申请和计费配置而 OpenClaw 这类方案虽然能接模型但用不上 Claude Code 的代码工具链。所以最终选择自己写一个 Node.js 桥接脚本直接对接微信 ilink API再通过claude -pCLI 调用 Claude形成一条完全自控的链路。整条链路是这样的微信用户发消息 → 微信服务器ilink API→wechat-claude-bridge.mjs桥接脚本 →claude -pCLI → Claude 返回 → 桥接脚本 → ilink API → 微信用户收到回复。中间没有任何第三方中转所有凭据、上下文、历史都落在你自己的机器上。这里有个关键点桥接脚本本身不直接调用 Claude 的 HTTP API而是调用本地的claude -p命令。claude -p是 Claude CLI 的非交互模式它可以从 stdin 读取 prompt然后把结果以文本形式输出。这样做的好处是你不需要单独管理 Anthropic API KeyCLI 自己会处理认证同时你还能用上 Claude Code 的代码工具能力比如读写文件、执行命令等。但这条路也有它的坑。最典型的就是 Windows 环境下多行 Unicode 文本传给子进程的问题以及 ilink API 返回空字符串导致??运算符穿透的 bug。这些在后面会详细展开。先把前置条件说清楚你需要一个能跑 Node.js 的环境建议 18一个已经登录 Claude CLI 的终端以及一个微信 ClawBot 的 bot_token。如果你还没有 Claude CLI可以先装好并完成一次交互式登录确保claude -p hello能正常返回。另外这个方案不依赖任何特殊网络手段所有请求都是正常的 HTTPS 调用。你只需要保证机器能正常访问微信 ilink API 和 Claude CLI 所需的端点即可。接下来我会从 TaoToken 统一 Key 的接入开始把配置、验证、排错一步步走完。2. TaoToken 统一 Key 接入与 Node.js 桥接前置配置在开始写桥接脚本之前先把 Key 和模型接入这一层理清楚。TaoToken 在这里的角色是统一管理你的模型访问凭据让你不用在多个地方散落 API Key。你可以把它理解成一个「凭据中枢」桥接脚本、Claude CLI、以及后续可能加进来的其他工具都从同一个地方拿 Key 和 Base URL。首先去官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册并登录然后在控制台里创建一个 API Key。创建的时候注意选择对应的模型权限如果你主要用 Claude 系列就勾选 Claude 相关的模型。创建完成后你会拿到一串以sk-开头的 Key以及一个 Base URL。这个 Base URL 在后续配置里会用到通常是https://taotoken.net/api这种形式。拿到 Key 之后你需要把它配置到 Claude CLI 能读取的地方。Claude CLI 的配置方式取决于你用的版本常见的是通过环境变量或者配置文件。如果你用的是 Claude Code 的 CLI可以在项目目录下创建一个.claude/settings.json内容如下{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的TaoTokenKey } }这个文件的作用是告诉 Claude CLI所有请求都走 TaoToken 的 Base URL并且用这个 Key 做认证。注意路径要和你的实际项目结构一致如果你是在全局配置可以放到用户目录下的.claude/settings.json。配置完之后先在终端里验证一下claude -p 用一句话说明你现在用的是哪个模型如果返回正常说明 Key 和 Base URL 都生效了。如果报 401先检查 Key 有没有复制完整以及 Base URL 有没有多写或少写斜杠。这一步是整个桥接方案的地基地基不稳后面全白搭。接下来是 Node.js 桥接层的准备。桥接脚本本身是零依赖的但你需要 Node.js 18 以上版本因为用到了原生的fetch和crypto模块。检查版本node -v如果低于 18建议升级。然后创建一个工作目录比如wechat-claude-bridge在里面初始化一个package.jsonmkdir wechat-claude-bridge cd wechat-claude-bridge npm init -y这个目录后面会放桥接脚本、凭据文件、历史记录等。凭据文件默认会写到~/.claude/channels/wechat/下包括account.jsonbot token、context_tokens.json回复所需的 context token 缓存、sync_buf.txt消息同步游标等。这些文件不要提交到 Git建议在.gitignore里加上~/.claude/channels/wechat/或者对应的本地路径。还有一点要注意如果你在 Windows 上跑claude -p需要 git-bash 的支持。Claude Code on Windows 会去找 git-bash 的路径如果装在非标准位置需要手动指定环境变量CLAUDE_CODE_GIT_BASH_PATH。这个在后面排错部分会详细说。现在你只需要确认claude -p在终端里能跑通并且 Node.js 版本达标就可以进入下一步了。3. 可复制的桥接配置与 ilink API 对接实现这一节是核心我会把桥接脚本的关键配置和 ilink API 对接的代码片段给出来你可以直接复制到自己的项目里。整个桥接脚本大约 600 行零依赖主要分三块ilink API 请求封装、消息长轮询、以及claude -p调用。先看 ilink API 的请求封装。所有请求都需要三个 HeaderContent-Type: application/json、Authorization: Bearer bot_token、AuthorizationType: ilink_bot_token以及一个X-WECHAT-UIN它是随机 base64 编码的 uint32。封装函数大概长这样import crypto from crypto; function generateWechatUin() { const uint32 crypto.randomBytes(4).readUInt32BE(0); return Buffer.from(String(uint32)).toString(base64); } async function apiFetch({ baseUrl, endpoint, body, token, timeoutMs 35000 }) { const controller new AbortController(); const timer setTimeout(() controller.abort(), timeoutMs); try { const resp await fetch(${baseUrl}/${endpoint}, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${token}, AuthorizationType: ilink_bot_token, X-WECHAT-UIN: generateWechatUin(), }, body, signal: controller.signal, }); const raw await resp.text(); return { status: resp.status, raw }; } finally { clearTimeout(timer); } }注意这里没有直接JSON.parse而是先把原始文本拿出来因为后面要检查业务错误码。ilink API 有个特点HTTP 状态码是 200但响应体里可能有ret或errcode不为 0 的情况。如果你只看 HTTP 状态码就会漏掉这些错误。接下来是长轮询拉取消息。ilink API 的getupdates端点支持 35 秒长轮询你需要带上get_updates_buf作为同步游标const raw await apiFetch({ baseUrl, endpoint: ilink/bot/getupdates, body: JSON.stringify({ get_updates_buf: getUpdatesBuf, base_info: { channel_version: 0.2.0 }, }), token, timeoutMs: 35000, });拿到消息后解析出msg对象里面有from_user_id、group_id、context_token等字段。这里有个关键点group_id可能是空字符串而不是null。如果你用??来做默认值空字符串会直接穿透导致contextKey变成空字符串后续发送消息时to_user_id为空微信侧收不到任何东西。正确的写法是用||const groupId msg.group_id; const senderId msg.from_user_id || unknown; const contextKey groupId || senderId;这个坑我在后面排错部分会再展开这里先记住当 API 可能返回空字符串表示「无值」时必须用||而不是??。然后是调用claude -p。这是整个方案里最容易出问题的地方尤其是在 Windows 上。核心思路是通过 stdin 把完整 prompt 传给claude -p而不是作为命令行参数import { spawn } from child_process; function callClaude(fullPrompt) { return new Promise((resolve, reject) { const proc spawn(claude, [-p, --output-format, text], { shell: true, stdio: [pipe, pipe, pipe], }); let stdout ; let stderr ; proc.stdout.on(data, (d) (stdout d.toString())); proc.stderr.on(data, (d) (stderr d.toString())); proc.on(close, (code) { if (code 0) resolve(stdout.trim()); else reject(new Error(claude exited ${code}: ${stderr})); }); proc.stdin.write(fullPrompt); proc.stdin.end(); }); }为什么不用参数传因为在 Windows 上cmd.exe无法正确传递包含换行符和特殊字符的多行 Unicode 文本。你如果写成spawn(claude, [-p, fullPrompt], { shell: true })cmd.exe会把多行 prompt 搞乱Claude 收到空 prompt回复「有什么可以帮你的」。而通过 stdin 管道传递就绕过了 shell 的参数解析稳定得多。发送消息的配置也要注意。sendmessage端点需要带上context_token没有它无法回复await apiFetch({ baseUrl, endpoint: ilink/bot/sendmessage, body: JSON.stringify({ msg: { to_user_id: to, client_id: generateClientId(), message_type: 2, message_state: 2, item_list: [{ type: 1, text_item: { text } }], context_token: contextToken, }, base_info: { channel_version: 0.2.0 }, }), token, });context_token的规则是每条收到的消息可能携带第一条通常没有需要等下一条收到后缓存起来按user_id或group_id分开存储。群消息中同时缓存group_id和sender_id的 token 标签。这些缓存写到~/.claude/channels/wechat/context_tokens.json重启后还能复用。最后发送消息后一定要检查响应体const resp JSON.parse(raw); const isError (resp.ret ! undefined resp.ret ! 0) || (resp.errcode ! undefined resp.errcode ! 0); if (isError) { throw new Error(sendmessage API error: ret${resp.ret} errcode${resp.errcode}); }别信任 HTTP 状态码很多 API 返回 200 但 body 里有业务错误码。这一步加上之后之前那种「日志显示成功但微信收不到」的问题就能被及时暴露出来。4. 端到端验证从扫码登录到消息收发成功配置写完之后最重要的一步是验证整条链路能不能跑通。我会按顺序把扫码登录、启动桥接、发消息、收回复这几个动作走一遍每一步都给出预期结果和检查点。第一步是扫码登录。运行node wechat-claude-bridge.mjs setup终端会显示一个二维码和一个扫码链接。用微信扫描二维码并确认。如果终端二维码扫不了就用输出的链接在手机浏览器打开然后用微信「从相册选取」扫描。登录成功后凭据会保存到~/.claude/channels/wechat/account.json下次启动不需要重复登录。你可以打开这个文件确认里面有bot_token字段但不要把它泄露出去。第二步是启动桥接node wechat-claude-bridge.mjs看到「Bridge 就绪开始监听微信消息...」就说明启动成功了。这时候桥接脚本会开始长轮询getupdates等待微信消息。你可以在另一个终端里观察日志正常情况下会看到类似[bridge] 开始长轮询的输出。第三步是在微信里给 ClawBot 发一条消息比如「你好帮我写一个 Python 的快速排序」。发送后桥接脚本的日志里应该出现[bridge] 处理私消息 [text]: fromo9cq803kQV5QpHeoBLqIKT2XMlUk 你好帮我写一个 Python 的快速排序 [bridge] 调用 claude -p --output-format text (stdin: 896 chars) [bridge] 已回复 (1 段, 28 chars)如果看到这三行说明消息已经成功传给 Claude并且拿到了回复。然后回到微信应该能看到 ClawBot 发回来的代码和说明。如果微信侧没收到但日志显示「已回复」那大概率是context_token或to_user_id的问题回到上一节检查contextKey的取值逻辑。第四步是验证图片消息。给 ClawBot 发一张图片日志里应该出现图片下载和解密的记录。微信 CDN 上的图片经过 AES-128-ECB 加密需要用消息中的aes_keybase64解密function decryptAesEcb(data, keyBase64) { const key Buffer.from(keyBase64, base64); const decipher crypto.createDecipheriv(aes-128-ecb, key, null); decipher.setAutoPadding(true); return Buffer.concat([decipher.update(data), decipher.final()]); }解密后保存为本地文件再传给claude -p作为图片参数。如果你发图片后 Claude 回复「只能看见一点儿」说明图片没有正确下载和解密检查aes_key是否拿到以及解密后的文件是否完整。第五步是验证对话历史。连续发几条消息比如先问「我叫什么名字」然后说「我叫张三」再问「我叫什么名字」。如果 Claude 能记住「张三」说明历史记录生效了。历史按用户或群组保存最近 20 轮对话存在~/.claude/channels/wechat/history/下。你可以打开对应的 JSON 文件确认内容。第六步是验证断点续传。在桥接脚本运行时直接 CtrlC 停掉然后再启动。之前没处理完的消息不应该丢失因为get_updates_buf会持久化到sync_buf.txt。重启后桥接脚本会从上次的游标继续拉取。这个特性在调试时很有用不用担心重启丢消息。最后一步是验证错误恢复。你可以故意把claude命令改成一个不存在的路径然后发消息。桥接脚本应该连续失败 3 次后进入 30 秒退避而不是无限重试刷屏。日志里会看到退避提示。恢复claude路径后再发消息应该能正常处理。走完这六步整条链路就算跑通了。如果中间某一步卡住先看日志里的具体报错然后对照下一节的常见错误排查。5. 常见报错排查401、local proxy failed、reading choices 与 OAuth这一节把我在实际搭建过程中遇到的报错按类型整理出来每个都给出原因和解决动作。你遇到问题时可以先在这里对照大概率能直接定位。401 错误通常出现在claude -p调用或 ilink API 请求时。如果是claude -p报 401先检查.claude/settings.json里的ANTHROPIC_API_KEY和ANTHROPIC_BASE_URL是否正确。Key 要以sk-开头Base URL 要是https://taotoken.net/api这种形式不要多写斜杠。如果是 ilink API 报 401检查AuthorizationHeader 里的bot_token是否过期。bot_token存在account.json里如果过期就重新跑setup扫码登录。local proxy failed这个报错通常和网络环境有关。先确认你的机器能正常访问https://taotoken.net/api和微信 ilink API 的端点。如果你在公司网络或特殊网络环境下可能会有代理拦截。检查环境变量里有没有HTTP_PROXY或HTTPS_PROXY如果有先临时取消再试。另外Claude CLI 本身可能也会读代理配置可以在.claude/settings.json里显式设置NO_PROXY: taotoken.net来排除。reading choices 报错这个通常出现在claude -p返回的 JSON 解析阶段。如果你用的是--output-format json返回的结构里应该有choices字段。如果报reading choices说明返回体不是预期的 JSON 格式可能是 CLI 版本不匹配或者 Base URL 返回了错误页面。先单独跑claude -p test --output-format json看返回的原始内容是什么。如果是 HTML 错误页说明 Base URL 或 Key 有问题。OAuth 相关报错如果你在 Claude CLI 里同时配置了 OAuth 登录和 API Key可能会冲突。Claude CLI 优先用 OAuth 凭据如果 OAuth 过期或无效就会报错。解决方法是先退出 OAuth 登录或者显式在.claude/settings.json里指定用 API Key。具体命令取决于你的 CLI 版本一般是claude logout然后再用 Key 认证。MODULE_NOT_FOUND这个最简单就是运行目录不对。确认你在wechat-claude-bridge目录下运行node wechat-claude-bridge.mjs而不是在其他目录。如果你把脚本放在了子目录里路径也要对应调整。spawn EINVAL在 Windows 上直接spawn(claude.cmd, args, { shell: false })会报这个错因为.cmd文件不能直接CreateProcess必须通过 shell。解决方法是改成shell: true并且用 stdin 传 prompt而不是作为参数。claude -p 找不到 git-bash报错信息是Claude Code on Windows requires git-bash。这是因为 git-bash 装在非标准路径。桥接脚本会自动检测几个常见路径也支持通过环境变量CLAUDE_CODE_GIT_BASH_PATH手动指定。注意路径要用 Windows 风格比如F:\\tools\\Git\\bin\\bash.exe而不是F:/tools/...。Unix 风格路径会导致unable to find CLAUDE_CODE_GIT_BASH_PATH path。消息发送成功但微信收不到ret-2这是最隐蔽的 bug。日志显示「已回复」但微信侧什么都没收到。根因是contextKey用了??运算符而 ilink API 返回的group_id是空字符串 ?? senderId结果是导致to_user_id为空。修复方法是用||const contextKey groupId || senderId;。同时给sendmessage加上响应体检查发现ret ! 0就抛错。图片不可见Bot 回复「只能看见一点儿」说明图片消息只转成了文本描述没有下载实际图片。检查aes_key是否拿到以及 AES-128-ECB 解密是否正确。解密后的文件要保存到本地再传给claude -p。消息被截断got cut off这是 Windows 上多行 Unicode 文本传递的问题。不要用命令行参数传 prompt改用 stdin 管道。spawn(claude, [-p, --output-format, text], { shell: true, stdio: [pipe, pipe, pipe] })然后proc.stdin.write(fullPrompt); proc.stdin.end();。把这些报错对照一遍基本能覆盖 90% 的搭建问题。如果还有没覆盖到的先看日志里的原始错误信息再回到对应的配置环节检查。6. 长期运行与 Coding Plan 接入建议桥接跑通之后下一步就是让它稳定地长期运行。这里有几个实践建议都是我在实际使用中踩过坑之后总结的。首先是进程守护。桥接脚本本身没有内置守护机制如果你直接node wechat-claude-bridge.mjs跑在终端里关掉终端就断了。建议用pm2或者systemd来守护。用pm2的话npm install -g pm2 pm2 start wechat-claude-bridge.mjs --name wechat-claude-bridge pm2 save pm2 startup这样即使机器重启桥接脚本也会自动拉起。日志可以用pm2 logs wechat-claude-bridge查看。其次是凭据轮换。bot_token和 TaoToken 的 API Key 都有有效期建议定期检查。account.json里的bot_token如果过期重新跑setup扫码即可。TaoToken 的 Key 可以在控制台里轮换轮换后更新.claude/settings.json里的ANTHROPIC_API_KEY然后重启桥接脚本。第三是历史记录清理。~/.claude/channels/wechat/history/下的对话历史会随着时间增长建议定期清理或者设置保留天数。你可以在桥接脚本里加一个定时任务删除超过 30 天的历史文件。或者直接用系统的cron或计划任务来做。第四是消息分段。ilink API 对单条消息有长度限制超过 2048 字符需要自动按换行分割发送。桥接脚本里已经处理了这个逻辑但你要注意如果 Claude 返回的代码块很长分段后可能会在代码中间断开。可以在分段前先按代码块边界切分保证代码完整性。第五是错误恢复策略。桥接脚本默认连续失败 3 次后退避 30 秒。如果你的网络环境不稳定可以适当调大退避时间比如 60 秒。同时建议加一个告警机制比如失败次数超过阈值时发一封邮件或者写一条系统日志方便你及时发现。最后说说 Coding Plan 的接入。如果你打算长期用这个桥接方案做编码辅助建议把 TaoToken 的 Coding Plan 用起来。它适合高频调用场景比按次计费更划算。接入方式很简单在 TaoToken 控制台里开通 Coding Plan然后把生成的 Key 配置到.claude/settings.json里就行。Base URL 和普通 Key 一样都是https://taotoken.net/api。如果你还想进一步扩展比如把桥接脚本接到 Cline MCP 或者 Codex 的auth.json核心三件套是一样的Base URL、Key、Model ID。Base URL 用https://taotoken.net/apiKey 用 TaoToken 生成的Model ID 根据你用的模型填比如claude-sonnet-4-20250514这种。配置好之后Cline 或 Codex 就能通过 TaoToken 统一走 Claude 模型。验证模型是否生效可以直接在模型对话页面里发一条测试消息看返回的模型标识是否正确。如果返回的是你配置的模型说明接入成功。长期编码或 Agent 场景建议直接用 Coding Plan省去每次调用的计费烦恼。整个方案的核心就是用自己的桥接脚本把微信和 Claude 连起来用 TaoToken 统一管理 Key用claude -p调用模型。链路完全自控不依赖任何官方未开放的功能。跑通之后你可以在微信里随时调用 Claude 的代码能力也可以把它接到其他工具里扩展性很好。
返回列表