【Nanobot项目笔记】项目架构

0.引言

最近找工作真实感受到了后端已死。。。遂打算转向Agent开发方向,准备多学习一些Agent相关的内容,今天准备从Nanobot的源码开始阅读,借助AI阅读项目,更好的理解Agent的流程。

Nanobot项目地址:nanobot

1.项目概述与架构介绍

在阅读一个项目之前,我们需要先知道这个项目是做什么的,以及其整体架构。Nanobot 是一个轻量级个人 AI 助手框架,其核心特点包括:

  • 支持多通道接入(Telegram、Discord、Slack、飞书、钉钉、微信等 15+ 平台)
  • 支持多 LLM Provider(OpenAI、Anthropic、Azure、GitHub Copilot 等)
  • 实现 AI Agent 工具调用循环(Tool Use Loop)
  • 具备记忆系统和会话管理

下图是一个简易的项目架构图,该项目一共分为5层,从上到下分别为:

  • UI层:支持多通道,包括飞书、微信、Telegram等;
  • Gateway层:消息网关,负责收发消息;
  • Core Agent:Agent核心部分,Agent Loop中又包含了上下文处理、记忆模块、子Agent等;
  • LLM Provider:大模型接口,支持国内外多种大模型,包括Chat GPT、Deepseek等。
  • Tool Use :工具层,负责工具注册与执行。

2.核心模块详解

2.1 Agent Loop(智能体循环)------核心推理引擎

AgentLoop 是 Nanobot 的"心脏",它负责:

  • 从 MessageBus 的 Inbound Queue 消费消息
  • 管理会话级别的串行执行(会话锁)
  • 控制全局并发数(并发闸门)
  • 创建 AgentRunner 来处理每个消息
  • 保存每轮对话(_save_turn)
bash 复制代码
┌─────────────────────────────────────────────────────────┐
│                    AgentLoop 工作机制                    │
│                                                         │
│  MessageBus (Inbound Queue)                             │
│  ┌──────────────────────────────┐                       │
│  │ msg1 │ msg2 │ msg3 │ ...     │                       │
│  └──┬───────────────────────────┘                       │
│     │                                                   │
│     ▼                                                   │
│  run() ─── 持续消费消息                                   │
│     │                                                   │
│     ├── 获取会话锁 (_session_locks)                       │
│     │   └── 确保同一会话的消息串行处理                      │
│     │                                                   │
│     ├── 获取并发闸门 (_concurrency_gate)                  │
│     │   └── 默认最多 3 个并发会话                          │
│     │                                                   │
│     ├── 创建 AgentRunner                                 │
│     │   └── 传入 provider, workspace, tools 等           │
│     │                                                   │
│     ├── AgentRunner.run()                               │
│     │   └── ReAct 循环                                   │
│     │                                                   │
│     ├── _save_turn() 持久化                              │
│     │   └── 保存到 HISTORY.md                            │
│     │                                                   │
│     └── 发送响应到 Outbound Queue                         │
│                                                         │
└─────────────────────────────────────────────────────────┘

2.2 AgentRunner(ReAct循环)------迭代执行器

AgentRunner 实现了完整的 ReAct 循环,具体流程如下:

bash 复制代码
┌─────────────────────────────────────────────────────────┐
│                 AgentRunner 执行流程                     │
│                                                         │
│  ┌─────────────────────────────────────────────┐        │
│  │            for i in range(max_iterations):  │        │
│  │                                             │        │
│  │  ┌──────────────────────┐                   │        │
│  │  │ before_iteration()   │  ← Lifecycle Hook │        │
│  │  └──────────┬───────────┘                   │        │
│  │             ↓                               │        │
│  │  ┌──────────────────────┐                   │        │
│  │  │ provider.chat_with_  │                   │        │
│  │  │ retry(messages,tools)│  ← 调用 LLM        │        │
│  │  └──────────┬───────────┘                   │        │
│  │             ↓                               │        │
│  │  ┌──────────────────────┐                   │        │
│  │  │ 有 tool_calls?       │                   │        │
│  │  └──────┬──────┬────────┘                   │        │
│  │     Yes │      │ No                         │        │
│  │         ↓      ↓                            │        │
│  │  ┌──────────┐  ┌────────────┐               │        │
│  │  │before_   │  │ 任务完成    │               │        │
│  │  │execute_  │  │ break 退出 │               │        │
│  │  │tools()   │  └────────────┘               │        │
│  │  └────┬─────┘                               │        │
│  │       ↓                                     │        │
│  │  ┌──────────────────────┐                   │        │
│  │  │ ToolRegistry.execute │                   │        │
│  │  │ (逐一执行工具调用)      │                   │        │
│  │  └──────────┬───────────┘                   │        │
│  │             ↓                               │        │
│  │  ┌──────────────────────┐                   │        │
│  │  │ 截断工具结果           │                   │        │
│  │  │ (>16000字符时截断)     │                   │        │
│  │  └──────────┬───────────┘                   │        │
│  │             ↓                               │        │
│  │  ┌──────────────────────┐                   │        │
│  │  │ after_iteration()    │  ← Lifecycle Hook │        │
│  │  └──────────┬───────────┘                   │        │
│  │             │                               │        │
│  │             └── 继续循环 ──────────→ 下一轮    │        │
│  │                                             │        │
│  └─────────────────────────────────────────────┘        │
│                                                         │
└─────────────────────────────────────────────────────────┘

2.3 MemoryStore(记忆系统)

MemoryStore 管理 Nanobot 的双层记忆系统。

bash 复制代码
┌─────────────────────────────────────────────────────────┐
│                  记忆系统架构                             │
│                                                         │
│  ┌─────────────────────────────────────────────┐        │
│  │              MemoryStore                    │        │
│  │                                             │        │
│  │  ┌────────────────┐   ┌────────────────┐    │        │
│  │  │  read_memory() │   │  save_memory() │    │        │
│  │  │  读取MEMORY.md  │   │  写入MEMORY.md │    │        │
│  │  └────────────────┘   └────────────────┘    │        │
│  │                                             │        │
│  │  ┌────────────────┐   ┌──────────────────┐  │        │
│  │  │ append_history()│  │MemoryConsolidator│  │        │
│  │  │ 追加HISTORY.md │   │ 压缩旧历史记录      │           │
│  │  └────────────────┘   └──────────────────┘  │        │
│  └─────────────────────────────────────────────┘        │
│                                                         │
│  ┌─────────────────┐    ┌─────────────────┐             │
│  │   MEMORY.md     │    │   HISTORY.jsonl │             │
│  │                 │    │                 │             │
│  │ 结构化长期记忆    │    │ 完整交互历史      │              │
│  │                 │    │                 │             │
│  │ ·用户偏好        │    │ ·时间戳          │              │
│  │ ·项目信息        │    │ ·用户消息摘要     │              │
│  │ ·重要决策        │    │ ·Agent回复摘要   │              │
│  │ ·学到的教训      │    │ ·工具调用记录     │              │
│  │                │    │                 │              │
│  │ 由 save_memory │    │ 自动追加          │             │
│  │ 虚拟工具触发写入  │    │ 定期压缩         │             │
│  └────────────────┘    └─────────────────┘             │
│                                                         │
└─────────────────────────────────────────────────────────┘

2.4 MessageBus(消息总线)------双队列架构

MessageBus 是 Nanobot 的消息中枢,使用经典的生产者-消费者模式

bash 复制代码
┌─────────────────────────────────────────────────────────┐
│                   MessageBus 架构                        │
│                                                         │
│  生产者 (Channels)              消费者 (AgentLoop)        │ 
│  ┌──────────┐                   ┌──────────────┐        │
│  │ Telegram │──┐                │              │        │
│  │ Channel  │  │  ┌──────────┐  │  AgentLoop   │        │
│  └──────────┘  ├─→│ Inbound  │─→│  .run()      │        │
│  ┌──────────┐  │  │  Queue   │  │              │        │
│  │ Discord  │──┤  └──────────┘  └──────┬───────┘        │
│  │ Channel  │  │                       │                │
│  └──────────┘  │                       │                │
│  ┌──────────┐  │                       ↓                │
│  │ 飞书      │──┘                ┌──────────────┐        │
│  │ Channel  │                   │  AgentRunner │        │
│  └──────────┘                   │  (处理消息)   │        │
│       ↑                         └──────┬───────┘        │
│       │                                │                │
│       │       ┌──────────┐             │                │
│       └───────│ Outbound │←────────────┘                │
│               │  Queue   │                              │
│               └──────────┘                              │
│                                                         │
│  消息类型:                                               │
│  · InboundMessage  = 用户发来的消息                       │
│  · OutboundMessage = Agent 要回复的消息                   │
│                                                         │
└─────────────────────────────────────────────────────────┘

3.数据流图

完整消息处理流程

bash 复制代码
步骤 1: 用户发送消息
┌──────────────────────────────────────────────────────────┐
│ 用户在 Telegram 发送: "帮我查一下北京天气"                    │
└──────────────────────────┬───────────────────────────────┘
                           ↓
步骤 2: Channel 接收并转换
┌──────────────────────────────────────────────────────────┐
│ TelegramChannel.on_message()                             │
│ → 将 Telegram 消息转换为 InboundMessage                    │
│ → InboundMessage {                                       │
│     session_id: "tg_12345",                              │
│     user_id: "user_001",                                 │
│     text: "帮我查一下北京天气",                             │
│     channel: "telegram",                                 │
│     timestamp: 1711958400                                │
│   }                                                      │
└──────────────────────────┬───────────────────────────────┘
                           ↓
步骤 3: 进入 Inbound Queue
┌──────────────────────────────────────────────────────────┐
│ MessageBus.inbound.put(inbound_message)                  │
└──────────────────────────┬───────────────────────────────┘
                           ↓
步骤 4: AgentLoop 消费消息
┌──────────────────────────────────────────────────────────┐
│ AgentLoop.run():                                         │
│ → msg = await bus.inbound.get()                          │
│ → 获取会话锁: _session_locks["tg_12345"]                  │
│ → 获取并发闸门: _concurrency_gate.acquire()               │
│ → 加载 workspace 上下文                                   │
└──────────────────────────┬───────────────────────────────┘
                           ↓
步骤 5: ContextBuilder 构建 Prompt
┌──────────────────────────────────────────────────────────┐
│ ContextBuilder.build_system_prompt():                    │
│ → Identity: "你是一个 AI 助手..."                         │
│ → Bootstrap: 基础行为规范                                 │
│ → Memory: 读取 MEMORY.md 的内容                           │
│ → Skills: 加载匹配的 SKILL.md                             │
│                                                          │
│ ContextBuilder.build_messages():                         │
│ → [system_prompt] + [history] + [user_message]           │
└──────────────────────────┬───────────────────────────────┘
                           ↓
步骤 6: AgentRunner ReAct 循环
┌──────────────────────────────────────────────────────────┐
│ 第 1 轮迭代:                                              │
│ → LLM: "用户想查北京天气,我需要调用天气工具"                  │
│ → tool_call: weather_api(city="北京")                     │
│ → 工具返回: {"temp": 22, "weather": "晴"}                  │
│                                                          │
│ 第 2 轮迭代:                                              │
│ → LLM: "我已经得到天气数据,可以回复用户了"                   │
│ → text: "北京今天天气晴朗,气温 22°C,适合外出。"             │
│ → 没有 tool_calls,循环结束                                │
└──────────────────────────┬───────────────────────────────┘
                           ↓
步骤 7: 保存记忆和历史
┌──────────────────────────────────────────────────────────┐
│ MemoryStore.append_history():                            │
│ → 将本轮对话摘要追加到 HISTORY.md                           │
│                                                          │
│ AgentLoop._save_turn():                                  │
│ → 持久化本轮对话数据                                      │
└──────────────────────────┬───────────────────────────────┘
                           ↓
步骤 8: 发送响应
┌──────────────────────────────────────────────────────────┐
│ MessageBus.outbound.put(outbound_message)                │
│ → OutboundMessage {                                      │
│     session_id: "tg_12345",                              │
│     text: "北京今天天气晴朗,气温 22°C,适合外出。",           │
│     channel: "telegram"                                  │
│   }                                                      │
└──────────────────────────┬───────────────────────────────┘
                           ↓
步骤 9: Channel 发送回复
┌──────────────────────────────────────────────────────────┐
│ TelegramChannel.send():                                  │
│ → 将 OutboundMessage 转换为 Telegram API 请求              │
│ → 发送到 Telegram 服务器                                   │
│ → 用户在 Telegram 收到回复                                 │
└──────────────────────────────────────────────────────────┘
相关推荐
菜鸟分享录1 小时前
OpenClaw Docker一键部署(轻松实现多容器隔离)
docker·ai·openclaw·小龙虾
小程故事多_801 小时前
[大模型面试系列] 深度解析如何提升AI Agent规划能力,从原理到落地全方案
人工智能·智能体
~kiss~1 小时前
quantizer 学习三
ai
E等于MC平方1 小时前
AI 辅助物理课堂实验
人工智能·ai·大模型·模拟·物理·实验
名不经传的养虾人1 小时前
从0到1:企业级AI项目迭代日记 Vol.17|让 AI 做代码重构,要盯着它的策略,不只是看结果
人工智能·agent·ai编程·ai创业·企业ai
knight_9___2 小时前
LLM工具调用面试篇6
人工智能·python·面试·职场和发展·llm·agent
用户3962691060032 小时前
asyncio + subprocess:Python异步调用外部命令踩坑实录
python
青木9602 小时前
智能体(Agent)开发与部署项目
langchain·benchmark·智能体·gaia
YBAdvanceFu2 小时前
开源版Suno来了!用扩散模型生成带歌词的完整歌曲,DiffRhythm2实战详解
人工智能·深度学习·机器学习·多智能体·智能体·suno·diffrhythm2