快速结论:当你在 Transformers 里用 get_json_schema 把带类型注解的 Python 函数转成工具 schema、且某个参数的类型注解是 Union(|)并包含 list[...]、dict[...]、tuple[...] 或 Literal[...] 时,生成的 JSON Schema 会丢掉 items、enum、additionalProperties、prefixItems 等关键字段,只剩一个不完整甚至非法的 type 数组。优先排查 Union 分支对子类型的合并逻辑。
适用环境:Issue 已确认:transformers 5.18.0.dev0(main @ 27166ea),也在 5.17.0 上复现;平台 macOS-15.3.1-arm64;Python 3.12.13;huggingface_hub 1.33.0;safetensors 0.8.0;accelerate 1.15.0;PyTorch 2.14.0(无加速器);未使用分布式或并行。
最快修复方案:暂无确认的一步修复方案。Issue 中提到的修复是修改 src/transformers/utils/chat_template_utils.py 的 _parse_type_hint Union 分支:把「每个子类型都有字符串 "type"」的合并条件收紧为「子类型恰好只有 {"type": ...}」,并补上去重,让带额外键的子类型落到已有的 anyOf 分支;但该 PR 是否已合并、对应正式版本,Issue 中未给出结论,不要直接照搬。
注意事项:该修复在本地测试通过(tests/utils/test_chat_template_utils.py、tests/utils/test_chat_parsing.py),但属提交者自述,未在本 Issue 元数据中标注为已合并。此外,response_parser._schema_types 已会递归处理 anyOf,因此改为 anyOf 输出不会影响仓库内的消费方;但如果你有下游代码在解析这个扁平化后的 type 数组,改动后会看到结构变化,需要自行适配。
问题场景
用户在 Transformers 中调用 transformers.utils.get_json_schema,把一个带类型注解和 docstring 的 Python 函数转换成工具调用的 JSON Schema(例如用于 chat templates / tool schemas 场景)。当某个参数的类型注解是 Union,且 Union 成员中含有 list[str]、dict[str, int]、Literal["a", "b"] 这类带附加约束的类型时,生成的 schema 会丢失这些附加信息。
问题并非在所有 Union 场景下出现:同样的注解在「Union 中只有一个非 None 成员」(如 list[str] | None)或与 Any 组合时都能正确保留,说明这是 Union 合并分支的行为不一致,而不是注解本身不被支持。
报错原文
get_json_schema drops `items` / `enum` when a Union contains `list[...]`, `dict[...]` or `Literal[...]`
Output on `main`:
{
"query": {"type": ["array", "string"], "description": "A single query or a list of queries"},
"unit": {"type": ["integer", "string"], "description": "Either a named unit or a raw integer code"}
}
- `list[str] | list[int]` -> `{"type": ["array", "array"]}` (no `items`, and duplicate entries in a `type` array are not valid JSON Schema)
- `Literal["a", "b"] | Literal["c"]` -> `{"type": ["string", "string"]}` (both enums lost)
- `dict[str, int] | list[int]` -> `{"type": ["array", "object"]}`
原因分析
最可能的原因在 src/transformers/utils/chat_template_utils.py 的 _parse_type_hint 函数。其 Union 分支中有一个「基础类型 Union」的快捷合并逻辑,判断条件是每个子类型都存在字符串形式的 "type":
elif all("type" in subtype and isinstance(subtype["type"], str) for subtype in subtypes):
return_dict = {"type": sorted([subtype["type"] for subtype in subtypes])}
问题在于 list / dict / tuple / Literal 生成的 schema 同样带有字符串 "type"(分别是 "array"、"object"、"string"),因此它们也会命中这个分支。该分支只提取 "type" 并排序,items、additionalProperties、prefixItems、enum 等其他键全部被丢弃;同时它也不做去重,所以会出现 ["array", "array"] 这种在 JSON Schema 中不合法的重复 type 数组。
社区在评论中复现了该问题,并确认根因就是这一行:捷径只检查每个子类型是否有字符串 "type",导致 list[...] 和 Literal 被塌缩成类型字符串。修复方向是仅在子类型恰好为 {"type": ...} 时才做合并,并去重,其余情况交给已有的 anyOf 分支处理。
环境排查
- 确认
transformers版本:Issue 在 5.18.0.dev0(main @ 27166ea)复现,也在 5.17.0 复现;不要假设其他版本行为一致。 - 确认 Python 版本:Issue 为 3.12.13;Union 语法
|需要 Python 3.10+。 - 确认
huggingface_hub1.33.0、safetensors0.8.0、accelerate1.15.0,但 Issue 未显示这些包与 schema 生成逻辑直接相关,仅作环境对照。 - 确认 PyTorch 版本与是否使用加速器:Issue 为 PyTorch 2.14.0、无加速器;该问题属纯 Python 类型解析,是否使用 CUDA/GPU 预计不影响结果。
- 确认是否使用分布式或并行:Issue 为否。
- 确认
chat_template_utils.py中_parse_type_hint的 Union 分支源码是否仍为"type" in subtype形式(而非subtype.keys() == {"type"}),以判断修复是否已进你的版本。
解决步骤
- 先用 Issue 中的最小复现脚本确认症状,观察输出里
query是否缺少items、unit是否缺少enum。 - 定位
src/transformers/utils/chat_template_utils.py的_parse_type_hintUnion 分支,检查那一行条件是否为all("type" in subtype and isinstance(subtype["type"], str) for subtype in subtypes)。 - 可优先尝试的修复方向(Issue 中提出、本地测试通过,但未确认已合并):把合并条件改为仅在子类型恰好只有
"type"键时才走扁平化,即subtype.keys() == {"type"},并对合并结果去重;这样list[...]、dict[...]、tuple[...]、Literal[...]会落到已有的anyOf分支,保留items/enum等键。 - 如上一步不可行,先不要修改或硬编码输出:在等待上游修复期间,避免在工具函数参数注解中对含附加约束的类型使用 Union,或改为不含 Union 的写法以绕过该分支。
- 如果你要自行验证修复,需按 Issue 提到的方式补充回归测试(
tests/utils/test_chat_template_utils.py、tests/utils/test_chat_parsing.py);这些测试是否为最终合入版本,Issue 未说明。
验证方法
重新运行 Issue 中的复现脚本,检查 get_json_schema(search)["function"]["parameters"]["properties"] 的输出。修复后 query 应为 anyOf 结构并保留 {"type": "array", "items": {"type": "string"}},unit 应保留 {"type": "string", "enum": ["celsius", "fahrenheit"]}。可再补测 list[str] | list[int](不应出现重复的 "array")、Literal["a", "b"] | Literal["c"](不应丢失 enum)、dict[str, int] | list[int](应保留 additionalProperties 等键)等组合。若生成的 schema 需被下游消费,再用实际的 chat template / 工具调用流程跑一遍,确认解析端能正确处理 anyOf。
参考来源
huggingface/transformers #49122
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。


