OpenClaw、pi-agent 与 nanobot:一个好用的 Agent 是怎样炼成的

这篇文章先讲清楚 Agent 的基础调用链,再对比三者实现的差异,包括:模型兼容层、工具调用回填、skills、memory、heartbeat 等。


一、先理解 Agent 在做什么

我们先统一一下语言。当你和一个 AI Agent 对话时,背后发生了这些事:

术语 含义
messages 模型可见的上下文,按时间顺序排列
tools 模型可调用的函数声明(名称、参数 JSON Schema、描述)
tool_call 模型请求调用工具的指令
tool_result 工具执行后的结果,作为下一轮模型输入的一部分
session 同一对话线程的长期状态
loop 模型生成 → 工具执行 → 结果回填 → 再次生成,直到结束

理解这些概念很重要,因为生产环境里的问题往往就出在这些细节上:

除了功能丰富度以外,这些也是 OpenClaw/pi-agent 与其他轻量 Agent 框架如 nanobot 等的体验拉开差距的地方。


二、一次完整的 Agent 调用

所有 Agent 系统都遵循同一个主干流程。理解了它,再看不同框架的实现差异就清晰多了。

2.1 通用调用流程

用户输入
  → 选择会话 / 组装上下文(system + history + memory + skills)
  → 调用 LLM(携带 tools 声明)
  → 解析流式输出
  → 若有 tool_calls:执行工具 → 追加结果 → 回到 LLM
  → 若无 tool_calls:产出最终回答
  → 持久化会话 / 记忆 / 遥测数据

这个流程看似简单,但真实工程的难点集中在四个地方:

  1. provider 兼容层怎么做
  2. tool_call/tool_result 如何保证跨模型兼容
  3. context 怎么控制长度和噪声
  4. loop 在中断、重试、并发下如何保持一致性

2.2 OpenClaw 的完整链路

OpenClaw 是一个平台级的实现,它的调用链路最完整。让我们看看一条消息从用户发出到返回,经历了哪些环节:

User
  |
  | 1) 发送消息
  v
Channel Adapter(解析来源账号/会话键)
  |
  | 2) 路由解析
  v
Route Resolver(命中 agent + session)
  |
  | 3) 进入队列(session lane / global lane)
  v
Embedded Runner(openclaw 核心)
  |
  | 4) 组装上下文(system + history + skills + memory)
  | 5) 创建/恢复 pi session
  v
pi-agent / pi-ai
  |
  | 6) streamSimple(model, context, tools)
  v
LLM Provider
  |
  | 7) 流式返回 text/thinking/toolcall
  v
pi-agent Loop
  |
  | 8) 执行工具(memory_search、exec、web 等)
  | 9) 回填 tool_result,再次请求 LLM
  v
Reply Dispatcher
  |
  | 10) 分块/打字效果/路由回渠道
  v
User

2.3 nanobot 的简化链路

nanobot 走的是轻量路线,链路更直接:

User → Channel → MessageBus(inbound)
     → AgentLoop
     → ContextBuilder
     → LiteLLMProvider.chat(...)
     → [有 tool_calls?]
          → ToolRegistry.execute(...)
          → 追加 tool result
          → 再次调用 LLM
        [无 tool_calls]
          → 返回最终回答
     → MessageBus(outbound) → User

三、三者分别在哪一层

这三个项目不在同一个抽象层,理解它们的定位很重要:

项目 层级 职责
pi-agent + pi-ai 内核层 负责 loop 语义和模型兼容
OpenClaw 平台层 直接嵌入 pi 运行时,补齐路由、调度、会话治理、插件和多渠道
nanobot 平台+内核(轻量复刻) 借鉴 openclaw 的主干思路,用更小代码体量实现完整闭环

读这三个项目,可以按「内核 → 平台 → 轻量复刻」的顺序。这样你能先理解核心机制,再看平台如何包装,最后看如何用最小代码量实现类似能力。


四、内核层:pi-ai + pi-agent

4.1 pi-ai:provider 兼容是核心资产

pi-ai 对外暴露统一的流式接口,内部通过 API 注册表分发到不同的 provider 适配器。这层做了大量细节兼容工作:

这些兼容逻辑集中在适配层,loop 层因此可以保持稳定。

4.2 结构化的事件流

pi-ai 的事件模型包含三类增量事件,最后统一收敛到 done/error:

start
  → text_* 事件(文本输出)
  → thinking_* 事件(思考过程)
  → toolcall_* 事件(工具调用)
  → done / error

这种设计带来几个好处:

  1. 可以把「思考」和「回答」分开展示
  2. 工具参数可以边流边拼,减少大 JSON 一次性解析失败
  3. usage/cost 可在流中累计,便于预算和监控

4.3 pi-agent 的 loop 语义

pi-agent 的 loop 采用双层语义:

它还支持 steering/interruption——工具执行过程中如果用户插入新消息,系统可以跳过剩余工具并写入「skipped」结果,防止旧任务继续污染上下文。这对长任务和多轮工具链很重要。


五、平台层:OpenClaw

OpenClaw 直接复用 pi 的内核,重点解决平台治理问题。

5.1 OpenClaw 新增了哪些能力

OpenClaw 的主要价值在 loop 外围,体现在四个方面:

1. 会话与并发治理

2. 运行生命周期治理

3. 上下文治理

4. 渠道与路由

看完这些能力,就能理解 OpenClaw 为什么会有更大的代码规模。

5.2 工具调用在 OpenClaw 里怎么走

OpenClaw 的工具链采用「组装管线」模式,大致步骤如下:

  1. 组装基础工具(读写编辑、exec/process、web 等)
  2. 追加平台工具(message、sessions、subagents、cron、browser、canvas 等)
  3. 合并插件工具和渠道工具
  4. 按 profile/agent/group/sandbox/subagent 规则做 allow/deny 过滤
  5. 对工具参数 schema 做 provider 兼容清洗(如 Gemini、Claude 兼容)
  6. 包装 before_tool_call / after_tool_call hook
  7. 包装 abort 信号,确保超时中止可传播到工具执行

最后才把这些工具交给 pi 会话。

5.3 工具回填的常见坑

工具回填是 Agent 系统最容易出错的地方。以下是几个常见坑和规避方法:

问题 解决方案
顺序错误 assistant(tool_calls) 必须先入历史,再追加每个 tool_result
ID 不兼容 不同 provider 对 ID 长度和字符集限制不同,需要规范化
空 assistant 部分模型不接受「无内容且无 tool_calls」的消息,构建时要过滤
截断导致孤立 历史压缩后可能出现 orphaned tool_result,调用前要做配对修复
用户中断 执行中收到新消息时,剩余工具应该跳过,避免旧任务继续写上下文

这些细节通常决定系统稳不稳定。

工具回填时序图

User Message
  → LLM
  → assistant(tool_calls)
  → append assistant(tool_calls) to messages
  → for each tool_call:
       → execute tool
       → if success:   tool_result(isError=false)
       → if exception: tool_result(isError=true, error text)
       → append tool_result
  → LLM (next round with updated messages)
  → final assistant reply

回填阶段有两个硬规则:

  1. assistant(tool_calls) 必须先入历史,再追加每个 tool_result
  2. 工具失败也要回填 tool_result,否则下一轮模型缺上下文,容易重复调用或直接报错

5.4 skills 的注册和加载

OpenClaw 的 skills 有明确的来源优先级和筛选机制:

这套机制的核心目标是:让模型能发现可用技能,同时把 token 成本压在可控范围。

5.5 memory 的加载机制

OpenClaw 的 memory 是两条并行机制:

在线检索链

长期沉淀链

这比「只把 MEMORY.md 整文件塞进 prompt」稳定得多。

5.6 heartbeat 的实现

OpenClaw 的 heartbeat 有调度语义:

这种方式更适合长期运行,心跳噪声更低。


六、轻量层:nanobot

nanobot 的定位很清楚:完整能力 + 小体量代码。

6.1 provider 层

nanobot 默认走 LiteLLM,本地保留一层 registry:

这种设计的好处是落地快、维护成本也可控。

6.2 loop 层

nanobot 的 loop 是标准闭环:

它没有实现 pi-agent 那套完整的 steering/follow-up 语义,复杂场景控制能力因此更轻。

6.3 skills 加载

nanobot 的 skills 机制非常直观:

「摘要 + 按需读取」的策略在工程上很有效,尤其适合控制 prompt 膨胀。

6.4 memory 与 heartbeat

实现简单,排查成本低,适合小团队快速迭代。


七、内置工具与自带 Skills

7.1 OpenClaw

内置工具

类别 工具 用途
编码与文件 read、write、edit、exec、process、apply_patch 代码改写与本地自动化
知识与网络 web_search、web_fetch、image、browser、canvas 检索、抓取、页面交互
会话与编排 sessions_*、subagents、cron、message、tts 多会话协作和任务调度
记忆能力 memory_search、memory_get 长期上下文检索(由 memory slot 提供)
平台扩展 nodes、gateway 以及 channel/plugin 注入工具 连接外部系统

自带 Skills

类别 Skills
开发与效率 coding-agent、github、gh-issues、tmux、session-logs、summarize
文档与知识 notion、obsidian、apple-notes、bear-notes、blogwatcher、nano-pdf
通信与协作 discord、slack、imsg、voice-call、bluebubbles
多媒体与创作 openai-image-gen、openai-whisper、video-frames、camsnap、songsee
生活与设备自动化 apple-reminders、things-mac、openhue、spotify-player、sonoscli、weather、food-order
平台与生态 clawhub、skill-creator、wacli、oracle(用于技能管理和系统接入)

主仓库内置技能约 50+,扩展仓库另有 feishu-doc、feishu-drive、feishu-perm、feishu-wiki 等垂直技能。

7.2 nanobot

内置工具

类别 工具 用途
文件与执行 read_file、write_file、edit_file、list_dir、exec 文件操作与命令执行
网络访问 web_search、web_fetch 信息检索与网页抓取
交互与调度 message、spawn、cron 消息发送、子进程、定时任务

可选 MCP 工具可动态接入

自带 Skills

类别 Skills
开发协作 github、tmux
知识处理 summarize、memory
自动化与生态 cron、weather、clawhub、skill-creator

7.3 pi-agent / pi-mono

内置工具

场景 工具
pi-agent-core 不预置具体工具,强调由宿主按场景注入
pi-coding-agent 默认 read、bash、edit、write(覆盖核心编码闭环)
pi-coding-agent 只读 read、grep、find、ls(适合审阅与诊断)

自带 Skills


八、nanobot 的改进方向

作者在体验 nanobot 时,发现 nanobot 目前在个人场景里仍会遇到几类典型失效:

第一类:调用链失效

一次工具调用报错后没有良好的恢复路径,模型容易重复发起相同调用,最后耗尽迭代次数。

第二类:模型链路失效

provider 的边界差异、限流或短时故障出现时,回退和重试策略不够稳,用户看到的就是「同一个问题有时能做、有时直接失败」。

第三类:状态失效

长会话里 memory 与历史上下文逐渐污染,heartbeat 又可能引入噪声,最终表现为「越聊越偏,越跑越不可靠」。

这些问题对个人体验影响很大,一旦 Agent 出现不稳定,很难自行恢复。因为在使用这类 Agent 的场景下,通常并不具备随时运维的条件,比如春节假期用手机在海边写下这篇文章的笔者。

改进路径

内核层应优先借鉴 pi-agent/pi-ai:

直接做成默认能力,减少后期补丁式修复。

运行时层可以借鉴 OpenClaw:

做成统一机制,减少「功能各自可用、组合后失稳」的情况。

这样 nanobot 才能保持轻量,同时真正跨过「个人可生产使用」的门槛。