正常直觉里,工具调用越少越简单。
一个工具调用应该比两个工具调用更稳定。
但 NousResearch/hermes-agent issue #15118 里,Hermes Memory provider 正好反过来:
单个 honcho_profile 工具调用:Unknown tool
多个工具调用并发路径:有时正常
这类 bug 特别容易误导用户。因为它看起来像是 Honcho 没配置好、memory provider 不可用、Gateway 没加载工具,甚至像模型乱调用不存在的工具。
但真正原因不是配置,而是 Hermes 内部有两条工具调度路径:
- concurrent path:知道把 memory tools 交给
MemoryManager; - sequential path:漏了
MemoryManager.has_tool()分支,直接掉进主工具 registry。
结果就是:schema 明明注入给模型了,模型也按 schema 调用了,执行时却回一句:
{"error": "Unknown tool: honcho_profile"}
表面现象:honcho_profile 变成 Unknown tool
issue 里的复现非常清楚。
用户按文档配置 Honcho:
hermes memory setup
或者放入有效的:
~/.hermes/honcho.json
配置:
memory:
provider: honcho
recall_mode: hybrid
session JSON 里也能确认:honcho tool schemas 已经注入进 LLM payload。
然后让模型只调用一个工具:
hermes chat -Q --max-turns 2 -q "Call only honcho_profile and report the JSON result verbatim"
实际返回:
┊ ⚡ honcho_pr 0.0s [error]
# tool response: {"error": "Unknown tool: honcho_profile"}
注意,这里最迷惑的是:
工具 schema 存在
模型调用了正确名字
执行时却说 Unknown tool
这会让用户误以为是 Honcho 配置没生效。
真正原因:两个 dispatch path 行为不一致
issue 里把根因拆得很清楚。
Hermes 里有两条工具执行路径:
| Path | 行为 | 是否走 MemoryManager |
_invoke_tool concurrent path | 并发/多工具路径 | ✅ 有 MemoryManager.has_tool() |
_execute_tool_calls_sequential sequential path | 单工具或顺序路径 | ❌ 漏了 memory branch |
问题发生在 sequential path。
当 assistant 只产生一个 tool call,或系统选择 sequential dispatch 时,代码会掉到:
handle_function_call()
而 handle_function_call() 查询的是主工具 registry。
但 honcho_profile、honcho_search、honcho_context、honcho_conclude 这类 memory provider tools 并不注册在主工具 registry,而是由 MemoryManager 管。
所以主 registry 当然会说:
Unknown tool: honcho_profile
为什么多个工具调用反而可能成功?
这就是这个 bug 最反直觉的地方。
如果某一轮 assistant 产生多个工具调用,Hermes 可能走 concurrent path。
而 concurrent path 里有这段逻辑:
elif self._memory_manager and self._memory_manager.has_tool(...):
...
也就是说,多工具并发路径知道要问 MemoryManager。
但单工具 sequential path 没有这段。
于是出现奇怪现象:
同一个 honcho_profile
同一份配置
同一个 provider
一个工具调用失败
多个工具调用有时成功
这也是为什么用户很容易把它误判成“间歇性配置问题”。
schema 注入成功,不代表执行路由成功
这是这篇最值得记住的点。
Hermes memory tools 的生命周期至少分三步:
1. MemoryManager.get_all_tool_schemas() 把工具 schema 注入给模型; 2. 模型在 response 里生成 tool call; 3. Hermes 执行层把 tool call 路由给正确 handler。
#15118 的情况是:
第 1 步成功
第 2 步成功
第 3 步失败
所以你不能只看 LLM payload 里有没有 honcho_profile schema。
也不能只看模型有没有调用正确工具名。
关键要看执行层最终把工具交给谁。
受影响的工具范围
issue 中列出的 memory provider tools 包括:
honcho_profilehoncho_searchhoncho_contexthoncho_conclude- 未来所有 memory-plugin tools
影响范围包括:
- Telegram Gateway;
- Slack Gateway;
- CLI non-interactive chat;
- 任何进入 sequential dispatch 的路径。
这就是为什么用户会以为“这个 gateway 不支持 memory”。
其实不是平台不支持,而是 execution path 没走 MemoryManager。
修复方式:给 sequential path 补上同样的 MemoryManager 分支
issue 建议的 patch 很直接:在 _execute_tool_calls_sequential 里增加和 _invoke_tool 一样的判断。
逻辑类似:
elif self._memory_manager and self._memory_manager.has_tool(function_name):
try:
function_result = self._memory_manager.handle_tool_call(function_name, function_args)
except Exception as tool_error:
function_result = json.dumps({
"error": f"Memory tool '{function_name}' failed: {tool_error}"
})
这样 honcho_profile 就不会掉到主工具 registry,而是交给 MemoryManager。
预期结果从:
{"error": "Unknown tool: honcho_profile"}
变成:
{"result": "No profile facts available yet."}
后续评论:其实 main 已经修过
评论里维护者指出,这个问题已经由 PR #4803 修复,commit 是:
e492420d
commit message:
fix: route memory provider tools in sequential execution path
后续当前 run_agent.py 在两条路径里都有 MemoryManager.has_tool() 分支:
- concurrent
_invoke_tool - sequential
_execute_tool_calls_sequential
issue 报告者的复现 HEAD 是:
29c98e8f
它位于一个还没合入该修复的分支上。
所以最终结论不是“Honcho memory 本身坏了”,而是:
拉最新 main / 升级到包含 #4803 的版本
用户怎么判断自己是否遇到这个 bug?
如果你看到下面组合,就很像 #15118:
memory.provider: honcho
recall_mode: hybrid
LLM payload 里能看到 honcho_* schemas
模型调用 honcho_profile / honcho_search
工具结果却是 Unknown tool: honcho_*
单工具调用更容易复现
多工具调用表现不稳定
这时排查顺序应该是:
1. 先确认版本
确认是否包含:
PR #4803
commit e492420d
或对应 release。
2. 对比单工具与多工具
用单工具 one-shot repro:
hermes chat -Q --max-turns 2 -q "Call only honcho_profile and report the JSON result verbatim"
如果单工具失败,多工具偶尔成功,就很符合 dispatch path 不一致。
3. 不要只检查 schema
schema 注入成功只能证明模型知道工具存在,不能证明执行层会正确路由。
4. 不要先怪 Gateway
Telegram / Slack 只是触发场景。根因在 run_agent.py 的工具执行路径。
和 DeepAI API 中转站的关系
这个问题和模型 API 中转几乎无关。
无论你使用:
- 官方模型 API;
- GitHub Copilot;
- 本地模型;
- DeepAI API 中转站;
- 其他 OpenAI-compatible provider;
只要 Hermes 已经把 honcho_* tool schema 注入给模型,后续失败点就在 Hermes 的 tool dispatch 层。
DeepAI API 中转站可以提供统一模型入口:
Base URL: https://api.deepai.wang/v1
API Key: 你的 DeepAI Key
Model: 以 DeepAI 控制台为准
但它不会改变 Hermes 内部如何把 honcho_profile 路由给 MemoryManager。
所以遇到 Unknown tool: honcho_profile 时,不要第一时间换 DeepAI Key、改 base_url 或怀疑模型。
先看 Hermes 版本和 memory tool dispatch 修复。
FAQ
为什么 schema 明明存在,还会 Unknown tool?
因为 schema 注入和工具执行路由是两步。模型知道工具,不代表 Hermes 执行层把它交给了正确 handler。
为什么单工具调用更容易失败?
单工具调用可能走 sequential dispatch,而旧代码的 sequential path 漏了 MemoryManager.has_tool() 分支。
为什么多个工具调用反而可能成功?
多个工具调用可能走 concurrent path,而 concurrent path 已经包含 MemoryManager 分支。
这是 Honcho 配置问题吗?
不一定。如果 schema 已注入、工具名正确,但执行返回 Unknown tool,更像 Hermes dispatch path 问题。
DeepAI API 中转站会影响 memory tools 吗?
不会直接影响。DeepAI 负责模型 API 入口,memory tools 的执行路由由 Hermes 内部 MemoryManager 和 tool dispatch 决定。
总结
#15118 的教训是:
工具系统不能只保证“模型看得到”,还要保证“执行层找得到”。
Honcho memory tools 已经被注入 schema,模型也能调用正确名字,但旧的 sequential dispatch path 没有把它们路由给 MemoryManager,于是单工具调用反而失败。
这类 bug 的反直觉之处在于:一个工具调用比两个工具调用更容易炸。
修复也很明确:让 sequential path 和 concurrent path 一样,都先检查 MemoryManager.has_tool()。