知识引擎/Hermes 知识引擎/工具运行时(Tools Runtime)

原文链接:Tools Runtime sidebar position: 9 title: "Tools Runtime" description: "Runtime behavior of the tool registry, toolsets, dispatch, and terminal environments

> 原文链接:Tools Runtime


sidebar_position: 9 title: "Tools Runtime" description: "Runtime behavior of the tool registry, toolsets, dispatch, and terminal environments"

工具运行时(Tools Runtime)

Hermes 工具是自注册的函数,按工具集(Toolset)分组,通过中央注册表/分发系统执行。

主要文件:

  • tools/registry.py
  • model_tools.py
  • toolsets.py
  • tools/terminal_tool.py
  • tools/environments/*

工具注册模型

每个工具模块在导入时调用 registry.register(...)

model_tools.py 负责导入/发现工具模块并构建模型使用的 Schema 列表。

registry.register() 的工作原理

tools/ 中的每个工具文件在模块级别调用 registry.register() 来声明自己。函数签名如下:

registry.register(
    name="terminal",               # 唯一工具名(用于 API Schema)
    toolset="terminal",            # 此工具所属的工具集
    schema={...},                  # OpenAI function-calling schema(描述、参数)
    handler=handle_terminal,       # 工具被调用时执行的函数
    check_fn=check_terminal,       # 可选:返回 True/False 表示可用性
    requires_env=["SOME_VAR"],     # 可选:需要的环境变量(用于 UI 显示)
    is_async=False,                # 处理程序是否为异步协程
    description="运行命令",         # 人类可读描述
    emoji="💻",                    # 用于旋转器/进度显示的表情符号
)

每次调用创建一个 ToolEntry,存储在单例 ToolRegistry._tools 字典中,以工具名为键。如果跨工具集出现名称冲突,会记录警告,后注册的优先。

发现:discover_builtin_tools()

model_tools.py 被导入时,它调用 tools/registry.py 中的 discover_builtin_tools()。此函数使用 AST 解析扫描每个 tools/*.py 文件,找到包含顶层 registry.register() 调用的模块,然后导入它们:

# tools/registry.py(简化版)
def discover_builtin_tools(tools_dir=None):
    tools_path = Path(tools_dir) if tools_dir else Path(__file__).parent
    for path in sorted(tools_path.glob("*.py")):
        if path.name in {"__init__.py", "registry.py", "mcp_tool.py"}:
            continue
        if _module_registers_tools(path):  # AST 检查顶层 registry.register()
            importlib.import_module(f"tools.{path.stem}")

这种自动发现意味着新的工具文件会被自动识别——无需维护手动列表。AST 检查只匹配顶层的 registry.register() 调用(不匹配函数内部的调用),因此 tools/ 中的辅助模块不会被导入。

每次导入触发模块的 registry.register() 调用。可选工具中的错误(例如图像生成缺少 fal_client)会被捕获并记录——它们不会阻止其他工具加载。

在核心工具发现之后,MCP 工具和插件工具也会被发现:

  1. MCP 工具tools.mcp_tool.discover_mcp_tools() 读取 MCP 服务器配置并注册来自外部服务器的工具。
  2. 插件工具hermes_cli.plugins.discover_plugins() 加载用户/项目/pip 插件,这些插件可能注册额外的工具。

工具可用性检查(check_fn

每个工具可以选择性地提供一个 check_fn——一个可调用对象,在工具可用时返回 True,否则返回 False。典型检查包括:

  • API 密钥存在 — 例如 lambda: bool(os.environ.get("SERP_API_KEY")) 用于网页搜索
  • 服务运行中 — 例如检查 Honcho 服务器是否已配置
  • 二进制已安装 — 例如验证浏览器工具的 playwright 是否可用

registry.get_definitions() 构建模型的 Schema 列表时,它运行每个工具的 check_fn()

# registry.py 简化版
if entry.check_fn:
    try:
        available = bool(entry.check_fn())
    except Exception:
        available = False   # 异常 = 不可用
    if not available:
        continue            # 跳过此工具

关键行为:

  • 检查结果每次调用缓存——如果多个工具共享相同的 check_fn,它只运行一次。
  • check_fn() 中的异常被视为"不可用"(安全失败)。
  • is_toolset_available() 方法检查工具集的 check_fn 是否通过,用于 UI 显示和工具集解析。

工具集解析

工具集(Toolsets)是工具的命名集合。Hermes 通过以下方式解析它们:

  • 显式启用/禁用的工具集列表
  • 平台预设(hermes-clihermes-telegram 等)
  • 动态 MCP 工具集
  • 精选的特殊用途集合如 hermes-acp

get_tool_definitions() 如何过滤工具

主入口点是 model_tools.get_tool_definitions(enabled_toolsets, disabled_toolsets, quiet_mode)

  1. 如果提供了 enabled_toolsets — 仅包含来自这些工具集的工具。每个工具集名称通过 resolve_toolset() 解析,将复合工具集展开为单独的工具名称。

  2. 如果提供了 disabled_toolsets — 从所有工具集开始,然后减去禁用的。

  3. 如果两者都未提供 — 包含所有已知工具集。

  4. 注册表过滤 — 解析后的工具名称集合传递给 registry.get_definitions(),应用 check_fn 过滤并返回 OpenAI 格式的 Schema。

  5. 动态 Schema 修补 — 过滤后,execute_codebrowser_navigate 的 Schema 会被动态调整,仅引用实际通过过滤的工具(防止模型幻觉出不可用的工具)。

旧版工具集名称

带有 _tools 后缀的旧版工具集名称(例如 web_toolsterminal_tools)通过 _LEGACY_TOOLSET_MAP 映射到其现代工具名称,以实现向后兼容。

分发(Dispatch)

运行时,工具通过中央注册表分发,部分 Agent 级别的工具(如 memory/todo/session-search 处理)由 Agent 循环直接处理。

分发流程:模型 tool_call → 处理程序执行

当模型返回 tool_call 时,流程如下:

带有 tool_call 的模型响应
    ↓
run_agent.py Agent 循环
    ↓
model_tools.handle_function_call(name, args, task_id, user_task)
    ↓
[Agent 循环工具?] → 由 Agent 循环直接处理(todo、memory、session_search、delegate_task)
    ↓
[插件前置钩子] → invoke_hook("pre_tool_call", ...)
    ↓
registry.dispatch(name, args, **kwargs)
    ↓
按名称查找 ToolEntry
    ↓
[异步处理程序?] → 通过 _run_async() 桥接
[同步处理程序?]  → 直接调用
    ↓
返回结果字符串(或 JSON 错误)
    ↓
[插件后置钩子] → invoke_hook("post_tool_call", ...)

错误包装

所有工具执行在两个级别进行错误处理:

  1. registry.dispatch() — 捕获处理程序的任何异常并返回 {"error": "Tool execution failed: ExceptionType: message"} 作为 JSON。

  2. handle_function_call() — 在二级 try/except 中包装整个分发,返回 {"error": "Error executing tool_name: message"}

这确保模型始终收到格式良好的 JSON 字符串,永远不会出现未处理的异常。

Agent 循环工具

四个工具在注册表分发之前被拦截,因为它们需要 Agent 级别的状态(TodoStore、MemoryStore 等):

  • todo — 规划/任务跟踪
  • memory — 持久化记忆写入
  • session_search — 跨会话召回
  • delegate_task — 生成子 Agent 会话

这些工具的 Schema 仍然在注册表中注册(用于 get_tool_definitions),但如果分发某种原因直接到达它们,其处理程序会返回一个占位错误。

异步桥接

当工具处理程序是异步的时,_run_async() 将其桥接到同步分发路径:

  • CLI 路径(无运行中的循环) — 使用持久化事件循环保持缓存的异步客户端存活
  • 网关路径(运行中的循环) — 使用 asyncio.run() 启动一次性线程
  • 工作线程(并行工具) — 使用存储在线程本地存储中的每线程持久化循环

DANGEROUS_PATTERNS 审批流程

终端工具集成了一个危险命令审批系统,定义在 tools/approval.py 中:

  1. 模式检测DANGEROUS_PATTERNS 是一个 (regex, description) 元组列表,覆盖破坏性操作:

    • 递归删除(rm -rf
    • 文件系统格式化(mkfsdd
    • SQL 破坏性操作(DROP TABLE、没有 WHEREDELETE FROM
    • 系统配置覆盖(> /etc/
    • 服务操纵(systemctl stop
    • 远程代码执行(curl | sh
    • Fork 炸弹、进程终止等
  2. 检测 — 在执行任何终端命令之前,detect_dangerous_command(command) 对照所有模式进行检查。

  3. 审批提示 — 如果发现匹配:

    • CLI 模式 — 交互式提示要求用户批准、拒绝或永久允许
    • 网关模式 — 异步审批回调将请求发送到消息平台
    • 智能审批 — 可选地,辅助 LLM 可以自动批准匹配模式但风险低的命令(例如 rm -rf node_modules/ 是安全的但匹配"递归删除")
  4. 会话状态 — 审批按会话跟踪。一旦你为某个会话批准了"递归删除",后续的 rm -rf 命令不会再次提示。

  5. 永久白名单 — "永久允许"选项将模式写入 config.yamlcommand_allowlist,跨会话持久化。

终端/运行时环境

终端系统支持多种后端:

  • local
  • docker
  • ssh
  • singularity
  • modal
  • daytona

它还支持:

  • 每任务的 cwd 覆盖
  • 后台进程管理
  • PTY 模式
  • 危险命令的审批回调

并发

工具调用可能根据工具组合和交互需求顺序或并发执行。

相关文档

Continue Exploring

继续探索

这不是课程式的上一篇下一篇,而是从当前节点向外继续漫游。

参考

工具集参考

工具集(Toolsets)是工具的命名捆绑包,控制 Agent 能做什么。它们是按平台、按会话或按任务配置工具可用性的主要机制。 每个工具恰好属于一个工具集。当你启用一个工具集时,该捆绑包中的所有工具都对 Agent 可用。工具集分为三类: 核心(Core) — 一组相关工具的逻辑分组(例如,file 捆绑了 read

参考

内置工具参考

原文链接:Built-in Tools Reference 本文档记录了 Hermes 工具注册表中的全部 47 个内置工具,按工具集(Toolset)分组。工具的可用性因平台、凭证和已启用的工具集而异。 快速统计: 10 个浏览器工具、4 个文件工具、10 个强化学习(RL)工具、4 个 Home Assistant

开发者指南

Agent 循环内部机制

sidebar position: 3 title: "Agent 循环内部机制" description: "AIAgent 执行、API 模式、工具、回调和回退行为的详细解析" 核心编排引擎是 run agent.py 中的 AIAgent 类——大约 10,700 行代码,负责从 Prompt(提示词)组装到工具

开发者指南

ACP 内部机制

原文链接:ACP Internals sidebar position: 2 title: "ACP Internals" description: "How the ACP adapter works: lifecycle, sessions, event bridge, approvals, and tool re

开发者指南

架构

本页面是 Hermes Agent 内部结构的顶层地图. 使用它来了解代码库的整体结构,然后深入子系统文档获取实现细节。 如果你是首次接触此代码库: 1. 本页面 — 了解整体结构 2. Agent 循环内部机制 — AIAgent 如何工作 3. 提示词组装 — 系统提示词构建

开发者指南

贡献指南

感谢你对 Hermes Agent 的贡献!本指南涵盖开发环境设置、理解代码库以及如何让你的 PR 被合并。 我们按以下顺序重视贡献: 1. Bug 修复 — 崩溃、不正确行为、数据丢失 2. 跨平台兼容性 — macOS、不同 Linux 发行版、WSL2 3. 安全加固 — Shell 注入、Prompt 注入、路

Developer Guide

开发者指南

面向二次开发者,解释架构、运行时、上下文引擎、插件、工具与扩展机制。

20 篇文档20 个节点

当前节点

工具运行时(Tools Runtime)

同主题继续探索

架构

本页面是 Hermes Agent 内部结构的顶层地图. 使用它来了解代码库的整体结构,然后深入子系统文档获取实现细节。 如果你是首次接触此代码库: 1. 本页面 — 了解整体结构 2. Agent 循环内部机制 — AIAgent 如何工作 3. 提示词组装 — 系统提示词构建

贡献指南

感谢你对 Hermes Agent 的贡献!本指南涵盖开发环境设置、理解代码库以及如何让你的 PR 被合并。 我们按以下顺序重视贡献: 1. Bug 修复 — 崩溃、不正确行为、数据丢失 2. 跨平台兼容性 — macOS、不同 Linux 发行版、WSL2 3. 安全加固 — Shell 注入、Prompt 注入、路

Agent 循环内部机制

sidebar position: 3 title: "Agent 循环内部机制" description: "AIAgent 执行、API 模式、工具、回调和回退行为的详细解析" 核心编排引擎是 run agent.py 中的 AIAgent 类——大约 10,700 行代码,负责从 Prompt(提示词)组装到工具

提示词组装

sidebar position: 5 title: "提示词组装" description: "Hermes 如何构建系统提示词、保持缓存稳定性和注入临时层" Hermes 刻意将以下两者分离: - 缓存的系统提示词状态 - 临时的 API 调用时添加内容 这是项目中最关键的设计决策之一,因为它影响:

上下文压缩与缓存

Hermes Agent 使用双重压缩系统和 Anthropic 提示词缓存,在长对话中高效管理上下文窗口的使用。 源文件:agent/context engine.py(ABC)、agent/context compressor.py(默认引擎)、agent/prompt caching.py、gateway/run

网关内部机制

sidebar position: 7 title: "网关内部机制" description: "消息网关如何启动、授权用户、路由会话和投递消息" 消息网关是一个长运行进程,通过统一架构将 Hermes 连接到 14+ 个外部消息平台。 当消息从任何平台到达时: 1. 平台适配器 接收原始事件,将其规范化为 Mess

相关节点

工具集参考

工具集(Toolsets)是工具的命名捆绑包,控制 Agent 能做什么。它们是按平台、按会话或按任务配置工具可用性的主要机制。 每个工具恰好属于一个工具集。当你启用一个工具集时,该捆绑包中的所有工具都对 Agent 可用。工具集分为三类: 核心(Core) — 一组相关工具的逻辑分组(例如,file 捆绑了 read

内置工具参考

原文链接:Built-in Tools Reference 本文档记录了 Hermes 工具注册表中的全部 47 个内置工具,按工具集(Toolset)分组。工具的可用性因平台、凭证和已启用的工具集而异。 快速统计: 10 个浏览器工具、4 个文件工具、10 个强化学习(RL)工具、4 个 Home Assistant

Agent 循环内部机制

sidebar position: 3 title: "Agent 循环内部机制" description: "AIAgent 执行、API 模式、工具、回调和回退行为的详细解析" 核心编排引擎是 run agent.py 中的 AIAgent 类——大约 10,700 行代码,负责从 Prompt(提示词)组装到工具

ACP 内部机制

原文链接:ACP Internals sidebar position: 2 title: "ACP Internals" description: "How the ACP adapter works: lifecycle, sessions, event bridge, approvals, and tool re

架构

本页面是 Hermes Agent 内部结构的顶层地图. 使用它来了解代码库的整体结构,然后深入子系统文档获取实现细节。 如果你是首次接触此代码库: 1. 本页面 — 了解整体结构 2. Agent 循环内部机制 — AIAgent 如何工作 3. 提示词组装 — 系统提示词构建

贡献指南

感谢你对 Hermes Agent 的贡献!本指南涵盖开发环境设置、理解代码库以及如何让你的 PR 被合并。 我们按以下顺序重视贡献: 1. Bug 修复 — 崩溃、不正确行为、数据丢失 2. 跨平台兼容性 — macOS、不同 Linux 发行版、WSL2 3. 安全加固 — Shell 注入、Prompt 注入、路