告别臃肿:nanobot,一个更轻、更纯粹的 AI Agent 的实践和原理解析

告别臃肿:nanobot,一个更轻、更纯粹的 AI Agent 的实践和原理解析

本地clawbot功能虽然强大,但整体较为复杂,这边香港大学开源了nanobot,仅4k多行,实现了clawbot的核心功能核心功能,相对于clawbot有代码少,易扩展的优点,而且还支持本地的vllm模型,能充分使用本地的模型节省成本,这边整理一下我的使用体验和代码具体原理分析。

实践:

首先使用

nanobot onboard

初始化配置文件后,在用户目录的.nanobot 下回有个config配置文件

##agent配置 包含使用模型,记忆窗口大小,最大工具调用次数等
"agents": {
    "defaults": {
      "workspace": "~/.nanobot/workspace",
      "model": "cyankiwi/Qwen3-VL-8B-Instruct-AWQ-4bit",
      "maxTokens": 8192,
      "temperature": 0.7,
      "maxToolIterations": 20,
      "memoryWindow": 1
    }
  },

我的场景主要想bot能帮我批量搜索总结信息 这边bot 原有的是使用,这边接入了免费的搜索工具ddgstool,
感兴趣可以看这个 https://github.com/nightli110/nanobot_prove库

"tools": {
  "web": {
    "search": {
      "provider":"duckduckgo",
"max_results":10
    }
  },

nanobot 有两种方式gateway和agent, 这边主要介绍agent方式, agent方式符合我使用的场景
agent方式,通过

nanobot agent --help

可以看到一些options选项


这边bot会以markdown的方式,保存在workspace中
通过添加 —no-markdown 和–logs 可以打印
这边以查询以chatdev的论文查询chatdev对应github项目库为例
先通过 启动agent对话模式
nanobot agent --no-markdown -logs
通过简单对话模型 调用websearch搜索,搜索到了对应的github项目地址,并且按我需要的格式返回搁我了,这个没有建立复杂的workflow

这边我使用模型本地vllm部署的cyankiwi/Qwen3-VL-8B-Instruct-AWQ-4bit, 由于bot会调用工具,在部署vllm时需要添加–enable-auto-tool-choice –tool-call-parser hermes,让模型能动态决定何时使用工具

可以用下面启动

python -m vllm.entrypoints.openai.api_server       --model cyankiwi/Qwen3-VL-8B-Instruct-AWQ-4bit       --gpu-memory-utilization 0.85       --max-model-len 32384    --dtype half   --host  0.0.0.0    --port 8000   --enable-auto-tool-choice --tool-call-parser hermes

下面来看看整个项目的结构,流程以及一些核心模块

2. 项目结构

nanobot/
├── nanobot/                 # 核心 Python 包
│   ├── cli/                 # 命令行接口
│   │   └── commands.py      # CLI 命令实现
│   ├── agent/               # 代理核心
│   │   ├── loop.py          # 主循环
│   │   ├── context.py       # 上下文构建
│   │   ├── subagent.py      # 子代理管理
│   │   ├── memory.py        # 记忆管理
│   │   ├── skills.py        # 技能加载
│   │   ├── session.py       # 会话管理
│   │   └── tools/           # 工具实现
│   │       ├── base.py      # 工具基类
│   │       ├── registry.py  # 工具注册表
│   │       ├── filesystem.py
│   │       ├── shell.py
│   │       ├── web.py
│   │       ├── message.py
│   │       ├── spawn.py
│   │       └── cron.py
│   ├── bus/                 # 消息总线
│   │   └── queue.py         # 异步消息队列
│   ├── channels/            # 聊天渠道
│   │   ├── manager.py       # 渠道管理器
│   │   ├── whatsapp.py
│   │   ├── telegram.py
│   │   ├── feishu.py
│   │   ├── dingtalk.py
│   │   ├── discord.py
│   │   ├── email.py
│   │   ├── slack.py
│   │   ├── qq.py
│   │   └── mochat.py
│   ├── config/              # 配置系统
│   │   ├── schema.py        # Pydantic 配置模型
│   │   └── loader.py        # 配置加载
│   ├── providers/           # LLM 提供者
│   │   ├── base.py          # 提供者基类
│   │   ├── litellm_provider.py
│   │   └── registry.py
│   ├── cron/                # 定时任务
│   │   └── service.py
│   ├── heartbeat/           # 心跳服务
│   ├── session/             # 会话管理
│   │   └── manager.py
│   └── skills/              # 内置技能
│       ├── cron/
│       ├── github/
│       ├── memory/
│       ├── skill-creator/
│       ├── summarize/
│       ├── tmux/
│       └── weather/
├── bridge/                  # Node.js 桥接服务
├── tests/                   # 测试
├── doc/                     # 文档
├── workspace/               # 默认工作区模板
├── case/                    # 使用案例
├── pyproject.toml          # 项目配置
└── README.md

3. 主流程架构

3.1 系统架构图

┌─────────────────────────────────────────────────────────────────┐
│                     CLI / Channels                              │
│  (WhatsApp, Telegram, Discord, Email, Feishu, DingTalk, Slack) │
└────────────┬────────────────────────────────────────────────────┘
             │
    ┌────────▼────────┐
    │   MessageBus    │ (Inbound/Outbound queues)
    └────────┬────────┘
             │
    ┌────────▼──────────┐
    │    AgentLoop      │ (Core processing engine)
    │  - ContextBuilder │ (System prompt + messages)
    │  - SessionManager │ (Conversation history)
    │  - ToolRegistry   │ (All available tools)
    │  - SubagentManager│ (Background task execution)
    └────────┬──────────┘
             │
    ┌────────▼──────────┐
    │    LLM Provider   │ (LiteLLM wrapper)
    │  (Claude, GPT-4,  │  supported)
    │   DeepSeek, etc.) │
    └────────┬──────────┘
             │
    ┌────────▼──────────┐
    │   Tool Execution  │ (Read, Write, Exec, Search, etc.)
    └────────────────────┘

3.2 消息处理流程

用户发送消息
    │
    ▼
[聊天渠道] ──解析消息──▶ Message {
    channel: "telegram",
    chat_id: "123456",
    content: "你好",
    ...
}
    │
    ▼
[MessageBus.inbound.put(message)]
    │
    ▼
[AgentLoop.run()] ◀────轮询获取消息
    │
    ▼
[AgentLoop._process_message(message)]
    │
    ├─▶ 会话管理
    │   SessionManager.get_or_create(
    │       channel, chat_id
    │   )
    │
    ├─▶ 命令处理 (如 /reset)
    │
    ├─▶ 记忆整合 (如需要)
    │   MemoryStore.consolidate()
    │
    ├─▶ 构建上下文
    │   ContextBuilder.build(
    │       system_prompt,    # 系统提示
    │       messages,         # 历史消息
    │       tools             # 可用工具
    │   )
    │
    ├─▶ 调用 LLM
    │   LLMProvider.call(
    │       messages,
    │       tools
    │   )
    │
    ├─▶ 处理响应
    │   ├─ 普通消息 ──▶ 直接返回
    │   └─ 工具调用 ──▶ 执行工具
    │       │
    │       ▼
    │       [Tool.execute()]
    │       │
    │       ▼
    │       继续调用 LLM (带工具结果)
    │       (循环直到无新工具调用)
    │
    └─▶ 发送响应
        MessageBus.outbound.put(response)
            │
            ▼
        [聊天渠道] ──▶ 用户

3.3 上下文构建流程

ContextBuilder.build()
    │
    ├─▶ 构建系统提示
    │   build_system_prompt()
    │   │
    │   ├─▶ 核心身份
    │   │   "You are an AI assistant..."
    │   │   "Time: 2025-01-20 10:30:00"
    │   │   "Workspace: /path/to/workspace"
    │   │
    │   ├─▶ 引导文件 (如存在)
    │   │   AGENTS.md ──读取──▶ 代理指令
    │   │   SOUL.md ────读取──▶ 个性定义
    │   │   USER.md ────读取──▶ 用户信息
    │   │   TOOLS.md ───读取──▶ 工具说明
    │   │   IDENTITY.md ──读取──▶ 身份定义
    │   │
    │   ├─▶ 内存上下文 (如存在)
    │   │   MEMORY.md ──读取──▶ 长期记忆
    │   │
    │   └─▶ 技能信息
    │       列出所有可用技能
    │
    ├─▶ 构建消息列表
    │   build_messages()
    │   │
    │   ├─▶ 历史消息
    │   │   从 Session 加载历史 (限制 memory_window)
    │   │
    │   ├─▶ 当前用户消息
    │   │   处理文本 + 媒体附件 (图片等)
    │   │
    │   └─▶ 工具结果 (如有)
    │       添加工具执行结果到消息列表
    │
    └─▶ 构建工具定义
        build_tools()
        │
        └─▶ 从 ToolRegistry 获取所有工具定义
            转换为 OpenAI 函数调用格式

4. 核心类详解

4.1 AgentLoop

文件: nanobot/agent/loop.py

职责: 核心处理引擎,负责消息处理、上下文构建、LLM 调用、工具执行。这个时主要关注方法

主要方法:

  1. _run_agent_loop,是Agent 的核心迭代循环,其是 ReAct(Reasoning + Acting) 模式的简化版本:LLM 可以交替进行推理(生成内容)和行动(调用工具),直到完成任务或达到最大迭代次数。
    核心流程:
    开始
       │
       ▼
     ┌─────────────────┐
     │  调用 LLM       │◄─────────────────┐
     │  (带工具定义)    │                  │
     └────────┬────────┘                  │
              │                          │
              ▼                          │
         ┌─────────┐                     │
         │有工具调用?│                    │
         └────┬────┘                    │
        是 /      \  否                 │
           /        \                   │
          ▼          ▼                  │
     ┌─────────┐  ┌──────────┐          │
     │执行工具  │  │返回最终  │          │
     │并添加结果│  │结果      │          │
     └────┬────┘  └──────────┘          │
          │                              │
          └──────────────────────────────┘
    

关键设计:

┌──────────┬──────────────────────────────────────────────────────────────────────┐
 │   步骤   │                                 说明                                 │
 ├──────────┼──────────────────────────────────────────────────────────────────────┤
 │ 迭代控制 │ 最大迭代次数由 max_iterations 控制(默认 20),防止无限循环          │
 ├──────────┼──────────────────────────────────────────────────────────────────────┤
 │ 工具调用 │ LLM 可以同时请求多个工具调用,按顺序执行                             │
 ├──────────┼──────────────────────────────────────────────────────────────────────┤
 │ 消息历史 │ 每次工具调用结果都会添加到消息上下文,供后续迭代使用                 │
 ├──────────┼──────────────────────────────────────────────────────────────────────┤
 │ 反思提示 │ 工具执行后添加 "Reflect on the results..." 提示,引导 LLM 决定下一步 │
 ├──────────┼──────────────────────────────────────────────────────────────────────┤
 │ 工具记录 │ 所有使用的工具名称被记录到 tools_used 列表,用于后续保存到会话       │
 └──────────┴──────────────────────────────────────────────────────────────────────┘
  1. _consolidate_memory 是记忆整合的核心方法,负责将旧对话归档到 HISTORY.md 并更新 MEMORY.md,同时实现了增量式记忆管理:只处理新增的旧消息,避免重复处理已归档的内容。。
    主要流程
    开始                                                                                                                                                                                                                                  │                                                                                                                                                                                                                                   ▼                                                                                                                                                                                                                               
     ┌─────────────────┐     是     ┌─────────────────────────┐
     │ archive_all?    │───────────►│ 处理所有消息            │
     │ (来自 /new 命令)│            │ keep_count = 0          │
     └─────────────────┘            │ old_messages = all      │
       │ 否                         └─────────────────────────┘
       ▼                            │
     ┌─────────────────┐            │
     │ 检查是否需要整合 │            │
     │                 │◄───────────┘
     │ messages >      │
     │ memory_window/2?│
     └─────────────────┘
       │ 否
       ▼
     返回 (无需整合)      是
       │                  ▼
       │           ┌─────────────────┐
       │           │ 取中间部分消息  │
       │           │ last_consolidated │
       │           │ 到 -keep_count  │
       │           └─────────────────┘
       │                  │
       └──────────────────┘
                          ▼
                 ┌─────────────────┐
                 │ 格式化对话文本  │
                 │ [时间] 角色: 内容│
                 │ + tools_used    │
                 └─────────────────┘
                          ▼
                 ┌─────────────────┐
                 │ 构建 LLM Prompt │
                 │ 要求返回 JSON:  │
                 │ - history_entry │
                 │ - memory_update │
                 └─────────────────┘
                          ▼
                 ┌─────────────────┐
                 │ 调用 LLM 处理   │
                 └─────────────────┘
                          ▼
                 ┌─────────────────┐
                 │ 解析 JSON 响应  │
                 │ 提取 entry &    │
                 │ update          │
                 └─────────────────┘
                          ▼
                 ┌─────────────────┐
                 │ 写入文件        │
                 │ - append_history│
                 │ - write_long_term│
                 └─────────────────┘
                          ▼
                 ┌─────────────────┐
                 │ 更新标记        │
                 │ last_consolidated│
                 │ = 新位置        │
                 └─────────────────┘
                          ▼
                        结束
    触发条件
  2. 消息数超过 memory_window:在 _process_message 中检查,异步触发
  3. /new 命令:用户主动触发,归档所有消息并重置会话
    压缩的promt:
    You are a memory consolidation agent. Process this conversation and return a JSON object with exactly two keys:
    
    1. "history_entry": A paragraph (2-5 sentences) summarizing the key events/decisions/topics. Start with a timestamp like [YYYY-MM-DD HH:MM]. Include enough detail to be useful when found by grep search later.
    
    2. "memory_update": The updated long-term memory content. Add any new facts: user location, preferences, personal info, habits, project context, technical decisions, tools/services used. If nothing new, return the existing content unchanged.
    
    ## Current Long-term Memory
    {current_memory or "(empty)"}
    
    ## Conversation to Process
    {conversation}
    
    Respond with ONLY valid JSON, no markdown fences.
    您是记忆整合代理。请处理此对话并返回一个包含两个键的 JSON 对象:
    
    1. "history_entry":一段总结关键事件/决策/主题的段落(2-5 句话)。以时间戳开头,例如 [YYYY-MM-DD HH:MM]。包含足够的细节,以便稍后通过 grep 搜索找到。
    
    2. "memory_update":更新后的长期记忆内容。添加任何新信息:用户位置、偏好、个人信息、习惯、项目背景、技术决策、使用的工具/服务。如果没有新内容,则返回现有内容,保持不变。
    
    ## 当前长期记忆
    
    {current_memory 或 "(empty)"}
    
    ## 待处理的对话
    
    {conversation}
    
    请仅返回有效的 JSON 格式,不要使用 Markdown 代码块。

其他方法:

方法 说明
run() 启动主循环,持续消费消息总线中的消息
_process_message() 处理单个消息,包括会话管理、命令处理、内存整合
_process_system_message() 处理系统消息(如子代理完成通知)
process_direct() 直接处理消息(用于 CLI 和 cron 任务)

工具注册 (_register_default_tools()):

  • 文件系统工具: ReadFileTool, WriteFileTool, EditFileTool, ListDirTool
  • Shell 工具: ExecTool
  • 网络工具: WebSearchTool, WebFetchTool
  • 消息工具: MessageTool
  • 子代理工具: SpawnTool
  • 定时任务工具: CronTool

4.2 ContextBuilder

文件: nanobot/agent/context.py

职责: 构建 LLM 的完整上下文,包括系统提示、历史消息、工具定义。
核心流程:

┌─────────────────────────────────────────────────────────┐
│                    build_system_prompt                  │
└─────────────────────────────────────────────────────────┘
                           │
                           ▼
        ┌────────────────────────────────┐
        │        _get_identity()          │
        │  - 核心身份 (nanobot 🐈)        │
        │  - 当前时间/时区                 │
        │  - 运行时信息 (OS, Python)        │
        │  - 工作区路径                    │
        └────────────────┬───────────────┘
                         │
                         ▼
        ┌────────────────────────────────┐
        │     _load_bootstrap_files()      │
        │  按顺序读取:                     │
        │  1. AGENTS.md                   │
        │  2. SOUL.md                     │
        │  3. USER.md                     │
        │  4. TOOLS.md                    │
        │  5. IDENTITY.md                  │
        └────────────────┬───────────────┘
                         │
                         ▼
        ┌────────────────────────────────┐
        │   memory.get_memory_context()    │
        │  长期记忆内容 (MEMORY.md)         │
        └────────────────┬───────────────┘
                         │
                         ▼
        ┌────────────────────────────────┐
        │   技能加载 (渐进式)               │
        │  ├─ Always Skills: 完整内容      │
        │  │   (始终加载的技能)              │
        │  └─ Available Skills: 摘要列表   │
        │      (需要时主动读取)              │
        └────────────────────────────────┘
                           │
                           ▼
              ┌────────────────────────┐
              │  用 "---" 连接各部分    │
              │  返回完整 system prompt  │
              └────────────────────────┘
                           │
                           ▼
              ┌─────────────────────────────────────┐
              │         build_messages              │
              │  ┌─────────────────────────────┐    │
              │  │ 1. system prompt            │    │
              │  │    (+ channel/chat_id 信息) │    │
              │  └─────────────────────────────┘    │
              │  ┌─────────────────────────────┐    │
              │  │ 2. history (历史消息)         │    │
              │  └─────────────────────────────┘    │
              │  ┌─────────────────────────────┐    │
              │  │ 3. current message          │    │
              │  │    (+ 可选图片媒体)          │    │
              │  └─────────────────────────────┘    │
              └─────────────────────────────────────┘
                           │
                           ▼
              ┌────────────────────────┐
              │  返回 messages 列表    │
              │  用于 LLM API 调用    │
              └────────────────────────┘

主要方法:
1.build_system_prompt(),构建完整的系统提示,包含以下部分(按顺序):

┌─────────────────┬───────────────────────────────┬────────────────────────────────────────────────────┐
│      部分       │             来源              │                        说明                        │
├─────────────────┼───────────────────────────────┼────────────────────────────────────────────────────┤
│ Identity        │ _get_identity()               │ 核心身份定义,包含时间、运行时、工作区路径         │
├─────────────────┼───────────────────────────────┼────────────────────────────────────────────────────┤
│ Bootstrap Files │ workspace/*.md                │ AGENTS.md, SOUL.md, USER.md, TOOLS.md, IDENTITY.md │
├─────────────────┼───────────────────────────────┼────────────────────────────────────────────────────┤
│ Memory Context  │ memory.get_memory_context()   │ 长期记忆内容                                       │
├─────────────────┼───────────────────────────────┼────────────────────────────────────────────────────┤
│ Always Skills   │ skills.get_always_skills()    │ 始终加载的技能                                     │
├─────────────────┼───────────────────────────────┼────────────────────────────────────────────────────┤
│ Skills Summary  │ skills.build_skills_summary() │ 可用技能列表(agent 需要主动读取)                 │
└─────────────────┴───────────────────────────────┴────────────────────────────────────────────────────┘
  1. build_messages() - 构建完整消息列表
    请求大模型的消息主要由:系统提示+历史消息+当前用户消息组成
    其中用户消息中的图片信息,主要由 _build_user_content方法处理:
  • 将图片文件转为 base64 编码
  • 返回 OpenAI 格式的 image_url 消息块

引导文件 (按优先级排序):

  1. AGENTS.md - 代理指令
  2. SOUL.md - 个性定义
  3. USER.md - 用户信息
  4. TOOLS.md - 工具说明
  5. IDENTITY.md - 身份定义

4.3 MemoryStore

MemoryStore 是 Nanobot 的记忆系统,实现了一个简单的双层记忆架构:
核心架构

┌─────────────────────────────────────┐                                                                                                                                                                                             │         MemoryStore                 │                                                                                                                                                                                           
├─────────────────────────────────────┤
│  Layer 1: MEMORY.md                 │
│  - 长期事实记忆(关键信息提取)      │
│  - 每次覆盖写入                     │
│  - 注入到 System Prompt              │
├─────────────────────────────────────┤
│  Layer 2: HISTORY.md                │
│  - 对话历史日志(grep-searchable)   │
│  - 追加写入                         │
│  - 用于回溯查找                      │
└─────────────────────────────────────┘

工作流程

1. 对话进行 → 消息积累在 Session 中
        │
        ▼
2. 触发记忆整合 (当消息数 > memory_window)
   - 在 loop.py 的 _consolidate_memory() 中
        │
        ▼
3. LLM 处理对话,生成:
   ├─ history_entry → append_history() → HISTORY.md
   └─ memory_update → write_long_term() → MEMORY.md
        │
        ▼
4. 下次对话时
   - MEMORY.md 内容注入 System Prompt
   - 作为长期记忆上下文

4.5 SkillsLoader

文件: nanobot/agent/skills.py
主要的技能加载器,负责加载和管理 agent 技能。

  1. 技能来源 (优先级从高到低)
  • Workspace skills: workspace/skills/ 目录下的技能(最高优先级)
  • Built-in skills: nanobot/skills/ 目录下的内置技能
  1. 核心方法
│           方法            │               功能               │
├───────────────────────────┼──────────────────────────────────┤
│ list_skills()             │ 列出所有可用技能,支持按需求过滤 │
├───────────────────────────┼──────────────────────────────────┤
│ load_skill(name)          │ 加载指定技能的 SKILL.md 内容     │
├───────────────────────────┼──────────────────────────────────┤
│ load_skills_for_context() │ 加载特定技能用于 agent 上下文    │
├───────────────────────────┼──────────────────────────────────┤
│ build_skills_summary()    │ 构建 XML 格式的技能摘要          │
├───────────────────────────┼──────────────────────────────────┤
│ get_skill_metadata()      │ 从 frontmatter 获取技能元数据    │
├───────────────────────────┼──────────────────────────────────┤
│ get_always_skills()       │ 获取标记为 always=true 的技能    │
└───────────────────────────┴──────────────────────────────────┘
  1. 技能文件格式

技能是 markdown 文件 (SKILL.md),包含:

  • YAML frontmatter: 元数据(名称、描述、要求等)
  • Markdown 内容: 技能说明和用法
  1. 依赖检查

_check_requirements() 方法检查:

  • bins: 需要的 CLI 工具是否存在 (shutil.which)
  • env: 需要的环境变量是否设置
  1. 元数据解析
  • _parse_nanobot_metadata(): 解析 frontmatter 中的 JSON 元数据(支持 nanobot 或 openclaw 键)

这个技能系统允许动态加载和过滤能力,使 agent 能够根据环境和需求使用不同的技能。

4.4 SubagentManager

文件: nanobot/agent/subagent.py

职责: 管理后台子代理执行,用于处理复杂任务。

特点:

  • 轻量级代理实例,后台运行
  • 共享 LLM 提供者,独立上下文
  • 专注特定任务的系统提示
  • 最大迭代次数限制(默认 15 次)

主要方法:

方法 说明
spawn() 生成新的子代理任务,返回任务ID
_run_subagent() 执行子代理循环,包括工具调用和结果收集
_announce_result() 通过消息总线向主代理宣布结果
_build_subagent_prompt() 构建子代理特定的系统提示

工具限制: 子代理只能访问有限工具集(无消息工具和生成子代理工具)

4.4 ToolRegistry

文件: nanobot/agent/tools/registry.py

职责: 动态注册和管理工具,支持参数验证和执行。

主要方法:

方法 说明
register() 注册工具实例
get_tool() 获取工具实例
get_tool_definitions() 获取所有工具定义(OpenAI 格式)
validate_params() 验证工具参数
execute() 执行工具调用

4.5 SessionManager

文件: nanobot/session/manager.py

职责: 管理用户会话,支持持久化和多会话隔离。

主要方法:

方法 说明
get_or_create() 获取或创建会话
load() 从磁盘加载会话
save() 保存会话到磁盘
reset() 重置会话历史

会话键格式: {channel}:{chat_id}


5. 启动流程详解

5.1 Gateway 模式启动流程

nanobot gateway
    │
    ▼
[commands.gateway()]
    │
    ├─▶ 加载配置
    │   ConfigLoader.load()
    │       ├─ 读取 ~/.nanobot/config.json
    │       └─ 合并环境变量
    │
    ├─▶ 初始化消息总线
    │   MessageBus()
    │       ├─ inbound queue
    │       └─ outbound queue
    │
    ├─▶ 创建 LLM 提供者
    │   ProviderRegistry.create(config)
    │       └─ 根据配置实例化提供者
    │
    ├─▶ 初始化会话管理器
    │   SessionManager(workspace)
    │
    ├─▶ 初始化定时任务服务
    │   CronService(bus, config)
    │
    ├─▶ 创建 AgentLoop 实例
    │   AgentLoop(config, bus, provider, session_manager)
    │       ├─ 初始化 ToolRegistry
    │       │   └─ _register_default_tools()
    │       └─ 初始化 SubagentManager
    │
    ├─▶ 初始化心跳服务
    │   HeartbeatService()
    │
    ├─▶ 初始化渠道管理器
    │   ChannelManager(config, bus)
    │       └─ 初始化所有启用的渠道
    │
    └─▶ 启动所有服务
        ├─ cron_service.start()
        ├─ heartbeat_service.start()
        ├─ agent.run()  (后台任务)
        └─ channels.start_all()  (阻塞)

5.2 Agent 模式启动流程

nanobot agent
    │
    ▼
[commands.agent()]
    │
    ├─▶ 加载配置
    │
    ├─▶ 创建 LLM 提供者
    │
    ├─▶ 创建 AgentLoop 实例 (direct_mode=True)
    │
    └─▶ 进入交互循环
        while True:
            ├─▶ 读取用户输入
            ├─▶ 检查退出命令 (exit/quit)
            ├─▶ 调用 AgentLoop.process_direct()
            └─▶ 显示响应

6. 关键设计模式

6.1 消息驱动架构

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│   Source    │────▶│  MessageBus  │────▶│   Handler   │
│ (Channels)  │     │  (Queues)    │     │(AgentLoop)  │
└─────────────┘     └──────────────┘     └─────────────┘
                            │
                            ▼
                     ┌──────────────┐
                     │  Subscribers │
                     │(Outbound Msgs)│
                     └──────────────┘

优点:

  • 解耦消息生产者和消费者
  • 支持异步处理
  • 便于扩展和测试

6.2 会话隔离

Session Key: {channel}:{chat_id}

Example Sessions:
  - telegram:123456
  - whatsapp:654321
  - discord:999888

每个会话独立存储:
  - 会话历史 (JSON)
  - 工作区目录
  - 记忆文件 (MEMORY.md)

6.3 内存整合机制

当会话历史超过阈值 (默认 50 条):
    │
    ▼
调用 LLM 总结对话:
    Prompt: "Summarize this conversation..."
    │
    ▼
更新 MEMORY.md:
    追加总结内容
    │
    ▼
更新 HISTORY.md:
    记录整合历史
    │
    ▼
重置会话历史:
    保留最近 N 条

6.4 工具系统架构

┌──────────────────────────────────────┐
│          ToolRegistry                │
│  ┌──────────────────────────────┐    │
│  │      Tool Definitions        │    │
│  │  (OpenAI Function Schema)    │    │
│  └──────────────────────────────┘    │
│  ┌──────────────────────────────┐    │
│  │      Tool Instances          │    │
│  │  (ReadFile, WriteFile, etc.) │    │
│  └──────────────────────────────┘    │
└──────────────────────────────────────┘
              │
              ▼
    ┌─────────────────────┐
    │    BaseTool         │
    │  (Abstract Class)   │
    │  - name: str        │
    │  - description: str │
    │  - parameters: dict │
    │  - execute()        │
    └─────────────────────┘
              │
    ┌─────────┼─────────┐
    ▼         ▼         ▼
┌───────┐ ┌───────┐ ┌───────┐
│ Read  │ │ Write │ │ Exec  │
└───────┘ └───────┘ └───────┘

7. 扩展开发指南

7.1 添加新工具

# nanobot/agent/tools/my_tool.py
from .base import Tool

class MyTool(Tool):
    name = "my_tool"
    description = "Description of what my tool does"
    parameters = {
        "type": "object",
        "properties": {
            "param1": {
                "type": "string",
                "description": "Description of param1"
            }
        },
        "required": ["param1"]
    }

    async def execute(self, param1: str) -> dict:
        # 实现工具逻辑
        result = do_something(param1)
        return {
            "content": result,
            "is_error": False
        }

在 AgentLoop._register_default_tools() 中注册:

self.tools.register(MyTool())

7.2 添加新渠道

# nanobot/channels/my_channel.py
from .base import Channel

class MyChannel(Channel):
    def __init__(self, config: dict, bus: MessageBus):
        self.config = config
        self.bus = bus

    async def start(self):
        # 启动渠道连接
        # 监听消息并转发到总线

    async def stop(self):
        # 停止渠道连接

    async def send(self, message: Message):
        # 发送消息到用户

在配置中启用:

{
  "channels": {
    "my_channel": {
      "enabled": true,
      "api_key": "..."
    }
  }
}

7.3 添加新 LLM 提供者

# nanobot/providers/my_provider.py
from .base import LLMProvider

class MyProvider(LLMProvider):
    def __init__(self, config: dict):
        self.api_key = config.get("api_key")

    async def call(self, messages: list, tools: list = None, **kwargs):
        # 调用 LLM API
        response = await call_llm_api(
            messages=messages,
            tools=tools,
            api_key=self.api_key
        )
        return parse_response(response)

在 ProviderRegistry 中注册:

registry.register("my_provider", MyProvider)

8. 总结

Nanobot 代码功能比较简短,也比较合适用来了解一个agent主要的原理,有极强的拓展性,现在作者在逐步完善代码库,功能会逐步复杂起来,部分功能可以参考比如更好支持mcp及openclawhub,我也会逐步把我需要的工具合入到自己的分支中。