











摘要:nanobot 是一个极简主义的 AI Agent 框架,它用不到 4000 行代码,构建了一个包含 多端接入 (Channel)、消息总线 (Bus)、ReAct 循环、多层记忆 (Memory) 以及 技能扩展 (Skills) 的完整系统。本文将从源码视角,剖析其核心设计理念,帮助开发者理解现代 AI Agent 的底层运作机制。
在 AI Agent 爆发的今天,像 OpenClaw 这样的大型项目虽然功能强大,但往往代码复杂,难以快速上手理解核心逻辑。nanobot 则提供了一个完美的“解剖样本”——它剥离了复杂的业务逻辑,只保留了 Agent 最核心的骨架。
理解了 nanobot,你就理解了大多数基于 ReAct 范式的 AI 助理是如何工作的。
nanobot 的项目结构非常扁平,核心模块一目了然:
nanobot/
├── agent/ # [核心] 智能体大脑
│ ├── loop.py # ReAct 主循环 (引擎心脏)
│ ├── context.py # 上下文组装 (Prompt 构建)
│ ├── memory.py # 记忆系统 (三层存储)
│ ├── skills.py # 技能管理
│ └── tools/ # 工具箱 (Shell, Web, File 等)
├── bus/ # [通信] 消息总线
│ ├── queue.py # 异步消息队列 (核心解耦机制)
│ └── events.py # 事件定义
├── channels/ # [触角] 多平台接入
│ ├── base.py # 标准接口定义
│ ├── manager.py # 渠道管理器
│ └── feishu/ # 具体实现 (如飞书、微信等)
├── config/ # [配置] Pydantic 配置管理
├── session/ # [存储] 会话持久化 (JSONL)
└── cli/ # [入口] 命令行启动器
nanobot 采用了一种经典的 分层架构,确保了各个模块的高内聚和低耦合。
graph TD User((用户)) <--> Channels["Access Layer: Channels (飞书/微信/CLI)"] %% 消息总线子图 subgraph "Message Bus (异步解耦)" InQueue["Inbound Queue"] OutQueue["Outbound Queue"] end Channels --> InQueue OutQueue --> Channels %% Agent核心引擎子图 subgraph "Agent Core (核心引擎)" Loop["Agent Loop<br/>(ReAct 循环)"] Context["Context Builder"] Mem["Memory System"] Skills["Skill Registry"] end InQueue --> Loop Loop --> OutQueue Loop <--> Context Context <--> Mem Loop <--> Skills %% 基础设施子图 subgraph "Infrastructure" LLM["LLM Provider"] Storage["File System"] end Loop <--> LLM Mem <--> Storage
设计哲学:如何让不可控的 LLM 稳定输出结构化数据?nanobot 给出的答案是——利用 Function Calling 协议,而不是依赖 Prompt 指令。
通常我们要求 LLM 输出 JSON 时,会使用如下 Prompt:
"请返回 JSON 格式,包含 action 和 reason 字段..."
但 LLM 经常会“自作聪明”地添加 Markdown 代码块,或者在 JSON 前后废话,导致解析失败。即使使用 JSON Mode,也难以严格约束字段类型(Schema)。
nanobot 引入了 “虚拟工具” 的概念。这是一种不注册到执行列表,但发送给 LLM 的工具定义。
工作流程:
tool_calls 时,直接读取其 arguments 参数——这就是经过严格校验的结构化数据。代码示意:
# 定义一个并不存在的工具,仅用于约束输出格式
VIRTUAL_TOOL_SCHEMA = [{
"type": "function",
"function": {
"name": "submit_decision",
"parameters": {
"type": "object",
"properties": {
"decision": {"type": "string", "enum": ["ignore", "reply"]},
"reason": {"type": "string"}
},
"required": ["decision", "reason"]
}
}
}]
# 调用 LLM
response = await llm.chat(messages, tools=VIRTUAL_TOOL_SCHEMA)
# 直接获取结构化结果,无需正则解析
result = response.tool_calls[0].arguments
# result = {"decision": "reply", "reason": "User is asking for help"}
这种模式在 nanobot 的 记忆归档 和 心跳检测 模块中被广泛使用,极大地提高了系统的稳定性。
nanobot 的总线设计极度精简,却实现了完美的异步解耦。
sequenceDiagram participant User participant FeishuChannel participant Bus participant Agent User->>FeishuChannel: 发送消息 "你好" FeishuChannel->>Bus: put(InboundMessage) Note over FeishuChannel, Agent: Channel 此时可以继续处理其他请求,无需等待 loop 异步监听 Agent->>Bus: get(InboundQueue) Bus-->>Agent: 收到消息 end Agent->>Agent: 思考 (ReAct Loop) Agent->>Bus: put(OutboundMessage) loop 异步监听 FeishuChannel->>Bus: get(OutboundQueue) Bus-->>FeishuChannel: 获取回复 end FeishuChannel->>User: 回复消息
agent/loop.py 是整个系统的主循环。它并不复杂,本质上是一个状态机:
为了解决 LLM 上下文窗口限制(Context Window)的问题,nanobot 设计了一套精巧的 三层记忆模型。
.jsonl 文件。HISTORY.md。
[2024-03-20 10:00] 用户询问了 nanobot 的部署方式。
grep 工具主动搜索查阅。MEMORY.md。
用户偏好使用 Python 语言。
项目的部署环境是 Ubuntu 22.04。
nanobot 并没有发明新的算法,它的高明之处在于工程实现的克制与优雅:
对于想要从零构建 AI Agent 的开发者来说,nanobot 绝对是教科书级别的最佳实践。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。