结论先说Hermes 的 tools 架构是“注册表 toolset 暴露 agent 执行器”的三层结构不是简单把tools/目录里所有函数都塞给模型。核心链路工具发现tools/registry.py 会扫描tools/*.py只导入存在顶层registry.register(...)的模块。导入本身触发注册。工具注册表tools/registry.py 的ToolRegistry保存name、toolset、OpenAI tool schema、handler、check_fn、env 需求、是否 async、emoji、结果大小限制等。schema 生成model_tools.py 的get_tool_definitions()根据启用/禁用的 toolsets 生成最终给模型看的 tools。真正计算在 model_tools.py。toolset 决定“模型看不看得到”toolsets.py 的_HERMES_CORE_TOOLS是默认核心工具集合。toolsets.py 的hermes-cli等平台 toolset 再组合这些工具。关键点工具文件自注册只表示 registry 知道它必须在 toolset 中解析出来模型才看得到。Agent 初始化加载 toolsagent/agent_init.py 调get_tool_definitions()然后把工具名放进agent.valid_tool_names。模型发 tool call 后执行并发/顺序执行入口在 agent/tool_executor.py 和 agent/tool_executor.py。单个工具调用会走 agent/agent_runtime_helpers.py。普通 registry 工具最终走 model_tools.py 的handle_function_call()和 tools/registry.py 的dispatch()。当前实际注册内容我本地导入后看到 71 个工具按 toolset 大致是web:web_search,web_extractterminal:terminal,processfile:read_file,write_file,patch,search_filesbrowser: navigate/click/type/scroll/snapshot/console/vision/images 等browser-cdp:browser_cdp,browser_dialogvision:vision_analyzeimage_gen:image_generatevideo:video_analyzevideo_gen:video_generatetts:text_to_speechcode_execution:execute_codedelegation:delegate_tasktodo,memory,session_search,clarifycronjobmessaging:send_messagehomeassistantdiscord,discord_adminfeishu_doc,feishu_driveyuanbaokanbancomputer_usemoa:mixture_of_agentsskills:skills_list,skill_view,skill_managex_search插件带来的spotify_*注意这个数量包含 repo 内插件发现后注册的工具不等于纯tools/目录文件数。代表性写法文件工具是最标准的例子tools/file_tools.py。每个工具通常有registry.register(nameread_file,toolsetfile,schemaREAD_FILE_SCHEMA,handler_handle_read_file,check_fn_check_file_reqs,emoji...,max_result_size_chars100_000,)Web 工具展示了 async handlertools/web_tools.py。Terminal 工具展示了复杂 schema、后台进程、超时、PTY、通知等tools/terminal_tool.py。handler 必须返回 JSON 字符串。辅助函数在 tools/registry.py 和 tools/registry.py也就是tool_error()/tool_result()。插件与 MCP自定义或本地工具按项目规则不应该优先改核心tools/而应该走插件。插件通过 hermes_cli/plugins.py 的ctx.register_tool()注册底层仍然进入同一个 registry。MCP 工具也是动态注册进 registrytools/mcp_tool.py。MCP 会用mcp-server作为 toolset并注册别名tools/mcp_tool.py。一个重要变化MCP discovery 不再是model_tools.py的导入副作用注释写在 model_tools.py。各入口要自己显式发现避免 gateway 事件循环被慢 MCP 卡住。工具启用方式平台级启用配置在 hermes_cli/tools_config.py。CLI 在 cli.py 读取当前平台启用 toolsets。Gateway 在 gateway/run.py 按平台加载。TUI 在 tui_gateway/server.py 也有自己的加载函数。实际用户侧就是hermes tools/ setup 保存到platform_toolsets再由_get_platform_tools()转成 enabled toolsets。几个关键坑todo、memory、session_search、delegate_task虽然注册在 registry但属于 agent-level tools会被 agent loop 特殊处理直接走普通handle_function_call()会被拦model_tools.py。check_fn有 30 秒 TTL 缓存tools/registry.py。改 env/config 后不是每次立即生效。discover_builtin_tools()只识别模块顶层registry.register(...)。如果把注册藏在函数里自动发现不会导入它。注册同名工具默认会被拒绝插件要有意覆盖必须overrideTruetools/registry.py。大输出不是简单截断。执行器会把超大结果持久化到 sandbox 文件再给模型预览tools/tool_result_storage.py整轮预算控制在 tools/tool_result_storage.py。TOOL_TO_TOOLSET_MAP在 model_tools.py 是 discovery 后构建的兼容常量动态 MCP/插件刷新后优先信 registry 实时查询不要过度依赖旧常量。我对架构的评价整体设计是对的registry 解耦工具实现toolset 控制暴露面agent executor 负责权限、并发、结果预算、插件 hook。这比“每个入口手写工具列表”稳很多。但也有明显技术债browser_tool.py、terminal_tool.py、code_execution_tool.py都偏巨型模块toolset 静态配置也比较长平台差异容易漂移。后续如果要继续扩展最好坚持插件路线并把核心大工具按 backend/schema/handler/guardrail 拆小而不是继续往单文件里堆。换一种方式讲Hermes 的 tools 系统本质上不是“工具目录”而是一个给 LLM 建立可控行动空间的运行时协议层。也就是说它解决的不是“Python 怎么调用函数”而是这几个更深的问题这个 agent 此刻允许做什么模型看到的动作空间如何被压缩、过滤、动态修正模型发来的 tool call 如何变成可信、可审计、可中断、可并发、可限流的真实操作外部插件、MCP、平台专属能力如何接进来但不污染核心工具结果如何返回给模型而不把上下文撑爆所以它的内核可以抽象成这条链工具实现 ↓ 注册 Registry系统知道有哪些能力 ↓ 选择 Toolset本轮/本平台允许暴露哪些能力 ↓ Schema model_tools把能力翻译成模型 API 能理解的 JSON Schema ↓ 模型决策 LLM 输出 tool_call ↓ 执行器 Agent runtime / tool_executor校验、审批、并发、拦截、调用 ↓ 返回 结果预算、持久化、插件 hook、写回 conversation真正的核心不是tools/而是“能力从存在到可见再到可执行”的分层控制。第一层工具存在不等于模型能用比如 tools/file_tools.py 注册了read_file/write_file/patch/search_files。这一步只是告诉 registry系统里有这么几个函数它们叫什么、schema 是什么、handler 是什么、属于哪个 toolset。但是模型并不会自动看到它们。模型是否看到要看 toolsets.py 里的工具集合以及平台配置最终启用了哪些 toolsets。这就是 Hermes 的第一个重要设计能力注册和能力暴露分离。为什么要分离因为 Hermes 不是只有 CLI。它还有 gateway、TUI、ACP、cron、API server、Discord、Feishu、Home Assistant 等入口。不同入口的风险边界不同CLI 可以用 terminalACP 要更偏代码编辑API server 不适合 interactive clarifyDiscord 可以额外暴露 Discord 工具某些工具只有 env/key 存在时才应该出现所以 registry 回答的是系统会什么toolset 回答的是这个场景允许模型做什么这两个问题不能混在一起。第二层schema 不是文档是模型的操作界面model_tools.py 的get_tool_definitions()很关键。它不是简单返回 registry 里的 schema而是在做“模型可见世界”的最终裁剪。比如enabled toolsets 解析成具体工具名disabled toolsets 再做减法check_fn失败的工具被隐藏execute_code的 schema 会根据当前实际可用工具重建browser schema 会在 web 工具不可用时移除误导描述Discord schema 会根据 bot 权限动态变化最后还要做 schema sanitizer兼容不同模型后端这说明一件事tool schema 是行为约束不只是说明书。对 LLM 来说它看到的 schema 就是它能采取行动的边界。如果 schema 里说“你可以调用 web_search”但实际 web_search 不可用模型就会被误导。因此 Hermes 做了很多动态修正目的就是让模型的“认知地图”和真实运行时尽量一致。这是深层内核之一工具系统不是给人看的 API而是给模型看的可行动作空间。第三层handler 不是直接执行而是进入管控管线模型发出 tool call 后不是直接handler(args)。先进入 agent/tool_executor.py 或顺序路径再到 agent/agent_runtime_helpers.py。这里开始有真正的 agent runtime 语义解析模型参数修复错误工具名检查 interruption触发插件pre_tool_call做 guardrail文件修改前 checkpointdestructive terminal command 前 checkpoint多个 tool call 可以并发执行工具执行中可以回调 UI 显示状态执行结果会被预算控制最后 append 成 tool message 回 conversation也就是说Hermes 的 tool call 不是普通函数调用而是一个事务化的 agent action。这个 action 需要考虑能不能执行怎么展示给用户怎么被中断怎么被审计失败怎么反馈输出太大怎么办多工具并发时顺序怎么保持插件能不能阻止或改写结果这就是为什么代码看起来厚。它厚不是因为“调用函数复杂”而是因为它在把 LLM 的不稳定输出包进一个相对可靠的执行环境。第四层有些工具是假 registry 工具真 agent 工具这个点很容易误解。model_tools.py 里有_AGENT_LOOP_TOOLS{todo,memory,session_search,delegate_task}这些工具虽然也注册 schema让模型能看见但执行时不能普通 dispatch。因为它们需要 agent 内部状态todo需要当前 agent 的 todo storememory需要 memory store / memory managersession_search需要当前 session DBdelegate_task需要当前 agent 的 delegation runtime所以它们是“对模型暴露为工具”但真实执行属于 agent loop。这揭示了另一个内核工具系统不是纯函数系统它承载 agent 状态。普通工具像web_search输入 query 输出 JSON。agent-level 工具像delegate_task会影响运行时结构甚至生成子 agent。所以 Hermes 的 tools 里混合了两类能力纯外部能力web/file/browser/terminal/tts 运行时能力memory/todo/delegation/session_search前者是“做事”。后者是“改变 agent 自己如何做事”。第五层结果不是直接塞回上下文LLM 工具系统最容易炸的地方是工具返回太多内容。Hermes 在 tools/tool_result_storage.py 做了一个很重要的设计大结果持久化。逻辑是工具返回内容 ↓ 如果小直接进上下文 ↓ 如果大写入 sandbox 文件 ↓ 上下文里只放 preview 文件路径 ↓ 模型需要细节时再 read_file 分页读取这其实是给 LLM 做“外部记忆分页”。否则一次search_files、terminal、web_extract就可能把上下文塞爆。所以 tool result storage 不是优化项而是 Hermes 能持续长任务的基础设施。第六层插件/MCP 是同一套能力模型的外延插件的ctx.register_tool()最终还是进 registryhermes_cli/plugins.py。MCP 工具也是转成 registry entrytools/mcp_tool.py。这说明 Hermes 没有给插件/MCP 另起一套调用机制而是把它们全部归一到name toolset schema handler check_fn这很好因为 agent runtime 不需要关心工具来自哪里。坏处是registry 成了一个非常关键的全局能力总线。它必须处理名字冲突toolset aliasMCP 动态刷新插件覆盖内置工具check_fn 缓存schema 兼容性所以 tools/registry.py 的ToolRegistry不是普通 map而是 Hermes 的“能力注册中心”。如果用一句话概括Hermes tools 的深层内核是把 LLM 的文本决策约束成一个动态、可配置、可审计、可中断、可扩展的行动系统。不是“模型调用 Python 函数”。而是“模型在一个被 Hermes 精心裁剪过的行动空间里选择动作然后 Hermes runtime 负责把动作安全地落地”。你读代码时可以这样分层看不要从browser_tool.py这种大文件开始读会被淹没。建议按这个顺序看注册协议tools/registry.py看暴露策略toolsets.py看 schema 生成model_tools.py看 tool call 执行agent/agent_runtime_helpers.py看并发和结果处理agent/tool_executor.py最后才看具体工具比如tools/file_tools.pytools/terminal_tool.py你可以把它想成一个操作系统的小内核registry 设备表 toolsets 权限/能力配置 schema 系统调用 ABI tool call 用户态请求 executor 内核调度器 handler 驱动实现 result store I/O 缓冲和分页 plugins/MCP 外接设备这个类比比“工具函数列表”更接近 Hermes tools 的真实结构。