05 - 工具注册与分发
学习目标
本章聚焦 Hermes Agent 的工具系统。你将了解:
ToolRegistry模块化单例如何实现自动注册- 工具集(toolset)分发如何通过
includes递归组合 - 五层审批门如何检测破坏性操作
- 七种终端后端的隔离策略
前置知识
本章涉及工具调用的通用原理,建议先阅读:
下文直接聚焦 Hermes 的工具注册与分发实现。
项目实践
工具注册表:模块化单例
tools/registry.py(约 590 行)是模块级单例:
class ToolRegistry: def register(name, toolset, schema, handler, ...) # 注册工具 def get_definitions(tool_names, quiet) -> List[dict] # 获取 schema def dispatch(name, args, **kwargs) -> str # 分发执行自动注册:每个 tools/*.py 文件在 import 时调用 registry.register(),无需手动维护导入列表。依赖链:
tools/registry.py (无依赖) ↑tools/*.py (import 时自动注册) ↑model_tools.py (触发工具发现) ↑run_agent.py / cli.py / gateway/run.py线程安全:注册使用 RLock,check_fn 有 30 秒 TTL 缓存,避免每次查询外部状态。
工具集(Toolset)分发
toolsets.py 定义 TOOLSETS 字典,支持 includes 递归组合:
TOOLSETS = { "messaging": { "description": "基础消息平台工具", "tools": ["web_search", "read_file", "write_file", ...], "includes": ["terminal", "file"], # 递归解析 }, # ... 27 个 toolset}特殊别名:
all/*:解析为所有 toolset 中所有工具的并集hermes-webhook:仅包含web_search、web_extract、vision_analyze、clarify(不可信源安全子集)hermes-acp:编辑器专用,不包含消息/音频/clarify
默认核心包:_HERMES_CORE_TOOLS 包含 40+ 工具,所有平台的基础 toolset 都继承自它。修改一次 _HERMES_CORE_TOOLS,所有平台自动更新。
五层审批门
tools/approval.py(约 62558 行)实现五层检测:
| 层级 | 检测内容 | 可绕过? |
|---|---|---|
| Hardline | rm -rf /、mkfs、fork bomb、dd 到块设备、shutdown/reboot | 不可(yolo 模式也不行) |
| Sudo stdin guard | 阻止密码猜测攻击 | 不可 |
| DANGEROUS_PATTERNS | ~47 个模式(递归删除、chmod 777、SQL DROP 等) | 用户确认 |
| Smart Approval | 辅助 LLM 评估风险 | 用户确认 |
| Tirith | 外部安全扫描 | 用户确认 |
批准持久化:用户可选择 once / session / always 三级批准,永久 allowlist 保存到 config.yaml。
七种终端后端
tools/environments/ 提供七种终端后端:
| 后端 | 隔离级别 | 适用场景 |
|---|---|---|
| 本地(默认) | 无 | 信任 LLM 的个人开发 |
| Docker | 容器隔离 | 项目级隔离 |
| SSH | 远程主机 | 远程执行 |
| Singularity | HPC 容器 | 科研计算 |
| Modal | 云函数 | 无服务器持久化 |
| Daytona | 云沙箱 | 无服务器持久化 |
| Vercel Sandbox | 云沙箱 | 低成本闲置 |
安全含义:终端后端隔离仅覆盖通过 shell/文件操作执行的内容,不覆盖 Python 进程内的代码执行工具(作为宿主子进程运行)、MCP 子进程、插件加载或技能加载。
问题与规避
工具 Schema 膨胀
问题:40+ 工具的 schema 会占用大量 token,尤其是包含详细参数描述时。
对策:每个平台使用不同的 toolset,只加载该平台需要的工具。hermes-webhook 安全子集仅 4 个工具。
审批门的图灵完备性
问题:Shell 是图灵完备的,字符串模式匹配不可能覆盖所有破坏性操作。
对策:Hermes 明确将审批门定位为”合作模式下的错误捕捉”,不是对抗性防护。对抗性场景需要 OS 级隔离(Docker/OpenShell)。
工具注册的导入时序陷阱
问题:discover_plugins() 只作为导入 model_tools.py 的副作用运行。不导入 model_tools.py 的代码路径无法看到插件工具。
对策:需要读取插件状态的代码必须先显式调用 discover_plugins()(该函数是幂等的)。
设计取舍
自动注册 vs 显式注册
| 方案 | 优势 | 代价 |
|---|---|---|
| 自动注册(Hermes) | 新增工具只需创建文件 + 注册调用,无需修改中央列表 | 导入时序依赖、隐式行为 |
| 显式注册 | 导入顺序可控、行为可预测 | 每次新增工具需修改中央文件 |
Hermes 选择自动注册,因为工具数量多(40+),手动维护中央列表容易遗漏。代价是需要理解导入时序。
参考来源
- 源码验证:
tools/registry.py、toolsets.py、tools/approval.py、tools/terminal_tool.py、tools/environments/