PicoBot/ARCHITECTURE.md
oudecheng e6b2fcfb6d docs+test: 补充架构文档与 anthropic provider 单测
P3 文档:
- 新增 ARCHITECTURE.md,聚焦数据流与 7 个关键设计决策
  (MessageBus 解耦/SessionPool 隔离/AgentLoop 循环/SQLite 池化/重启机制/嵌入静态文件/Safety Guard)
- 不写代码导读,只写'为什么这样设计',代码是唯一真相源

P2 测试:
- src/providers/anthropic.rs 曾零测试(396 行),补 15 个纯函数单测
- 覆盖:data URL 解析、图片过滤逻辑、内部字段过滤、响应反序列化、错误链格式化
- providers 模块测试密度 31% -> 提升,重点补齐 anthropic 空白
2026-08-03 23:45:41 +08:00

7.0 KiB
Raw Permalink Blame History

PicoBot 架构

本文档聚焦"为什么这样设计"和"数据如何流动",不是代码导读。 代码是唯一真相源,文档可能滞后;有冲突以代码为准。

一句话定位

PicoBot 是一个多渠道接入的 Agent 网关:外部消息(微信/飞书/Web/CLI经统一总线进入 由会话管理器路由到对应 Agent 循环Agent 调用 LLM + 工具完成任务,结果原路返回。

核心数据流

┌─────────┐   ┌──────────┐   ┌──────────────┐   ┌────────────┐   ┌──────────┐
│ Channel │──▶│ MessageBus│──▶│InboundProc.  │──▶│ Session    │──▶│AgentLoop │
│ (微信/   │   │ (解耦)    │   │(并发+限流)    │   │ Manager    │   │(LLM+工具)│
│ 飞书/Web)│   │          │   │              │   │            │   │          │
└─────────┘   └──────────┘   └──────────────┘   └────────────┘   └────┬─────┘
     ▲                                                                       │
     │                                                                       ▼
┌────┴────┐   ┌──────────┐                            ┌────────────┐  ┌──────────┐
│Outbound │◀──│ MessageBus│◀─── SessionMessageSender ◀─│  storage   │◀─│  tools   │
│Dispatcher│   │          │                            │  (SQLite)  │  │(bash/file│
└─────────┘   └──────────┘                            └────────────┘  │ /memory) │
                                                                        └──────────┘

入站Channel → MessageBus → InboundProcessor并发控制 + 限流)→ SessionManager → AgentLoop 出站AgentLoop → SessionMessageSender → MessageBus → OutboundDispatcher → Channel 持久化AgentLoop / Tools → SessionStoreSQLite + r2d2 连接池)

关键设计决策

1. MessageBus 解耦 Channel 与 Session

问题:多个 Channel微信/飞书/Web接入每个 Channel 协议不同,但 Session 处理逻辑相同。 决策:引入 MessageBus 作为中间件Channel 只负责协议适配和收发Session 不关心消息来自哪个 Channel。 代价:多一层间接。换来的是新增 Channel如钉钉只需实现 Channel trait不碰 Session 逻辑。

2. SessionPool 会话隔离

问题:多用户同时对话,会话状态不能串扰。 决策SessionManager 持有 SessionPool按 (channel_name, chat_id) 路由到独立 Session。 每个 Session 有自己的 AgentLoop、消息历史、工具上下文。 代价:内存占用随活跃会话数增长。用 session_ttl_hours 过期回收。

3. AgentLoop 的工具循环

问题LLM 需要多轮工具调用才能完成任务(如"读文件→分析→写文件")。 决策AgentLoop 是一个有界循环max_tool_iterations默认 1000每轮

  1. 把消息历史 + 工具定义发给 LLM
  2. LLM 返回文本或 tool_call
  3. 如果是 tool_call执行工具把结果加入历史回到 1
  4. 如果是文本,结束循环 代价:单次对话可能很长。用 CancelManager 支持中途取消。

4. SQLite + r2d2 连接池

问题:需要持久化会话历史、话题、记忆、待办,且要支持并发读写的 sub-agent 场景。 决策SQLitebundled+ r2d2 连接池max_size=8+ busy_timeout(30s)。 代价SQLite 写并发有限。通过 busy_timeout + 事务隔离级别(之前的修复)缓解锁冲突。 不选 Postgres 的原因:单机部署、零外部依赖、足够用。

5. 重启机制watch channel

问题:配置变更后需要重启 gateway但不能要求用户手动杀进程。 决策main.rs 用 while should_restart 循环gateway 通过 watch::Sender<bool> 通知是否需要重启。 配置 API /api/restart 触发 graceful shutdownmain 收到 should_restart=true 后重新初始化。 代价:重启期间短暂不可用。比热重载简单且可靠。

6. 嵌入式静态文件

问题Web 前端需要随二进制分发,但不想要求用户额外下载。 决策build.rs 在 cargo build 时执行 npm run build产物通过 rust-embed 编译进二进制。 开发时设 STATIC_DIR 环境变量走磁盘文件,支持热更新。 代价:二进制体积增大。换来的是单文件部署。

7. Safety Guard命令安全护栏

问题Agent 可以调用 bash 工具执行任意命令,需要防止误操作(如 format C:rm -rf)。 决策platform 模块按平台注入危险命令正则,执行前匹配拦截。 关键教训:正则要精确(曾因 \bformat\s+ 误拦 dart format),按平台分组避免跨平台误伤。

模块职责速查

模块 职责 关键文件
gateway HTTP/WS 服务、路由、生命周期 gateway/mod.rs, gateway/runtime.rs
gateway/session 会话管理、路由、池化 gateway/session.rs, session_pool.rs
gateway/processor 入站消息处理、并发控制 gateway/processor.rs
agent Agent 循环、上下文压缩 agent/agent_loop.rs
providers LLM Provider 抽象OpenAI/Anthropic providers/openai.rs, anthropic.rs
tools 工具实现与注册 tools/ (bash/file/memory/task/...)
storage SQLite 持久化 storage/mod.rs, migrations.rs
channels 渠道适配(微信/飞书/CLI channels/
bus 消息总线(解耦 channel 与 session bus/message.rs
command 前端命令处理(话题/会话/记忆 CRUD command/handlers/
mcp Model Context Protocol 客户端 mcp/client.rs
scheduler 定时任务调度 scheduler/mod.rs
skills 技能加载与激活 skills/mod.rs
experts 专家配置运行时 experts/mod.rs

测试策略

  • 单元测试:与代码同文件 #[cfg(test)] mod tests,覆盖纯函数和逻辑分支
  • 集成测试tests/ 目录,覆盖跨模块请求格式
  • 测试密度test 行 / 总行tools 98.8%、gateway 96.4%、storage 91.8% 为高覆盖区; providers 31%anthropic 曾为 0%已补、bus 18.7%、cli 4.5% 为薄弱区
  • 不强制覆盖率工具:静态审计 + 高风险区定向补测,比全量 tarpaulin 更务实

工程化基线

  • 格式化rustfmtRust+ prettier前端CI 强制 --check
  • 静态检查clippyRust+ eslint前端CI 强制
  • CIGitHub Actions双平台ubuntu + windows跑 fmt + clippy + test + eslint + tsc + vitest
  • 本地make check 与 CI 完全对齐