乐于分享
好东西不私藏

源码拆解|工具系统与子 agent;如何把 nanobot 改造成你的 AI 产品

源码拆解|工具系统与子 agent;如何把 nanobot 改造成你的 AI 产品

这是系列文章的第 4 篇。

前面我拆解了 nanobot 的技术架构,它如何实现 Agent Loop,长期记忆,以及集成 Skills。

现在,我会重点拆它的工具系统(tools)与子 agent(subagent)。

随后,我会讨论如何把它当成可读的最小内核,融入到我们的生产级 AI 产品中。

我想用两个视角把它说清楚。

  • nanobot 已经做对了什么,这些你应该保留

  • 你必须补齐什么,不补齐,上生产很容易翻车

最后,给出一份 12 个改造点的落地清单。

PART 01|工具系统,ToolRegistry + JSON Schema 是扩展的底座

nanobot 的工具系统更像一个最小的 function calling runtime。

  • 每个工具是一个 Tool 子类

  • 用 JSON Schema 定义参数

  • ToolRegistry 统一注册与执行

在 nanobot/agent/tools/base.py 里,工具 schema 的出口是 to_schema()。

def to_schema(self) -> dict[strAny]:    return {        "type""function",        "function": {            "name"self.name,            "description"self.description,            "parameters"self.parameters,        }    }

在 nanobot/agent/tools/registry.py 里,关键在两件事。

  • 参数校验(validate_params)

  • 捕获异常,返回字符串错误,不让主 loop 直接崩

errors = tool.validate_params(params)if errors:    return f"Error: Invalid parameters for tool '{name}': " + "; ".join(errors)return await tool.execute(**params)

这套结构很适合嵌进产品。

你可以用同样的 registry 接入自己的工具,无论是数据库查询、工单系统、企业知识库,还是内部 API。

PART 02|提供默认工具,刚刚够用

在 nanobot/agent/loop.py 的 _register_default_tools() 里,nanobot 默认注册了一组通用生产力工具。

  • 文件工具,read_file / write_file / edit_file / list_dir

  • 命令工具,exec

  • 网络工具,web_search / web_fetch

  • 消息工具,message

  • 子 agent,spawn

  • 定时任务,cron(可选,取决于是否启用 cron service)

这组工具满足了一个 agent 内核最基础的闭环,能看、能写、能跑、能查、能通知、能拆分任务

如果你做产品,应该保留这种克制。工具多不是优势,工具的边界清晰才是优势。

PART 03|工具的安全边界,restrict_to_workspace 只是起点

nanobot 已经做了一些安全默认值。

比如文件工具在 nanobot/agent/tools/filesystem.py 里通过 allowed_dir 做路径限制。

resolved = Path(path).expanduser().resolve()if allowed_dir and not str(resolved).startswith(str(allowed_dir.resolve())):    raise PermissionError(f"Path {path} is outside allowed directory {allowed_dir}")

再比如 exec 工具在 nanobot/agent/tools/shell.py 里有 deny patterns(禁止 rm -rf 等危险命令)。

self.deny_patterns = [    r"\brm\s+-[rf]{1,2}\b",          # rm -r, rm -rf, rm -fr    r"\bdel\s+/[fq]\b",              # del /f, del /q    r"\brmdir\s+/s\b",               # rmdir /s    r"\b(format|mkfs|diskpart)\b",   # disk operations    r"\bdd\s+if=",                   # dd    r">\s*/dev/sd",                  # write to disk    r"\b(shutdown|reboot|poweroff)\b",  # system power    r":\(\)\s*\{.*\};\s*:",          # fork bomb]

这些都很有用。但如果你要上生产,我更愿意把它理解成最低配防线,不是最终答案。

生产里你需要更硬的隔离。

容器 sandbox、受控文件系统、网络 egress 控制、命令 allowlist、审计日志、权限审批(approval),一个都少不了。

PART 04|spawn 子 agent,把复杂任务拆成后台任务

nanobot 的 subagent 机制值得一提。

在 nanobot/agent/tools/spawn.py 里,spawn 工具只是把一个 task 丢给 SubagentManager。

return await self._manager.spawn(    task=task,    label=label,    origin_channel=self._origin_channel,    origin_chat_id=self._origin_chat_id,)

真正的关键在 nanobot/agent/subagent.py。

  • subagent 运行在后台 asyncio.create_task

  • subagent 自己也会调用模型 + 工具,但工具集被刻意限制

  • subagent 不能直接发消息给用户,只能把结果注入成 system message 交回主 agent

它的回传设计很巧妙。

msg = InboundMessage(    channel="system",    sender_id="subagent",    chat_id=f"{origin['channel']}:{origin['chat_id']}",    content=announce_content,)await self.bus.publish_inbound(msg)

主 agent 收到 system message 后,会在 _process_system_message()里解析 chat_id,把结果路由回原对话。

这套机制的价值在于,它没有引入复杂的分布式队列,也没有强行实现并行推理。它只是把任务放到后台去做,同时还能回传、能追溯

PART 05|MCP,把外部工具生态变成原生工具

nanobot v0.1.4 里加入 MCP 支持,信号很明确,扩展正在协议化。

在 nanobot/agent/tools/mcp.py 里,nanobot 会把 MCP server 的 tool 包装成一个本地 Tool。

self._name = f"mcp_{server_name}_{tool_def.name}"

然后在 AgentLoop 启动时做懒连接(lazy connect)。

if self._mcp_connected or not self._mcp_servers:    returnawait connect_mcp_servers(self._mcp_servers, self.tools, self._mcp_stack)

这对产品化很关键。你不用把所有工具都写进代码库,可以通过协议接入更多服务能力。

但同样,生产里你要非常小心。MCP 工具相当于外部执行面,权限、隔离、审计、供应链安全,一个都不能少。

PART 06|如何做生产级改造

以下为 12 个改造点,可供参考。

1)多租户隔离,workspace、sessions、memory 全部按 tenant 切分

现在默认 workspace 是一个目录,session_key 是 `channel:chat_id`。产品化后要加 tenant 维度,否则会出现跨用户数据污染。

2)权限系统,工具调用必须过 policy

把 ToolRegistry.execute() 前面加一道策略层。哪些用户能用 exec,能不能 web_fetch,能不能读某个目录,都别靠 prompt 去赌。  

不要指望 prompt 约束。

3)审批流(approval),高风险工具一律需要确认

企业里最现实的形态很常见,模型提议(propose),人确认(approve),系统执行(execute)。  

exec、写文件、对外发消息,都应该可审批。

4)更硬的 sandbox,容器隔离 + 网络 egress 控制

deny_patterns 更像文档级安全,sandbox 才是系统级安全。

5)观测与审计,每次 LLM 调用、每次 tool 调用都要可追溯

建议做 structured logging,request_id、session_id、tool_name、duration、tokens、cost。  

没有审计的 agent,在企业里不可用。

6)成本预算,把 max_iterations 变成多维预算

迭代上限只是其一。你还需要 token budget、web 调用次数、exec 次数、外部 API 次数、总 cost cap。

7)幂等与去重,渠道消息必须处理重复投递

真实渠道会重试、会乱序。你需要 message_id 去重与“至少一次投递”语义下的幂等处理。

8)并发与取消,任何长任务都必须可取消

用户关闭窗口、撤回消息、系统升级,都应该能 cancel 正在跑的 tool 和子任务。

9)记忆治理,PII 脱敏 + schema 化 + 冲突处理

MEMORY.md 很灵活,但企业里更需要结构化字段、脱敏规则、版本控制(避免并发覆盖)。

10)技能治理,技能市场必须有签名/白名单/审核

技能是给模型看的说明书,也是潜在的供应链入口。生产里要做治理。

11)回退与降级,provider 不稳定时要自动切换

LiteLLM 把多 provider 接入简化了,但产品里你还需要 fallback 策略,比如超时、限流、错误码处理。

12)测试与回归,给工具系统和关键链路补自动化测试

至少把这些变成可测试项。ContextBuilder、ToolRegistry 参数校验、session 持久化、memory consolidation 的 JSON 解析、exec guard。

PART 07|我建议的落地路径

具体怎么开始呢?我的建议是三步走。

  1. 先做隔离与权限,workspace、tenant、tool policy、审批流

  2. 再做观测与预算,trace、审计、成本护栏

  3. 最后做扩展与生态,MCP、技能市场、业务 connector

你会发现一个规律,先把边界做硬,后面你接的工具多了,系统还是会很稳健。

至此,nanobot 源码拆解系列文章写完了。

我们可以看到,nanobot 并没有替你把所有功能都做完。它的价值在于用极简的代码,把一套 agent 系统的关键骨架写清楚了,loop、tools、memory、skills、subagents、bus。

剩下的事,交给你,把它变成你的产品的一部分。

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » 源码拆解|工具系统与子 agent;如何把 nanobot 改造成你的 AI 产品

评论 抢沙发

4 + 9 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮