Hermes Agent 常见问题(深度 FAQ)
以下问题大多可在 Hermes 七天子站 找到交互验证入口:Tool Call Inspector(工具格式与失败链)、Persona Lab(角色漂移)、Code Sandbox(MCP 与沙箱)、课表锚点(按 Day 定位知识点)。
本文不是「一句话百科」,而是 15+ 个生产级 FAQ:每个含背景、机制、决策树、代码或配置片段、与子 站实验的对应关系。按主题分组,便于检索。
格式与协议
Q1:Hermes 格式与 OpenAI Functions 有什么本质区别?能否混用?
背景:OpenAI Functions 把工具定义成 JSON Schema,模型输出结构化 tool_calls 数组;Nous Hermes 系列模型常训练于 XML 风格标签 <tool_call> / <tool_response>,与 ChatML 交织。Claude 则偏 XML tool use。三者 语义相同(name + arguments),序列化不同。
| 维度 | OpenAI Functions | Hermes 标签 | Claude XML |
|---|---|---|---|
| 定义方式 | tools=[{type:function, function:{...}}] | System 内嵌工具说明 + 标签约定 | tools + XML block |
| 模型输出 | message.tool_calls[] | 文本内 <tool_call>{...}</tool_call> | <invoke name="..."> |
| SDK 支持 | 原生 | 需手写 parser 或模板 | Anthropic SDK |
| 适合模型 | GPT-4o、Qwen2.5(API 模式) | Hermes-2-Pro、部分开源 | Claude 3+ |
能 否混用? 不能在同一轮解析路径混用。错误做法:用 OpenAI SDK 绑工具,却跑 Hermes-2-Pro 期望标签输出——会得到纯文本「假 JSON」,解析器 silent fail。
推荐决策:
与子站配合:在 Tool Call Inspector 左侧选格式,粘贴 model_raw,右侧看解析器是否提取 name/arguments。Day 1 Morning 所有对比实验都应在此完成。
实践建议:团队统一 Internal IR(中间表示):无论外层格式,解析后都变成 ToolCall(name, args: dict),再进网关。详见 快速开始 第二、三节双路径。
Q2:Claude XML 与 Hermes 标签谁更易维护?
长期看 OpenAI Functions / 厂商原生 tool_calls 最易维护(SDK 负责边界)。Hermes 标签优势在 开源本地部署 与 训练数据一致性——同一模型从预训练到 SFT 标签一致,函数调用准确率 often 更高。
维护成本对比:
| 格式 | Parser 复杂度 | 流式友好 | 多工具并行 |
|---|---|---|---|
| OpenAI | 低 | 是 | 是 |
| Hermes | 中(正则+JSON 修复) | 需缓冲 | 需约定 |
| Claude XML | 低(SDK) | 是 | 是 |
若 仅一只模型、一个环境,跟模型文档走;若多模型路由, invest in IR 层。
失败处理与可靠性
Q3:工具调用失败怎么办?Retry、Fallback、自我修正如何组合?
失败 taxonomy:
| 类型 | 示例 | 策略 |
|---|---|---|
| 可重试 | 429、503、timeout | 指数退避 Retry ≤3 |
| 参数错误 | 422 validation | 把 error 喂回模型 self-correct 1–2 次 |
| 逻辑错误 | 空结果 | Fallback Tool 或换 query |
| 权限错误 | 403 | 停止 + 用户提示,禁止 blind retry |
| 永久错误 | unknown tool | 开发 bug,告警 |
推荐状态机(Day 1 Evening / Day 4 Afternoon):
async def invoke_with_recovery(tool_fn, args, *, max_retry=3):
for attempt in range(max_retry):
try:
return {"ok": True, "data": await tool_fn(**args)}
except TransientError as e:
await asyncio.sleep(2 ** attempt)
except ValidationError as e:
return {"ok": False, "code": "validation", "message": str(e)}
# Fallback 映射
alt = FALLBACK_MAP.get(tool_fn.__name__)
if alt:
return await invoke_with_recovery(alt, remap_args(args), max_retry=1)
return {"ok": False, "code": "exhausted"}
自我修正 Prompt 片段(Observation 回灌):
工具 search_web 失败:HTTP 400,原因 query 超过 256 字符。
请缩短 query 或改用 read_file 读取用户已上传文档。不要重复相同参数。
反模式:无限 Retry;不向用户暴露最终失败原因;把 stack trace 直接 show 给用户。
子站验证:Code Sandbox 故意注入失败 API,观察 trace 中 Retry/Fallback 计数是否符合预期。