## 问题现象 在 Hermes Agent 中把模型切换到 `claude-opus-4-7` 后,请求直接失败: ```text HTTP 400: custom.input_schema: JSON schema is invalid. It must match JSON Schema draft 2020-12 ``` 同一套工具 schema 在 `gpt-5.5` 等模型上正常,但在 Claude/Anthropic 兼容接口上报错。 ## 初步判断 报错信息指向: ```text custom.input_schema ``` 也就是 **tool/function 的 input schema** 不被 Claude 的工具调用校验器接受。 这类问题通常不是模型本身不可用,而是某个 tool 的 JSON Schema 写法在某些后端比较宽松,在 Anthropic/Claude 兼容后端比较严格。 ## 排查方法 ### 1. 导出当前 Hermes 工具列表 Hermes 的工具定义会经过: ```text tools/registry.py model_tools.py schema_sanitizer.py ``` 最终生成 OpenAI 格式的 tools: ```json { "type": "function", "function": { "name": "xxx", "description": "...", "parameters": { "type": "object", "properties": {} } } } ``` ### 2. 单独测试每一个 tool 把当前工具逐个提交给 `claude-opus-4-7`,定位到底哪些 schema 会触发 400。 最终发现报错工具包括: ```text browser_back browser_console browser_get_images browser_snapshot delegate_task send_message session_search skills_list todo ``` 这些工具的共同点是:`parameters` 或嵌套对象里存在 object schema,但没有显式声明 `required`。 例如: ```json { "type": "object", "properties": {} } ``` 或者: ```json { "type": "object", "properties": { "query": { "type": "string" } } } ``` ## 根因 JSON Schema Draft 2020-12 中,`required` 字段是可以省略的。 也就是说: ```json { "type": "object", "properties": {} } ``` 从标准 JSON Schema 角度看是合法的。 但 Anthropic/Claude 的 tool input schema 校验器更严格,实际要求 object schema 必须显式带上 `required` 数组。 如果没有必填字段,也要写成: ```json { "type": "object", "properties": {}, "required": [] } ``` 所以问题不是 schema 完全非法,而是 Claude 工具调用接口对 schema 有额外兼容要求。 ## 解决方法 在 Hermes 的 schema sanitizer 里,对所有 object schema 自动补上: ```json "required": [] ``` 前提是该 object schema 有 `properties`,但没有合法的 `required` 数组。 修改文件: ```text tools/schema_sanitizer.py ``` 核心逻辑: ```python def ensure_object_required_arrays(schema: Any) -> Any: """Add required: [] to every object schema missing it.""" if isinstance(schema, list): return [ensure_object_required_arrays(item) for item in schema] if not isinstance(schema, dict): return schema out = dict(schema) if out.get("type") == "object" and isinstance(out.get("properties"), dict): required = out.get("required") if not isinstance(required, list) or not all(isinstance(item, str) for item in required): out["required"] = [] for key, value in list(out.items()): if key in {"properties", "$defs", "definitions"} and isinstance(value, dict): out[key] = { sub_key: ensure_object_required_arrays(sub_value) for sub_key, sub_value in value.items() } elif key in {"items", "additionalProperties"}: if not isinstance(value, bool): out[key] = ensure_object_required_arrays(value) elif key in {"anyOf", "oneOf", "allOf"} and isinstance(value, list): out[key] = [ensure_object_required_arrays(item) for item in value] return out ``` 然后在 sanitizer 流程中调用: ```python fn["parameters"] = ensure_object_required_arrays(fn["parameters"]) ``` ## 验证结果 修复前,多个工具单独发送给 `claude-opus-4-7` 会返回 400。 修复后: ```text TOOL_COUNT 30 MISSING_REQUIRED_OBJECTS 0 CLAUDE_OPUS_4_7_ALL_TOOLS 200 OK ``` 也就是说,当前 30 个工具一起提交给 `claude-opus-4-7` 已经可以正常通过。 ## 经验总结 1. OpenAI/GPT 兼容接口能接受的 schema,不代表 Claude/Anthropic 兼容接口一定接受。 2. Claude tool schema 对 object 的 `required` 更敏感。 3. 即使没有必填字段,也建议显式写: ```json "required": [] ``` 4. 最稳妥的处理方式是在统一的 schema sanitizer 层修复,而不是逐个 tool 手动改。 5. 遇到 tool schema 400,优先用“逐个 tool 单独请求”的方式二分/枚举定位。 ## 最终结论 这次 `claude-opus-4-7` 报错的根因是:Hermes 部分工具 schema 的 object 节点缺少显式 `required` 数组。 通过在 `schema_sanitizer.py` 中自动补齐 `required: []`,即可兼容 Claude/Anthropic 工具调用校验器。 Loading... ## 问题现象 在 Hermes Agent 中把模型切换到 `claude-opus-4-7` 后,请求直接失败: ```text HTTP 400: custom.input_schema: JSON schema is invalid. It must match JSON Schema draft 2020-12 ``` 同一套工具 schema 在 `gpt-5.5` 等模型上正常,但在 Claude/Anthropic 兼容接口上报错。 ## 初步判断 报错信息指向: ```text custom.input_schema ``` 也就是 **tool/function 的 input schema** 不被 Claude 的工具调用校验器接受。 这类问题通常不是模型本身不可用,而是某个 tool 的 JSON Schema 写法在某些后端比较宽松,在 Anthropic/Claude 兼容后端比较严格。 ## 排查方法 ### 1. 导出当前 Hermes 工具列表 Hermes 的工具定义会经过: ```text tools/registry.py model_tools.py schema_sanitizer.py ``` 最终生成 OpenAI 格式的 tools: ```json { "type": "function", "function": { "name": "xxx", "description": "...", "parameters": { "type": "object", "properties": {} } } } ``` ### 2. 单独测试每一个 tool 把当前工具逐个提交给 `claude-opus-4-7`,定位到底哪些 schema 会触发 400。 最终发现报错工具包括: ```text browser_back browser_console browser_get_images browser_snapshot delegate_task send_message session_search skills_list todo ``` 这些工具的共同点是:`parameters` 或嵌套对象里存在 object schema,但没有显式声明 `required`。 例如: ```json { "type": "object", "properties": {} } ``` 或者: ```json { "type": "object", "properties": { "query": { "type": "string" } } } ``` ## 根因 JSON Schema Draft 2020-12 中,`required` 字段是可以省略的。 也就是说: ```json { "type": "object", "properties": {} } ``` 从标准 JSON Schema 角度看是合法的。 但 Anthropic/Claude 的 tool input schema 校验器更严格,实际要求 object schema 必须显式带上 `required` 数组。 如果没有必填字段,也要写成: ```json { "type": "object", "properties": {}, "required": [] } ``` 所以问题不是 schema 完全非法,而是 Claude 工具调用接口对 schema 有额外兼容要求。 ## 解决方法 在 Hermes 的 schema sanitizer 里,对所有 object schema 自动补上: ```json "required": [] ``` 前提是该 object schema 有 `properties`,但没有合法的 `required` 数组。 修改文件: ```text tools/schema_sanitizer.py ``` 核心逻辑: ```python def ensure_object_required_arrays(schema: Any) -> Any: """Add required: [] to every object schema missing it.""" if isinstance(schema, list): return [ensure_object_required_arrays(item) for item in schema] if not isinstance(schema, dict): return schema out = dict(schema) if out.get("type") == "object" and isinstance(out.get("properties"), dict): required = out.get("required") if not isinstance(required, list) or not all(isinstance(item, str) for item in required): out["required"] = [] for key, value in list(out.items()): if key in {"properties", "$defs", "definitions"} and isinstance(value, dict): out[key] = { sub_key: ensure_object_required_arrays(sub_value) for sub_key, sub_value in value.items() } elif key in {"items", "additionalProperties"}: if not isinstance(value, bool): out[key] = ensure_object_required_arrays(value) elif key in {"anyOf", "oneOf", "allOf"} and isinstance(value, list): out[key] = [ensure_object_required_arrays(item) for item in value] return out ``` 然后在 sanitizer 流程中调用: ```python fn["parameters"] = ensure_object_required_arrays(fn["parameters"]) ``` ## 验证结果 修复前,多个工具单独发送给 `claude-opus-4-7` 会返回 400。 修复后: ```text TOOL_COUNT 30 MISSING_REQUIRED_OBJECTS 0 CLAUDE_OPUS_4_7_ALL_TOOLS 200 OK ``` 也就是说,当前 30 个工具一起提交给 `claude-opus-4-7` 已经可以正常通过。 ## 经验总结 1. OpenAI/GPT 兼容接口能接受的 schema,不代表 Claude/Anthropic 兼容接口一定接受。 2. Claude tool schema 对 object 的 `required` 更敏感。 3. 即使没有必填字段,也建议显式写: ```json "required": [] ``` 4. 最稳妥的处理方式是在统一的 schema sanitizer 层修复,而不是逐个 tool 手动改。 5. 遇到 tool schema 400,优先用“逐个 tool 单独请求”的方式二分/枚举定位。 ## 最终结论 这次 `claude-opus-4-7` 报错的根因是:Hermes 部分工具 schema 的 object 节点缺少显式 `required` 数组。 通过在 `schema_sanitizer.py` 中自动补齐 `required: []`,即可兼容 Claude/Anthropic 工具调用校验器。 最后修改:2026 年 05 月 26 日 © 允许规范转载 打赏 赞赏作者 赞 2 如果觉得我的文章对你有用,请随意赞赏