登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

结构化输出遇到递归字段时怎样约束模式

来源:17golang原创

时间:2026-10-09 13:29:22 215浏览 收藏

结构化输出遇到递归字段时,关键不是把对象定义成“无限嵌套”,而是让每一层都长成同一个、可收敛的节点。最稳妥的做法是:固定 type、label、children 三个字段,在 children.items 中用 $ref: "#" 回指根 schema,叶子节点用空数组结束递归,再用输出预算限制实际深度。

官方地址:https://developers.openai.com/api/docs/guides/structured-outputs

要点速览
  • 递归结构的核心是“固定节点 + 根引用”,不是为每一层复制一套属性。
  • strict: true约束输出形状,但不会替你判断业务值、拒答或截断。
  • 空 children、节点总数和最大深度要成为明确的工程边界。

先把递归对象改成可收敛的树节点

菜单、组件树、目录和流程节点都可以抽象成树。节点字段最好保持稳定:type 表示节点种类,label 保存展示文本,children 永远是数组。没有子节点时返回 [],不要省略字段,也不要一会儿返回数组、一会儿返回对象。

结构化输出递归节点的固定字段、叶子节点和子节点关系说明图
图1:递归节点的字段契约与叶子收敛关系说明图,不是运行截图。
字段建议约束工程意义
type字符串枚举避免下游按自由文本分支
label必填字符串保证每个节点可定位
children必填数组空数组就是递归终点

用根引用表达 children 的自嵌套关系

JSON Schema 不需要预先写出“第一层、第二层、第三层”。把 children.items 指向根 schema,就能让同一个节点继续包含节点。下面的例子使用 Responses API 的 text.format 形式;如果使用工具调用,则把同一思路放进工具参数 schema。

from openai import OpenAI

client = OpenAI()

schema = {
    "type": "object",
    "properties": {
        "type": {"type": "string", "enum": ["root", "section", "item"]},
        "label": {"type": "string"},
        # 子节点复用根定义,表达任意层级的树结构
        "children": {"type": "array", "items": {"$ref": "#"}}
    },
    # 空 children 表示叶子节点,所有字段都保持稳定
    "required": ["type", "label", "children"],
    "additionalProperties": False
}

response = client.responses.create(
    model="gpt-6-astra",
    input="把产品导航整理成树状节点",
    text={"format": {
        "type": "json_schema",
        "name": "navigation_tree",
        "strict": True,
        "schema": schema
    }},
    # 给递归结果设上限,防止合法嵌套耗尽输出预算
    max_output_tokens=1200
)

print(response.output_text)

这里的 $ref 只负责描述形状;它不会自动阻止模型生成很深的树。递归模式应当和业务提示一起使用,例如要求“最多五层、每个节点最多八个 children”,然后在服务端再次统计深度和节点数。

strict 只是形状约束,深度仍要靠预算管理

Structured Outputs 比 JSON mode 多了一层 schema 遵循能力,但它不能保证字段里的事实一定正确。递归响应至少要区分三种结果:正常 JSON、拒答、生成被长度或其他停止条件截断。只有第一种且完成原因正常时,才适合交给后续渲染。

结构化输出递归树的深度、节点数量和拒答截断分支边界说明图
图2:递归输出的深度预算、节点数量和异常分支说明图,不是运行截图。

落地时可把边界写成检查清单:最大深度限制渲染成本,最大节点数限制内存和数据库写入,max_output_tokens 防止结果无限增长;遇到拒答或截断则记录原因并走重试、降级或人工处理,不能把半棵树当成完整导航。

相关问题

递归 schema 一定要把 children 设成必填吗?

建议必填。叶子节点返回空数组,比缺少字段更容易让序列化、类型生成和前端渲染保持单一分支。

JSON mode 能不能代替递归 Structured Outputs?

不能完全代替。JSON mode 主要保证结果是合法 JSON,不能保证每个递归节点都符合预定义 schema。

为什么 schema 正确,页面仍可能渲染失败?

schema 只管结构,不管标签内容、节点权限和引用是否存在。渲染前仍需做业务值校验、深度限制和节点数量限制。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>