主题
Day 2 — Channel 设计文档
设计目标:通过抽象基类定义统一的渠道接口,让系统能无感知地支持多种接入方式(CLI、WebChat、Webhook),且新增渠道不需要修改任何已有代码。
一、核心接口设计
1.1 Channel 抽象基类
| 方法 | 签名 | 说明 |
|---|---|---|
| start | async start() | 启动渠道 |
| stop | async stop() | 停止渠道 |
| receive | async receive() -> AsyncIterator[GatewayMessage] | 持续接收消息的异步迭代器 |
| send | async send(message: GatewayMessage) | 发送消息到渠道 |
为什么用 ABC(抽象基类)?
- 强制所有渠道实现这四个方法,避免遗漏
- 上层代码面向
Channel接口编程,不依赖具体实现 - 新增渠道只需
class NewChannel(Channel)并实现四个方法
1.2 CLIChannel
| 属性/方法 | 说明 |
|---|---|
| user_id | CLI 用户标识,默认 "cli_user" |
| receive() | 用 asyncio.get_event_loop().run_in_executor() 在线程池中读取 stdin,避免阻塞事件循环 |
| send() | 直接 print() 到 stdout |
关键设计:标准输入 input() 是阻塞的,在 asyncio 中直接调用会卡住整个事件循环。解决方案是放到线程池执行器中。
1.3 WebChatChannel
| 端点 | 方法 | 说明 |
|---|---|---|
/chat | POST | 接收 JSON {"message": "...", "user_id": "..."} |
/ws | WebSocket | 全双工实时通信 |
/health | GET | 健康检查,返回 {"status": "ok"} |
内部架构:
为什么用 Queue?
- 生产者(HTTP handler、WebSocket handler)和消费者(receive())解耦
- 多个生产者可以同时往 Queue 写入,线程安全
- Queue 有背压机制——满了会自动阻塞生产者,防止内存溢出
1.4 WebhookChannel
| 配置 | 说明 |
|---|---|
| parsers | Dict[str, Callable] 平台名 → 解析函数 |
| 路由 | POST /webhook/{platform} → 查找对应 parser |
二、关键流程图
消息接收流程(以 WebChatChannel 为例)
三、设计决策与权衡
决策 1:receive() 使用 async generator 而非回调
| 方案 | 优点 | 缺点 |
|---|---|---|
| async generator(选择) | 调用方用 async for 自然消费,代码直观 | 需要理解生成器概念 |
| 回调函数 | 传统模式,很多人熟悉 | 回调地狱,错误处理复杂 |
| 返回消息列表 | 最简单 | 不适合持续接收的场景 |
决策 2:CLI 用线程池读取输入
input() 是阻塞调用。在 asyncio 中有三种处理方式:
| 方案 | 优点 | 缺点 |
|---|---|---|
| run_in_executor(选择) | 最简单,不阻塞事件循环 | 多了一个线程 |
| aioconsole 库 | 专业的异步控制台库 | 多一个依赖 |
| select/poll | 无额外线程 | 跨平台兼容性差 |
决策 3:WebhookChannel 用可插拔解析器
不同平台的 Webhook 数据格式完全不同(飞书 vs 微信 vs Slack),硬编码解析逻辑会导致代码膨胀。
用 register_parser(platform, parser_func) 的方式,每个平台的解析逻辑独立在一个函数里——新增平台只需注册新的解析函数。
四、与前序章节的集成点
- 依赖 Day 1:所有 Channel 的输出都是
GatewayMessage格式 - 被 Day 3 依赖:Session 管理需要从 Channel 获取
user_id和channel名称来路由会话
五、与真实生产系统的对比
| 维度 | miniOpenClaw | 生产级实现 |
|---|---|---|
| CLI | 仅用于调试 | 同样仅用于调试和管理 |
| Web | aiohttp 单进程 | Nginx + Gunicorn + FastAPI 多 worker |
| Webhook | 简单路由 | 签名验证、重放攻击防护、幂等处理 |
| 队列 | asyncio.Queue | Redis Queue / RabbitMQ |
| 消息格式转换 | 简单 JSON 解析 | 完整的 Schema 校验 + 版本适配 |