Agent 调用工具时,不只会看用户的话,也会看工具 schema。参数名、描述、示例值,都会进入模型上下文,影响模型对“应该怎么用这个工具”的判断。
NousResearch/hermes-agent issue `#22013` 记录了一个很典型的问题:用户并没有安装 Claude Code、Claude Desktop,也没有主动要求使用 Claude 相关工具,但 Hermes Agent 在复杂 delegation 场景里偶发尝试走 Claude ACP / Claude Code 这类路径,最终产生错误。
表面上看,这是“模型乱调用工具”。更准确地说,这是工具定义里的示例和描述对模型产生了 schema priming:delegate_task 的 acp_command / acp_args 参数里把 claude、Claude Code 写成显眼示例,导致模型在选择子代理 harness 时被引向并不存在的 Claude 平台。
现象:没有 Claude 环境,却尝试调用 Claude ACP
issue 中的用户描述是:在一些复杂任务线程里,Hermes Agent 会尝试使用类似:
Claude ACP
Claude Desktop
Claude Code
claude --acp --stdio
但用户的环境里并没有这些工具,也没有把 Claude 平台接入 Hermes。
这类问题通常不是每次都稳定复现。它更容易出现在:
- 长任务;
- 多步骤任务;
- 子代理 delegation;
- 需要判断“用哪个 agent harness”的模糊场景;
- 模型在多个工具参数之间做选择时。
简单 delegation 可能不会出错,但只要模型开始推理“我应该开一个什么样的 child agent”,工具 schema 中的示例值就可能变成强提示。
根因:工具参数描述本身在提示模型
issue 中指出,delegate_task 工具 schema 暴露了两个和 ACP 相关的参数:
acp_command
acp_args
其中旧描述包含类似内容:
Override ACP command for child agents (e.g. 'claude', 'copilot')
Enables spawning Claude Code (claude --acp --stdio)
这类描述对人类来说只是例子,但对 LLM 来说,它也是上下文里的高权重 token。
当模型需要决定 acp_command 写什么时,schema 已经给了它一个非常具体的候选项:
claude
并且还补充了可执行形态:
claude --acp --stdio
如果用户环境没有 Claude,这个示例仍然存在于工具定义里,模型就可能误以为这是可用、推荐或默认的 delegation 方式。
为什么禁用 skill 不一定有效?
issue 中有个关键判断:禁用 claude-code skill 只能阻止相关 skill 被加载,但不能删除 core tool schema 里的 acp_command / acp_args 描述。
也就是说:
skill disabled
↓
Claude skill 不加载
↓
但 delegate_task 的 ACP 参数仍然出现在工具 schema
↓
模型仍能看到 claude 示例
↓
复杂场景里仍可能被示例值带偏
这说明问题不在某个 skill,而在 framework-level tool definition。
工具定义如果对某个生态做了强示例,就会形成默认偏见。即使平台没有安装,模型也可能被提示文本引导过去。
schema priming:工具描述也是 prompt 的一部分
很多人排查 Agent 工具误调用时,只看用户 prompt 和模型输出,容易忽略工具 schema。
但对函数调用模型来说,工具定义通常包含:
- tool name;
- description;
- parameter name;
- parameter description;
- enum / default;
- example;
- constraints;
- 禁止事项。
这些内容都会参与模型决策。
如果一个参数写着:
acp_command: e.g. 'claude', 'copilot'
模型就会把 claude 和 copilot 视为高可用候选。
如果又写着:
Enables spawning Claude Code
那么 Claude 的权重会进一步升高。
这就是 schema priming:并不是模型凭空幻想,而是工具定义给了它方向。
维护者反馈:旧描述已在 #19055 中调整
issue 评论中,维护者提到这类 priming surface 已在 `#19055` / commit 69692039e 中处理,并随 v2026.5.7 发布:
current schema lists only 'copilot' as the example
and removes the Claude Code reference
但用户随后贴出的 delegate_task 工具描述仍然包含:
(e.g. 'claude', 'copilot')
Enables spawning Claude Code (claude --acp --stdio)
这说明实际环境里可能还有版本、安装路径或生成 schema 不一致的问题。
因此排查时不能只看 release note,还要看当前会话里模型实际看到的 tool schema。
排查清单:如何确认是不是 tool schema 带偏?
遇到 Agent 尝试调用不存在的 Claude / Copilot / ACP harness,可以按这个顺序查。
1. 查看 Hermes 版本
hermes --version
确认是否至少在包含相关 schema 修复的版本之后。
2. 打印当前会话里的 delegate_task 描述
让 Agent 输出它实际看到的 delegate_task tool schema,重点看:
acp_command
acp_args
claude
Claude Code
copilot
--acp --stdio
不要只看源码文件,也不要只看文档。模型真正看到的 schema 才是关键。
3. 检查 $PATH 里是否真的有相关 CLI
例如:
which claude
which copilot
如果 binary 不存在,工具层不应该默认尝试该 harness。
4. 检查是否有多份安装或旧文件残留
有时版本号已经更新,但实际加载的文件来自旧路径,例如:
~/.hermes/hermes-agent
pipx env
系统 Python site-packages
开发版 checkout
5. 检查 tool schema 生成路径
如果源码里已经改掉,但运行时 schema 仍是旧文本,说明 schema 可能来自缓存、打包文件或另一份安装。
更好的工具定义应该怎么写?
对 delegate_task 这种通用子代理工具,参数描述最好避免把某个厂商工具写成“首选示例”。
较好的表达方式是:
acp_command: Optional ACP-compatible command, only use when the user has explicitly configured or requested that harness.
而不是:
acp_command: e.g. claude, copilot; enables Claude Code...
如果一定要给例子,也应该更中性:
Examples depend on installed ACP-compatible CLIs. Do not infer availability from this schema.
同时,工具层可以增加硬约束:
只有检测到可执行文件存在,才暴露对应 example;
未配置 ACP harness 时隐藏 acp_command;
参数描述中明确“不要调用未安装命令”;
运行前校验 command 是否在 allowlist 或 PATH 中。
这能从根上减少模型被示例值带偏。
为什么这个问题适合放在“工具可用性”而不是“模型幻觉”里?
把它简单归为 hallucination 不够准确。
模型确实做出了错误选择,但它的错误输入来自工具定义。工具 schema 提供了:
参数名:acp_command
示例值:claude
能力描述:Claude Code
默认参数:--acp --stdio
在没有更强约束的情况下,模型把这些当成可用路径并不意外。
更客观的归因是:
工具 schema 把某个未必存在的 ACP harness 写得太像默认选项;
模型在复杂 delegation 推理中被这个 schema 诱导;
运行环境没有对应 CLI,于是调用失败。
外链与进一步阅读
- GitHub issue:`NousResearch/hermes-agent #22013`
- Hermes Agent 项目:`NousResearch/hermes-agent`
- ACP 相关背景可参考 Agent Client Protocol 项目与各类 ACP-capable CLI 的实现说明。
站内相关分析:
- `/reload-mcp 一按就卡死:Hermes CLI 为什么会在确认框里等不到回车?`
- `Hermes terminal 误拦截 setsid:安全过滤为什么不能只靠全文正则`
- `DeepSeek Anthropic-compatible API 第二轮 HTTP 400:为什么 thinking blocks 不能被一刀切剥掉?`
与 DeepAI API 中转站的关系:减少工具层与模型层的误导
很多开发者会把 Hermes、Cline、Cherry Studio、Dify、Open WebUI 等工具接到统一的 OpenAI-compatible 入口,例如 DeepAI API 中转站,用来管理 Base URL、API Key、模型路由和多模型切换。
这类统一入口能解决“模型从哪里来、密钥怎么管、路由怎么切”的问题。但 Agent 工具链还需要额外注意:
工具 schema 是否会诱导错误 harness;
模型 ID 是否与工具能力匹配;
ACP / MCP / terminal tool 是否真的安装;
子代理 delegation 是否需要显式配置;
OpenAI-compatible endpoint 与 Anthropic-compatible endpoint 是否混用。
也就是说,模型 API 层可以统一,工具执行层仍然要做可用性校验和清晰描述。否则即使模型路由配置正确,Agent 也可能因为工具 schema 的示例而尝试不存在的本地程序。
FAQ
为什么 Agent 会调用我没安装的 Claude?
因为旧 delegate_task schema 里把 claude 和 Claude Code 写成显眼示例。模型在复杂 delegation 场景中可能把示例误当成可用 harness。
禁用 Claude skill 为什么还不够?
禁用 skill 只影响 skill 加载,不一定会移除 core tool schema 中的 acp_command / acp_args 参数描述。
怎么确认当前 schema 是否还有 Claude 引用?
让 Agent 打印当前会话里它看到的 delegate_task tool description,重点搜索 claude、Claude Code、acp_command、acp_args。
这个问题是模型幻觉吗?
更准确地说是 schema priming。模型确实做了错误决策,但工具 schema 给了它强烈的错误候选。
最稳的修复是什么?
工具定义应避免把未必安装的厂商 CLI 写成默认示例;ACP 参数应在未配置 harness 时隐藏或弱化;运行前还应校验命令是否存在。
总结
#22013 的核心不是“Claude 相关工具坏了”,而是:
delegate_task 的工具 schema 把 claude / Claude Code 写成高权重示例,导致模型在 delegation 场景中倾向调用用户并未安装的 ACP harness。
这类问题提醒我们:Agent 的工具 schema 本身就是 prompt。参数示例、默认值和描述措辞都会影响模型行为。
要减少这类误调用,不能只靠用户配置禁用 skill,还要从 tool definition、runtime capability detection、PATH 校验、内置示例和模型可见上下文一起收紧。