# Wechat Pi Bridge

> 把微信变成电脑上 AI agent 的遥控器：微信收语音/文字 → 本地 whisper 转文字 → 交给 pi 在本机执行 → 结果回发微信。当用户想「用微信远程指挥电脑」「手机上发语音让电脑干活」「把 agent 接到微信」，或需要安装、登录、启动、排障、修改这个桥接时使用。也覆盖腾讯 iLink Bot 协议接入、微信 SILK 语音本地识别、长轮询断点续传、无人值守 agent 的安全与防卡死设计。

- Skill: `bswj520/wechat-pi-bridge` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add bswj520/wechat-pi-bridge`
- Raw SKILL.md: https://api.skillmd.com/api/skills/bswj520/wechat-pi-bridge/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: MIT
- Author: bswj520 (https://skillmd.com/u/bswj520)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/bswj520/wechat-pi-bridge

---


# wechat-pi-bridge

在微信里用语音指挥本机的 AI 编程助手。发一条语音，它在你电脑上真的执行，结果回到微信。

## 它能干什么

- 手机上发语音或文字 → 电脑执行 → 微信收结果
- 支持 `/new` `/stop` `/status` 内置命令管理会话
- 长任务每 40 秒播报进度，不会静默卡死
- 只有扫码登录的那个微信号能下达指令（`ownerOnly`）

## 架构速查

```
微信 ──► 腾讯 iLink 长轮询 ──► bridge.mjs ──► pi --mode rpc ──► 本机执行
                                   │
              语音：AES 解密 → silk-wasm 解码 → 重采样 16k → whisper-server 识别
              回发：Markdown 拍平 → 按 1500 字切段 → sendmessage
```

各文件职责：

| 文件 | 职责 |
|------|------|
| `src/bridge.mjs` | 主循环：登录态加载、长轮询、消息路由、进度播报、回复切段 |
| `src/ilink.mjs` | 腾讯 iLink Bot 协议：二维码、getUpdates、sendText、sendTyping |
| `src/login.mjs` | 二维码登录（PNG + 终端 ASCII），登录态落 `data/accounts.json` |
| `src/pi.mjs` | `PiSession`：spawn `pi --mode rpc`，JSONL over stdio，回合结束看 `agent_settled` |
| `src/store.mjs` | `data/` 下的 token、context_token、getUpdates 游标读写（权限 600） |
| `src/voice.mjs` | 微信 SILK 语音解密解码 + whisper 识别（常驻 server 优先，cli 兜底） |

## 首次安装

按顺序执行，每步确认通过再往下。参考 [README.md](README.md)。

```bash
# 1. 依赖
node -v                                   # 需要 >= 20
pi --version                              # 没有就 npm i -g @earendil-works/pi-coding-agent
brew install whisper-cpp                  # 或源码编译

# 2. 模型（约 1.5GB，放仓库 models/ 下）
mkdir -p models
curl -L -o models/ggml-large-v3-turbo.bin \
  https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo.bin

# 3. 装依赖并配置
npm install
./install.sh

# 4. 扫码登录（必须由用户本人拿手机扫，agent 不要尝试代扫）
node src/login.mjs

# 5. 启动
node src/bridge.mjs
```

登录和扫码是**必须用户本人完成**的一步。二维码会以 PNG 弹出并打印 ASCII 版，让用户用手机微信扫。agent 不要试图自动化这一步。

## 日常操作

```bash
node src/bridge.mjs                # 前台启动，日志到终端和 logs/bridge.log
./scripts/install-launchd.sh       # macOS 装成开机自启服务
tail -f logs/bridge.log            # 跟踪运行日志
tail -f logs/pi.log                # 跟踪 pi 侧的工具调用
```

检查是否在跑：

```bash
pgrep -fl 'src/bridge.mjs'         # 主进程
pgrep -fl 'whisper-server'         # 语音识别常驻进程
```

## 排障

先看 `logs/bridge.log`，它记了每条消息的收发、语音转写耗时、pi 的工具调用。对照下表：

| 现象 | 原因与处理 |
|------|-----------|
| 启动即退出，提示「尚未登录」 | 没跑 `node src/login.mjs`，或 `data/accounts.json` 被删 |
| 发消息没反应 | 看日志有没有 `📥 收到消息`。没有就是长轮询断了，看 `长轮询错误` 行；有但显示 `⛔ 拒绝未授权发送者` 就是 sender 不是 owner，确认扫码的号和发消息的号是同一个 |
| 回复「语音识别失败」 | `logs/whisper-server.log`。常见是模型路径不对、模型没下完、或端口被占 |
| 首次语音特别慢 | 正常，`whisper-server` 首次加载 1.5GB 模型要约 15 秒。之后常驻内存，单条 1-2 秒 |
| 发出去的消息是乱码或带星号 | `src/bridge.mjs` 的 `toPlainText()` 没覆盖到那种 Markdown 语法，补一条正则 |
| 任务跑一半没了 | 撞上 `turnTimeoutMs`（默认 5 分钟）。调大 `config.json` 里的值，或让用户拆小任务 |
| 命令挂死不返回 | 子进程在等输入。确认 `src/bridge.mjs` 的 `NON_INTERACTIVE_ENV` 覆盖了那个工具需要的环境变量 |
| 同一件事被跑了两遍 | 长轮询重连重放了消息。检查 `msg_id` 去重是否生效（`isDuplicate`） |

## 改这个桥接的注意点

**改回复格式** —— 入口是 `src/bridge.mjs` 的 `toPlainText()` 和 `splitForWeChat()`。微信完全不渲染 Markdown，`**粗体**` 会显示成字面的星号。任何新增的格式化语法都要在这里拍平。

**改 agent 行为** —— 不要改 `src/bridge.mjs`，去改 `config.json` 的 `piArgs`。用 `--append-system-prompt` 定制风格最干净，例如：

```json
{
  "piArgs": ["--append-system-prompt", "回复控制在 5 行内，不要复述用户的话。"]
}
```

**配置字段查表** —— `config.json` 所有字段、默认值、常见配方、环境变量清单都在 `docs/CONFIGURATION.md`；模板是 `config.example.json`（由 `install.sh` 复制成 `config.json`）。字段没写就用默认值，JSON 写错不会崩，只会在日志里提示一句。

**换 agent** —— 只改 `src/pi.mjs`。`PiSession` 对外只暴露 `start/ask/abort/newSession` 和 `tool-start`/`tool-end`/`exited` 事件，契约很窄。

**换语音识别** —— 只改 `src/voice.mjs`。已经是双通道：优先常驻 `whisper-server` 的 HTTP 接口，失败退回一次性 `whisper-cli`。环境变量 `WHISPER_BIN` / `WHISPER_SERVER_BIN` / `WHISPER_MODEL` 都可覆盖。

**处理新消息类型** —— `src/bridge.mjs` 的 `handleMessage()`。目前只认文字和语音，其他类型回一句说明。图片/文件要自己加下载和落盘逻辑。

## 安全红线

这个桥接等于把本机 shell 权限交给了微信背后的人。改动时守住这几条：

1. **`ownerOnly` 默认保持 `true`**。改成 `false` 等于把 shell 开放给任何能给这个号发消息的人。
2. **不要以 root 跑**。桥接进程的权限就是它执行的每条命令的权限。
3. **`NON_INTERACTIVE_ENV` 里每一条都不要删**。少一条，对应工具就会在无人值守时挂死等输入：`GIT_EDITOR=true` 防 git 打开编辑器、`GIT_TERMINAL_PROMPT=0` 防 git 卡在输密码、`DEBIAN_FRONTEND=noninteractive` 防安装器弹交互框。
4. **系统提示词里必须保留「需要用户手动操作时停下来说明」**。否则 agent 会在 sudo 密码提示、权限弹窗上无限等下去。
5. **凭据文件保持 600**。`data/accounts.json` 里的 bot token 就是完整控制权。
6. **提醒用户：语音识别可能出错**。涉及删除、转账、对外发送这类不可逆动作，建议让 agent 先复述确认再执行。
7. **账号疑似泄露时**，让用户删掉 `data/accounts.json` 重新扫码，旧 token 立刻失效。

## 验证安装是否成功

三步，缺一不可：

```bash
# 1. 长轮询通了（日志出现 bridge 启动，且没有反复报长轮询错误）
node src/bridge.mjs

# 2. 语音链路通了（日志出现 🎤 转写完成 + 耗时）
#    让用户在微信发一条语音

# 3. agent 链路通了（日志出现 [pi] 完成 + 毫秒数）
#    看微信有没有收到执行结果
```

只有三条都过，才算装好了。任何一条不过，按上面的排障表定位。

