乐于分享
好东西不私藏

NanoBot源代码详解-2:工具调用

NanoBot源代码详解-2:工具调用

调用工具

在loop.py中,当LLM返回的消息中包含tools_calls时,程序会遍历这些调用请求,并通过self.tools.execute()发起执行。

# loop.py L214-220for tool_call in response.tool_calls:# ... (日志记录)# 调用注册表执行工具    result = await self.tools.execute(tool_call.name, tool_call.arguments)# 将结果添加回消息历史    messages = self.context.add_tool_result(        messages, tool_call.id, tool_call.name, result    )

然后在registry.py中,异步调用

# registry.py L38-60async def execute(self, name: str, params: dict[str, Any]) -> str:    tool = self._tools.get(name) # 1. 查找工具if not tool:return f"Error: Tool '{name}' not found"    try:        errors = tool.validate_params(params) # 2. 参数验证if errors:return ... return await tool.execute(**params) # 3. 执行具体工具逻辑    except Exception as e:return f"Error executing {name}: {str(e)}" # 4. 异常捕获

流程如下图:

系统源代码中已经自带了部分工具:

文件系统工具filesystem.py

包含工具 : ReadFileTool , WriteFileTool , EditFileTool , ListDirTool 主要使用python标准库pthlib.Path进行路径操作和文件IO。

消息发送工具message.py

包含工具MessageTool 依赖nanobot.bus.events.OutboundMessage数据结构,通过回调函数self._send_callback(msg)将消息发送出去。 这个回调函数通常连接到系统的消息总线(MessageBus),最终由具体的适配器(如 Telegram Bot API 或 CLI 输出)处理发送逻辑。

这里回调时,先构造消息事件

msg = OutboundMessage(       channel=target_channel,       chat_id=target_chat_id,       content=content   )

然后异步回调

await self._send_callback(msg)

这个回调函数的发起在loop.py中,而实现在bus/queue.py中的publish_outbound方法中。

Sell命令执行工具shell.py

包含工具ExecTool,使用Python的asyncio库进行异步子进程管理。 调用 asyncio.create_subprocess_shell(command, …) 来启动 Shell 进程。 使用 process.communicate() 获取标准输出 (stdout) 和标准错误 (stderr)。_guard_command 方法,使用正则表达式( re 模块)拦截高危命令(如 rm -rf , format , dd 等)和路径遍历攻击。

也就是说如果你可以将某些命令加入黑名单deny_patterns,禁止其运行。也可以加入白名单allow_patterns

self.deny_patterns = deny_patterns or [          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      ]

基于正则的命令过滤 ( _guard_command ) 本质上是脆弱的,可以通过字符串拼接,编码等绕过。所以这里是有安全漏洞的。

子Agent生成工具spawn.py

用于创建后台任务(子Agent)。 它本身不执行复杂逻辑,而是代理调用 self._manager.spawn(...) 。 SubagentManager (在 nanobot.agent.subagent 中定义)负责实例化新的 AgentLoop 并在后台运行。

async def execute(self, task: str, label: str | None = None, **kwargs: Any) -> str:"""Spawn a subagent to execute the given task."""return await self._manager.spawn(            task=task,            label=label,            origin_channel=self._origin_channel,            origin_chat_id=self._origin_chat_id,        )

网络工具web.py

提供网络搜索和网页抓取功能。 包含工具 : WebSearchTool , WebFetchTool 使用 httpx (异步 HTTP 客户端)和 readability-lxml (网页内容提取)库。

WebSearchTool封装了Brave Search API,

async def execute(self, query: str, count: int | None = None, **kwargs: Any) -> str:if not self.api_key:return "Error: BRAVE_API_KEY not configured"        try:            n = min(max(count or self.max_results, 1), 10)            async with httpx.AsyncClient() as client:                r = await client.get("https://api.search.brave.com/res/v1/web/search",                    params={"q": query, "count": n},                    headers={"Accept""application/json""X-Subscription-Token": self.api_key},timeout=10.0                )                r.raise_for_status()            results = r.json().get("web", {}).get("results", [])      ...

如果需要封装其它的搜索引擎,可以在这里修改,比如我想将Brave修改成我喜欢的Tavily,就得修改这里的URL。如果需要定制化,可以在这里增加多种搜索引擎。

任务调度工具cron.py

定义了一个名为 CronTool 的工具类,该类赋予了 Agent 安排提醒和重复性任务的能力。它是 Nanobot 任务调度系统与 LLM 之间的桥梁。 这里只有_add_job(添加任务)、_list_jobs(列出任务)和_remove_job(删除任务)的函数,主要是管理任务。而具体的实现在 nanobat/cron/service.py中CronService。

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » NanoBot源代码详解-2:工具调用

评论 抢沙发

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