菜鸟AI - 让提示词生成更简单! 全站导航 全站导航
AI工具安装 新手教程 进阶教程 辅助资源 AI提示词 热点资讯 技术资讯 产业资讯 内容生成 模型技术 AI信息库

已有账号?

首页 > AI教程 > OpenClaw平替之Nanobot源码解析(二):Agent命令、消息总线与循环引擎深度评测
进阶教程 Agent命令

OpenClaw平替之Nanobot源码解析(二):Agent命令、消息总线与循环引擎深度评测

2026-06-08
阅读 0
热度 0
作者 菜鸟AI编辑部
摘要

摘要

上一篇文章带大家跑通了 nanobot 的“启动仪式”——现在,你的 Agent 已经能正常运转了。

上一篇文章带大家跑通了 nanobot 的“启动仪式”——现在,你的 Agent 已经能正常运转了。不过,当你输入 nanobot agent 并发送一条消息时,底层到底发生了什么?为什么这个框架既能支持终端对话,又能轻松扩展到 Telegram 或飞书?本文就借 nanobot agent 命令,拆解 nanobot 的心脏——MessageBus(消息总线),以及驱动对话的核心引擎 AgentLoop

1. agent 命令:通往智能体的入口

agent 命令的执行逻辑在 nanobot/cli/commands.pyagent 方法里,是用户与 Agent 交互最直接的入口。

参数一览:借助 Typer 框架,nanobot 提供了如下丰富参数:

参数 缩写 类型 默认值 说明
--message -m str None 发送给 Agent 的消息;提供后会进入单次消息模式
--session -s str cli:direct 会话 ID,用于区分不同对话上下文
--workspace -w str None 工作区目录,定义 Agent 运行时的根目录
--config -c str None 配置文件路径,默认为 ~/.nanobot/config.json
--markdown bool True 是否以 Markdown 格式渲染 Agent 输出
--logs bool False 是否在聊天过程中显示运行时日志(调试神器)

两种运行模式:单次任务 vs 持续交互

根据是否提供 -m / --message 参数,agent 命令会自动切换:

  1. 单次消息模式 (Single-Message Mode):运行 nanobot agent -m "你好",Agent 直接处理这条消息,打印回复后立即退出。适合脚本调用或简单的单次查询。
  2. 交互模式 (Interactive Mode):只运行 nanobot agent(不带 -m),进入持续交互会话。可以连续发送多条消息,Agent 会保留对话上下文。输入 exitquitCtrl+C 即可退出。

2. 核心架构:极简消息总线(MessageBus)

nanobot 能支持多渠道,核心在于一个极简的生产者-消费者模型。它将“消息来源”(Telegram、终端等)与“消息处理”(Agent 核心)完全解耦。

源码分析:nanobot/bus/queue.py

实现出人意料地简单(不到 50 行代码):

class MessageBus:
    def __init__(self):
        self.inbound: asyncio.Queue[InboundMessage] = asyncio.Queue()
        self.outbound: asyncio.Queue[OutboundMessage] = asyncio.Queue()

    async def publish_inbound(self, msg: InboundMessage):
        await self.inbound.put(msg)

    async def consume_inbound(self) -> InboundMessage:
        return await self.inbound.get()
    # ... outbound 同理
  • inbound 队列:所有渠道(CLI、Telegram 等)将用户输入封装成 InboundMessage 丢进去。
  • outbound 队列:Agent 处理完后,将回复封装成 OutboundMessage 丢进去,由对应渠道取走发送给用户。

精妙之处:Agent 根本不需要知道消息从哪里来。它只管从 inbound 取消息,处理完丢进 outbound。这为后续接入新渠道提供了极大灵活性。

3. 内置工具集:Agent 的“瑞士军刀”

代码在 nanobot/agent/tools 目录下。nanobot 默认提供了一套精简而强大的内置工具,让 Agent 能与现实世界交互。分三大类:

  • 文件系统 (Filesystem):读写代码和文档的能力。
    • read_file:读取指定文件内容。
    • write_file:创建新文件或覆盖现有文件。
    • edit_file:通过精确的行匹配和替换逻辑,安全修改文件内容。
    • list_dir:列出目录下的文件和子目录,帮助 Agent 探索项目结构。
  • 网页能力 (Web):获取实时信息。
    • web_search:基于 Bra ve Search 引擎进行联网搜索。
    • web_fetch:抓取指定 URL 的网页内容并转换为 Markdown 格式,方便 LLM 阅读。
  • 系统与编排 (System & Orchestration):实现复杂任务的核心。
    • exec:在 shell 中执行任意命令(如运行测试、安装依赖)。
    • spawn:创建一个子 Agent(Subagent)异步处理耗时任务,实现“多智能体协作”。
    • message:发送主动消息,用于向用户汇报进度或在多渠道间传递信息。
    • cron:管理定时任务,让 Agent 具备“时间观念”,能按计划执行操作。

4. 智能体循环:AgentLoop 的“五步走”

如果说 MessageBus 是血管,那么 AgentLoop 就是心脏。它驱动整个对话的生命周期。在 nanobot/agent/loop.py 中,核心逻辑被拆解为五个关键步骤:

1)第一步:接收 (Receive)
Agent 持续监听 MessageBus.inbound 队列。一旦有新消息(无论来自终端、Telegram 还是系统任务),Agent 就取出并启动处理流程。

2)第二步:构建上下文 (Context)
这是 AI 思考的基础。ContextBuilder 将以下信息“缝合”在一起:

  • 对话历史:最近的聊天记录。
  • 长期记忆:从 MEMORY.md 中提取的事实。
  • 当前任务:用户刚发送的消息。
  • 技能索引:可用工具的简要说明。

3)第三步:调用模型 (LLM Call)
将构建好的上下文发送给大模型(如 Gemini 或 GPT-4)。Agent 告诉模型:“这是目前状况,请决定下一步:直接回答用户,还是调用某个工具?”

4)第四步:执行工具 (Tool Execution)
如果模型决定调用工具(如 read_fileweb_search),AgentLoop 代为执行。

循环往复:工具执行结果作为“新信息”添加回上下文,回到第三步让模型继续思考。直到模型认为信息足够,给出最终答复。

5)第五步:发送回复 (Respond)
模型给出最终答案后,AgentLoop 将其封装成 OutboundMessage 发回 MessageBus.outbound。对应渠道(如 Telegram 插件)推送给用户。

实战演练:Agent 是怎么思考的?

为了更直观理解这个循环,看一个真实的 Debug 案例。用户问:“为什么这个项目可以直接使用 nanobot 命令?”Agent 经历了三次循环:

第一次循环:探索环境

输入:

  • messages:两条 messages,其中系统提示词读取工作空间下的 USER.md、SOUL.md 等文件内容,拼接成一个大的提示词。篇幅有限,不全部贴出。openclaw平替之nanobot源码解析(二):agent命令、消息总线与循环引擎
  • tools:符合 OpenAI Function Call 规范的工具定义(JSON Schema)
[{"function": {"description": "Read the contents of a file at the given path.","name": "read_file","parameters": {"properties": {"path": {"description": "The file path to read","type": "string"},"required": ["path"],"type": "object"}},"type": "function"}]

调用大模型,提供 messages、tools、temperature、max_tokens 等参数:

response = await self.provider.chat(
    messages=messages,
    tools=self.tools.get_definitions(),
    model=self.model,
    temperature=self.temperature,
    max_tokens=self.max_tokens,
    reasoning_effort=self.reasoning_effort,
)

模型思考:意识到需要先了解项目结构,于是决定调用工具。

模型回复:发出 list_dir 指令。

LLMResponse(
    content=None,
    tool_calls=[ToolCallRequest(id="PyPXnKIhI", name="list_dir", arguments={"path": "/Users/chaoxu.ren/PycharmProjects/nanobot"})],
    finish_reason="tool_calls",
    usage={"prompt_tokens": 3388, "completion_tokens": 357, "total_tokens": 3745},
    reasoning_content=None,
    thinking_blocks=None,
)

执行:Agent 执行 list_dir,结果(文件列表)追加至上下文。现在上下文中有 4 条消息。openclaw平替之nanobot源码解析(二):agent命令、消息总线与循环引擎

第二次循环:定位关键文件

输入:之前的 4 条 messages、tools JSON schema、temperature 等参数。

模型思考:在列表中看到 pyproject.toml,判断这是关键配置文件。

模型回复:发出 read_file 指令。

LLMResponse(
    content=None,
    tool_calls=[ToolCallRequest(id="undktOZkf", name="read_file", arguments={"path": "/Users/chaoxu.ren/PycharmProjects/nanobot/pyproject.toml"})],
    finish_reason="tool_calls",
    usage={"prompt_tokens": 3565, "completion_tokens": 103, "total_tokens": 3668},
    reasoning_content=None,
    thinking_blocks=None,
)

执行:Agent 读取文件内容,并将 pyproject.toml 内容追加至 messages。现在上下文中有 6 条消息。openclaw平替之nanobot源码解析(二):agent命令、消息总线与循环引擎

第三次循环:给出最终答案

输入:之前的 6 条 messages、tools JSON schema、temperature 等参数。

模型思考:在文件中找到 [project.scripts] 配置,逻辑闭环,可以回答了。

模型回复:直接给出最终文字解释,不再调用工具。

LLMResponse(
    content="在这个项目中可以直接使用 `nanobot` 命令,是因为在项目的 `pyproject.toml` 配置文件中定义了命令行脚本入口(Entry Points)。\n\n具体来说,在 `pyproject.toml` 文件中有一段这样的配置:\n\n```toml\n[project.scripts]\nnanobot = \"nanobot.cli.commands:app\"\n```\n\n它的工作原理是:\n1. **`[project.scripts]`** 是 Python 打包标准(PEP 621)中用来定义全局命令行工具的部分。\n2. **`nanobot = ...`** 表示要在系统或虚拟环境中注册一个名为 `nanobot` 的可执行命令。\n3. **`nanobot.cli.commands:app`** 指定了当你在终端输入 `nanobot` 时,Python 应该去执行 `nanobot/cli/commands.py` 文件中的 `app` 对象(通常是一个 Typer 或 Click 的应用实例)。\n\n当你使用 `pip install -e .` 或者 `uv pip install -e .` 在当前目录安装这个项目时,包管理器会自动在你的 Python 环境的 bin 目录(或 Windows 的 Scripts 目录)下生成一个名为 `nanobot` 的可执行文件,从而让你能够在终端里直接调用它。",
    tool_calls=[],
    finish_reason="stop",
    usage={"prompt_tokens": 4788, "completion_tokens": 397, "total_tokens": 5185},
    reasoning_content=None,
    thinking_blocks=None,
)

结束:Agent 将最终回复发送给用户,循环结束。同时将大模型回复添加到上下文中,以便后续轮次问答。现在上下文中有 7 条消息。openclaw平替之nanobot源码解析(二):agent命令、消息总线与循环引擎

完整的对话记录 nanobot 会保存在工作空间的 sessions 文件夹下

Debug 日志实录

debug PyCharm 配置如下:

openclaw平替之nanobot源码解析(二):agent命令、消息总线与循环引擎

如果开启 --logs,会看到这一连串动作的清晰轨迹:

/Users/chaoxu.ren/PycharmProjects/nanobot/.venv/bin/python -X pycache_prefix=... --file nanobot.cli.commands agent -m 为什么这个项目可以直接使用nanobot命令 --logs -s 2026-03-09 -w ./.nanobot
Connected to pydev debugger (build 251.26094.141)
Created HEARTBEAT.md
Created USER.md
Created SOUL.md
Created AGENTS.md
Created TOOLS.md
Created memory/MEMORY.md
Created memory/HISTORY.md
2026-03-09 19:51:34.472 | INFO | nanobot.agent.loop:_process_message:357 - Processing message from cli:user: 为什么这个项目可以直接使用nanobot命令
2026-03-09 20:03:07.247 | INFO | nanobot.agent.loop:_run_agent_loop:230 - Tool call: list_dir({"path": "/Users/chaoxu.ren/PycharmProjects/nanobot"})
2026-03-09 20:09:14.111 | INFO | nanobot.agent.loop:_run_agent_loop:230 - Tool call: read_file({"path": "/Users/chaoxu.ren/PycharmProjects/nanobot/pyproject.toml"})
2026-03-09 20:15:29.075 | INFO | nanobot.agent.loop:_process_message:449 - Response to cli:user: 在这个项目中可以直接使用 `nanobot` 命令,是因为在项目的 `pyproject.toml` 配置文件中定义了命令行脚本入口(Entry Points)...
? nanobot
在这个项目中可以直接使用 nanobot 命令,是因为在项目的 pyproject.toml配置文件中定义了命令行脚本入口(Entry Points)...

总结

nanobot 的设计哲学在 agent 命令和 MessageBus 中体现得淋漓尽致:用最简单的 Python 原生工具(如 asyncio.Queue),解决最复杂的解耦问题。

理解了这一层,就掌握了 nanobot 跨渠道通信的精髓。下一篇,将深入 nanobot 最具特色的部分:Markdown 驱动的系统提示词——理解系统提示词往往成为理解整个 Agent 系统的核心。

从算法层面看,nanobot 并没有什么碘伏性创新,但其工程思维却值得每一位 Agent 从业者深入学习。

来源:互联网

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

同类文章推荐

相关文章推荐

更多