PicoBot/README.md
2026-07-15 10:40:56 +08:00

390 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PicoBot
PicoBot 是一个用 Rust 编写的个人 AI 助手运行时。它在本地启动 Gateway接入 CLI TUI、飞书/Lark 等聊天渠道,把会话、消息、记忆和定时任务持久化到 SQLite并为 Agent 提供文件、Shell、HTTP、Web、MCP、Skill、记忆、浏览器和子 Agent 等工具能力。
它更像一个可扩展的“个人助手操作系统”渠道负责收发消息SessionManager 负责会话和上下文AgentLoop 负责模型与工具循环Storage 负责可靠落盘。
完整的组件边界、并发不变量、启动/关停顺序和扩展指南见 [架构文档](docs/ARCHITECTURE.md)。
## 适合做什么
- 在终端里和本地 AI 助手持续对话。
- 在浏览器中聊天,并查看日志、任务和记忆,修改运行配置与助手档案。
- 将同一套 Agent 能力接入飞书/Lark。
- 让 Agent 使用本地文件、Shell、搜索、HTTP、浏览器、MCP 工具完成任务。
- 把长期偏好、事实和历史摘要存成可检索记忆。
- 用 Cron 定时执行任务,并把结果发回目标渠道。
- 通过 Skills 为 Agent 注入项目知识和专用操作指南。
## 快速开始
### 1. 准备环境
需要:
- Rust toolchain项目使用 edition 2024。
- 一个可用的 LLM Provider API Key。
### 2. 构建项目
```bash
cargo build
```
### 3. 准备配置
PicoBot 按以下顺序加载配置:
1. `~/.picobot/config.json`
2. 当前目录 `./config.json`
Gateway 首次启动时会把模板释放到 `~/.picobot/config.example.json`。模板源文件在 [resources/templates/config.example.json](resources/templates/config.example.json)。
最小配置示例:
```json
{
"providers": {
"openai": {
"type": "openai",
"base_url": "https://api.openai.com/v1",
"api_key": "<OPENAI_API_KEY>",
"extra_headers": {}
}
},
"models": {
"gpt-4o": {
"model_id": "gpt-4o",
"temperature": 0.7,
"max_tokens": 4096,
"input_type": ["text", "image"]
}
},
"agents": {
"default": {
"provider": "openai",
"model": "gpt-4o",
"max_tool_iterations": 99,
"token_limit": 128000
}
},
"workspace_dir": "~/.picobot/workspace"
}
```
`.env` 会由 PicoBot 自己解析。配置里的 `<OPENAI_API_KEY>` 这类占位符会在 `.env` 和系统环境变量加载后替换。
### 4. 启动 Gateway
```bash
cargo run -- gateway
```
默认监听 `127.0.0.1:19876`。Gateway 启动后会把进程工作目录切到 `workspace_dir`,默认 SQLite 数据库也会写到该 workspace 下的 `picobot.db`
### 5. 启动 CLI 客户端
另开一个终端:
```bash
cargo run -- chat
```
CLI 默认连接 `ws://127.0.0.1:19876/ws`。如需指定地址,可使用 `--gateway-url`
### 5.1 使用 WebUI
Gateway 启动后直接打开:
```text
http://127.0.0.1:19876/
```
WebUI 随二进制嵌入,不需要 Node.js、npm 或单独部署静态文件,提供:
- 在线聊天、会话创建/切换与历史回放。
- Cron 定时任务、最近运行记录和后台子任务状态。
- Knowledge/Timeline 记忆的分类与全文检索。
- 本地滚动日志的尾部查看、过滤和自动刷新。
- `config.json``~/.picobot/USER.md``~/.picobot/AGENTS.md` 编辑。
配置接口会掩码 API Key、secret、password 和 token保留 `********` 再保存不会覆盖原密钥。运行配置采用原子写入并在 Gateway 重启后生效,`USER.md``AGENTS.md` 则会用于后续构建的 Agent 上下文。
WebUI 当前与 Gateway 使用同一信任边界,不额外提供登录认证。默认只监听 `127.0.0.1`;如果通过 `--host 0.0.0.0`、反向代理或端口转发暴露 Gateway必须在外层配置 TLS 和访问认证,否则聊天及管理 API 会对网络访问者开放。
#### WebUI 开发
WebUI 源码位于 `webui/`,使用 Svelte 5、Vite 和无样式的 Bits UI 可访问组件原语。运行发布版 PicoBot 不需要 Node.js从源码编译或修改前端时需要 Node.js 20+
```bash
cd webui
npm ci
npm run check
npm run build
```
直接运行 `npm run build` 会在被忽略的 `webui/dist/` 生成独立检查产物。正常执行 `cargo build` 时,`build.rs` 会监听前端源码和构建配置,只有它们发生变化时才调用 Vite将生产资源生成到 Cargo `OUT_DIR` 并嵌入二进制;`node_modules` 缺失或 `package-lock.json` 变化时会先自动运行 `npm ci`。前端产物不提交到仓库。
### 6. 作为 systemd 用户服务运行Linux
安装会把当前 PicoBot 可执行文件注册为 `picobot.service` 并设置为登录后自动启动;安装本身不会立即启动 Gateway
```bash
picobot service install
picobot service start
```
服务管理命令:
```bash
picobot service status
picobot service restart
picobot service stop
picobot service uninstall
```
unit 位于 `~/.config/systemd/user/picobot.service`,以执行 `service install` 时的当前目录作为初始工作目录。服务异常退出时由 systemd 自动重启;`stop``restart` 会通过 SIGTERM 触发 Gateway 的有界优雅关停。
TUI 会把一个随机客户端标识保存到 `~/.picobot/tui_client_id`,因此关闭并重新打开客户端后会恢复同一组 dialog 和最近使用的会话。界面支持历史回放、会话列表与归档筛选、命令补全、Unicode/中文编辑、括号粘贴和多行输入。
常用快捷键:
| 快捷键 | 操作 |
|--------|------|
| `F1` / `Ctrl+H` | 打开帮助 |
| `Tab` / `Ctrl+S` | 切换焦点 / 聚焦会话列表 |
| `Ctrl+N` | 新建会话 |
| `Ctrl+R` / `Ctrl+A` / `Ctrl+D` | 重命名 / 归档 / 删除所选会话 |
| `Ctrl+L` / `Ctrl+O` | 清空历史 / 显示归档会话 |
| `Enter` / `Shift+Enter` | 发送 / 换行 |
| `PageUp` / `PageDown` | 滚动对话历史 |
| 连按两次 `Ctrl+C` | 退出客户端 |
## 运行时数据流
用户消息进入 PicoBot 后,会被转换为统一的 inbound message经由 MessageBus 交给 SessionManager。SessionManager 选择当前 dialog、组装上下文、调用 AgentLoopAgentLoop 调用模型和工具,最终响应通过 outbound bus 回到原渠道。
详细时序和失败语义见 [架构文档:消息与控制数据流](docs/ARCHITECTURE.md#4-消息与控制数据流)。
同一 session 的普通消息由专属有界队列串行处理,不同 session 可以并发;出站消息按 `(channel, chat_id)` 分 lane 保序慢渠道不会阻塞其他目标。Gateway 的长生命周期任务统一由 `TaskSupervisor` 取消和限时回收。
核心边界:
| 模块 | 职责 |
|------|------|
| `channels` | 接入外部渠道,只做收发,不直接处理会话或 LLM |
| `bus` | 异步消息队列,承载 inbound、outbound、control 三类消息 |
| `session` | 管理会话生命周期、dialog 操作、上下文、记忆召回、压缩和持久化 |
| `agent` | 执行无状态 LLM/tool 循环,处理模型响应和工具调用 |
| `providers` | OpenAI 兼容接口和 Anthropic Messages API 客户端 |
| `tools` | Agent 可调用工具集合 |
| `storage` | SQLite schema、CRUD、消息和任务持久化 |
| `scheduler` | 轮询 Cron 任务并把任务 prompt 送入目标会话 |
| `skills` | 加载 Skill并把 Skill 指南注入系统提示 |
| `mcp` | 连接 MCP Server将远端工具包装成普通 Tool |
| `task_supervisor` | 统一管理 Gateway 后台任务的取消和有界关停 |
## 核心能力
### 渠道
| 渠道 | 说明 |
|------|------|
| `cli_chat` | Ratatui 终端客户端,通过 WebSocket 连接 Gateway |
| `feishu` | 飞书/Lark 消息、反应、文件上传下载和媒体引用 |
### 会话
Session ID 使用三段式:
```text
<channel>:<chat_id>:<dialog_id>
```
同一个 `channel:chat_id` 下可以有多个 dialog。当前支持的 dialog 操作包括创建、列表、切换、重命名、归档、删除、清空历史、压缩、导出、查看信息和停止任务。
常用 slash commands
| 命令 | 说明 |
|------|------|
| `/new` | 创建新 dialog |
| `/sessions` | 列出最近 dialog |
| `/switch <dialog_id>` | 切换 dialog |
| `/rename <title>` | 重命名当前 dialog |
| `/delete` | 删除当前 dialog 并创建新 dialog |
| `/compact` | 手动压缩上下文 |
| `/info` | 查看当前 dialog 信息 |
| `/dump` | 导出当前 dialog 为 Markdown |
| `/mcp` | 查看 MCP 服务器和工具状态 |
| `/stop` | 停止当前任务并清空队列 |
| `/?`, `/help` | 查看帮助 |
### 记忆
PicoBot 有两类记忆:
| 类型 | 用途 | 生命周期 |
|------|------|----------|
| Knowledge | 偏好、事实、项目规则、长期可复用信息 | 长期保留,手动删除 |
| Timeline | 长对话压缩后的历史摘要 | 默认保留 90 天 |
每轮处理用户消息时MemoryManager 会按用户输入召回 Knowledge并作为运行时上下文附加到本轮用户消息。当前召回上限固定为 5`memory.recall_limit` 已支持解析但尚未接入 worker。上下文压缩产生的摘要会保存为 Timeline后续可通过 `timeline_recall` 工具检索。
### 工具
基础工具集:
| 工具 | 说明 |
|------|------|
| `calculator` | 数学表达式和统计计算 |
| `file_read` / `file_write` / `file_edit` | 文件读写和编辑 |
| `file_search` / `content_search` | 文件名和内容搜索 |
| `bash` | 在 workspace 中执行 Shell 命令 |
| `http_request` / `web_fetch` | HTTP 请求和网页文本抽取 |
| `get_skill` | 列出或读取本地 Skill |
| `memory_store` / `memory_recall` / `timeline_recall` / `memory_forget` | 长期记忆操作 |
| `delegate` | 启动 inline、background 或 parallel 子 Agent |
| `send_message` | 向指定渠道发送消息 |
| `chat_manager` | 查看渠道、会话和历史消息 |
| `cron_add/list/remove/enable/disable/update` | 管理定时任务 |
| `browser` | 可选 WebDriver 浏览器自动化 |
| MCP tools | 从配置的 MCP Server 动态发现并注册 |
### Skills
Skill 是包含 `SKILL.md` 的目录。加载优先级从高到低:
1. `{workspace}/skills`
2. `~/.picobot/skills`
3. `~/.agents/skills`
同名 Skill 会按高优先级覆盖低优先级。内置 Skill 位于 [resources/skills](resources/skills),首次运行时会安装到 `~/.picobot/skills`
## 配置速查
顶层配置字段:
| 字段 | 说明 |
|------|------|
| `providers` | LLM Provider 配置 |
| `models` | 模型参数与输入能力 |
| `agents` | Agent 使用哪个 provider/model |
| `gateway` | HTTP/WebSocket、数据库、调度器、后台任务限制 |
| `client` | CLI 客户端默认 Gateway URL |
| `channels` | 渠道配置,目前主要是飞书/Lark |
| `memory` | 记忆召回、归并和 Timeline 保留策略 |
| `mcp` | MCP Server 配置 |
| `browser` | 可选浏览器自动化配置 |
| `workspace_dir` | 文件工具、Shell、数据库和 workspace skills 的工作目录 |
重要默认值:
| 配置 | 默认值 |
|------|--------|
| `gateway.host` | `127.0.0.1` |
| `gateway.port` | `19876` |
| `gateway.max_concurrent_background_tasks` | `10` |
| `gateway.scheduler.enabled` | `true` |
| `client.gateway_url` | `ws://127.0.0.1:19876/ws` |
| `memory.recall_limit` | `5`(当前运行时固定为 5 |
| `memory.timeline_retention_days` | `90` |
| `mcp.tool_timeout_secs` | `180` |
| `browser.enabled` | `false` |
更完整的配置字段说明见 [resources/skills/about-picobot/references/config.md](resources/skills/about-picobot/references/config.md)。
## WebSocket API
Gateway 暴露:
| Method | Path | 说明 |
|--------|------|------|
| `GET` | `/health` | 健康检查和版本信息 |
| `GET` | `/ws` | WebSocket 聊天协议 |
Inbound 消息类型:
| Type | 主要字段 |
|------|----------|
| `user_input` | `content`,可选 `channel``chat_id``sender_id` |
| `clear_history` | 可选 `chat_id``session_id` |
| `create_session` | 可选 `title` |
| `list_sessions` | `include_archived` |
| `load_session` | `session_id` |
| `get_session_history` | `session_id`,可选 `limit`(服务端限制为 12000 |
| `rename_session` | 可选 `session_id``title` |
| `archive_session` | 可选 `session_id` |
| `delete_session` | 可选 `session_id` |
| `get_slash_commands` | 无 |
| `ping` | 无 |
Outbound 消息类型包括 `assistant_response``error``session_established``session_created``session_list``session_loaded``session_history``session_renamed``session_archived``session_deleted``history_cleared``slash_commands_list``pong``command_executed``system_notification`。其中异步 `assistant_response` / `system_notification` 可携带 `session_id`,客户端应避免把迟到结果显示到其他 dialog。
## 测试
```bash
# 单元测试
cargo test --lib
# 离线集成/协议测试
cargo test --test test_scheduler
cargo test --test test_request_format
# 模型 API 集成测试需要 tests/test.env 中有真实 API key
cp tests/test.env.example tests/test.env
cargo test --test test_integration -- --ignored
cargo test --test test_tool_calling -- --ignored
```
会真实调用模型 API 的测试标记为 `#[ignore]`;离线集成测试默认执行。
## 项目结构
```text
src/
agent/ LLM loop、上下文压缩、系统提示、媒体处理、子 Agent
bus/ inbound、outbound、control 消息队列
channels/ CLI chat 和飞书/Lark 集成
client/ Ratatui 终端 UI
config/ 配置加载、环境变量替换、路径展开
gateway/ Axum HTTP/WebSocket server 和 GatewayState 装配
mcp/ MCP 客户端连接和工具包装
memory/ 记忆管理和记忆类型
observability/ Agent/tool telemetry observer
providers/ OpenAI 兼容和 Anthropic provider
scheduler/ 定时任务运行时
session/ 会话生命周期、dialog 命令、持久化集成
skills/ Skill 加载和内置 Skill 安装
storage/ SQLite schema 和 CRUD
tools/ Agent 工具实现
task_supervisor.rs Gateway 后台任务的生命周期管理
resources/
skills/ 构建时嵌入的内置 Skills
templates/ 首次运行释放的配置和用户模板
tests/ 单元测试和 ignored 集成测试
docs/ 面向维护者和 Agent 的架构与开发文档
```
## 关键依赖
| Crate | 用途 |
|-------|------|
| `axum`, `tokio`, `tokio-tungstenite` | Gateway 和 WebSocket runtime |
| `sqlx` | SQLite 持久化 |
| `reqwest` | LLM 和 HTTP 客户端 |
| `ratatui`, `crossterm`, `termimad` | 终端 UI |
| `rmcp` | MCP 客户端 |
| `fantoccini` | 可选浏览器自动化 |
| `cron`, `chrono-tz` | 定时任务 |
| `jieba-rs` | 中文记忆检索分词 |
| `zstd`, `tar` | 内置 Skill 打包和释放 |
## 进一步阅读
- [维护者架构文档](docs/ARCHITECTURE.md)
- [内置 Skill架构机制](resources/skills/about-picobot/references/architecture.md)
- [配置说明](resources/skills/about-picobot/references/config.md)
- [命令说明](resources/skills/about-picobot/references/commands.md)
- [工具说明](resources/skills/about-picobot/references/tools.md)
- [数据库结构](resources/skills/about-picobot/references/db-schema.md)