Technical Guide
09. Tools 源码:registry、toolsets、tool_executor 怎么配合
按源码文件拆解 Hermes 工具从注册、发现、筛选到执行的完整链路。
这篇解决什么问题
上一篇讲 Tools 的概念,这一篇看源码。
目标不是把每个工具都读完,而是看懂工具系统的骨架。看懂骨架后,再读 terminal_tool.py、web_tools.py、file_tools.py 才不会乱。
先看 tools/registry.py
tools/registry.py 是中央注册表。
文件注释里已经说明了导入链路:
tools/registry.py
↑
tools/*.py 通过 registry.register 注册
↑
model_tools.py 导入 registry 和所有工具模块
↑
run_agent.py / cli.py / batch_runner.py 使用 model_tools
这句话基本就是工具系统地图。
registry.register 做什么
每个工具文件会在模块顶层调用 registry.register()。
注册内容包括:
name 工具名
toolset 所属工具集
schema 给模型看的参数说明
handler 实际执行函数
check_fn 可用性检查
requires_env 依赖环境变量
比如 tools/web_tools.py 会注册 web_search 和 web_extract。
tools/terminal_tool.py 会注册 terminal。
discover_builtin_tools 怎么工作
registry.py 里有 discover_builtin_tools()。
它会扫描 tools/ 目录,找包含顶层 registry.register(...) 的 Python 文件,然后 import 这些模块。
import 的副作用就是完成注册。
这是一种常见插件式设计:工具文件自己声明自己,中央模块只负责发现。
toolsets.py 负责分组
toolsets.py 里有 _HERMES_CORE_TOOLS 和 TOOLSETS。
_HERMES_CORE_TOOLS 是 CLI 和消息平台共享的核心工具列表,里面包括:
web_search / web_extract
terminal / process
read_file / write_file / patch / search_files
vision_analyze / image_generate
skills_list / skill_view / skill_manage
browser_* 系列
todo / memory / session_search
clarify / execute_code / delegate_task / cronjob
TOOLSETS 则定义工具分组,例如:
web
search
vision
terminal
skills
browser
cronjob
file
tts
model_tools.py 是薄编排层
model_tools.py 文件注释说得很清楚:它是工具 registry 上的一层薄编排。
主要公开 API 包括:
get_tool_definitions(...)
handle_function_call(...)
get_all_tool_names()
get_toolset_for_tool(name)
check_tool_availability(...)
其中最关键是两个:
get_tool_definitions 给模型准备工具 schema
handle_function_call 按工具名执行 handler
tool_executor.py 负责执行策略
agent/tool_executor.py 处理工具调用执行。
它关心的是:
- 顺序执行还是并发执行;
- 工具调用被中断怎么办;
- 工具结果怎么包装成 tool message;
- 工具输出太大怎么办;
- 执行过程怎么展示;
- destructive command 是否要审批。
所以它不关心 web_search 内部怎么搜。它关心的是“模型发来了这一批 tool_calls,我怎么安全、稳定地执行完”。
一条源码链路
把几个文件串起来:
tools/web_tools.py
→ registry.register(name="web_search", ...)
→ model_tools.discover_builtin_tools()
→ registry.get_definitions()
→ model_tools.get_tool_definitions()
→ AIAgent 把 schema 发给模型
→ 模型返回 web_search tool_call
→ agent/tool_executor.py 执行
→ model_tools.handle_function_call("web_search", args)
→ registry.dispatch / handler
→ 工具结果回到 messages
这条线看懂,就能自己加工具。
新增工具应该改哪里
通常只需要:
1. 新建 tools/your_tool.py
2. 在文件里实现 handler
3. 调用 registry.register(...)
4. 如果要纳入某个默认 toolset,更新 toolsets.py
5. 写 check_fn,避免依赖缺失时暴露工具
不要直接在 Agent loop 里硬塞特殊工具逻辑。
下一篇看什么
下一篇看 Skills。
Tools 解决“能做什么”,Skills 解决“遇到某类任务时应该怎么做”。