aidoc.uz

2-qism · Matn generatsiyasi·05-bob

Structured Outputs: qat'iy JSON formatda javob

Modelni erkin matn emas, aniq belgilangan JSON sxemasida javob berishga majburlash — dastur uchun ishonchli ma'lumot olish, sxema qoidalari va real xatolar.

Model javobini foydalanuvchiga o'qish uchun emas, dasturingizga uzatish uchun ishlatsangiz (masalan, bazaga yozish, boshqa funksiyaga argument sifatida berish), erkin matn muammo tug'diradi: bugun {"ism": "Aziz"} qaytarsa, ertaga Ism: Aziz deb yozishi mumkin. Dastur uchun bu — doimiy sinish xavfi.

1. Muammo: "iltimos JSON qaytar" yetarli emas#

Ko'p boshlovchi shunday yozadi:

response = client.responses.create(
    model="gpt-4o-mini",
    input="Aziz, 28 yoshda, Toshkentda yashaydi. Buni JSON qilib ber.",
)

Bu ko'pincha ishlaydi, lekin kafolat yo'q. Model qo'shimcha izoh qo'shib javob berishi (masalan, "Mana JSON: ..." deb boshlab), maydon nomini o'zgartirishi yoki noto'g'ri turdagi qiymat qaytarishi mumkin ("yosh": "yigirma sakkiz" matn sifatida, raqam emas). Production kodida json.loads() tasodifiy portlab turadi.

2. Yechim: qat'iy sxema berish#

text.format parametri orqali JSON Schema beriladi — model shu sxemaga mos javob qaytarishga majburlanadi, erkin matn emas:

response = client.responses.create(
    model="gpt-4o-mini",
    input="Aziz, 28 yoshda, Toshkentda yashaydi.",
    text={
        "format": {
            "type": "json_schema",
            "name": "shaxs_malumoti",
            "schema": {
                "type": "object",
                "properties": {
                    "ism": {"type": "string"},
                    "yosh": {"type": "integer"},
                    "shahar": {"type": "string"},
                },
                "required": ["ism", "yosh", "shahar"],
                "additionalProperties": False,
            },
            "strict": True,
        },
    },
)
 
import json
data = json.loads(response.output_text)
print(data["ism"], data["yosh"], data["shahar"])

strict: True — kalit so'z. Bu yoqilganda model sxemadan chetga chiqa olmaydi: qo'shimcha maydon qo'sha olmaydi, talab qilingan maydonni tashlab keta olmaydi, noto'g'ri tur qaytara olmaydi. Sxema — kafolat, taxmin emas.

3. Pydantic bilan — Python'da qulayroq yo'l#

Sxemani qo'lda JSON sifatida yozish zerikarli va xatoga moyil. Python'da pydantic klassidan avtomatik sxema chiqarish mumkin:

from pydantic import BaseModel
 
class ShaxsMalumoti(BaseModel):
    ism: str
    yosh: int
    shahar: str
 
response = client.responses.parse(
    model="gpt-4o-mini",
    input="Aziz, 28 yoshda, Toshkentda yashaydi.",
    text_format=ShaxsMalumoti,
)
 
shaxs = response.output_parsed
print(shaxs.ism, shaxs.yosh, shaxs.shahar)  # to'g'ridan-to'g'ri Python obyekti

.parse() metodi sxemani avtomatik quradi VA javobni qayta Pydantic obyektiga aylantiradi — json.loads() ham, qo'lda tekshirish ham shart emas. IDE'ingiz shaxs.ism deb yozganingizda avtokompleteni ko'rsatadi, chunki bu — oddiy tiplangan Python obyekti.

4. Enum — cheklangan variantlar to'plami#

Ba'zan maydon cheksiz matn emas, balki oldindan belgilangan variantlardan biri bo'lishi kerak — masalan, "holat" faqat uchta qiymatdan biri bo'lsin:

from enum import Enum
from pydantic import BaseModel
 
class Holat(str, Enum):
    OCHIQ = "ochiq"
    JARAYONDA = "jarayonda"
    YOPILGAN = "yopilgan"
 
class Murojaat(BaseModel):
    mavzu: str
    holat: Holat
 
response = client.responses.parse(
    model="gpt-4o-mini",
    input="Mijoz internet ulanishi ishlamayapti deb yozdi, hali hal bo'lmagan.",
    text_format=Murojaat,
)
 
murojaat = response.output_parsed
print(murojaat.holat)  # Holat.OCHIQ — model boshqa hech narsa qaytara olmaydi

Bu klassifikatsiya vazifalarida ayniqsa foydali — model "balki ochiq, balki yopilgan" kabi noaniq javob berish imkoniga umuman ega emas.

5. Murakkabroq sxema: ro'yxatlar va ichma-ich obyektlar#

from pydantic import BaseModel
 
class Mahsulot(BaseModel):
    nomi: str
    narxi: float
    mavjud: bool
 
class Buyurtma(BaseModel):
    mijoz_ismi: str
    mahsulotlar: list[Mahsulot]
    jami_narx: float
 
response = client.responses.parse(
    model="gpt-4o-mini",
    input="""
    Mijoz Dilnoza. U ikkita narsa buyurtma qildi: noutbuk kompyuter — narxi
    8500000 so'm, mavjud. Va simsiz sichqoncha — narxi 120000 so'm, hozircha
    tugagan. Jami: 8620000 so'm.
    """,
    text_format=Buyurtma,
)
 
buyurtma = response.output_parsed
for mahsulot in buyurtma.mahsulotlar:
    print(f"{mahsulot.nomi}: {mahsulot.narxi:,.0f} so'm — {'bor' if mahsulot.mavjud else 'yo\\'q'}")

Model matndagi tabiiy tilni avtomatik ravishda to'g'ri turlangan ma'lumotga aylantiradi — raqamlarni floatga, ha/yo'qni boolga. Bu — noaniq matndan (email, foydalanuvchi xabari, hujjat) tuzilgan ma'lumot ajratib olishning eng ishonchli yo'li.

6. refusal — model rad etganda nima bo'ladi#

Ba'zan model xavfsizlik siyosati asosida javob berishdan bosh tortadi (masalan, zararli so'rov bo'lsa). Structured Outputs bilan ishlaganda bu holat ham strukturalangan tarzda keladi, shuning uchun uni maxsus tekshirish kerak — aks holda kodingiz bo'sh yoki noto'g'ri ma'lumotni haqiqiy natija deb qabul qilib qo'yishi mumkin:

response = client.responses.parse(model="gpt-4o-mini", input="...", text_format=ShaxsMalumoti)
 
if response.output[0].content[0].type == "refusal":
    print("Model javob berishdan bosh tortdi:", response.output[0].content[0].refusal)
else:
    shaxs = response.output_parsed

7. Qachon kerak, qachon ortiqcha#

Yodda saqlang
  • 01Javob to'g'ridan-to'g'ri dasturga (bazaga, funksiyaga, API'ga) ketayotgan bo'lsa — Structured Outputs ishlating.
  • 02Javob shunchaki foydalanuvchiga o'qish uchun matn bo'lsa (masalan, chat javobi) — sxema shart emas, ortiqcha murakkablik qo'shadi.
  • 03"Model bu formatda javob berishi kerak" degan har qanday talab — bu sxema kerakligining belgisi.
  • 04strict: True har doim yoqing, agar SDK'ingiz qo'llab-quvvatlasa — u xato ehtimolini deyarli nolga tushiradi.
  • 05Cheklangan variantlar (holat, kategoriya) uchun erkin string emas, enum ishlating.

8. Nima noto'g'ri ketishi mumkin#

BelgiSababYechim
additionalProperties xatosistrict: True bilan bu maydon unutilganSxemaga "additionalProperties": false qo'shing
Ixtiyoriy maydon xato beradistrict rejimida hamma maydon required'da bo'lishi kerakIxtiyoriy maydonni ["string", "null"] turi bilan belgilang
output_parsed bo'sh yoki NoneModel rad etgan (refusal)Har doim refusal holatini alohida tekshiring
Sxema juda murakkab deb rad etiladiIchma-ich darajalar yoki maydonlar soni chegaradan oshganSxemani soddalashtiring yoki bir necha kichikroq so'rovga bo'ling
Amaliy topshiriq

Chek ma'lumotini sxemaga soling

Erkin matn ko'rinishidagi (masalan, "Bugun, 14-sentabr, do'kondan non — 8000 so'm va sut — 15000 so'm oldim") xabarni qat'iy sxemaga ega tuzilgan ma'lumotga aylantiruvchi Pydantic klass va so'rov yozing. Natijada jami summani ham avtomatik hisoblatib ko'ring (modeldan so'rang yoki o'zingiz Python'da yig'indini oling — ikkala yondashuvni solishtiring).

Maslahatni ko'rsatish

Pydantic klassida DokonNomi, Sana, JamiSumma va Mahsulotlar (ro'yxat, har biri Nomi+Narxi) maydonlarini aniqlang. Namunaviy matnni qo'lda yozib, .parse() orqali sinab ko'ring.