# 结构化输出 (/docs/cloud/services/model/guides/structured-output)



结构化输出将回答约束为指定的 JSON 结构；接收端仍需检查终态、解析 JSON 并验证业务字段。

## 选择支持的模型 [#选择支持的模型]

先查看 `GET /openai/v1/models` 中的 `supported_parameters`：候选模型应列有 `response_format` 和 `structured_outputs`。2026-10-12，`gpt-5.6-sol` 的 Chat Completions `json_schema` + `strict` 和 `claude-opus-5` 的 Messages `output_config` 均实测通过，下面分别使用它们。

`deepseek-flash` 虽列有上述参数，本次 `json_schema` 请求仍返回 400，因此本页不使用它演示 schema 约束。目录声明不能替代实际响应验证。`json_object`（JSON mode）只表达 JSON 格式要求，不等于 schema 约束；需要固定字段和类型时使用本页的 `json_schema`。

## 1. 准备终端 [#1-准备终端]

将 Praxis 云 API Key 放入环境变量 `PRAXIS_API_KEY`；获取方式见 [Key 与鉴权](/docs/cloud/account/api-keys)。不要把 Key 写入代码。准备 Python 和 [uv](https://docs.astral.sh/uv/getting-started/installation/)；TypeScript 示例使用 [Bun](https://bun.sh/docs/installation)。

```bash
test -n "$PRAXIS_API_KEY"
```

期望：退出码为 0。示例默认使用 `https://api.deepraxis.ai`。切换环境时，将 `PRAXIS_API_BASE` 设为相应 API 域名，不带末尾斜杠或 API 路径。

将每段 Python 保存为标明的文件名，以 `uv run -q --no-project --with openai --with anthropic python <文件名>` 执行。各段代码独立运行。

## 2. 使用 json\_schema 和 strict [#2-使用-json_schema-和-strict]

保存为 `structured-output.py`，运行 `uv run -q --no-project --with openai --with anthropic python structured-output.py`。

`response_format.json_schema` 中同时给出 `name`、`strict: true` 和 `schema`。本例将所有属性列入 `required`，并用 `additionalProperties: false` 禁止额外字段。

```python
import json
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ['PRAXIS_API_KEY'],
    base_url=os.environ.get('PRAXIS_API_BASE', 'https://api.deepraxis.ai') + '/openai/v1')
schema = {'type':'object', 'properties':{
    'city':{'type':'string'}, 'temperature':{'type':'integer'}},
    'required':['city','temperature'], 'additionalProperties':False}
response = client.chat.completions.create(model='gpt-5.6-sol', max_tokens=1024,
    messages=[{'role':'user','content':'Return JSON for Paris with temperature 22.'}],
    response_format={'type':'json_schema','json_schema':{
        'name':'weather','strict':True,'schema':schema}})
print('X-Request-Id:', response._request_id)
choice = response.choices[0]
assert choice.finish_reason == 'stop' and not choice.message.refusal
value = json.loads(choice.message.content)
assert set(value) == {'city','temperature'}
assert isinstance(value['city'], str) and type(value['temperature']) is int
assert value == {'city':'Paris','temperature':22}, value
print(value)
```

期望：输出 `{'city': 'Paris', 'temperature': 22}`，退出码为 0。代码不剥除 Markdown 围栏；只有直接可解析、字段和类型符合要求的 JSON 才通过。

先检查 `finish_reason` 和 `refusal`，再解析内容。被截断或拒绝的回答不能当成符合 schema 的业务结果；流式回答应先收齐文本再解析。

## 3. 用 TypeScript 验证相同结果 [#3-用-typescript-验证相同结果]

保存为 `structured-output.ts`，运行 `bun structured-output.ts`；无需安装 SDK。

```typescript
import assert from 'node:assert/strict';
const base = process.env.PRAXIS_API_BASE ?? 'https://api.deepraxis.ai';
const schema = {type: 'object', properties: {
  city: {type: 'string'}, temperature: {type: 'integer'}},
  required: ['city', 'temperature'], additionalProperties: false};
const response = await fetch(`${base}/openai/v1/chat/completions`, {
  method: 'POST', headers: {'Authorization': `Bearer ${process.env.PRAXIS_API_KEY}`, 'Content-Type': 'application/json'},
  body: JSON.stringify({model: 'gpt-5.6-sol', max_tokens: 1024,
    messages: [{role: 'user', content: 'Return JSON for Paris with temperature 22.'}],
    response_format: {type: 'json_schema', json_schema: {name: 'weather', strict: true, schema}}}),
});
console.log('X-Request-Id:', response.headers.get('x-request-id'));
const data = await response.json();
assert(response.ok, JSON.stringify(data));
const choice = data.choices[0];
assert.equal(choice.finish_reason, 'stop');
assert(!choice.message.refusal);
const value = JSON.parse(choice.message.content);
assert.deepEqual(value, {city: 'Paris', temperature: 22});
console.log(value);
```

期望：同样得到 `city=Paris`、整数 `temperature=22`，没有额外字段，退出码为 0。

## 4. 使用 Messages 的 output\_config [#4-使用-messages-的-output_config]

Messages 将 schema 放在 `output_config.format` 下，`type` 为 `json_schema`；不要把 Chat Completions 的 `response_format` 或 `json_schema.name` 外壳搬过来。这里也不添加 OpenAI 的 `strict` 字段。

保存为 `structured-output-anthropic.py`，运行 `uv run -q --no-project --with openai --with anthropic python structured-output-anthropic.py`。

```python
import json
import os
from anthropic import Anthropic

client = Anthropic(api_key=os.environ['PRAXIS_API_KEY'],
    base_url=os.environ.get('PRAXIS_API_BASE', 'https://api.deepraxis.ai') + '/anthropic')
schema = {'type':'object', 'properties':{
    'city':{'type':'string'}, 'temperature':{'type':'integer'}},
    'required':['city','temperature'], 'additionalProperties':False}
raw = client.messages.with_raw_response.create(model='claude-opus-5', max_tokens=1024,
    messages=[{'role':'user','content':'Return JSON for Paris with temperature 22.'}],
    output_config={'format':{'type':'json_schema','schema':schema}})
print('X-Request-Id:', raw.headers.get('x-request-id'))
message = raw.parse()
assert message.stop_reason == 'end_turn'
value = json.loads(''.join(block.text for block in message.content if block.type == 'text'))
assert set(value) == {'city','temperature'}
assert isinstance(value['city'], str) and type(value['temperature']) is int
assert value == {'city':'Paris','temperature':22}, value
print(value)
```

期望：`stop_reason=end_turn`，JSON 验证通过并输出相同对象，退出码为 0。

## 实测失败与处理 [#实测失败与处理]

`deepseek-flash` 的 schema 请求返回 HTTP 400，错误消息的固定部分为：

> This response\_format type is unavailable now

消息还会附带当次请求标识。切换为本页已实测通过的 `gpt-5.6-sol` 后通过。不要将 HTTP 200、Markdown 中的一段 JSON 或能解析的普通 JSON 当成 schema 约束已生效；保留示例中的完整验证。

协议细节：[OpenAI](https://developers.openai.com/api/docs/guides/structured-outputs) · [Anthropic](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)。

[API 参考 →](/docs/api/compatible/openai) · [Cookbook →](/docs/cookbook)
