Langsung ke konten
Output Terstruktur

Output Terstruktur

Minta jawaban sebagai JSON: objek JSON apa pun, atau JSON yang mengikuti skema yang Anda kirim. Gunakan ketika program, bukan manusia, yang membaca balasan.

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 adalah teks jawaban, di 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}
  }
}

Mode response_format

response_format adalah field dari /v1/chat/completions. Tanpanya, jawaban berupa teks biasa.

Mode Nilai Yang Anda dapatkan
Objek JSON {"type": "json_object"} Jawaban berupa JSON tanpa bentuk yang ditentukan. Sebutkan di prompt key mana yang Anda inginkan.
Skema JSON {"type": "json_schema", "json_schema": {"name": "…", "schema": {…}}} Jawaban mengikuti skema yang Anda kirim: key, tipe, dan field wajibnya.
Strict "strict": true Field dari json_schema, bukan mode ketiga. Nilainya true kecuali Anda mengirim false.
Field Tipe Default Deskripsi Diterapkan oleh
type string json_object atau json_schema. Wajib di dalam response_format. text diterima dan menghasilkan jawaban teks biasa. Setiap model yang menerima mode ini
json_schema.schema object JSON Schema yang diikuti jawaban. Kirim kapan pun type adalah json_schema. Setiap model yang menerima mode ini
json_schema.name string Label untuk skema, seperti pada format OpenAI. Model open-weight hosted
json_schema.strict boolean true Apakah jawaban harus mengikuti skema dengan tepat. Model Shannon menerapkan setiap skema sebagai strict. Model open-weight hosted

Mode objek JSON tidak memerlukan skema. Sebutkan key di prompt:

Body permintaan
{
  "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"}
}

Dukungan per model

Model json_object json_schema
Setiap model Shannon (shannon-*) Ya Ya
Model open-weight hosted, kecuali yang disebut di bawah Ya Ya
Laguna-S-2.1-W4A16-AUTOROUND-REAP — —
inkling-W4A16-AUTOROUND-REAP Ya —

GET /v1/models melaporkan hal yang sama per id: capabilities.json_schema pada setiap model, dan capabilities.response_format pada model open-weight hosted. Model & harga

Kata kunci skema yang didukung

Apa yang diterima model dari skema Anda bergantung pada model dan endpoint:

Model /v1/chat/completions /v1/responses
Model Shannon Subset kata kunci di bawah, diterapkan sebagai strict. Skema sebagaimana Anda kirim, diterapkan sebagai strict.
Model open-weight hosted Skema sebagaimana Anda kirim. strict adalah true kecuali Anda mengirimnya. Skema sebagaimana Anda kirim. strict adalah true kecuali Anda mengirimnya.

Subset kata kunci model Shannon pada /v1/chat/completions:

Kata kunci Cara membacanya
Kata kunci yang dibaca type, format, title, description, nullable, enum, items, properties, required, minItems, maxItems, minimum, maximum, minLength, maxLength, pattern, anyOf, default
$ref Diselesaikan dari $defs atau definitions di level teratas skema. Kata kunci yang ditulis di samping $ref, seperti description, dipertahankan. Referensi tanpa definisi yang cocok dibaca sebagai {"type": "object"}.
allOf Anggotanya digabung menjadi satu skema. Jika dua anggota menyetel kata kunci yang sama, yang belakangan yang dipakai.
oneOf Dibaca sebagai anyOf.
Skema yang merujuk dirinya sendiri Diperluas hingga 24 level. Level yang lebih dalam dibaca sebagai {"type": "object"}.
Di luar subset Setiap kata kunci lain, misalnya additionalProperties, const, multipleOf, uniqueItems, exclusiveMinimum, exclusiveMaximum, patternProperties, prefixItems, minProperties, maxProperties, not, dan if / then / else. Ini bukan bagian dari skema yang diterima model.

Pada /v1/responses: text.format

/v1/responses menuliskan permintaan yang sama sebagai text.format. Skema berada langsung di format, di samping name dan strict, bukan di bawah key json_schema. Untuk mode objek JSON, kirim {"format": {"type": "json_object"}}.

Body permintaan
{
  "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 adalah text dari bagian output_text pada item 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": []
        }
      ]
    }
  ]
}

Dukungan per model dan error sama seperti pada /v1/chat/completions. Responses API

Pada /v1/messages: tool sebagai skema

Format Messages tidak memiliki field output terstruktur. Untuk JSON dari model yang sama, panggil /v1/chat/completions atau /v1/responses dengan kunci yang sama.

Untuk tetap di /v1/messages, deskripsikan objek sebagai tool: taruh skema Anda di input_schema dan sebut nama tool di tool_choice. input pada blok tool_use kemudian adalah objek Anda, sudah di-parse. tool_choice bernama diterapkan oleh model open-weight hosted.

Body permintaan
{
  "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"}
    }
  ]
}

Pastikan stop_reason adalah tool_use sebelum Anda membaca bloknya. Pemanggilan fungsi

Bagaimana JSON datang

  • JSON adalah string. Balasan tidak memiliki objek yang sudah di-parse di sampingnya: jalankan parser JSON Anda pada message.content.
  • Dengan stream: true, JSON datang dalam potongan delta.content. Gabungkan dan parse setelah stream berakhir; satu potongan saja bukan JSON yang valid.
  • Model open-weight hosted menjawab permintaan response_format tanpa teks penalaran: reasoning_content adalah null.

Periksa apa yang Anda terima

Skema memandu cara model menulis. API tidak membandingkan jawaban akhir dengan skema Anda, jadi kode Anda yang melakukan pemeriksaan akhir:

  • Parse di dalam error handler, seperti pada contoh di bagian atas.
  • Validasi objek hasil parse dengan skema yang sama di kode Anda sendiri, misalnya dengan pustaka JSON Schema, Pydantic, atau Zod.
  • Jawaban yang panjang dapat berakhir sebelum JSON lengkap. Balasan tanpa stream hanya melaporkan finish_reason sebagai stop atau tool_calls, jadi error parse adalah tandanya. Tanya lagi, atau minta objek yang lebih kecil.

Error

Status Tipe Pesan Kapan
400 invalid_request_error <id> does not accept response_format Model tidak menerima kedua mode.
400 invalid_request_error <id> does not accept response_format json_schema; use json_object Model menerima json_object dan Anda mengirim json_schema.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … response_format tidak memiliki type, atau bukan objek JSON.

Kedua balasan 400 dikirim sebelum apa pun diambil dari saldo Anda. Penanganan kesalahan