رفتن به محتوا
خروجی‌های ساختاریافته

خروجی‌های ساختاریافته

پاسخ را به‌صورت JSON بخواهید: هر شیء JSON، یا JSON که از schemaای که می‌فرستید پیروی کند. وقتی پاسخ را یک برنامه می‌خواند، نه یک انسان، از آن استفاده کنید.

POST https://api.shannon-ai.com/v1/chat/completions

import json
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1")

response = client.chat.completions.create(
    model="Kimi-K3-3BIT-REAP",
    messages=[
        {"role": "user", "content": "Extract the person: John Doe, 30 years old, engineer."}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "person",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "age": {"type": "integer"},
                    "occupation": {"type": "string"},
                },
                "required": ["name", "age", "occupation"],
            },
        },
    },
)

# The JSON arrives as text in message.content: parse it, then check it.
try:
    person = json.loads(response.choices[0].message.content)
except json.JSONDecodeError:
    person = None  # ask again, or report the failure

print(person)

JSON همان متن پاسخ است، در choices[0].message.content:

200 JSON
{
  "id": "chatcmpl-0c4e7a1b9d2f4e6a8b3c5d7e9f1a2b3c",
  "object": "chat.completion",
  "created": 1791590400,
  "model": "Kimi-K3-3BIT-REAP",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "{\"name\":\"John Doe\",\"age\":30,\"occupation\":\"engineer\"}",
        "reasoning_content": null
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 96,
    "completion_tokens": 19,
    "total_tokens": 115,
    "prompt_tokens_details": {"cached_tokens": 0},
    "completion_tokens_details": {"reasoning_tokens": 0}
  }
}

حالت‌های response_format

response_format یکی از فیلدهای /v1/chat/completions است. بدون آن پاسخ متن معمولی است.

حالت مقدار چه می‌گیرید
شیء JSON {"type": "json_object"} پاسخ JSON است بدون شکل از پیش تعیین‌شده. در پرامپت بگویید چه کلیدهایی می‌خواهید.
JSON schema {"type": "json_schema", "json_schema": {"name": "…", "schema": {…}}} پاسخ از schemaای که می‌فرستید پیروی می‌کند: کلیدها، نوع‌ها و فیلدهای الزامی آن.
Strict "strict": true یک فیلد از json_schema است، نه حالت سوم. مقدارش true است مگر اینکه false بفرستید.
فیلد نوع پیش‌فرض توضیحات اعمال‌شده توسط
type string json_object یا json_schema. داخل response_format الزامی است. text پذیرفته می‌شود و پاسخ متنی معمولی می‌دهد. هر مدلی که این حالت را می‌پذیرد
json_schema.schema object JSON Schema‌ای که پاسخ از آن پیروی می‌کند. هر وقت type برابر json_schema است آن را بفرستید. هر مدلی که این حالت را می‌پذیرد
json_schema.name string یک برچسب برای schema، مانند قالب OpenAI. مدل‌های open-weight میزبانی‌شده
json_schema.strict boolean true اینکه آیا پاسخ باید دقیقاً از schema پیروی کند یا نه. مدل‌های Shannon هر schema را به‌صورت strict اعمال می‌کنند. مدل‌های open-weight میزبانی‌شده

حالت شیء JSON به schema نیاز ندارد. کلیدها را در پرامپت نام ببرید:

بدنه درخواست
{
  "model": "shannon-3",
  "messages": [
    {
      "role": "user",
      "content": "Name the capital of France. Answer as JSON with the keys city and country."
    }
  ],
  "response_format": {"type": "json_object"}
}

پشتیبانی به تفکیک مدل

مدل json_object json_schema
هر مدل Shannon (shannon-*) بله بله
مدل‌های open-weight میزبانی‌شده، به‌جز مواردی که در ادامه نام برده شده‌اند بله بله
Laguna-S-2.1-W4A16-AUTOROUND-REAP — —
inkling-W4A16-AUTOROUND-REAP بله —

GET /v1/models همین را به تفکیک id گزارش می‌کند: capabilities.json_schema برای هر مدل، و capabilities.response_format برای مدل‌های open-weight میزبانی‌شده. مدل‌ها و قیمت‌ها

کلیدواژه‌های پشتیبانی‌شده schema

اینکه مدل از schema شما چه چیزی دریافت می‌کند به مدل و به endpoint بستگی دارد:

مدل‌ها /v1/chat/completions /v1/responses
مدل‌های Shannon زیرمجموعه کلیدواژه‌های زیر، با اعمال strict. schema همان‌طور که می‌فرستید، با اعمال strict.
مدل‌های open-weight میزبانی‌شده schema همان‌طور که می‌فرستید. strict برابر true است مگر اینکه خودتان بفرستید. schema همان‌طور که می‌فرستید. strict برابر true است مگر اینکه خودتان بفرستید.

زیرمجموعه کلیدواژه‌های مدل‌های Shannon در /v1/chat/completions:

کلیدواژه چگونه خوانده می‌شود
کلیدواژه‌های خوانده‌شده type, format, title, description, nullable, enum, items, properties, required, minItems, maxItems, minimum, maximum, minLength, maxLength, pattern, anyOf, default
$ref از $defs یا definitions در سطح بالای schema حل می‌شود. کلیدواژه‌هایی که کنار $ref نوشته شوند، مانند description، حفظ می‌شوند. ارجاعی که تعریف مطابق ندارد به‌صورت {"type": "object"} خوانده می‌شود.
allOf اعضا در یک schema ادغام می‌شوند. اگر دو عضو یک کلیدواژه را تنظیم کنند، عضو بعدی معتبر است.
oneOf به‌صورت anyOf خوانده می‌شود.
schemaهایی که به خودشان ارجاع می‌دهند تا 24 سطح باز می‌شوند. سطح عمیق‌تر به‌صورت {"type": "object"} خوانده می‌شود.
خارج از زیرمجموعه هر کلیدواژه دیگر، مثلاً additionalProperties، const، multipleOf، uniqueItems، exclusiveMinimum، exclusiveMaximum، patternProperties، prefixItems، minProperties، maxProperties، not و if / then / else. این‌ها جزو schemaای که مدل دریافت می‌کند نیستند.

خروجی ساختاریافته در /v1/responses با فیلد text.format

/v1/responses همین درخواست را به‌صورت text.format می‌نویسد. schema مستقیم در format قرار می‌گیرد، کنار name و strict، نه زیر کلید json_schema. برای حالت شیء JSON مقدار {"format": {"type": "json_object"}} را بفرستید.

بدنه درخواست
{
  "model": "Kimi-K3-3BIT-REAP",
  "input": "Extract the person: John Doe, 30 years old, engineer.",
  "text": {
    "format": {
      "type": "json_schema",
      "name": "person",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "name": {"type": "string"},
          "age": {"type": "integer"},
          "occupation": {"type": "string"}
        },
        "required": ["name", "age", "occupation"]
      }
    }
  }
}

JSON همان text بخش output_text از آیتم message است:

200 JSON
{
  "output": [
    {
      "id": "msg_7e1d3c5b9a2f4d6e8c0b1a3f5e7d9c2b",
      "type": "message",
      "role": "assistant",
      "status": "completed",
      "content": [
        {
          "type": "output_text",
          "text": "{\"name\":\"John Doe\",\"age\":30,\"occupation\":\"engineer\"}",
          "annotations": []
        }
      ]
    }
  ]
}

پشتیبانی به تفکیک مدل و خطاها همان‌هایی است که در /v1/chat/completions هستند. Responses API

در /v1/messages: یک ابزار به‌جای schema

قالب Messages فیلدی برای خروجی ساختاریافته ندارد. برای JSON از همین مدل‌ها، با همان کلید /v1/chat/completions یا /v1/responses را فراخوانی کنید.

برای ماندن روی /v1/messages، شیء را به‌صورت یک ابزار توصیف کنید: schema خود را در input_schema بگذارید و ابزار را در tool_choice نام ببرید. آن‌گاه input بلوک tool_use همان شیء شماست، که از قبل پارس شده است. tool_choice نام‌دار را مدل‌های open-weight میزبانی‌شده اعمال می‌کنند.

بدنه درخواست
{
  "model": "Kimi-K3-3BIT-REAP",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": "Extract the person: John Doe, 30 years old, engineer."
    }
  ],
  "tools": [
    {
      "name": "record_person",
      "description": "Record the extracted person.",
      "input_schema": {
        "type": "object",
        "properties": {
          "name": {"type": "string"},
          "age": {"type": "integer"},
          "occupation": {"type": "string"}
        },
        "required": ["name", "age", "occupation"]
      }
    }
  ],
  "tool_choice": {"type": "tool", "name": "record_person"}
}
200 JSON
{
  "stop_reason": "tool_use",
  "content": [
    {
      "type": "tool_use",
      "id": "toolu_4b8d2f6a1c3e4a5b9d7f0e2c4a6b8d1f",
      "name": "record_person",
      "input": {"name": "John Doe", "age": 30, "occupation": "engineer"}
    }
  ]
}

پیش از خواندن بلوک، بررسی کنید که stop_reason برابر tool_use باشد. فراخوانی توابع

JSON چگونه می‌رسد

  • JSON یک رشته است. کنار پاسخ هیچ شیء پارس‌شده‌ای نیست: پارسر JSON خود را روی message.content اجرا کنید.
  • با stream: true، JSON در تکه‌های delta.content می‌رسد. آن‌ها را به هم بچسبانید و بعد از پایان stream یک بار پارس کنید؛ یک تکه به‌تنهایی JSON معتبر نیست.
  • مدل open-weight میزبانی‌شده به درخواست response_format بدون متن استدلال پاسخ می‌دهد: reasoning_content برابر null است.

آنچه دریافت می‌کنید را بررسی کنید

schema نحوه نوشتن مدل را هدایت می‌کند. API پاسخ نهایی را با schema شما مقایسه نمی‌کند، پس بررسی نهایی با کد شماست:

  • پارس را داخل یک error handler انجام دهید، همان‌طور که نمونه بالای صفحه نشان می‌دهد.
  • شیء پارس‌شده را در کد خودتان با همان schema اعتبارسنجی کنید، مثلاً با یک کتابخانه JSON Schema، Pydantic یا Zod.
  • یک پاسخ بلند ممکن است پیش از کامل شدن JSON تمام شود. پاسخی که stream نشده فقط stop یا tool_calls را به‌عنوان finish_reason گزارش می‌کند، پس خطای پارس همان نشانه است. دوباره بپرسید، یا شیء کوچک‌تری بخواهید.

خطاها

وضعیت نوع پیام چه زمانی
400 invalid_request_error <id> does not accept response_format مدل هیچ‌یک از دو حالت را نمی‌پذیرد.
400 invalid_request_error <id> does not accept response_format json_schema; use json_object مدل json_object را می‌پذیرد و شما json_schema فرستاده‌اید.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … response_format فیلد type ندارد، یا یک شیء JSON نیست.

این دو پاسخ 400 پیش از آنکه چیزی از موجودی شما کم شود فرستاده می‌شوند. مدیریت خطا