背景
我经常遇到这样的场景:
- 出门在外,突然需要 Trae IDE 里的 AI Agent(Solo) 帮我改个 bug、查个资料
- 电脑在公司运行着,我想让 AI 帮我执行一些操作,但不想远程桌面
- 手边只有手机,但我需要和 Trae 里的 AI 对话
为了解决这个问题,我写了 Lark → Trae 桥接工具。
它能帮你做什么?
手机飞书 ←→ 飞书服务器 ←→ lark-cli ←→ Trae IDE (AI Agent)
- 手机发消息 → AI 处理:在飞书给 Bot 发消息,自动注入到 Trae 的聊天输入框,AI Agent 收到并处理
- AI 结果 → 推送回手机:AI 处理完后,通过 lark-cli 把结果(文字/截图)发回你的飞书
- 自动确认:收到消息后自动回复"已收到,正在处理中…"
- 智能指令:自动附加回复指令,让新对话的 AI 也知道怎么把结果发回来
技术架构
┌─────────────────────────────────────────────────────────────┐
│ lark-to-trae │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ LarkListener │───→│ Bridge │───→│ TraeController│ │
│ │ │ │ (编排层) │ │ │ │
│ │ lark-cli │ │ │ │ pyautogui │ │
│ │ event consume│ │ 消息回调 │ │ 窗口操控 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ 飞书 WebSocket 消息解析/过滤 点击输入框 │
│ 长连接 确认/保存 剪贴板粘贴 │
│ 回车发送 │
└─────────────────────────────────────────────────────────────┘
核心组件
组件 职责 技术
LarkListener 监听飞书消息 lark-cli event consume,WebSocket 长连接
TraeController 操控 Trae 窗口 pyautogui + pygetwindow,点击定位 + 键盘模拟
Bridge 消息编排 回调处理、确认回复、发送者信息保存
reply 结果回传 lark-cli im +messages-send,支持文字/图片/截图
消息流
- 用户在飞书发消息
- lark-cli event consume 收到 NDJSON 事件
- LarkListener 解析消息,过滤(白名单/前缀)
- Bridge 构建注入文本(来源标签 + 原文 + 回复指令)
- TraeController 激活 Trae 窗口 → 点击输入框 → 粘贴 → 回车
- Bridge 发送"已收到"确认到飞书
- Bridge 保存发送者信息到 _pending_message.json
- AI 处理完毕,执行 lark-to-trae --reply “结果”
- reply 模块读取发送者信息,通过 lark-cli 发送回飞书
关键技术点
- lark-cli event consume 的 stdin 陷阱
lark-cli 的 event consume 命令将 stdin EOF 视为退出信号。如果用 subprocess.Popen 启动时不传 stdin=subprocess.PIPE,进程会立刻退出:
错误:进程启动后立即退出
proc = subprocess.Popen(
[“lark-cli”, “event”, “consume”, “im.message.receive_v1”, “–as”, “bot”],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
正确:保持 stdin 开启
proc = subprocess.Popen(
[“lark-cli”, “event”, “consume”, “im.message.receive_v1”, “–as”, “bot”],
stdin=subprocess.PIPE, # 关键!
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
- Windows GBK 编码问题
Windows 控制台默认使用 GBK 编码,无法输出 emoji 和部分中文字符。解决方案是在 CLI 入口处重新配置 stdout 编码:
def main():
if sys.platform == “win32”:
try:
sys.stdout.reconfigure(encoding=“utf-8”, errors=“replace”)
sys.stderr.reconfigure(encoding=“utf-8”, errors=“replace”)
except Exception:
pass
注意:不要用 io.TextIOWrapper 包装,会导致输出缓冲区无法刷新,命令无响应。
- 回调风暴防护
Bot 发送确认消息后,会触发新的 im.message.receive_v1 事件。如果不过滤,会形成死循环:
用户发消息 → Bot 收到 → 发确认 → Bot 收到确认 → 又发确认 → …
解决方案是匹配确认消息内容来过滤:
def _should_process(self, msg_info):
confirm_msg = self.config.get(“confirm_message”, “
已收到,正在处理中…”)
if confirm_msg and msg_info[“text”].startswith(confirm_msg):
return False # 忽略 Bot 自己的确认消息
… 其他过滤逻辑
- 窗口定位与注入
Trae IDE 的聊天输入框位置不固定,需要动态计算:
def _calc_input_position(self, win):
根据窗口尺寸和比例计算输入框坐标
panel_w = int(win.width * self.config[“left_panel_ratio”])
x = int(win.left + panel_w * self.config[“input_x_ratio”])
y = int(win.top + win.height - self.config[“input_bottom_offset”])
return x, y
注入流程:激活窗口 → 点击输入框 → 剪贴板粘贴(支持中文)→ 回车发送
快速开始
1. 安装
pip install lark-to-trae==1.1.5
2. 安装 lark-cli
npm install -g @larksuite/cli
3. 在飞书开放平台创建 Bot(配置事件订阅 im.message.receive_v1)
4. 配置 lark-cli
lark-cli config init --new
lark-cli auth login --recommend
5. 初始化
lark-to-trae --setup
6. 启动
lark-to-trae
项目信息
GitHub:https://github.com/ZyanWan/Lark_to_Trae
PyPI:https://pypi.org/project/lark-to-trae/
许可证:MIT
总结
我设计这个工具的核心思路很简单:把飞书当遥控器,把 Trae 当执行器。
通过 lark-cli 的 WebSocket 长连接接收飞书消息,通过 pyautogui 模拟键鼠操作注入到 Trae,再通过 lark-cli 把结果发回飞书。整个过程无需远程桌面,无需暴露端口,只需要一个飞书 Bot。
如果你也用 Trae IDE,又经常需要在外面让 AI 帮你干活,可以试试这个工具。
