2.5. 工具调度机制让同一个 Agent 服务于多个前端

工具调度机制让同一个 Agent 服务于多个前端

2026 年初,一家小型 SaaS 团队在给产品接 AI 能力时遇到了一个典型的工程难题。他们的用户分散在 Slack、网页端和 Discord 上,每个端都希望用自然语言执行相同的操作——生成报表、查询库存、触发一条工作流。最初的做法是给每个端写一个独立的 Agent 实例,3 个端就是 3 套推理逻辑、3 套工具封装。两个月后,维护成本开始失控:一个工具的参数变更要改三遍,模型升级要改三遍,就连 prompt 里的措辞调整也要同步到三份代码里。

这不是个例。Agent 从"单终端玩具"迈向"生产级智能体"时,首先要过的坎就是如何让一套推理能力被多个交互方式复用。Hermes Agent 的工具调度机制(Tool Dispatch)正是为此设计的。它不是简单地把工具列表暴露给不同前端,而是在 Agent 的"大脑"(推理循环)与"手脚"(工具执行)之间插入了一层标准化的调度抽象,让同一个 Agent 实例可以同时服务于 CLI、Web 面板、聊天 API、消息网关等任意数量的调用方——每一侧看到的能力集合、安全边界和错误反馈都可以不同,但底层共享同一套工具实现。

核心结论:Tool Dispatch 的核心价值不是"能调用工具",而是"用同一种方式描述、校验和追踪来自不同前端的工具调用"。它把"谁在调用""能调什么""调用后怎么反馈"这三个问题彻底解耦,形成一条从请求到执行再到日志的工业级流水线。


工具注册表与发现

在 Hermes Agent 的工具系统里,一个工具要能被调度,首先必须被注册。注册不是简单的名字登记,而是一套携带元数据的自描述协议。

每个工具通过装饰器或配置类声明自己的身份信息:

  • 工具名称(name):唯一标识符,用于在调度时匹配;
  • 描述(description):自然语言说明,直接影响模型推理时的工具选择准确率;
  • 参数 Schema(parameters):JSON Schema 格式的参数定义,决定输入如何校验;
  • 所属工具集(toolset):逻辑分组,按平台或业务域归类;
  • 权限标签(permissions):标记是否需要审批、是否能写文件、是否需要容器隔离等。

注册后的工具被放入一个全局的工具注册表,这是一个在 Agent 启动时构建的内存索引。它的核心职责只有两件:"按名查找"和"按平台过滤"

以下是工具注册表的结构示意:

字段 类型 作用 示例
name str 工具唯一标识 read_file
description str 供 LLM 推理使用的功能描述 读取指定路径的文件内容
parameters JSON Schema 定义输入格式与约束 {"type":"object","properties":{...}}
toolset str 逻辑分组 filesystem
platforms list[str] 允许使用该工具的前端列表 ["cli","web","discord"]
requires_approval bool 是否需要人工审批 true
timeout int 执行超时(秒) 30

工具发现的过程也因此变得简单:当一个前端(比如 Discord Bot)通过消息网关向 Agent 发起请求时,调度层会从注册表中拉取所有 platforms 包含 discord 的工具,生成该端专属的工具清单,注入到推理上下文中。模型看见的只是它被允许调用的工具子集,而不是整个注册表。

从当前调研资料看,Hermes 文档中明确提到"工具集可以按平台启用或禁用",这证实了平台级过滤是注册表的核心能力。截至 2026 年 4 月,其内置工具注册表已涵盖网页搜索、浏览器自动化、终端执行、文件编辑、记忆、委派、RL 训练、消息投递、Home Assistant 等 70+ 工具。

这种设计解决了多前端场景下的第一个矛盾:不同调用方对工具的需求和安全要求是不同的。CLI 可能需要全部文件操作权限,而 Discord 应该被严格限制在只读查询和消息发送。工具注册表 + 平台过滤提供了声明式的权限边界。


参数模式与校验流程

有了注册表,调度层知道"有哪些工具"和"谁能调用它们"。但工具被调用时,参数是否正确、类型是否匹配、必填项是否缺失——这些问题不能依赖调用方自觉,更不能依赖模型不犯错。

Hermes Agent 采用了 JSON Schema 驱动的自动校验。每个工具在注册时已经声明了参数 Schema,调度层在执行前会自动完成一轮校验。流程如下:

  1. 模型根据上下文推理,决定调用某个工具,并以 JSON 格式传回参数;
  2. 调度层截获这个 JSON,与工具注册表中的 parameters Schema 进行匹配;
  3. 校验通过,参数被标准化后传给工具函数;
  4. 校验失败,生成结构化的错误对象,回传模型进行修正或直接返回调用方。

关键点在于:校验发生在工具函数被真正调用之前。这意味着无论来自哪个前端的请求,都会走同一条校验管道,而且校验规则由工具定义者(而非调用方)决定。

以下是一个典型的参数校验状态流转表:

阶段 操作 成功 失败处理
模型输出 生成工具调用 JSON 进入校验
Schema 校验 对照 parameters 检查类型与必填项 参数标准化,进入执行 生成 ValidationError,回传模型重试
权限检查 判断调用方是否在该工具的 platforms 列表中 进入执行 返回 PermissionError,终止本次调用
执行 调用工具函数 返回结果 捕获异常,生成 ToolExecutionError
结果回传 将执行结果注入模型上下文 模型继续推理 模型根据错误描述调整策略

作者的结论:参数 Schema 不仅是文档,更是调度层的"契约"。它让工具开发者和 Agent 编排者各自独立工作——开发者只需维护 Schema 和函数体,编排者只需配置平台权限。调用方的多样性不再传导到工具实现层。

值得注意的是,Hermes 的工具系统还支持动态工具——通过 MCP(Model Context Protocol)协议连接的外部工具服务器。这些外部工具同样会暴露参数 Schema,调度层对它们的校验流程与内置工具完全一致,只是在执行时通过 MCP 客户端转发请求。这意味着即使是第三方的、运行在独立进程中的工具,也能被纳入同一个校验体系。


调用链追踪与错误处理

多前端并发场景下,最后一个棘手的问题是:出错了怎么办,从哪里定位

当一个来自 Telegram 的请求触发了工具调用链 search_web → read_page → generate_summary,其中第二步超时时报错,开发者需要知道:

  • 错误发生在哪个工具?
  • 是哪个前端的哪个会话触发的?
  • 模型收到了什么错误信息,又是如何反应的?

Hermes Agent 的调度层通过调用链追踪(Call Chain Tracing)机制解决了这个问题。每一次工具调用都被封装为一个 ToolCall 对象,携带唯一的 call_id、时间戳、调用方标识和父子关系指针,形成一个可追溯的执行树。

追踪字段 内容 用途
call_id UUID 全局唯一标识一次工具调用
parent_call_id UUID 指向触发本次调用的上层调用
frontend_id str 标识来自哪个前端(如 discord_bot_01
session_id str 标识属于哪个对话会话
tool_name str 被调用的工具名
input JSON 标准化后的输入参数
output JSON / null 执行结果或错误对象
started_at datetime 调用开始时间
finished_at datetime / null 调用结束时间
status enum pending / success / error / timeout

这些追踪数据有两类消费者:

  • 实时消费者:错误发生时,调度层将 ToolCall 的错误信息格式化后注入模型上下文,让 Agent 自己判断是重试、换用其他工具还是向用户道歉。
  • 异步消费者:日志系统将追踪数据写入持久化存储,供开发者事后复盘和统计工具调用成功率。

在错误处理策略上,Hermes 的调度层采用了分层降级的设计:

  1. 校验层错误(参数不合法):直接返回错误描述,模型自行修正;
  2. 权限层错误(该前端无权限):返回安全提示,模型不会获得任何系统内部信息;
  3. 执行层错误(工具内部异常或超时):捕获并包装为结构化错误对象,模型可以感知错误原因但无法直接访问系统堆栈;
  4. 致命错误(进程级崩溃):由容器或沙箱机制兜底,保证其他并发调用不受影响。

从当前调研资料看,Hermes Agent 的安全模块包含命令审批、授权和容器隔离。这为分层错误处理提供了底层支撑——即使某个前端触发的工具调用发生了最坏情况,也只会影响隔离环境内部的子进程,不会扩散到其他前端的并发调用。


总结与适用场景

Tool Dispatch 的本质是把 Agent 的工具执行路径拆成了三个独立的关注点:

  • 谁能调 → 注册表 + 平台过滤
  • 怎么调才是对的 → JSON Schema + 自动校验
  • 调完怎么反馈和溯源 → 调用链追踪 + 分层错误处理

这让同一套工具实现可以服务于多个前端,且每个前端的权限、错误反馈和追踪链路都得到精细控制。

对比维度 无调度层的做法 Hermes Tool Dispatch
工具注册 散落在各端的代码中,重复定义 统一注册表,声明式元数据
参数校验 各端各自实现,标准不一 JSON Schema 集中校验
权限控制 依赖各端自己的 if-else 注册表级 platform 过滤
错误溯源 日志分散,难以跨端追踪 统一 call_id + 调用树
新增前端 需要复制整套工具逻辑 只在配置中增加 platform 声明
作者的结论 适合原型和单端场景 3 个以上前端时,维护成本差异显著

按场景推荐

  • 仅有 1 个前端(如纯 CLI 使用):调度层的价值主要在于校验和追踪,复杂度可控,建议保留注册表但无需 platform 过滤配置。
  • 2-3 个前端(如 CLI + Web + 一个消息平台):此时调度层开始体现优势,建议严格划分 platform 权限并建立追踪日志。
  • 多平台网关场景(5+ 个前端,含 Telegram、Discord、Slack、WhatsApp 等):调度层是唯一可维护的方案。Hermes 内置的消息网关已原生支持 20+ 平台,此时 Tool Dispatch 的复用价值最大化。

在下一章《多终端后端让 Hermes 可以无缝融入现有基础设施》中,我们将看到工具调度机制的上游——Agent 实例本身是如何启动的。无论是 CLI 命令行、REST Gateway 还是嵌入到现有 Python 服务中,Hermes 的三种启动模式让同一套推理+调度逻辑不再受制于部署形态。调度层解决了"调谁、怎么调"的问题,启动层要解决的则是"Agent 本身长在什么地方"。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~