01|为什么需要轻量级的 Agent 框架?

Nanobot是香港大学数据科学实验室(HKUDS)开源的一个项目,号称是 OpenClaw 的精简版实现。整个框架核心代码只有约 4000 行,比 OpenClaw 小了 99%,但功能一点都不含糊:工具调用、定时任务、记忆系统、多模型兼容、多平台支持,该有的都有。

更关键的是,这 4000 行代码写得非常清爽,几乎没有什么过度抽象,读源码就像读业务代码一样直白。对我这种喜欢折腾底层、想真正理解 Agent 是怎么运转的人来说,简直就是宝藏。

今天这篇教程,我就带你理解 Nanobot 的设计理念、核心架构,最后手把手教你从零搭建一个 Text-to-SQL 的 Agent。读完这篇文章,你不仅能跑通案例,还能理解每一行代码背后的原理,甚至能根据自己的需求改框架。


02|Nanobot 是什么?

Nanobot 的定位很明确:超轻量级个人 AI 助手框架

它的 GitHub 地址是 https://github.com/HKUDS/nanobot,

目前已经在开源社区获得了不少关注。

核心特点

极致轻量:核心代码约 4000 行,没有臃肿的抽象层,资源占用极低,启动飞快。我自己的笔记本上,从启动到能接收第一条消息,只需要 2-3 秒。

研究友好:代码简洁易读,方便修改和扩展。如果你想研究 Agent 是怎么做工具调用、怎么管理上下文的,直接读源码就行,不需要在层层叠叠的抽象里迷路。

开箱即用:支持 pip、uv 或源码安装,一个 config.json 就能定义完整的 Agent(模型、工具、提供商),5 分钟就能跑起来。

多平台支持:内置 WhatsApp、Telegram、Discord、Matrix、Slack、飞书、QQ 等聊天渠道,你想在哪个平台部署都能搞定。

多模型兼容:支持 OpenRouter、本地 vLLM 等任意 OpenAI 兼容接口,也原生支持通义千问(DashScope)、DeepSeek、OpenAI、Anthropic 等 20 多个提供商。

主要功能

  • 工具调用:支持 MCP 工具服务器,可执行代码、搜索网络、操作文件等
  • 定时任务:内置 Cron 支持,可设置周期性提醒和自动化工作流
  • 记忆系统:支持持久化记忆,长期保存重要上下文
  • 多实例运行:可同时运行多个针对不同平台或不同用途的机器人实例

与其他 Agent 框架的对比

维度 Nanobot DeepAgents
框架体量 轻量,纯 Python 重型,依赖 LangGraph + LangChain
配置方式 config.json 声明式 Python 代码构建
Skills 机制 原生渐进式加载(SKILL.md 自动发现) SkillsMiddleware 中间件注入
工具定义 继承 Tool 基类,显式注册 @tool 装饰器 + 中间件管理
上下文管理 ContextBuilder + MemoryConsolidator SummarizationMiddleware
入口方式 CLI (nanobot) / Python SDK 纯 Python 脚本

Nanobot 的核心理念可以用一句话概括:config.json(配置) + AGENTS.md(身份) + skills/(技能) + Tool 类(工具) = 组合即 Agent


03|核心架构揭秘:四个核心组件

Nanobot 的架构设计非常清晰,主要由四个核心组件构成:AgentLoop、ContextBuilder、ToolRegistry 和 AgentHook。理解了这四个组件,你就理解了 Nanobot 的全部工作原理。

AgentLoop —— 核心运行时

AgentLoop 是整个框架的心脏,所有逻辑的入口。它负责接收消息、构建上下文、调用 LLM、执行工具、返回响应,形成一个完整的处理闭环。

它的初始化代码非常直观:

class AgentLoop:    def __init__(self, bus, provider, workspace, model, ...):        self.context = ContextBuilder(workspace)  # System Prompt 组装        self.tools = ToolRegistry()              # 工具注册表        self.runner = AgentRunner(provider)       # LLM+工具循环        self.subagents = SubagentManager(...)     # 子 Agent 管理        self._register_default_tools()            # 注册内置工具

可以看到,AgentLoop 就像一个指挥官,把各个模块组装在一起,然后按照固定的流程运转。

ContextBuilder —— System Prompt 组装

这是 Nanobot 最精妙的设计之一。ContextBuilder 负责从多个来源组装完整的 System Prompt,让 Agent 知道自己是谁、能做什么、该怎么做。

它的组装逻辑是这样的:

class ContextBuilder:    def build_system_prompt(self):        parts = [self._get_identity()]              # 1. 内置身份描述        parts.append(self._load_bootstrap_files())  # 2. AGENTS.md / SOUL.md        parts.append(self.memory.get_memory_context())  # 3. memory/MEMORY.md        parts.append(always_skills)                 # 4. always=true 的技能        parts.append(self.skills.build_skills_summary())  # 5. 技能 XML 摘要        return "\n\n".join(parts)

这里的关键是第 5 步:ContextBuilder 只将技能的名称和描述(XML 摘要)注入 prompt,而不是把每个技能的完整内容都塞进去。当 Agent 真正需要使用某个技能时,它会通过 read_file 工具去读取完整的 SKILL.md 内容。

这种"渐进式加载"的设计非常聪明。想象一下,如果你有 10 个技能,每个技能 2000 字,全部塞进 prompt 就要 20000 字(约 5000 tokens),成本高不说,还容易让模型分心。而 XML 摘要只有几百字,Agent 按需读取,既省钱又高效。

ToolRegistry —— 工具注册

ToolRegistry 管理所有可用工具,提供 JSON Schema 格式的工具定义给 LLM。Nanobot 内置了以下工具:

工具 功能
ReadFileTool 读取文件
WriteFileTool 写入文件
EditFileTool 编辑文件
ListDirTool 列出目录
ExecTool 执行 Shell 命令
WebSearchTool 网络搜索(支持 5 种搜索引擎)
WebFetchTool 获取网页内容
SpawnTool 生成子 Agent
MessageTool 发送消息
CronTool 定时任务
MCP Tool MCP 协议工具桥接

自定义工具也很简单,继承 Tool 基类即可:

class MyCustomTool(Tool):    @property    defname(self) -> str:        return"my_tool"        @property    defdescription(self) -> str:        return"工具描述,告诉模型这个工具能做什么"        @property    defparameters(self) -> dict:        return {            "type": "object",            "properties": {                "param": {"type": "string", "description": "参数描述"}            },            "required": ["param"]        }        asyncdefexecute(self, **kwargs) -> Any:        # 执行逻辑        pass

AgentHook —— 生命周期钩子

AgentHook 是 Nanobot 提供的扩展机制,类似 DeepAgents 的中间件,但更轻量。它允许你在 Agent 运行周期的关键节点插入自定义逻辑:

class AgentHook:    asyncdefbefore_iteration(self, ctx)       # 每轮 LLM 调用前    asyncdefon_stream(self, ctx, delta)       # 流式输出每个 token    asyncdefbefore_execute_tools(self, ctx)   # 工具执行前(可拦截/修改)    asyncdefafter_iteration(self, ctx)        # 每轮结束后    deffinalize_content(self, ctx, content)    # 最终输出后处理

每个方法默认都是空的(pass),不挂钩就不执行任何逻辑。这种"非侵入式"的设计让框架保持简洁,同时又提供了足够的扩展性。

AgentLoop 的每一轮迭代都会按顺序调用这些钩子:

(1) hook.before_iteration(ctx)     # LLM 调用前(2) 调用 LLM 模型    ├─ hook.on_stream(ctx, delta)  # 每个 token 流出时    └─ hook.on_stream_end(ctx)     # 流式结束(3) 如果有 tool_calls:    ├─ hook.before_execute_tools(ctx)  # 工具执行前    ├─ 执行工具    └─ hook.after_iteration(ctx)       # 本轮结束(4) 如果返回最终文本:    ├─ hook.finalize_content(ctx, text)  # 后处理    └─ hook.after_iteration(ctx)         # 本轮结束

04|Skills 渐进式加载机制

为什么需要渐进式加载?

假设你搭建了一个投研 Agent,有 8 个技能:股票查询、财报分析、新闻监控、估值计算、风险评估、组合优化、报告生成、邮件发送。每个 SKILL.md 平均 2000+ 字符,如果全部塞进 prompt,仅技能指导就要占用 16000+ 字符(约 4000 tokens),成本爆炸不说,模型还要在这些信息里找重点,容易分心。

Nanobot 的解决方案是三级加载系统

第 1 级:元数据(永远在 context 中,约 100 words/skill)

SkillsLoader.build_skills_summary() 把所有技能生成 XML 摘要注入 system prompt:

<skills>  <skill available="true">    <name>web-search</name>    <description>联网搜索实时市场信息</description>    <location>/path/to/web-search/SKILL.md</location></skill><skill available="false">    <name>database-query</name>    <description>查询本地数据库</description>    <location>/path/to/database-query/SKILL.md</location></skill></skills>

Agent 看到的是一个技能清单,知道自己"有什么工具可以用",但不需要知道"具体怎么用"。

第 2 级:always 技能(全文自动注入)

SKILL.md 的 frontmatter 中可以标记 always: true,这类技能的完整内容会自动塞进 system prompt:

---name: memorydescription: Two-layer memory system with grep-based recall.always: true---

目前内置的只有 memory 技能标记了 always: true,因为记忆系统需要随时可用。

第 3 级:按需加载(模型自主 read_file)

System prompt 中会注入提示,告诉模型需要时去 read_file:

# SkillsThe following skills extend your capabilities. To use a skill, read its SKILL.md file using the read_file tool.Skills with available="false" need dependencies installed first - you can try installing them with apt/brew.

当 Agent 判断需要使用某个技能时,它会主动调用 read_file 工具读取完整的 SKILL.md,然后按照里面的指导执行。

SKILL.md 文件格式

一个标准的 SKILL.md 长这样:

---name: web-searchdescription: "联网搜索实时市场信息,获取最新股价、行业动态等"keywords: 联网, 搜索, 最新, 实时, 行情---# web-search 技能指南## 适用场景- 查询某只股票的最新行情- 获取最新的行业政策## 工作流1. 确定搜索关键词2. 调用 web_search 工具3. 分析搜索结果4. 整理输出

渐进式披露设计原则(Progressive Disclosure Design Principle)在这里体现得淋漓尽致:只给模型当前需要的信息,不多不少


05|实战案例:从零搭建 Text-to-SQL Agent

光讲理论没意思,我们来实战一个案例:搭建一个 Text-to-SQL Agent,让用户可以用自然语言查询数据库。

项目结构

nanobot-examples/text-to-sql/├── config.json          # 模型配置├── AGENTS.md            # Agent 身份和规则├── agent.py             # 入口 + QueryDBTool 自定义工具├── chinook.db           # 示例数据库(自动下载)└── skills/    ├── schema-exploration/   # 数据库结构探索技能    └── query-writing/        # SQL 编写与错误恢复技能

第一步:自定义 QueryDBTool

这是整个案例的核心。我们需要创建一个能执行只读 SQL 查询的工具:

from nanobot.agent.tools.base import ToolclassQueryDBTool(Tool):    """SQL 查询工具 - 在 Chinook 数据库上执行只读 SQL"""        def__init__(self, db_path: Path):        self._db_path = db_path        @property    defname(self) -> str:        return"query_db"        @property    defdescription(self) -> str:        return (            "Execute a read-only SQL query against the Chinook database. "            "Returns query results as formatted text. Only SELECT and "            "PRAGMA statements are allowed."        )        @property    defparameters(self) -> dict[str, Any]:        return {            "type": "object",            "properties": {                "sql": {                    "type": "string",                    "description": "The SQL query to execute (SELECT only)"                }            },            "required": ["sql"]        }        @property    defread_only(self) -> bool:        returnTrue# 标记为只读,可安全并行执行        asyncdefexecute(self, **kwargs: Any) -> str:        sql = kwargs.get("sql", "").strip()        ifnot sql:            return"Error: empty SQL query"                # 安全校验:只允许 SELECT 和 PRAGMA        upper = sql.upper().lstrip()        ifnot (upper.startswith("SELECT") or upper.startswith("PRAGMA")):            return"Error: only SELECT and PRAGMA statements are allowed"                try:            conn = sqlite3.connect(str(self._db_path))            cursor = conn.cursor()            cursor.execute(sql)                        columns = [desc[0] for desc in cursor.description] if cursor.description else []            rows = cursor.fetchall()            conn.close()                        ifnot rows:                return"Query returned 0 rows."                        # 格式化为文本表格            lines = [" | ".join(columns)]            lines.append("-" * len(lines[0]))            for row in rows[:50]:  # 最多返回 50 行                lines.append(" | ".join(str(v) for v in row))                        iflen(rows) > 50:                lines.append(f"... ({len(rows)} total rows, showing first 50)")                        return"\n".join(lines)                    except Exception as e:            returnf"SQL Error: {e}"

这个工具的设计有四个层次:

  1. 工具元数据namedescriptionparameters 会被 ToolRegistry 收集,转换成 LLM function calling 的 schema 发给模型
  2. 安全校验:代码层面强制只允许 SELECT 和 PRAGMA,防止误操作
  3. 执行 SQL:连接数据库、执行查询、获取结果
  4. 结果限制:最多返回 50 行,防止大表查询撑爆上下文窗口

第二步:组装整个 Agent

def build_bot() -> Nanobot:    """创建 Nanobot 实例,使用 config.json 配置"""    bot = Nanobot.from_config(        config_path=WORKSPACE / "config.json",        workspace=WORKSPACE,    )    # 注册自定义 SQL 查询工具    bot._loop.tools.register(QueryDBTool(DB_PATH))    return bot

组装完成后,Agent 可用的工具集包括:

  • read_file(框架内置):读文件(加载 SKILL.md)
  • write_file(框架内置):写文件
  • exec(框架内置):执行 shell 命令
  • query_db(自定义):执行只读 SQL

第三步:配置 config.json

{  "providers":{    "custom":{      "apiKey":"your-key-or-dummy",      "apiBase":"https://api.your-provider.com/v1"    }},"agents":{    "defaults":{      "provider":"custom",      "model":"your-model-name"    }}}

第四步:定义 AGENTS.md

# SQL Query AgentYou are a SQL database analyst. You help users query databases using natural language.## Rules- Always explore the schema before writing queries- Use query_db tool to execute SQL; NEVER use exec for SQL- Only use SELECT statements (read-only access)- Format results clearly for the user- If a query fails, analyze the error and try a different approach

这里的关键是明确约束:用 query_db 执行 SQL,不要用 exec。因为 exec 是通用 shell,如果模型用 exec 去跑 sqlite3,就绕过了 QueryDBTool 的安全限制。

第五步:编写 Skills

schema-exploration SKILL.md

## Workflow1. Use `query_db(sql="SELECT name FROM sqlite_master WHERE type='table'")` to list all tables2. For each relevant table, run `query_db(sql="PRAGMA table_info(TableName)")` to see columns3. Identify primary keys, foreign keys, and relationships4. Summarize the schema for the user

query-writing SKILL.md

## Workflow### Step 1: Understand the Question- Identify what tables and columns are needed- If unsure about schema, read the `schema-exploration` skill first### Step 2: Write the Query- Start simple, then add complexity- Use JOINs when data spans multiple tables- Use GROUP BY for aggregations- Use ORDER BY + LIMIT for "top N" questions### Step 3: Execute and Verify- Run with `query_db(sql="YOUR QUERY")`- If error: analyze the message, fix the query, retry- If results look wrong: check JOINs and WHERE clauses## Error Recovery- "no such table" -> re-list tables with schema-exploration- "no such column" -> re-check table_info- "ambiguous column" -> add table alias prefix

第六步:运行效果

执行命令:

python agent.py "How many customers are from Canada?"

输出:

Text-to-SQL Agent (nanobot)Question: How many customers are from Canada?=> 模型加载 schema-exploration SKILL.md=> query_db("SELECT name FROM sqlite_master WHERE type='table'")=> query_db("PRAGMA table_info(Customer)")=> 模型加载 query-writing SKILL.md=> query_db("SELECT COUNT(*) FROM Customer WHERE Country = 'Canada'")Answer: There are 8 customers from Canada in the database.exit_code: 0 | elapsed: 35s

整个过程完全自主:Agent 先探索数据库结构,再编写并执行查询,最后给出答案。如果上一次运行已经缓存了 schema 信息,下次查询会直接命中,无需重新探索。

如果查询出错,比如表名大小写不对,Agent 会根据 Error Recovery 的指导自动修正。这就是 Skills 的价值:把领域知识(如何探索 schema、如何写 SQL、如何纠错)封装在 SKILL.md 里,框架负责调度,两者各司其职。


06|给开发者的建议

总结

Nanobot 的核心价值在于 “轻量但不简陋” 。4000 行代码的背后,是对 Agent 开发本质的深刻理解:

  1. 配置优先:一个 config.json 就能定义完整 Agent,不需要写大量胶水代码
  2. Skills 渐进式加载:用三级加载系统高效管理上下文,避免 token 浪费
  3. 显式工具注册:继承 Tool 基类的方式虽然比装饰器多写几行代码,但参数验证、只读标记等元数据一目了然
  4. 非侵入式扩展:AgentHook 提供生命周期钩子,不改框架源码就能插入自定义逻辑

适用场景

Nanobot 特别适合以下场景:

  • 个人项目:想快速搭一个能用的 Agent,不想引入重型框架
  • 学习研究:想深入理解 Agent 的工作原理,读源码不迷路
  • 定制化需求:框架的某个行为不符合预期,直接改源码
  • 资源受限环境:边缘设备、低配置服务器,需要轻量级方案

不适用场景

如果你需要:

  • 复杂的 多 Agent 协作流程(虽然 nanobot 支持 spawn 子 Agent,但不如 LangGraph 的图编排强大)
  • 企业级的监控、日志、权限管理
  • 可视化的 Workflow 编排界面

那可能还是 LangChain/LangGraph 更适合你。

最后的话

我一直觉得,好的工具应该像一把顺手的瑞士军刀——功能齐全、体积小巧、开箱即用。Nanobot 就是这样一把刀。

它不是万能的,但在它擅长的领域,它做得足够好。更重要的是,当你需要调整它时,你能看懂它在做什么,而不是对着一堆抽象层发懵。

如果你也对轻量级 Agent 开发感兴趣,不妨试试 Nanobot。4000 行代码,也许就是你理解 AI Agent 的最佳入口。

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

在这里插入图片描述

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐