> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inputapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# JSON 模式与结果校验

> 运行 Chat 与 Responses 的 json_object 示例，区分合法 JSON、字段约束和业务正确性。

## 已支持的字段

| 协议 | JSON 模式 | 严格 Schema 模式 |
| - | - | - |
| Chat | `response_format: {type: json_object}` | `response_format.json_schema` |
| Responses | `text: {format: {type: json_object}}` | `text.format` 中的 json\_schema 配置 |

请求 DTO 可以表达这些字段，当前 Chat ↔ Responses 文本格式转换会映射 json\_object 类型。模型与渠道仍需实际支持；本页不承诺所有兼容模型都支持 JSON，也不把工具声明的 strict 限制套用到最终文本格式。

JSON 模式用于需要 JSON、但不使用服务端 Schema 约束的接入。支持且适合使用 json\_schema 时，参见 [结构化输出](/zh/guides/structured-output)。不要在 Schema 请求失败后静默降级，让业务把较弱约束误认为已通过。

## 三层检查

1. **协议完成**：Chat 检查 stop、角色、拒答和工具结果；Responses 检查 completed 及输出项。截断但碰巧可解析的 JSON 也不能作为成功结果。
2. **JSON 语法**：提示中明确要求输出 JSON；收到完整文本后再解析。Markdown 围栏、空白、两个连续对象或坏 JSON 都作为失败，示例不修复或自动重试。
3. **业务结构**：合法 JSON 仍可能是数组、null、字段缺失或类型错误。本例要求 sku=NOTEBOOK、quantity 为 0–100 的安全整数、notes 必须存在且为字符串或 null，禁止额外字段和类型强转。

`notes: null` 与缺少 notes 不等价；数量字符串 `"3"` 与整数 3 不等价。通过结构检查不证明抽取事实正确，更不能直接触发库存变更、付款等操作。更复杂的业务对象应使用已有 Schema 校验库。

## 示例边界

通过 `API_JSON_PROTOCOL=chat|responses` 选择一个协议，每次运行只发一个请求。Responses 示例只接受一个助手消息的 output\_text，可包含多个文本块；不将多个独立消息拼成一个业务对象。reasoning 项被忽略且不记录，拒答或函数调用导致失败。

JSON 模式不意味着 OpenRouter response-healing 插件已在本网关启用。字符串解析和业务校验在客户端进行，网关不会替应用保证字段语义。流式 JSON 必须等成功结束后再解析，不能对每个 delta 单独 JSON.parse。见 [流式接入](/zh/guides/streaming) 和 [常见问题](/zh/guides/troubleshooting)。

源码：`relaykit/dto/openai_request.go` 和 Chat / Responses 请求转换器。上游语义参见 [JSON 模式说明](https://developers.openai.com/api/docs/guides/structured-outputs?api-mode=responses)。

## 可运行示例

在文档目录运行；复制脚本时一并保留 `http-client.mjs`，配置见 [REST 运行时](/zh/guides/http-runtime)。

```sh theme={null}
export API_ROOT_URL='https://gateway.example.com'
export API_KEY='YOUR_API_KEY'
export API_MODEL='YOUR_MODEL_ID'
export API_JSON_PROTOCOL='chat'
node examples/json-mode.mjs
```

```javascript theme={null}
import { requestJSON } from './http-client.mjs';

try {
  const model = process.env.API_MODEL;
  const protocol = process.env.API_JSON_PROTOCOL || 'chat';
  if (!model?.trim() || !['chat', 'responses'].includes(protocol)) throw new Error('Invalid configuration.');
  const instruction = 'Return only a JSON object with exactly sku, quantity, notes. sku must be NOTEBOOK, quantity an integer from 0 to 100, and notes a string or null. Extract: three notebooks, no notes.';
  const result = await requestJSON(protocol === 'chat' ? '/v1/chat/completions' : '/v1/responses',
    protocol === 'chat' ? { model, messages: [{ role: 'user', content: instruction }], response_format: { type: 'json_object' } }
      : { model, input: instruction, text: { format: { type: 'json_object' } }, store: false });
  let text;
  if (protocol === 'chat') {
    const choice = result.choices?.[0];
    const message = choice?.message;
    if (!Array.isArray(result.choices) || result.choices.length !== 1 || choice?.index !== 0
      || choice.finish_reason !== 'stop' || message?.role !== 'assistant'
      || message.refusal != null || message.tool_calls != null || message.function_call != null
      || typeof message.content !== 'string') throw new Error('Incomplete text.');
    text = message.content;
  } else {
    if (result.status !== 'completed' || !Array.isArray(result.output)) throw new Error('Incomplete response.');
    const parts = [];
    let messages = 0;
    for (const item of result.output) {
      if (item?.type === 'reasoning') continue;
      if (item?.type !== 'message' || item.role !== 'assistant' || item.status !== 'completed'
        || !Array.isArray(item.content) || ++messages > 1) throw new Error('Unexpected output.');
      for (const part of item.content) {
        if (part?.type !== 'output_text' || typeof part.text !== 'string') throw new Error('Unexpected content.');
        parts.push(part.text);
      }
    }
    text = parts.join('');
  }
  // Parse only complete JSON; do not strip fences, repair truncation, or coerce field types.
  const value = JSON.parse(text);
  if (!value || Array.isArray(value) || Object.keys(value).length !== 3 || value.sku !== 'NOTEBOOK'
    || !Number.isSafeInteger(value.quantity) || value.quantity < 0 || value.quantity > 100
    || !(value.notes === null || typeof value.notes === 'string')) throw new Error('Invalid business object.');
  console.log(JSON.stringify({ sku: value.sku, quantity: value.quantity, notes: value.notes }));
} catch {
  console.error('JSON mode example failed. Check protocol, completion, and business fields. No automatic repair or retry.');
  process.exitCode = 1;
}
```

[Read in English](/en/guides/json-mode)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.