Code Reader
首页
帮助
设计文档
首页
帮助
设计文档
  • Nanobot 项目最终整合报告

Nanobot 项目最终整合报告

报告日期: 2026-02-04
nanobot 版本: latest (基于核心代码分析)
核心代码规模: ~4,000 行


执行摘要

Nanobot 是一个超轻量级个人 AI 助手框架,采用事件驱动 + 异步消息总线架构。通过极简的设计(仅约 4,000 行核心代码),实现了多渠道聊天、工具调用、子代理并行、持久化记忆等完整功能。

核心结论

维度评估
架构复杂度低 - 清晰的分层设计
扩展性高 - 支持渠道、工具、技能、LLM 提供商扩展
性能优秀 - 全异步设计,高效资源利用
可维护性优秀 - 代码简洁,模块化清晰
创新点渐进式技能加载、上下文注入、子代理工具隔离

三个深挖技术专题

  1. 异步化工具执行 - 全异步接口设计,支持 Shell、HTTP、文件 I/O 非阻塞执行
  2. 工具上下文注入机制 - 运行时动态注入会话信息,支持工具复用和多渠道
  3. 渐进式技能加载 - Always Skills 与 Available Skills 分离,节省 81% token 开销

项目概览

设计目标

nanobot 的核心设计理念是构建一个轻量、可扩展、异步的个人 AI 助手框架,支持:

  • 多通道消息处理 - Telegram、WhatsApp、Discord、CLI 等
  • 工具调用能力 - 文件操作、Shell 命令、Web 搜索、消息发送
  • 子代理并行执行 - 后台任务处理,异步通知结果
  • 持久化记忆系统 - 长期记忆 + 日记式记录
  • 渐进式技能加载 - 按需加载,优化 token 效率

技术栈

组件技术选型
异步框架Python asyncio
LLM 提供商LiteLLM (支持 100+ 模型)
Web 请求httpx (AsyncClient)
消息协议Telegram Bot API, WhatsApp WebSocket (Node.js 桥接)
数据存储JSONL (会话), Markdown (记忆)
配置管理Pydantic Settings
Shell 执行asyncio.create_subprocess_shell

核心架构(6 个维度)

维度 1: Agent 核心机制

架构图

核心类

类名文件位置行号职责
AgentLoopagent/loop.py24主处理引擎,消息循环
ContextBuilderagent/context.py12构建系统提示和消息列表
SubagentManageragent/subagent.py20管理后台子代理
ToolRegistryagent/tools/registry.py8工具注册和执行
SessionManagersession/manager.py61会话管理和持久化

Agent Loop 处理流程

关键参数:

  • max_iterations: 20 (主代理) / 15 (子代理)
  • 超时: 1 秒 (消息队列), 60 秒 (Shell 命令)

详细分析: 参见 task_001: Agent 核心机制


维度 2: 消息总线与渠道架构

消息总线设计

组件说明
Inbound Queue存储来自渠道的入站消息
Outbound Queue存储待发送到渠道的出站消息
_outbound_subscribers按渠道名分类的订阅者回调

消息流转

渠道实现对比

渠道协议文件位置特点
TelegramBot API (长轮询)channels/telegram.pyMarkdown→HTML 转换, 语音转录
WhatsAppWebSocket (Node.js 桥接)channels/whatsapp.py自动重连, QR 码认证
BaseChannel抽象接口channels/base.py统一接口, 权限检查

系统消息路由

  • 子代理结果路由: 使用 chat_id="origin_channel:origin_chat_id" 格式
  • 主代理恢复上下文: 解析 chat_id 并设置工具上下文

详细分析: 参见 task_002: 消息总线与渠道架构


维度 3: 工具系统设计

工具抽象

所有工具必须继承 Tool 基类并实现以下方法:

class Tool(ABC):
    @property
    @abstractmethod
    def name(self) -> str:
        """工具名称"""
        pass

    @property
    @abstractmethod
    def description(self) -> str:
        """工具描述 (给 LLM)"""
        pass

    @property
    @abstractmethod
    def parameters(self) -> dict[str, Any]:
        """JSON Schema 参数"""
        pass

    @abstractmethod
    async def execute(self, **kwargs: Any) -> str:
        """异步执行,返回字符串结果"""
        pass

内置工具清单

工具名称文件位置功能异步特性
read_filetools/filesystem.py读取文件内容Path.read_text
write_filetools/filesystem.py写入文件 (自动创建目录)Path.write_text
edit_filetools/filesystem.py精确替换编辑Path.read/write
list_dirtools/filesystem.py列出目录 (带图标)Path.iterdir
exectools/shell.py执行 Shell 命令asyncio.create_subprocess_shell
web_searchtools/web.pyBrave 搜索httpx.AsyncClient.get
web_fetchtools/web.py获取网页内容httpx.AsyncClient.get
messagetools/message.py发送消息到聊天通道动态上下文注入
spawntools/spawn.py生成子代理动态上下文注入

工具执行流程

详细分析: 参见 task_003: 工具系统设计


维度 4: 会话与记忆系统

会话管理架构

组件存储格式特点
Session数据类内存中的会话对象
SessionManagerJSONL 文件磁盘持久化 + 内存缓存

JSONL 存储格式

~/.nanobot/sessions/telegram_123456.jsonl
{"_type":"metadata","created_at":"2024-01-15T10:00:00","updated_at":"2024-01-15T11:30:00","metadata":{}}
{"role":"user","content":"Hello","timestamp":"2024-01-15T10:00:00"}
{"role":"assistant","content":"Hi there!","timestamp":"2024-01-15T10:00:01"}
{"role":"user","content":"How are you?","timestamp":"2024-01-15T11:30:00"}

JSONL 优势:

  • 流式处理,可逐行读取
  • 易于追加,单行即一条消息
  • 版本控制友好,git diff 清晰
  • 容错性强,单行损坏不影响其他消息

记忆系统架构

存储类型文件路径内容
长期记忆workspace/memory/MEMORY.md用户信息、偏好设置、项目上下文
日记式记忆workspace/memory/YYYY-MM-DD.md按日期记录的日常笔记

跨渠道会话隔离

session_key 格式示例会话文件
"telegram:123456"Telegram 私聊telegram_123456.jsonl
"whatsapp:5511999888777"WhatsApp 聊天whatsapp_5511999888777.jsonl
"cli:direct"CLI 模式cli_direct.jsonl

详细分析: 参见 task_004: 会话与记忆系统


维度 5: 子代理架构

子代理 vs 主代理对比

特性主代理子代理
系统提示完整 (身份、记忆、技能)专注 (仅任务描述)
工具集所有默认工具 (9个)有限工具集 (6个)
上下文会话历史 + 系统提示仅任务描述
通信方式直接响应用户通过消息总线 announce
生命周期持久运行任务完成后结束
最大迭代次数2015
MessageTool✓✗ (防止直接通信)
SpawnTool✓✗ (防止递归创建)

子代理执行流程

结果公告机制

子代理完成后,通过系统消息通知主代理:

msg = InboundMessage(
    channel="system",
    sender_id="subagent",
    chat_id=f"{origin_channel}:{origin_chat_id}",  # 路由信息
    content=announce_content,
)
await bus.publish_inbound(msg)

主代理处理系统消息时:

  1. 解析 chat_id 获取原始会话
  2. 恢复工具上下文
  3. 生成用户友好的自然语言摘要

详细分析: 参见 task_005: 子代理架构


维度 6: 扩展机制

技能系统

渐进式加载策略:

技能类型加载方式Token 消耗使用场景
Always Skills完整内容直接注入系统提示较高核心工具、常用操作
Available Skills仅显示 XML 摘要极低 (~100 words/技能)领域专长、偶发任务

Token 节省示例:

  • 假设 20 个技能: 2 Always Skills + 18 Available Skills
  • Always 模式 (全部加载): 20 × 500 tokens = 10,000 tokens
  • 渐进式模式: 2 × 500 + 18 × 50 = 1,900 tokens
  • 节省: 81%

Cron 定时任务

支持的调度类型:

类型表达式示例
at一次性时间戳"at_ms": 1738689200000
every固定间隔 (毫秒)"every_ms": 3600000 (1小时)
cron标准 cron 表达式"expr": "0 9 * * *" (每天9点)

心跳服务

机制: 定期检查 workspace/HEARTBEAT.md 文件

# HEARTBEAT.md 示例
# Pending Tasks

- [ ] Review PR #123
- [ ] Update documentation
- [ ] Deploy to staging

跳过规则: 空行、标题、已完成的复选框

配置系统

多 LLM 提供商优先级:

OpenRouter > Anthropic > OpenAI > Gemini > Zhipu > Groq > vLLM

环境变量格式:

NANOBOT_AGENTS__DEFAULTS__WORKSPACE=/home/user/workspace
NANOBOT_PROVIDERS__ANTHROPIC__API_KEY=sk-ant-xxx
NANOBOT_CHANNELS__TELEGRAM__TOKEN=bot_token

详细分析: 参见 task_006: 扩展机制


深挖技术专题

专题 1: 异步化工具执行

设计理念

所有工具必须实现异步 execute() 方法,确保:

  • 非阻塞执行: 单个工具的耗时操作不应阻塞整个 Agent Loop
  • 高资源利用: 充分利用异步 I/O 的并发能力
  • 简洁错误处理: 统一的字符串返回格式简化错误传播

Shell 工具异步实现

async def execute(self, command: str, **kwargs) -> str:
    process = await asyncio.create_subprocess_shell(
        command,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
        cwd=cwd,
    )
    
    try:
        stdout, stderr = await asyncio.wait_for(
            process.communicate(),
            timeout=self.timeout  # 默认 60 秒
        )
    except asyncio.TimeoutError:
        process.kill()  # 立即终止进程
        return f"Error: Command timed out after {self.timeout} seconds"

Web 工具异步实现

async def execute(self, url: str, **kwargs) -> str:
    async with httpx.AsyncClient() as client:
        r = await client.get(
            url,
            headers={"User-Agent": USER_AGENT},
            follow_redirects=True,
            timeout=30.0
        )
        r.raise_for_status()
    # ... 处理响应 ...

错误处理策略

三层错误处理:

  1. 工具内部: 捕获具体异常并返回错误字符串
  2. 注册表层: 统一异常捕获和格式化
  3. Loop 层: 记录日志但继续处理

为什么返回字符串而非抛出异常:

  • LLM 友好: 错误信息可以直接作为工具结果传递给 LLM
  • 简化流程: 无需在 Loop 层处理异常类型
  • 容错性强: 即使一个工具失败,其他工具仍可继续执行

详细分析: 参见 task_007: 异步化工具执行


专题 2: 工具上下文注入机制

设计目标

  1. 工具复用性: 同一工具实例可在多个会话间共享
  2. 会话隔离性: 确保不同渠道/会话的工具行为互不干扰
  3. 上下文传递: 支持子代理向原始会话路由结果

MessageTool 上下文注入

class MessageTool(Tool):
    def __init__(
        self,
        send_callback: Callable[[OutboundMessage], Awaitable[None]],
        default_channel: str = "",
        default_chat_id: str = ""
    ):
        self._send_callback = send_callback
        self._default_channel = default_channel   # 动态上下文
        self._default_chat_id = default_chat_id  # 动态上下文
    
    def set_context(self, channel: str, chat_id: str) -> None:
        """Set current message context."""
        self._default_channel = channel
        self._default_chat_id = chat_id

调用位置 (agent/loop.py:143-150):

# 每次处理消息前更新上下文
message_tool = self.tools.get("message")
if isinstance(message_tool, MessageTool):
    message_tool.set_context(msg.channel, msg.chat_id)

SpawnTool 上下文注入

class SpawnTool(Tool):
    def __init__(self, manager: "SubagentManager"):
        self._manager = manager
        self._origin_channel = "cli"    # 默认值
        self._origin_chat_id = "direct"  # 默认值
    
    def set_context(self, channel: str, chat_id: str) -> None:
        """Set origin context for subagent announcements."""
        self._origin_channel = channel
        self._origin_chat_id = chat_id

子代理结果路由链路:

上下文优先级

channel = channel or self._default_channel  # 1. 显式参数优先
chat_id = chat_id or self._default_chat_id

优先级: 显式参数 (LLM 工具调用) > 上下文注入值 > 空值 (返回错误)

详细分析: 参见 task_008: 工具上下文注入机制


专题 3: 渐进式技能加载

Always Skills vs Available Skills

维度Always SkillsAvailable Skills
加载时机每次对话始终加载仅展示摘要,按需加载
内容范围完整技能内容仅元数据 (name + description + location)
Token 消耗较高 (每次对话)极低 (~100 words/技能)
使用场景核心工具、常用操作领域专长、偶发任务
响应速度即时可用需要额外调用 read_file

系统提示结构

# nanobot 🐈 [Identity]

---

[Bootstrap Files]

---

## Long-term Memory

---

## Today's Notes

---

# Active Skills [Always Skills - Full Content]

---

# Skills [Available Skills - Summary Only]

The following skills extend your capabilities. To use a skill, read its SKILL.md file using the read_file tool.
<skills>
  <skill available="true">
    <name>github</name>
    <description>Interact with GitHub using gh CLI.</description>
    <location>/path/to/github/SKILL.md</location>
  </skill>
  <skill available="false">
    <name>docker</name>
    <description>Docker container management.</description>
    <location>/path/to/docker/SKILL.md</location>
    <requires>CLI: docker</requires>
  </skill>
</skills>

按需加载机制

技能元数据格式

---
name: github
description: "Interact with GitHub using gh CLI."
homepage: https://github.com/cli/cli
metadata: {"nanobot":{"emoji":"🐙","requires":{"bins":["gh"]}}}
---

# GitHub Skill

Use `gh` CLI to interact with GitHub...

metadata 字段:

字段类型说明示例
namestring技能名称"github"
descriptionstring技能描述"Interact with GitHub..."
alwaysboolean是否始终加载true/false
requires.binsstring[]需要的 CLI 工具["gh", "git"]
requires.envstring[]需要的环境变量["OPENAI_API_KEY"]
emojistring技能图标"🐙"

详细分析: 参见 task_009: 渐进式技能加载


设计亮点与创新

1. 极简主义哲学

代码规模: 仅约 4,000 行核心代码,实现完整功能集

组件代码行数功能
Agent Loop~330 行消息处理、工具执行、会话管理
工具系统~700 行9 个工具 + 注册表
消息总线~170 行队列、分发、事件模型
技能加载~230 行渐进式加载、依赖检查
会话记忆~110 行JSONL 存储、双模式记忆

设计原则:

  • 单一抽象: 所有工具统一为 async def execute() -> str
  • 零配置: 工具注册无需额外配置代码
  • 隐式依赖: 通过上下文注入而非显式参数传递

2. 错误即对话

将错误信息作为普通字符串返回,让 LLM 能够理解并处理错误:

  • 错误不是程序异常,而是对话的一部分
  • LLM 可以基于错误信息自主调整策略
  • 实现了"自愈"的 AI 助手能力

示例:

# 工具返回错误
"Error: File not found: /tmp/data.json"

# LLM 看到错误后调整策略
# LLM: 让我检查一下目录

3. 异步即解耦

全异步设计不仅带来了性能提升,更重要的是实现了组件解耦:

  • Shell 工具不会阻塞 Web 工具
  • 文件 I/O 不会阻塞网络请求
  • 为未来的并发执行预留了接口

4. 上下文即路由

动态上下文注入机制巧妙地解决了多渠道消息路由问题:

  • 工具无需知道具体渠道
  • LLM 无需传递路由参数
  • 实现了渠道无关的工具设计

5. 渐进式加载

区分 Always Skills 和 Available Skills,实现真正的"按需加载" (Just-In-Time Loading):

  • Token 节省: 在 20 个技能场景下节省 81% token 开销
  • 无限扩展: 理论上可以支持数百个技能
  • 智能推荐: LLM 可以根据任务选择合适的技能

6. 子代理工具隔离

子代理不包含 MessageTool 和 SpawnTool,防止:

  • 递归创建子代理 (避免无限层级)
  • 子代理直接与用户通信 (所有结果必须通过主代理)
  • 确保结果路由的一致性

关键指标统计

代码规模统计

模块文件数代码行数 (估算)
Agent Loop1~330
工具系统7~700
消息总线2~170
会话记忆2~110
技能加载1~230
子代理1~240
Cron/心跳2~280
配置系统1~150
渠道实现3~500
总计~20 文件~2,710 行

功能统计

功能类别数量
内置工具9 个
聊天渠道3+ (Telegram, WhatsApp, 可扩展)
LLM 提供商7+ (支持 100+ 模型)
调度类型3 种 (at, every, cron)
技能类型Always + Available

性能指标

指标值
Token 节省81% (20 技能场景)
最大工具迭代20 (主代理) / 15 (子代理)
Shell 超时60 秒
HTTP 超时10-30 秒
心跳间隔1800 秒 (30 分钟)

结论

nanobot 是一个设计精巧、实现简洁的个人 AI 助手框架。通过约 4,000 行核心代码,实现了完整的 AI 助手功能,包括多渠道聊天、工具调用、子代理并行、持久化记忆、定时任务、心跳服务等。

核心优势

  1. 轻量级: 极简代码,易于理解和维护
  2. 异步优先: 全异步设计,高效资源利用
  3. 可扩展: 清晰的抽象层,易于添加新功能
  4. 智能优化: 渐进式技能加载,节省 81% token 开销
  5. 用户友好: 上下文注入、错误处理、子代理通知等细节优化

设计亮点

  • 事件驱动架构: 消息总线解耦渠道和代理
  • 工具抽象: 统一的异步接口,支持多种外部操作
  • 上下文管理: 动态注入,支持多渠道和子代理
  • 持久化设计: JSONL + Markdown,无需数据库
  • 渐进式加载: Always Skills + Available Skills,按需加载

适用场景

  • 个人 AI 助手: 支持 Telegram、WhatsApp 等多平台
  • 自动化任务: Shell 执行、文件操作、Web 交互
  • 代码审查和重构: 读取、编辑、执行测试
  • 文档生成和管理: 集成文档编写和更新流程
  • 数据分析和可视化: 支持脚本执行和结果返回

这个框架证明了:简洁的设计也能实现强大的功能。nanobot 是学习和构建轻量级 AI 助手系统的优秀参考。


相关文档链接

任务文档路径
Task 001 - Agent 核心机制task_001_agent_core_mechanism.md
Task 002 - 消息总线与渠道架构task_002_message_bus_channels.md
Task 003 - 工具系统设计task_003_tool_system.md
Task 004 - 会话与记忆系统task_004_session_memory.md
Task 005 - 子代理架构task_005_subagent_architecture.md
Task 006 - 扩展机制task_006_extension_mechanisms.md
Task 007 - 异步化工具执行task_007_async_tool_execution.md
Task 008 - 工具上下文注入机制task_008_tool_context_injection.md
Task 009 - 渐进式技能加载task_009_progressive_skill_loading.md