4000 行代碼搞定 AI Agent:NanoBot 架構(gòu)深度拆解

本文深度拆解了 NanoBot,僅用 4000 行代碼實(shí)現(xiàn)了完整的 AI Agent 能力,講解了其最小化架構(gòu)設(shè)計(jì)思路,告訴你如何構(gòu)建真正可控、可讀、可改的 AI Agent。原文:How to Learn Anything Faster With AI (6 Practical Workflows I Use Every Day)

當(dāng) 43 萬(wàn)行代碼對(duì)陣 4000 行代碼時(shí),一個(gè)問(wèn)題自然而然浮現(xiàn):刪掉了什么?保留了什么?

本文是純架構(gòu)拆解。沒(méi)有部署指南,也沒(méi)有開(kāi)箱即用的演示。我們來(lái)剖析 NanoBot 如何用最小骨架運(yùn)行 Agent,并保證代碼可讀、可修改、可管控。

NanoBot 倉(cāng)庫(kù)地址:https://github.com/HKUDS/nanobot

為什么重要:能力之上,可控先行

很多人想要"能用的 Agent",但又害怕變成黑盒 —— 不知道工具何時(shí)被調(diào)用,哪些文件被修改,也不知道執(zhí)行為什么突然跑偏。

NanoBot 采用了直截了當(dāng)?shù)姆桨福合劝?Agent 構(gòu)建為最小可行運(yùn)行時(shí)。消息到達(dá) → 上下文組裝 → LLM 決策 → 工具執(zhí)行 → 結(jié)果回填 → 返回響應(yīng)。

追求三個(gè)目標(biāo):

  • 能通讀整條端到端流水線(代碼庫(kù)足夠?。?/li>
  • 能精確定位問(wèn)題發(fā)生的位置(邊界清晰)
  • 可以安全的逐步增量添加能力(組件可替換)

結(jié)論

NanoBot 的工作是以工程為中心:將 Agent 分解為流水線,用 MessageBus 解耦,用 AgentLoop 驅(qū)動(dòng)核心循環(huán),通過(guò) Cron/Heartbeat 實(shí)現(xiàn)主動(dòng)性。

最值得學(xué)習(xí)的不是"連接了 Telegram/WhatsApp/Slack",而是這個(gè)最小骨架:

  • 入口:Channels 將不同 IM 消息統(tǒng)一為 InboundMessage
  • 樞紐:MessageBus 解耦了"接收消息"和"生成響應(yīng)"
  • 核心:AgentLoop 驅(qū)動(dòng) LLM ? 工具循環(huán)
  • 上下文:ContextBuilder 將規(guī)則/人格/工具描述/技能/記憶組裝到系統(tǒng)提示詞中
  • 可擴(kuò)展性:ToolRegistry + JSON Schema 驗(yàn)證將工具變?yōu)榭勺?cè)、可驗(yàn)證的插件
  • 主動(dòng)性:Cron 處理定時(shí)任務(wù),Heartbeat 處理周期性喚醒

如果想構(gòu)建可控 Agent,這個(gè)結(jié)構(gòu)讓你以最小成本閉合循環(huán),然后逐步添加多模型路由、更強(qiáng)的記憶檢索、更嚴(yán)格的權(quán)限邊界和更可靠的審計(jì)回放。

對(duì)比:OpenClaw 給你成品,NanoBot 給你骨架

如果你研究過(guò) OpenClaw,就能感覺(jué)到定位差異。這里有個(gè)清晰的對(duì)比:

OpenClaw 更像"生產(chǎn)就緒產(chǎn)品",NanoBot 更像"用于學(xué)習(xí)和復(fù)刻的最小運(yùn)行時(shí)"。

TL;DR

  • NanoBot 將 Agent 精簡(jiǎn)到最基礎(chǔ)的循環(huán):消息 → 上下文 → LLM → 工具 → 回填 → 響應(yīng)
  • 用 MessageBus 解耦:Channels 只負(fù)責(zé)收發(fā),AgentLoop 只負(fù)責(zé)"思考和執(zhí)行"
  • AgentLoop 是標(biāo)準(zhǔn)的"工具調(diào)用循環(huán)":LLM 給出工具調(diào)用,逐個(gè)執(zhí)行,將結(jié)果作為工具消息回填,LLM 繼續(xù)推理
  • ContextBuilder 的核心是基于文件的設(shè)計(jì):AGENTS/SOUL/USER/TOOLS/IDENTITY + memory 目錄都是可版本控制的可信源
  • 工具系統(tǒng)不是散落的 if-else:ToolRegistry 統(tǒng)一注冊(cè),工具參數(shù)使用 JSON Schema 驗(yàn)證,錯(cuò)誤被收斂為可讀字符串
  • exec 工具擁有粗粒度安全護(hù)欄(危險(xiǎn)命令正則攔截 + 可選工作空間限制),但生產(chǎn)環(huán)境仍需要允許列表和審計(jì)
  • 會(huì)話使用 JSONL 保存對(duì)話歷史(易讀、易回放),但默認(rèn)存儲(chǔ)在 ~/.nanobot/sessions,而非項(xiàng)目工作區(qū)
  • Cron/Heartbeat 解決了"沒(méi)人說(shuō)話時(shí) Agent 也能做事"的問(wèn)題,本質(zhì)上為 AgentLoop 提供定時(shí)觸發(fā)
  • README 說(shuō)"約 4000 行",實(shí)際 nanobot/ 目錄總計(jì)約 5k 行;差異來(lái)自橋接、通道、cron、工具和外圍組件的統(tǒng)計(jì)口徑

01 | 正確分類:NanoBot 究竟是什么

把 NanoBot 叫做"聊天機(jī)器人"低估了它。

更準(zhǔn)確的工程描述是:運(yùn)行在本地機(jī)器上的 Agent 運(yùn)行時(shí)。

它將"對(duì)話"升級(jí)為"可執(zhí)行工作流入口":

  • 你從 Telegram/WhatsApp/Slack 發(fā)送消息
  • LLM 首先決定"是否要調(diào)用工具,調(diào)用哪個(gè),傳什么參數(shù)"
  • 工具在本地/受控環(huán)境中執(zhí)行(讀寫(xiě)文件、運(yùn)行命令、網(wǎng)頁(yè)抓取等)
  • 結(jié)果回填給 LLM
  • 最終答案返回原聊天窗口

一旦穩(wěn)定了這條流水線,其他一切都是增量添加的。

02 | 架構(gòu)概覽:一張圖展示數(shù)據(jù)流

重點(diǎn)不在于漂亮的圖片,而在于每個(gè)框都對(duì)應(yīng)倉(cāng)庫(kù)中真實(shí)的文件:

  • nanobot/channels/*: 通道適配器和啟動(dòng)邏輯
  • nanobot/bus/*: 消息事件和隊(duì)列
  • nanobot/agent/loop.py: 核心循環(huán)
  • nanobot/agent/context.py: 系統(tǒng)提示詞組裝
  • nanobot/agent/tools/*: 工具系統(tǒng)
  • nanobot/cron/* + nanobot/heartbeat/*: 調(diào)度和心跳

03 | 核心循環(huán):LLM 不"做事" —— 只決定"要做什么"

AgentLoop 的邏輯是教科書(shū)級(jí)的:

  1. 從入隊(duì)隊(duì)列拉取一條消息
  2. 獲取/創(chuàng)建會(huì)話,從歷史中獲取最近 N 條消息
  3. 使用 ContextBuilder 組裝系統(tǒng)提示詞,然后將歷史 + 當(dāng)前消息打包成消息列表
  4. 調(diào)用 LLM(將工具定義作為函數(shù) schema 傳給模型)
  5. 如果模型返回工具調(diào)用:逐個(gè)執(zhí)行,將工具結(jié)果作為工具角色消息回填,繼續(xù)下一輪
  6. 如果模型停止調(diào)用工具:獲取最終內(nèi)容,寫(xiě)入會(huì)話,發(fā)送到出隊(duì)隊(duì)列

其價(jià)值在于:"思考"和"執(zhí)行"明確分離。

  • LLM 只輸出結(jié)構(gòu)化工具調(diào)用
  • 工具處理執(zhí)行
  • 結(jié)果回填
  • LLM 基于"真實(shí)結(jié)果"繼續(xù)推理

這比"讓模型通過(guò)想象執(zhí)行結(jié)果"強(qiáng)太多了。

關(guān)鍵消息格式:

messages = [system_prompt] + history + [user_message]
assistant -> tool_calls[]  # 決定要做什么
tool_results -> messages   # 將真實(shí)執(zhí)行結(jié)果反饋回去

在這個(gè)循環(huán)中,最重要的不是"更多工具",而是"工具調(diào)用證據(jù)鏈":

  • 你能看到模型是如何決策的(消息中的工具調(diào)用)
  • 你能看到工具返回了什么(消息中的工具結(jié)果)
  • 你能明白最終響應(yīng)為什么是這樣(它基于這些證據(jù))

這就是可控性的基礎(chǔ):所有關(guān)鍵動(dòng)作都可以在上下文中回放。

兩個(gè)影響穩(wěn)定性的實(shí)現(xiàn)細(xì)節(jié):

  • 上限:max_iterations 默認(rèn)是 20,防止模型進(jìn)入工具調(diào)用死循環(huán)
  • 歷史存儲(chǔ):Session 使用 JSONL 格式寫(xiě)入 ~/.nanobot/sessions,第一行是元數(shù)據(jù),后續(xù)行是獨(dú)立消息;對(duì)調(diào)試和回放非常友好
03.1 | MessageBus:為什么要加一層隊(duì)列

很多 Agent 開(kāi)發(fā)者把"接收消息"和"處理消息"混在一起。問(wèn)題在于:

  • 不同通道有不同消息格式(Telegram 有語(yǔ)音,WhatsApp 有媒體,Slack 有 @提及)
  • 處理邏輯需要串行控制(否則會(huì)話狀態(tài)會(huì)損壞)
  • 當(dāng)你需要可觀測(cè)性(日志、審計(jì))時(shí),沒(méi)有地方插入

NanoBot 的 MessageBus 有兩個(gè)隊(duì)列:

self.inbound: asyncio.Queue[InboundMessage] = asyncio.Queue()
self.outbound: asyncio.Queue[OutboundMessage] = asyncio.Queue()

Channels 將各種格式的消息統(tǒng)一為 InboundMessage,扔進(jìn)入隊(duì)隊(duì)列。AgentLoop 從隊(duì)列拉取處理,將 OutboundMessage 扔進(jìn)出隊(duì)隊(duì)列。ChannelManager 訂閱出隊(duì)隊(duì)列,按通道分發(fā)回去。

這個(gè)設(shè)計(jì)的好處:

  • Channels 不需要知道 Agent 如何工作
  • AgentLoop 不需要知道消息來(lái)自哪里
  • 想要添加審計(jì)、限流、優(yōu)先級(jí)?在隊(duì)列層添加即可
03.2 | 子代理生成:從主會(huì)話中分離復(fù)雜任務(wù)

NanoBot 有一個(gè)實(shí)用但容易被忽略的能力:spawn(生成子代理)。

沒(méi)有"多智能體"那么復(fù)雜;方法非常直接:

  • 主 Agent 接收到任務(wù),發(fā)現(xiàn)太長(zhǎng)或太復(fù)雜
  • 使用 spawn 拉起一個(gè)子代理處理特定隔離工作(比如"先讀完這一批文件,生成結(jié)構(gòu)化摘要")
  • 子代理完成后,通過(guò) MessageBus 將結(jié)果作為系統(tǒng)消息返回給主 Agent
  • 主 Agent 為用戶更自然的總結(jié)結(jié)果

SubagentManager 的關(guān)鍵限制:

# 子代理沒(méi)有消息工具,沒(méi)有生成工具
tools.register(ReadFileTool())
tools.register(WriteFileTool())
tools.register(ListDirTool())
tools.register(ExecTool(...))
tools.register(WebSearchTool(...))
tools.register(WebFetchTool())

這就是設(shè)計(jì)價(jià)值:子代理工具更少,權(quán)限更小,目標(biāo)更聚焦 —— 不會(huì)變成第二個(gè)全能黑盒。

03.3 | Gateway:同時(shí)啟動(dòng) AgentLoop、Channels、Cron、Heartbeat

當(dāng)你運(yùn)行 nanobot gateway,不只是"啟動(dòng)一個(gè)機(jī)器人"。

它在同一個(gè)進(jìn)程中拉起四個(gè)組件:

  • AgentLoop:消費(fèi)入隊(duì),生成出隊(duì)
  • ChannelManager:按配置啟動(dòng) Telegram/WhatsApp/Slack,處理出隊(duì)分發(fā)
  • CronService:從 ~/.nanobot/cron/jobs.json 讀寫(xiě)定時(shí)任務(wù),按計(jì)劃觸發(fā) Agent
  • HeartbeatService:默認(rèn)每 30 分鐘喚醒一次,讓 Agent 讀取 HEARTBEAT.md 檢查待處理任務(wù)

這就是為什么我稱它為最小運(yùn)行時(shí):它將"持續(xù)運(yùn)行"作為架構(gòu)的一部分。

04 | ContextBuilder:為什么它也像 OpenClaw 一樣使用一堆 Markdown 文件

你會(huì)在工作區(qū)看到一組熟悉的文件:

  • AGENTS.md: 工作規(guī)范(如何做事)
  • SOUL.md: 人格/價(jià)值觀/邊界(如何說(shuō)話,如何選擇)
  • USER.md: 用戶偏好(你是誰(shuí),關(guān)心什么)
  • TOOLS.md: 工具描述(有什么能力,如何調(diào)用)
  • IDENTITY.md: 身份(名稱,風(fēng)格)
  • memory/: 每日筆記 + 長(zhǎng)期信息

ContextBuilder 的工作就是:將這些"可信源"組裝成系統(tǒng)提示詞:

BOOTSTRAP_FILES = ["AGENTS.md", "SOUL.md", "USER.md", "TOOLS.md", "IDENTITY.md"]

def build_system_prompt(self, skill_names: list[str] | None = None) -> str:
    parts = []
    parts.append(self._get_identity())
    bootstrap = self._load_bootstrap_files()
    if bootstrap:
        parts.append(bootstrap)
    memory = self.memory.get_memory_context()
    if memory:
        parts.append(f"# Memory\n\n{memory}")
    # ...
    return "\n\n---\n\n".join(parts)

這種基于文件的方法的好處是:

  • 規(guī)則可版本控制:Git 能追蹤"這個(gè)邊界是什么時(shí)候添加的"
  • 上下文可控:想要 Agent 更克制?編輯 SOUL。想要工具更穩(wěn)定?編輯 TOOLS。想要它更懂你?編輯 USER
  • 連續(xù)性不依賴對(duì)話:對(duì)話丟了不是致命問(wèn)題,文件還在

我喜歡用一句話來(lái)理解:文本勝過(guò)大腦。

04.1 | SkillsLoader:漸進(jìn)式技能加載

NanoBot 的技能系統(tǒng)有一個(gè)設(shè)計(jì)點(diǎn)值得一提:不是所有技能都一次性塞進(jìn)系統(tǒng)提示詞。

def build_skills_summary(self) -> str:
    # 只返回技能名稱/描述/位置
    # Agent 需要時(shí)用 read_file 讀取完整內(nèi)容

這解決了一個(gè)真實(shí)問(wèn)題:技能太多會(huì)炸掉系統(tǒng)提示詞。

它的方案:

  1. always=true 的技能:直接進(jìn)入系統(tǒng)提示詞
  2. 其他技能:只給 Agent 展示摘要(名稱 + 描述 + 路徑)
  3. 當(dāng) Agent 需要時(shí):自己用 read_file 讀取完整內(nèi)容

這就是"漸進(jìn)式加載":讓 Agent 按需獲取,而不是提前把所有東西都給出去。

04.2 | MemoryStore:記事本級(jí)別的記憶

MemoryStore 做兩件事:

  • 每日筆記:memory/YYYY-MM-DD.md,一天一個(gè)文件
  • 長(zhǎng)期記憶:memory/MEMORY.md,手動(dòng)維護(hù)的持久化信息
def get_memory_context(self) -> str:
    parts = []
    long_term = self.read_long_term()
    if long_term:
        parts.append("## Long-term Memory\n" + long_term)
    today = self.read_today()
    if today:
        parts.append("## Today's Notes\n" + today)
    return "\n\n".join(parts) if parts else ""

它滿足了"讓 Agent 記住你告訴它的東西"這個(gè)基本需求。

但距離"可檢索的長(zhǎng)期記憶"還有差距,路線圖也將長(zhǎng)期記憶列為待完成工作。

05 | 工具系統(tǒng):為什么"可控 Agent "離不開(kāi) ToolRegistry + 參數(shù)驗(yàn)證

很多 Agent 開(kāi)發(fā)者最后工具越來(lái)越亂,最終變成:

  • 一堆散落的函數(shù)
  • 一堆"如果模型說(shuō)了某個(gè)關(guān)鍵詞就執(zhí)行"
  • 一堆基于約定的參數(shù)格式

NanoBot 的工具系統(tǒng)有兩點(diǎn)做對(duì)了:

  1. 工具是"注冊(cè)式",不是"松散腳本"。

ToolRegistry 統(tǒng)一注冊(cè),把所有工具定義打包成給模型的函數(shù) schema。

def _register_default_tools(self) -> None:
    self.tools.register(ReadFileTool())
    self.tools.register(WriteFileTool())
    self.tools.register(EditFileTool())
    self.tools.register(ListDirTool())
    self.tools.register(ExecTool(...))
    self.tools.register(WebSearchTool(...))
    self.tools.register(WebFetchTool())
    self.tools.register(MessageTool(...))
    self.tools.register(SpawnTool(...))

AgentLoop 不需要知道"有哪些工具",只需要知道"所有工具長(zhǎng)得都一樣":名稱/描述/參數(shù)/執(zhí)行。

  1. 參數(shù)使用 JSON Schema 驗(yàn)證,失敗也可讀

工具基類有 validate_params(),按照 schema 檢查類型、必填字段、枚舉、最大最小值等。

這對(duì)穩(wěn)定性至關(guān)重要:

  • 當(dāng)模型輸出錯(cuò)誤參數(shù)時(shí),不會(huì)用異常炸掉整個(gè)循環(huán)
  • 將錯(cuò)誤收斂為可讀文本,反饋給模型進(jìn)行修正
  • 你能在日志中看到"哪個(gè)字段錯(cuò)了"
05.1 | web_fetch 返回 JSON,不是"文章正文"

為了避免你以為它是"隨便寫(xiě)的爬蟲(chóng)",這里有兩個(gè)細(xì)節(jié):

  1. web_search 使用 Brave Search API,需要 tools.web.search.apiKey(或環(huán)境變量 BRAVE_API_KEY
  2. web_fetch 返回值是 JSON 字符串,包含 finalUrl、status、extractor、truncated、text 等字段

這對(duì) Agent 很關(guān)鍵。因?yàn)槟P托枰牟恢皇?正文",它需要知道"這次抓取實(shí)際得到了什么,是否被截?cái)?,是否重定向到另一個(gè)域名"。

這就是我喜歡的風(fēng)格:工具輸出盡可能結(jié)構(gòu)化,讓模型讀取"可驗(yàn)證的證據(jù)"而非隨機(jī)文本。

05.2 | LiteLLM Provider:簡(jiǎn)單的多模型路由實(shí)現(xiàn)

NanoBot 使用 LiteLLM 進(jìn)行多模型路由:

class LiteLLMProvider(LLMProvider):
    def __init__(self, api_key, api_base, default_model="anthropic/claude-opus-4-5"):
        # 根據(jù) api_key 前綴判斷提供商
        self.is_openrouter = api_key and api_key.startswith("sk-or-v1")
        self.is_vllm = bool(api_base) and not self.is_openrouter

支持的提供商:

  • OpenRouter(推薦,可訪問(wèn)所有模型)
  • Anthropic / OpenAI / DeepSeek / Gemini / Groq(直連)
  • vLLM(本地模型)

配置很簡(jiǎn)單:

{
  "providers": {
    "openrouter": { "apiKey": "sk-or-v1-xxx" }
  },
  "agents": {
    "defaults": { "model": "anthropic/claude-opus-4-5" }
  }
}

本地模型配置:

{
  "providers": {
    "vllm": {
      "apiKey": "dummy",
      "apiBase": "http://localhost:8000/v1"
    }
  },
  "agents": {
    "defaults": { "model": "meta-llama/Llama-3.1-8B-Instant" }
  }
}

06 | 主動(dòng)性:Cron 和 Heartbeat 是兩種不同的"喚醒方式"

很多 Agent 在一點(diǎn)上體驗(yàn)很差:它們只等著你發(fā)消息。

NanoBot 使用兩種機(jī)制:

Cron:顯式定時(shí)任務(wù)

CronService 管理任務(wù),時(shí)間到了給 Agent 發(fā)一條"類似用戶輸入"的消息(走一輪 Agent 流程),然后可選擇將結(jié)果投遞到指定通道。

你可以把它理解為:產(chǎn)品化的"提醒/例行檢查"。

# 添加任務(wù)
nanobot cron add --name "daily" --message "Good morning!" --cron "0 9 * * *"

# 列出任務(wù)
nanobot cron list

# 刪除任務(wù)
nanobot cron remove <job_id>
Heartbeat:輕量級(jí)周期性喚醒

HeartbeatService 每 30 分鐘觸發(fā)一次,但不強(qiáng)制任務(wù) —— Agent 自己讀取 HEARTBEAT.md:

  • 如果文件里什么都沒(méi)有,什么也不做
  • 如果有待處理項(xiàng),按照檢查列表執(zhí)行

我非常喜歡這個(gè)設(shè)計(jì):讓主動(dòng)性變成一個(gè)"非常廉價(jià)的接口",不需要重新發(fā)明復(fù)雜的工作流 DSL。

06.1 | Channels:更多入口,更嚴(yán)邊界

從架構(gòu)角度看,Channels 的意義不是"連接幾個(gè)聊天應(yīng)用",而是把"入口不確定性"擋在門(mén)外。

典型的不確定性:

  • Telegram 可能有語(yǔ)音(還要轉(zhuǎn)寫(xiě))
  • WhatsApp 需要橋接(Node 橋)
  • Slack 使用長(zhǎng)連接(WebSocket)
  • 不同通道的 sender_id、chat_id 語(yǔ)義不一致

NanoBot 的處理方式:不跟入口糾纏,統(tǒng)一成 InboundMessage / OutboundMessage。

需要注意的是配置層的 allowFrom 字段。入口越多,越容易發(fā)生"沒(méi)打算響應(yīng)的人也得到了響應(yīng)"的意外。

如果 allowFrom 為空,BaseChannel 邏輯默認(rèn)開(kāi)放。

如果真的部署給團(tuán)隊(duì)使用,建議把"誰(shuí)允許觸發(fā)"設(shè)為硬門(mén)檻,而不是隨便配置一下。

06.2 | 三個(gè)通道的工程細(xì)節(jié)

Telegram

  • 長(zhǎng)輪詢,不需要公開(kāi) webhook
  • 下載的圖片/語(yǔ)音/文件存在 ~/.nanobot/media
  • 語(yǔ)音轉(zhuǎn)寫(xiě)是可選的:配置 Groq API 密鑰后,使用 Whisper 轉(zhuǎn)換為文本,再喂給 Agent
  • 發(fā)送消息時(shí),將 Markdown 轉(zhuǎn)換為 Telegram 安全的 HTML,失敗則降級(jí)為純文本

WhatsApp

  • Python 端不直接實(shí)現(xiàn)協(xié)議,通過(guò) WebSocket 連接到 Node.js 橋接
  • 橋接使用 @whiskeysockets/baileys(WhatsApp Web 協(xié)議 —— 實(shí)際的麻煩都在這里)
  • 語(yǔ)音消息目前不支持從橋接端直接下載和轉(zhuǎn)寫(xiě)

Slack

  • 使用 WebSocket 長(zhǎng)連接,更適合企業(yè)系統(tǒng)集成
  • 有 message_id 去重緩存,超過(guò)閾值時(shí)修剪,避免重復(fù)處理
  • 收到消息后給出反應(yīng)(類似"已讀/已處理"信號(hào)),然后轉(zhuǎn)發(fā)給 AgentLoop

這三塊的細(xì)節(jié)說(shuō)明了一個(gè)事實(shí):通道不是"適配完完事",而是迫使你補(bǔ)全可靠性、權(quán)限邊界和可觀測(cè)性。

07 | 最值得借鑒的是什么,需要注意什么

值得借鑒:4 點(diǎn)

  1. 消息總線解耦:Channels 和 AgentLoop 之間只有 Inbound/OutboundMessage
  2. 清晰的工具循環(huán):工具調(diào)用生命周期(調(diào)用 → 執(zhí)行 → 結(jié)果 → 繼續(xù))在一個(gè)文件中可讀
  3. 基于文件的上下文:工作區(qū) Markdown 承載穩(wěn)定規(guī)則和偏好
  4. 輕量級(jí)主動(dòng)性:Cron/Heartbeat 都只是給 AgentLoop 發(fā)送"下一個(gè)輸入"

需要注意/建議補(bǔ)充:4 點(diǎn)

  1. 更強(qiáng)的記憶檢索:當(dāng)前的 MemoryStore 更像"記事本",距離"可檢索的長(zhǎng)期記憶"仍然有距離
  2. 更嚴(yán)格的權(quán)限邊界:exec 的正則護(hù)欄是必要的但不夠;生產(chǎn)環(huán)境最好引入允許列表、二次確認(rèn)、審計(jì)回放
  3. 會(huì)話和可移植性:會(huì)話默認(rèn)存儲(chǔ)在 ~/.nanobot/sessions,對(duì)"將工作區(qū)遷移到另一臺(tái)機(jī)器"不太友好
  4. 異步并發(fā)策略:現(xiàn)在是"逐個(gè)執(zhí)行工具調(diào)用",足夠簡(jiǎn)單,但對(duì)于復(fù)雜編排(并行工具、通道隊(duì)列、重試策略)還需要更多工作

還有一個(gè)小坑:process_direct() 當(dāng)前忽略傳入的 session_key,導(dǎo)致 Cron/Heartbeat 這種"系統(tǒng)觸發(fā)"的輸入可能和你的 CLI 會(huì)話混淆。

這類問(wèn)題不難修復(fù),但它提醒你:Agent 穩(wěn)定性往往不取決于模型,而取決于"狀態(tài)隔離"。

結(jié)語(yǔ):為什么建議讀一遍 NanoBot 代碼

很多 Agent 框架讀完讓你更焦慮:更多概念,更多抽象,實(shí)際執(zhí)行流水線反而更模糊。

NanoBot 的好處:把"能工作的 Agent"壓縮到你能讀完的規(guī)模。

不需要把它當(dāng)成最終解決方案,最好把它當(dāng)成"最小可行骨架":先閉合循環(huán),然后逐步添加護(hù)欄、添加記憶、添加工作流。

這就是構(gòu)建可控 Agent 的正確節(jié)奏。

如果準(zhǔn)備開(kāi)始閱讀,建議這個(gè)順序,基本不會(huì)迷路:

  1. nanobot/agent/loop.py: 先理解主流水線
  2. nanobot/agent/context.py: 再看上下文如何組裝
  3. nanobot/agent/tools/*: 最后看工具系統(tǒng)和安全護(hù)欄
  4. nanobot/cron/* + nanobot/heartbeat/*: 理解"主動(dòng)性"如何接入
  5. nanobot/channels/*: 需要連接新入口時(shí)再看

這就是為什么 NanoBot 是一個(gè)值得學(xué)習(xí)的最小骨架,而不僅僅是另一個(gè)框架。

關(guān)鍵技術(shù)指標(biāo)(2026 年 2 月):

  • 實(shí)際代碼量:~3,510 行(核心 Agent 代碼,通過(guò) core_agent_lines.sh 驗(yàn)證)
  • 啟動(dòng)時(shí)間:0.8 秒(對(duì)比 OpenClaw 的 8-12 秒)
  • 內(nèi)存占用:基礎(chǔ)操作 45MB(對(duì)比 OpenClaw 的 200-400MB)
  • GitHub 指標(biāo):15.9K star,2.2K fork,32+ 貢獻(xiàn)者
  • 最新發(fā)布:v0.1.3.post6(2026 年 2 月 10 日)
  • 支持通道:Telegram, Discord, WhatsApp, Mochat, DingTalk, Slack, Email, QQ
  • 支持 LLM 提供商:13+,包括 OpenRouter, Anthropic, OpenAI, DeepSeek, Gemini, Groq, vLLM

這個(gè)架構(gòu)證明,有效的 AI Agent 不需要龐大的框架。通過(guò)將 Agent 設(shè)計(jì)精簡(jiǎn)到基礎(chǔ)要素,NanoBot 實(shí)現(xiàn)了更快的實(shí)驗(yàn)、更容易的調(diào)試、更低的資源消耗和更強(qiáng)的執(zhí)行控制。這證明當(dāng)架構(gòu)正確時(shí),減少 99% 的代碼仍能保持完整功能。

本文由mdnice多平臺(tái)發(fā)布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容