xiaoski 2f11aed44a feat(skills): add built-in skill packaging mechanism and about-picobot documentation
- Add build.rs: scan resources/skills/, compress each with tar+zstd, embed via include_bytes!
- Add src/skills/builtin.rs: runtime auto-install built-in skills to ~/.picobot/skills/
- Add about-picobot built-in skill: SKILL.md index + references/ (config, db-schema, architecture, faq, commands) + assets/config.example.json
- Update skill loading: reverse priority (agents < picobot < workspace), deduplicate by name
- Update skills prompt: re-query get_skill when user asks about installed skills
- Change max_tool_iterations default from 20 to 99
2026-05-15 12:00:18 +08:00

7.5 KiB
Raw Blame History

PicoBot 架构机制

核心数据流

Channel → MessageBus → SessionManager → AgentLoop → (tools) → SessionManager → MessageBus → OutboundDispatcher → Channel
                ↑
          ControlChannel → SessionManager (dialog 操作: 创建/切换/归档/删除)

模块职责

模块 职责
gateway HTTP/WebSocket 服务器,持有 GatewayState
client TUI 聊天客户端
channels 外部集成飞书、CLI仅收发消息
bus 异步消息队列,纯队列不路由
session 会话生命周期管理、dialog 操作
agent LLM 调用循环、工具执行、上下文压缩
providers LLM API 客户端OpenAI 兼容、Anthropic
tools Agent 工具bash、文件操作、HTTP、web、get_skill 等)
skills Skill 加载、管理和 prompt 构建
storage SQLite 持久化
scheduler Cron 作业调度
observability Observer 模式agent/工具遥测事件
protocol WebSocket 协议消息定义
config 配置加载、环境变量替换、路径解析
memory 长期记忆存储与检索
mcp MCPModel Context Protocol工具集成

功能边界

  • Channels 仅收发消息,不感知 session 或 LLM
  • MessageBus 是纯异步队列,不路由
  • SessionManager 拥有 session 状态,不直接调 LLM负责注入 skills prompt
  • AgentLoop 无状态,接收 dialog 事件调用 LLM、执行工具
  • Providers 是纯 HTTP 客户端,无 bus/session/channel 感知
  • Tools 接收原始参数,返回字符串结果

关键约束

  • Gateway 启动时切换到 workspace 目录
  • SQLite 数据在 {workspace}/picobot.db
  • ChannelManager 持有 MessageBus 和所有 channel
  • OutboundDispatcher 通过 ChannelManager 路由出站消息
  • Config .env 加载使用 unsafe { env::set_var(...) }

上下文压缩

当上下文接近 token 限制时触发:

  1. 快速裁剪:合并连续同角色消息,截断工具输出
  2. 硬截断:移除过老消息
  3. 压缩后保留用户消息确保结构完整

Skill 系统

三个优先级(高覆盖低):

  1. {workspace}/skills/ — 最高优先级
  2. ~/.picobot/skills/ — 中等优先级
  3. ~/.agents/skills/ — 最低优先级

同名 skill 按优先级覆盖。每个 skill 是包含 SKILL.md 的目录。内置 skill 在 ~/.picobot/skills/ 下不存在时自动从二进制释放安装。

会话系统

会话 ID 格式

统一会话 ID 为三段式:<channel>:<chat_id>:<dialog_id>

部分 含义 示例
channel 消息渠道 cli_chatfeishu
chat_id 聊天/群组标识 sid_abc123
dialog_id 对话标识 defaultd_xxxx(短 ID

同一 channel:chat_id 下可有多个 dialog。chat_scope() 返回 "channel:chat_id" 用于分组。

Session 生命周期

create → 存入 Storage → 载入 memory → 设为当前 dialog
                                 ↓
                          get_or_create
                                 ↓
                      ← 接收消息、LLM 响应 →
                                 ↓
                      switch → rename → archive → delete(soft)
操作 效果
create 新建 dialog_id立即持久化到 SQLite设为当前
get_or_create 先在内存 HashMap 中找 → 再查 Storage → 都不存在则新建
switch_dialog 切换当前 dialog目标 session 自动从 Storage 恢复入内存
list_dialogs 列出 channel:chat_id 下最近 10 个 session
rename 更新标题,内存 + Storage 同步
delete 软删除(设 deleted_at从内存移除
archive 当前为空操作

SessionManager 数据结构

两层追踪:

  • sessionsHashMap<String, Arc<Mutex<Session>>> — 所有已加载的 sessionkey 为完整 session ID
  • current_sessionsHashMap<String, String> — 每个 channel:chat_id 当前的 session ID

消息到达时 resolve_dialog_id() 按顺序确定接收 session当前 session → Storage 最近活跃 session → 新建。

消息处理三阶段

阶段 1持锁:斜杠命令检测 → 用户消息入库 → 提取记忆上下文 → 构建系统提示skills + memory_context→ 上下文压缩 → 创建 AgentLoop

阶段 2无锁agent.process(history) → LLM 调用 + 工具执行。上下文溢出时自动重新压缩重试

阶段 3持锁:持久化 agent 响应消息 → 自动生成标题(消息数 ≥ 5 且标题为"新对话"时)

会话恢复

从 Storage 恢复 session 时:

  • last_compressed_message_at 存在:先加载近 3 条 Timeline 记忆作为 [Previous Context],再加载压缩标记后的原始消息
  • 若无压缩记录:正常加载全部消息
  • 自动修复断链的工具调用gateway 崩溃中途重启导致)

记忆系统

记忆类别

类别 用途 生命周期 检索方式
Knowledge 事实、偏好、模式、洞察 长期保留,手动删除 每轮注入系统提示,关键词匹配
Timeline 历史会话摘要 自动清理(默认 90 天) timeline_recall 工具按需检索

MemoryEntry 字段

字段 说明
id UUID
key 唯一键,同 key 写入覆盖旧值
content 记忆内容
category knowledgetimeline
importance 权重 (0.01.0)Timeline 默认为 0.3
session_id 关联会话(可选)

存储与检索

  • 主表 memories + FTS5 虚拟表 memory_fts(key, content) 全文索引
  • 中文分词使用 jieba-rs 逐词精确匹配,用 OR 连接
  • FTS5 无结果时回退到 LIKE 模糊匹配
  • 支持 category、session_id、时间范围过滤

工作流程

用户消息到达
  → MemoryManager::recall(content, 5, Knowledge)
    返回最多 5 条匹配的知识记忆(按 importance DESC
  → 格式化为 "- key: content"
  → 注入系统提示的 "记忆上下文" 部分
  → LLM 可见,辅助回答

记忆工具

工具 写操作 说明
memory_store 存储 Knowledge。必填: key, content。可选: importance
memory_recall 搜索 Knowledge。必填: query(空格分隔关键词)。可选: since, until, limit
timeline_recall 搜索 Timeline压缩后的会话摘要。必填: query。可选: session_id, since, until
memory_forget 按 key 删除记忆

上下文压缩与 Timeline

LLM 对话上下文接近 token 限制 (默认 128K × 70%) 时自动触发压缩:

  1. 快速裁剪:工具输出 ≥ 2000 字符时截断
  2. LLM 摘要:最多 3 轮,每轮找连续用户消息对,将中间的 assistant/tool 消息压缩为摘要 → 摘要作为 Timeline 记忆 持久化importance 0.3
  3. 硬截断:若仍超 90%,只保留前 N + 后 N 条消息

压缩后 last_compressed_message_at 标记边界,后续恢复时从标记点加载原始消息,以 Timeline 提供更早的上下文。

关键集成点

时机 操作
每次消息处理 memory_manager.recall() 提取 Knowledge 上下文
系统提示构建 MemorySection 渲染记忆指南 + 匹配的记忆
有压缩历史时 HistorySection 提示 LLM 使用 timeline_recall
压缩完成后 摘要自动存储为 Timeline 记忆
空闲时 可配置自动 consolidationidle_consolidation_minutes