Skip to content
This page has been auto-translated and may contain errors.View in English

संरचित आउटपुट

docs.scrimba.com

पहले, समस्या का आकार। संरचित आउटपुट मॉडल को ऐसा डेटा लौटाने की प्रथा है जिसे आपका कोड सीधे पढ़ सकता है, एक फ़ील्ड जिसे आप शाखा दे सकते हैं, न कि एक पैराग्राफ जिसे आपको हाथ से पार्स करना हो। यह अध्याय उसे विश्वसनीय बनाने के बारे में है।

अब तक मॉडल आपको टेक्स्ट देता है, जो अच्छा है जब कोई व्यक्ति इसे पढ़े। लेकिन सॉफ़्टवेयर पैराग्राफ से ज्यादा कुछ नहीं कर सकता। मॉडल के उत्तर पर कोड में कार्य करने के लिए, आपको इसकी जरूरत है डेटा के रूप में: एक फ़ील्ड जिसे आप पढ़ सकते हैं, एक मान जिस पर आप शाखा दे सकते हैं, एक रिकॉर्ड जिसे आप सहेज सकते हैं।

बदलाव छोटा है लेकिन यह डाउनस्ट्रीम में सबकुछ बदल देता है। एक बार जब मॉडल { "sentiment": "negative" } लौटाता है, तो एक वाक्य के बजाय इस बारे में कि ग्राहक कैसे असंतुष्ट लगता है, आपका कोड टिकट को रूट कर सकता है, एक डैशबोर्ड अपडेट कर सकता है, या एक सतर्कता भेज सकता है। दिलचस्प हिस्सा यह है कि जब मॉडल केवल टेक्स्ट की भविष्यवाणी करता है तो आप इसे स्वच्छ डेटा कैसे उत्पन्न करते हैं, और उत्तर एक लीवर को प्रकट करता है जिसे आप नहीं जानते थे।

मॉडल टेक्स्ट लौटाता है। आपके कोड को डेटा की जरूरत है: एक फ़ील्ड पढ़ने के लिए, एक मान जिस पर शाखा दी जाए, एक रिकॉर्ड स्टोर करने के लिए। यह अध्याय उन दोनों के बीच पुल है, और कदम यह है कि मॉडल को चीजों को अच्छी तरह से फॉर्मेट करने की आशा करना बंद करें और आउटपुट को सीमित करना शुरू करें।

यहाँ एक असली लीवर है, प्रॉम्प्टिंग चाल नहीं। LLM कैसे काम करते हैं से एक ही सैंपलिंग लूप को स्टीयर किया जा सकता है ताकि आउटपुट आपके चाहे गए आकार में बाध्य हो, जो एक अस्पष्ट टेक्स्ट जेनरेटर को एक घटक में बदल देता है जिसे आपका बाकी सिस्टम भरोसा कर सकता है।

एक मॉडल जो गद्य लौटाता है वह एक घटक है जिसे आप कंपोज़ नहीं कर सकते। जब इसका आउटपुट किसी अन्य सिस्टम को फीड करता है, तो आपको ज्ञात आकार वाला डेटा चाहिए, और आपको उस डेटा को प्राप्त करने की विफलता के तरीके ऐसे होने चाहिए जिन्हें आप देख सकते हैं और संभाल सकते हैं।

यह अध्याय एक स्कीमा में पीढ़ी को सीमित करने के बारे में है और वह लेटेंसी में क्या खर्च करता है, यह आपको क्या नहीं देता है (सही मान), और यह किनारों पर कैसे विफल होता है। अंदर की मशीनरी वही है जो टूल उपयोग को चलाती है: एक टूल कॉल स्कीमा के स्थान पर एक फ़ंक्शन हस्ताक्षर के साथ संरचित आउटपुट है।

JSON माँगें

पहली वृत्ति प्रॉम्प्ट में पूछना है: "JSON" के रूप में उत्तर दें", सादे-पाठ प्रारूप जो सॉफ़्टवेयर डेटा पास करने के लिए उपयोग करते हैं, घुंघराले ब्रेसिज़ के अंदर फ़ील्ड और मान के रूप में लिखे गए हैं। इसे आजमाएं और यह ज्यादातर काम करता है, जो जाल है। मॉडल अभी भी संभावित टेक्स्ट की भविष्यवाणी करने के अलावा कुछ नहीं कर रहा है, और कभी-कभी संभावित टेक्स्ट कोड बाड़ है, या डेटा से पहले एक दोस्ताना "ठीक है, यहाँ जाओ!", या इसके बाद एक अनुगामी टिप्पणी है। इनमें से कोई भी JSON को पढ़ने वाले कोड को तोड़ देता है। दया से पूछना JSON की ओर भविष्यवाणी को पूर्वाग्रह करता है; यह इसे मजबूर नहीं करता है।

तो प्रदाता आपको एक असली लीवर देते हैं। response_format के साथ JSON मोड चालू करना सिर्फ पूछने से अधिक करता है: यह मॉडल को सीमित करता है ताकि सिंटैक्स मान्य JSON के रूप में वापस आए।

python
import json

response = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": 'शहर और तापमान निकालें। JSON के रूप में उत्तर दें: { "city": string, "tempC": number }.'},
        {"role": "user", "content": "यह अभी ओस्लो में लगभग 18 डिग्री है।"},
    ],
    response_format={"type": "json_object"},  # आउटपुट को मान्य JSON सिंटैक्स में बाध्य करता है
)

data = json.loads(response.choices[0].message.content)
print(data["city"], data["tempC"])  # "Oslo" 18

response_format={"type": "json_object"} आउटपुट को मान्य JSON सिंटैक्स बनाता है, इसलिए json.loads भटकते हुए गद्य पर चोक नहीं करेगा। आप अभी भी प्रॉम्प्ट में चाहने वाली फ़ील्ड का वर्णन करते हैं, क्योंकि JSON मोड मान्य JSON का वादा करता है, आपके ध्यान में रखी गई विशेष फ़ील्ड को नहीं। यह "बिल्कुल JSON नहीं" को नियम से बाहर करता है, "गलत आकार के साथ JSON" को नहीं। एक चीज जो यह अभी भी वादा नहीं कर सकता है: यदि उत्तर आधे रास्ते में काट दिया जाता है, तो आप एक आधा JSON ऑब्जेक्ट प्राप्त कर सकते हैं, इसलिए यह विश्वसनीय सिंटैक्स है, हर मामले में एक कठोर गारंटी नहीं है।

JunoJSON माँगें अकेले प्रॉम्प्ट में JSON माँगना अस्थिर है, क्योंकि मॉडल केवल संभावित टेक्स्ट की भविष्यवाणी करता है और इसे बाड़ में या बातचीत में लपेट सकता है जो पार्स को तोड़ता है। response_format को JSON मोड पर सेट करना सिंटैक्स को बाध्य करता है ताकि यह मान्य JSON के रूप में वापस आए। यह वादा नहीं करता है कि फ़ील्ड मेल खाते हैं जो आपने पूछा है, और आधे रास्ते में कटा हुआ उत्तर अभी भी आधा ऑब्जेक्ट आ सकता है, इसलिए प्रॉम्प्ट में आकार का वर्णन करें और जांचें कि क्या होता है।

प्रवृत्ति प्रॉम्प्ट में "JSON के रूप में उत्तर दें" लिखना है, जहाँ JSON डेटा प्रारूप है जिसे सॉफ़्टवेयर पास करते हैं। यह ज्यादातर काम करता है, जो बिल्कुल समस्या है: ज्यादातर एक अनुबंध नहीं है। मॉडल संभावित टेक्स्ट की भविष्यवाणी करता है, और संभावित टेक्स्ट कभी-कभी कोड बाड़, "ठीक है!" प्रस्तावना, या अनुगामी नोट शामिल करते हैं, जो सभी json.loads को तोड़ते हैं।

JSON मोड पहला असली लीवर है। response_format को JSON ऑब्जेक्ट प्रकार पर सेट करना पीढ़ी को सीमित करता है ताकि सिंटैक्स मान्य JSON हो, गद्य नहीं जो इसकी तरह दिखता है।

python
import json

response = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": 'शहर और तापमान निकालें। JSON के रूप में उत्तर दें: { "city": string, "tempC": number }.'},
        {"role": "user", "content": "यह अभी ओस्लो में लगभग 18 डिग्री है।"},
    ],
    response_format={"type": "json_object"},  # आउटपुट को मान्य JSON सिंटैक्स में बाध्य करता है
)

data = json.loads(response.choices[0].message.content)
print(data["city"], data["tempC"])  # "Oslo" 18

यहाँ response_format का आकार OpenAI का है; अन्य प्रदाता अपने स्वयं के फ़ील्ड के अंतर्गत एक ही विचार को उजागर करते हैं, इसलिए अवधारणा को पोर्ट करें, शाब्दिक कुंजी को नहीं। JSON मोड सिंटैक्स को सीमित करता है, कभी फ़ील्ड आकार को नहीं। आप प्रॉम्प्ट में फ़ील्ड का वर्णन करते हैं, और मॉडल उन्हें पुनः नाम देने, छोड़ने, या विभिन्न तरीके से नेस्ट करने के लिए स्वतंत्र है जबकि अभी भी मान्य JSON उत्सर्जित करता है।

एक और दरार है: JSON मोड केवल तभी अच्छी तरह से गठित JSON का वादा करता है जब प्रतिक्रिया समाप्त होती है। अपनी max_tokens छत को मिडऑब्जेक्ट पर मार दें और आप ट्रंकेटेड, अपार्सेबल आउटपुट प्राप्त करते हैं, इसलिए पार्स को किसी भी तरह सुरक्षा की आवश्यकता होती है।

JunoJSON माँगें JSON मोड सिंटैक्स को सीमित करता है ताकि मॉडल डेटा को बाड़ में और बातचीत में लपेटना बंद करे, लेकिन यह कभी भी फ़ील्ड को पिन नहीं करता है, इसलिए मॉडल अभी भी उन्हें पुनः नाम दे सकता है या छोड़ सकता है। response_format कुंजी OpenAI का है; अन्य प्रदाता इसे अलग तरीके से स्पेल करते हैं। और वादा केवल तभी रहता है जब प्रतिक्रिया समाप्त हो जाती है, इसलिए `max_tokens` द्वारा ट्रंकेट किया गया उत्तर अपार्सेबल आता है। किसी भी तरह पार्स की सुरक्षा करें।

प्रॉम्प्ट में "JSON के रूप में उत्तर दें" एक सुझाव है, और सुझाव भार के तहत विफल होते हैं: यहाँ कोड बाड़, वहाँ प्रस्तावना, एक अनुगामी टिप्पणी जब मॉडल बातूनी महसूस करता है, प्रत्येक उत्पादन में एक json.loads अपवाद। JSON मोड (यहाँ response_format={"type": "json_object"}) सुझाव को उत्पन्न सिंटैक्स पर एक बाधा के साथ बदल देता है, ताकि जो बाइट वापस आती हैं वह JSON को पार्स करती हैं।

python
import json

response = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": 'शहर और तापमान निकालें। JSON के रूप में उत्तर दें: { "city": string, "tempC": number }.'},
        {"role": "user", "content": "यह अभी ओस्लो में लगभग 18 डिग्री है।"},
    ],
    response_format={"type": "json_object"},  # आउटपुट को मान्य JSON सिंटैक्स में बाध्य करता है
)

data = json.loads(response.choices[0].message.content)
print(data["city"], data["tempC"])  # "Oslo" 18

इसे स्पष्ट करें कि यह क्या सीमित करता है। JSON मोड सिंटैक्स को पिन करता है, स्कीमा को नहीं, और केवल एक पूर्ण प्रतिक्रिया पर। मॉडल अभी भी फ़ील्ड नाम चुनता है, एक आवश्यक फ़ील्ड छोड़ सकता है, और जैसे वह चाहे नेस्ट कर सकता है।

गारंटी पीढ़ी की समाप्ति पर सशर्त है: यदि मॉडल मिडऑब्जेक्ट में max_tokens से टकराता है, तो आप एक ट्रंकेटेड स्ट्रिंग प्राप्त करते हैं जो मान्य JSON नहीं है, जिसका मतलब है कि एक विफलता मोड जो JSON मोड हटाता नहीं है वह एक जो आपके पुनः प्रयास पथ को सबसे अधिक सहायता की आवश्यकता है। यहाँ दिखाई गई response_format कुंजी OpenAI की है; अन्य प्रदाताओं पर समकक्ष एक अलग नाम के तहत रहता है, इसलिए अवधारणा को पोर्टेबल मानें और शाब्दिक फ़ील्ड को नहीं। आकार गारंटियों के लिए आपको एक स्कीमा चाहिए, जो अगला भाग है।

JunoJSON माँगें JSON मोड एक समाप्त प्रतिक्रिया पर सिंटैक्स को सीमित करता है, और अधिक कुछ नहीं: मॉडल अभी भी फ़ील्ड का नाम देता है, छोड़ता है, और नेस्ट करता है जैसा वह चाहता है, और `max_tokens` द्वारा मारा गया पीढ़ी आपको ट्रंकेटेड, अपार्सेबल आउटपुट देता है। वह ट्रंकेशन मामला वह है जो आपकी त्रुटि पथ को मालिक बनना है, क्योंकि मोड नहीं करेगा। response_format आकार OpenAI का है, इसलिए विचार को पोर्ट करें, कुंजी को नहीं। आकार के लिए, आपको स्कीमा चाहिए।

स्कीमा के साथ आकार को लॉक करें

JSON मोड सिंटैक्स को रखता है, लेकिन मॉडल अभी भी किसी फ़ील्ड को पुनः नाम दे सकता है, छोड़ सकता है, या चीजों को अलग तरीके से नेस्ट कर सकता है। उस विगलरूम को हटाने के लिए, इसे एक स्कीमा दें: फ़ील्ड और प्रकारों का सटीक विवरण जो आउटपुट को रखना चाहिए, एक फॉर्म जो मॉडल को भरना आवश्यक है। strict: true के साथ, आउटपुट को फिर उस फॉर्म से मेल खाने की गारंटी दी जाती है।

python
import json

response = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": "संदेश से संपर्क विवरण निकालें।"},
        {"role": "user", "content": "हाय, मैं मारा लिन हूँ, मुझसे [email protected] पर संपर्क करें।"},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "contact",
            "strict": True,  # स्कीमा को बिल्कुल लागू करें
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "email": {"type": "string"},
                },
                "required": ["name", "email"],
                "additionalProperties": False,
            },
        },
    },
)

contact = json.loads(response.choices[0].message.content)
# {"name": "Mara Lin", "email": "[email protected]"}

एक स्कीमा कैसे कठोर गारंटी हो सकता है जब मॉडल केवल टोकन की भविष्यवाणी करता है? क्योंकि प्रदाता यह सीमित करता है कि कौन से टोकन की भविष्यवाणी की जा सकती है। प्रत्येक चरण पर मॉडल अभी भी सभी संभावित अगले टोकन को रैंक करता है, लेकिन सिस्टम उन लोगों को हटा देता है जो आपकी स्कीमा को तोड़ेंगे, और मॉडल जो बचता है उससे चुनता है।

यदि स्कीमा कहता है कि अगली फ़ील्ड email होनी चाहिए, तो जो भी टोकन किसी अन्य फ़ील्ड को शुरू करेंगे वह मॉडल चुनने से पहले तालिका से हटा दिए जाते हैं। ऑफ-शेप टोकन हटा दिए जाते हैं, इसलिए मॉडल ऑफ-शेप से दूर नहीं हो सकता।

एक नरम प्रभाव जानने योग्य है। आप जो फ़ील्ड नाम चुनते हैं वह मॉडल को पढ़ने में मदद करता है जब मूल्य की भविष्यवाणी करता है, इसलिए एक स्पष्ट नाम बेहतर उत्तर का मार्गदर्शन करता है। tempC भरने के लिए कहा जाता है, मॉडल सेल्सियस संख्या की ओर झुकता है; value भरने के लिए पूछा जाता है, इसके पास बहुत कुछ नहीं है। फ़ील्ड को स्पष्ट रूप से नाम देना आंशिक निर्देश, आंशिक स्कीमा है।

Junoस्कीमा के साथ आकार को लॉक करें एक स्कीमा फॉर्म है जो मॉडल को भरना है, और strict: true के साथ इसे सटीक फ़ील्ड और प्रकार मिलते हैं, क्योंकि सिस्टम मॉडल चुनने से पहले कोई भी टोकन हटा देता है जो आकार को तोड़ेगा। वह प्रवर्तन है, एक विनम्र अनुरोध नहीं। अपनी फ़ील्ड को स्पष्ट रूप से भी नाम दें, क्योंकि फ़ील्ड नाम संदर्भ है जो मॉडल पढ़ता है जब यह मूल्य की भविष्यवाणी करता है। मुझे यह विश्वास करने में समय लगा कि `tempC` जैसा नाम असली काम करता है।

JSON मोड सिंटैक्स को पिन करता है लेकिन मॉडल को फ़ील्ड को पुनः नाम देने, छोड़ने, या फिर से नेस्ट करने के लिए स्वतंत्र छोड़ता है। एक स्कीमा उस अंतराल को बंद करता है: फ़ील्ड और प्रकारों का सटीक विवरण, और strict: true के साथ आउटपुट इसे मेल खाने की गारंटी दी जाती है।

python
import json

response = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": "संदेश से संपर्क विवरण निकालें।"},
        {"role": "user", "content": "हाय, मैं मारा लिन हूँ, मुझसे [email protected] पर संपर्क करें।"},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "contact",
            "strict": True,  # स्कीमा को बिल्कुल लागू करें
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "email": {"type": "string"},
                },
                "required": ["name", "email"],
                "additionalProperties": False,
            },
        },
    },
)

contact = json.loads(response.choices[0].message.content)
# {"name": "Mara Lin", "email": "[email protected]"}

तंत्र बाधित डिकोडिंग है: सैंपलिंग चरण पर लागू किया गया टोकन प्रूनिंग। हर स्थिति पर मॉडल सभी टोकन पर अपने सामान्य रैंकिंग का उत्पादन करता है, फिर सिस्टम किसी भी टोकन को मास्क करता है जो आउटपुट को स्कीमा से मेल खाना बंद कर देगा, और मॉडल जीवक से नमूना लेता है। यदि व्याकरण कहता है कि अगला टोकन email फ़ील्ड को खोलना चाहिए, तो जो भी अन्य चीज़ को शुरू करेंगे वह ड्रॉ से पहले शून्य कर दिए जाते हैं। मॉडल ऑफ-शेप से दूर नहीं हो सकता क्योंकि ऑफ-शेप चाल बोर्ड से हटा दी गई हैं, न कि प्रॉम्प्ट में हतोत्साहित।

दो व्यावहारिक हैंडल। फ़ील्ड नाम निर्देश हैं, इसलिए जिस मान को आप चाहते हैं उसके लिए उन्हें नाम दें। tempC उस स्थान पर सेल्सियस की ओर झुकाता है जहाँ value अनुमान लगाने के लिए छोड़ देता है, और फ़ील्ड पर विवरण कठोर होता है। और एक ही बाधा एक enum (अनुमत मानों की एक निश्चित सूची) या एक संख्या श्रृंखला को लागू करती है, जो वर्गीकरण को विश्वसनीय बनाता है: लेबल स्थिति पर, केवल आपकी सूचीबद्ध लेबल मास्क से बचती हैं, इसलिए मॉडल सूची से भी एक श्रेणी को गढ़ नहीं सकता।

Junoस्कीमा के साथ आकार को लॉक करेंstrict: true के साथ, बाधित डिकोडिंग मॉडल नमूना से पहले स्कीमा को तोड़ने वाले सभी टोकन को मास्क करता है, इसलिए आकार लागू किया जाता है, अनुरोध नहीं किया जाता है। इसे चलाएं: फ़ील्ड नाम और विवरण निर्देश हैं, इसलिए `value` नहीं `tempC` नाम दें और मॉडल इसे बेहतर भरता है। एक ही मास्किंग `enum` को लागू करता है, जो वर्गीकरण को धारण करता है, मॉडल ऐसा लेबल नहीं बना सकता है जो आपकी सूची में न हो।

JSON मोड आपको पार्सेबल बाइट देता है; एक स्कीमा आपको ज्ञात आकार देता है। strict: true के साथ आउटपुट को उन फ़ील्ड सेट और प्रकारों से मेल खाने की गारंटी दी जाती है जो आप घोषित करते हैं, जो डेटा के बीच का अंतर है जिसे आप अंधे में इंडेक्स कर सकते हैं और डेटा जिसे आप रक्षात्मक रूप से जांच करते हैं।

python
import json

response = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": "संदेश से संपर्क विवरण निकालें।"},
        {"role": "user", "content": "हाय, मैं मारा लिन हूँ, मुझसे [email protected] पर संपर्क करें।"},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "contact",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "email": {"type": "string"},
                },
                "required": ["name", "email"],
                "additionalProperties": False,
            },
        },
    },
)

contact = json.loads(response.choices[0].message.content)

तंत्र बाधित डिकोडिंग है, और आप इसे शून्य से समझना चाहते हैं क्योंकि इसकी लागत मुक्त नहीं है। मॉडल अपनी शब्दावली में प्रत्येक टोकन के लिए हर चरण पर एक संभावना उत्सर्जित करता है। बाधित डिकोडिंग आपकी स्कीमा को व्याकरण में संकलित करता है (टोकन अनुक्रम कानूनी हैं इसका एक सेट नियम), फिर हर चरण पर एक मास्क बनाता है जो प्रत्येक अवैध टोकन की संभावना को शून्य पर सेट करता है, इसलिए नमूना केवल एक टोकन पर उतर सकता है जो आउटपुट को अब तक मान्य रखता है। आकार निर्माण द्वारा लागू किया जाता है, पूछने के द्वारा नहीं।

वह संकलन मुक्त नहीं है, और यह लेटेंसी के रूप में दिखाई देता है। एक नई स्कीमा के विरुद्ध पहली कॉल व्याकरण बनाने के लिए एक बार की लागत देती है, इसलिए एक ताजा स्कीमा पर कोल्ड-स्टार्ट लेटेंसी स्थिर अवस्था की तुलना में अधिक है। अपनी स्कीमा को स्थिर और पुनः उपयोग करें और न कि प्रति-अनुरोध उत्पन्न करें, या आप उस संकलन को बार-बार देते हैं।

additionalProperties: false और एक पूर्ण required सूची सजावट नहीं है: वे ही हैं जो सिस्टम को अतिरिक्त या लापता फ़ील्ड को खुले तौर पर अस्वीकार करने देते हैं, और प्रदाताओं पर जो स्कीमा-संचालित अस्वीकार का समर्थन करते हैं, वे भी जो मॉडल को एक संरचित अस्वीकार के बजाय एक विकृत ऑब्जेक्ट लौटाने का एक साफ तरीका देते हैं। उन्हें छोड़ दें और आप जो मान्य गिनता है उसे चौड़ा करते हैं, जो सख्त मोड तक पहुँचने का विपरीत है।

कुछ उत्पादन वास्तविकताएं। सख्त समर्थन असमान है: कुछ प्रदाता असली व्याकरण को लागू करते हैं, अन्य इसे अनुमानित करते हैं या केवल JSON स्कीमा का एक सबसेट समर्थन करते हैं (कोई pattern नहीं, सीमित नेस्टिंग), इसलिए यह मान लेने के बजाय कि आपका प्रदाता वास्तव में क्या सम्मान करता है। आंशिक और स्ट्रीमिंग आउटपुट अजीब मामला है: जबकि टोकन स्ट्रीम करते हैं, आप एक वाक्यात्मक रूप से अधूरे ऑब्जेक्ट को पकड़ते हैं, इसलिए या तो पार्स से पहले पूर्णता तक बफर करें या एक वर्धनशील पार्सर का उपयोग करें जो एक आधा-निर्माण संरचना को सहन करता है। और यह टूल उपयोग के समान तंत्र है: एक फ़ंक्शन का तर्क स्कीमा समान तरीके से बाधित है, इसलिए यहाँ सबकुछ सीधे विश्वसनीय टूल कॉल बनाने के लिए स्थानांतरित होता है।

Junoस्कीमा के साथ आकार को लॉक करें बाधित डिकोडिंग आपकी स्कीमा को व्याकरण में संकलित करता है और नमूने से पहले हर अवैध टोकन को शून्य करता है, इसलिए आकार निर्माण द्वारा लागू किया जाता है। वह संकलन एक नई स्कीमा के विरुद्ध पहली कॉल पर लेटेंसी करता है, इसलिए स्कीमा को प्रति-अनुरोध एक प्रिंट करने के बजाय पुनः उपयोग करें। additionalProperties: false और एक पूर्ण required सूची रखें, वे अस्वीकृति को लागू करते हैं और, कुछ प्रदाताओं पर, एक साफ संरचित अस्वीकार। सख्त समर्थन भिन्न होता है, स्ट्रीमिंग आपको आधा ऑब्जेक्ट देता है, और एक ही मास्किंग टूल-कॉल तर्क को चलाता है, इसलिए जो आप यहाँ सीखते हैं वह दो बार भुगतान करता है।

फिर भी मान्य करें

एक स्कीमा आकार को सीमित करता है, लेकिन आउटपुट को बाहरी दुनिया से डेटा मानते हैं। आकार मान्य हो सकता है जबकि सामग्री गलत हो सकती है: निकाला गया ईमेल जो वास्तव में एक टाइपो है, एक संख्या जो मॉडल ने अनुमान लगाई है, एक फ़ील्ड खाली छोड़ दी गई क्योंकि इनपुट इसमें नहीं था। और कॉल अभी भी साधारण तरीके से विफल हो सकता है, जैसे max_tokens से कट जाना और ट्रंकेटेड JSON के रूप में आना। रक्षात्मक रूप से पार्स करें: एक मान्य आकार सही मान नहीं है।

python
import json

def parse_contact(raw):
    try:
        data = json.loads(raw)
        if not data.get("name") or not data.get("email"):
            return None  # मौजूद लेकिन खाली
        return data
    except json.JSONDecodeError:
        return None  # मान्य JSON नहीं (उदाहरण के लिए, ट्रंकेटेड प्रतिक्रिया)

contact = parse_contact(response.choices[0].message.content)
if not contact:
    pass  # विफलता को संभालें: पुनः प्रयास, फिर से पूछें, या एक दोस्ताना त्रुटि दिखाएँ

यह LLM कैसे काम करते हैं से मतिभ्रम पाठ नए कपड़ों में है: आकार सही होने से मान सही नहीं होते हैं। एक स्कीमा आपको name फ़ील्ड देने की गारंटी देता है; यह नाम सही होने की गारंटी नहीं देता है। पार्स के चारों ओर try/except साथ-साथ मान जांच सस्ता बीमा है उस जवाब के खिलाफ जो अच्छी तरह से गठित है और अभी भी गलत है।

Junoफिर भी मान्य करें एक स्कीमा आकार की गारंटी देता है, कभी मान की सच्चाई नहीं, इसलिए एक मान्य रिकॉर्ड अभी भी गलत या खाली मान रख सकता है, और कॉल अभी भी ट्रंकेटेड आ सकता है। पार्स को try/except में लपेटें और विश्वास से पहले मान जांचें। तय करें कि सत्यापन विफल होने पर क्या होता है, पुनः प्रयास या दोस्ताना त्रुटि, इसलिए यह बाद में एक हड़बड़ी नहीं है।

सख्त मोड आकार की गारंटी देता है, सामग्री की नहीं। आउटपुट स्कीमा से मेल खा सकता है और फिर भी गलत हो सकता है: एक प्रशंसनीय-दिखने वाला ईमेल जो एक टाइपो है, एक संख्या एक आवश्यक फ़ील्ड भरने के लिए बनाई गई है, एक खाली स्ट्रिंग जहाँ इनपुट कुछ नहीं रहा। और पार्स max_tokens पर ट्रंकेट होने पर पूरी तरह विफल हो सकता है। तो आप हर बार मान्य करते हैं।

python
import json

def parse_contact(raw):
    try:
        data = json.loads(raw)
    except json.JSONDecodeError:
        return None, "unparseable"  # ट्रंकेटेड या विकृत

    if not data.get("name") or not data.get("email"):
        return None, "empty_field"  # मौजूद लेकिन खाली
    if "@" not in data["email"]:
        return None, "bad_email"  # आकार ठीक है, मान नहीं
    return data, None

contact, error = parse_contact(response.choices[0].message.content)
if error == "unparseable":
    pass  # एक बार पुनः प्रयास करें, संभवतः ट्रंकेशन: max_tokens बढ़ाएँ या इनपुट छोटा करें
elif error:
    pass  # मान-स्तर की विफलता को लॉग करें और वापस गिरें

पैटर्न एक रक्षात्मक पार्स है जो विफलता तरीकों को अलग करता है, क्योंकि वे अलग हैंडलिंग चाहते हैं। एक JSONDecodeError आमतौर पर ट्रंकेशन का मतलब है, इसलिए max_tokens बढ़ाएँ या इनपुट सिकोड़ें और पुनः प्रयास करें। एक खाली या सीमा से बाहर मान एक सामग्री विफलता है, प्रारूप एक नहीं है, इसलिए एक ही कॉल पुनः प्रयास करना शायद ही मदद करता है; लॉग करें और वापस गिरें।

"पार्स नहीं कर सके" को "पार्स किए गए लेकिन गलत" से अलग करें, क्योंकि फिक्स भिन्न होता है। यह मतिभ्रम से जुड़ता है: बाधित डिकोडिंग विकृत-आउटपुट विफलता मोड को हटाया और गलत-मान वाली को पूरी तरह छोड़ दिया।

Junoफिर भी मान्य करें सख्त मोड आकार को पिन करता है, सामग्री को नहीं, तो हर बार मान्य करें: एक रिकॉर्ड अच्छी तरह से गठित हो सकता है और टाइपो, अनुमान, या खाली रख सकता है। विफलताओं को विभाजित करें, क्योंकि `JSONDecodeError` आमतौर पर ट्रंकेशन का मतलब है (max_tokens उठाएँ या इनपुट सिकोड़ें और पुनः प्रयास करें) जबकि एक खराब मान सामग्री मिस है जो एक ही कॉल पुनः प्रयास करने से नहीं है। बाधित डिकोडिंग विकृत-आउटपुट समस्या को हटाया और गलत-मान को अक्षत छोड़ा।

बाधित डिकोडिंग विकृत-आउटपुट विफलता मोड को बंद करता है और और कुछ नहीं बंद करता है। आकार की गारंटी है; सामग्री नहीं है। एक आवश्यक फ़ील्ड जो इनपुट कभी समर्थित नहीं किया था एक आत्मविश्वासी अनुमान के साथ भरा जाता है, एक संख्या किसी भी समझदारी वाली श्रृंखला के बाहर उतरती है, एक ईमेल स्ट्रिंग के रूप में पार्स करता है लेकिन एक टाइपो है।

प्रारूप गारंटी ही ट्रंकेशन पर समाप्त होती है। तो सत्यापन वैकल्पिक स्वच्छता नहीं है, यह परत है जो पकड़ता है जो स्कीमा संरचनात्मक रूप से नहीं कर सकता।

python
import json

def parse_contact(raw, retry):
    try:
        data = json.loads(raw)
    except json.JSONDecodeError:
        return None, "truncated"  # अधूरी पीढ़ी, सामग्री समस्या नहीं

    if not data.get("name") or "@" not in data.get("email", ""):
        return None, "invalid_value"  # आकार रहा, मान नहीं
    return data, None

contact, failure = parse_contact(raw, retry=False)
if failure == "truncated":
    pass  # max_tokens बढ़ाएँ या इनपुट ट्रिम करें, फिर कॉल को पुनः प्रयास करें
elif failure == "invalid_value":
    pass  # मरम्मत पथ: खराब आउटपुट को वापस फीड करें निर्देश के साथ इसे ठीक करने के लिए, या वापस गिरें

एक बार जो एक सत्यापक को पकड़ता है जो एक try/except से अलग है जो सबकुछ निगलता है, तीन चीजें हैं:

  • विफलता को वर्गीकृत करें: ट्रंकेशन एक बजट समस्या है और अधिक max_tokens के साथ पुनः प्रयास करके ठीक किया जाता है, जबकि एक अमान्य मान एक सामग्री समस्या है जो एक अंधा पुनः प्रयास पुनः उत्पादन करेगा।
  • मान-स्तर की स्थिति के लिए एक मरम्मत पथ बनाएँ केवल वापसी के बजाय। अमान्य आउटपुट को वापस फीड करना अक्सर एक अतिरिक्त कॉल में इसे पुनः प्राप्त करता है, जो अनुरोध विफल करने से सस्ता है, लेकिन पुनः प्रयास को सीमित करें ताकि एक लगातार गलत इनपुट लूप न हो सके।
  • लागत को सीमित करें: हर पुनः प्रयास एक और बिल किया गया कॉल है और लेटेंसी का एक और दौर है, इसलिए एक पुनः प्रयास बजट डिज़ाइन का हिस्सा है, न कि बाद का विचार।

मान को मान्य करें, अकेले पार्स को नहीं। यह मतिभ्रम निहितार्थ कहानी संरचित डेटा पर लागू है: बाधित डिकोडिंग एक साफ लिफाफा देता है और यह बताता है कि अंदर क्या है। तो लिफाफा ठीक वह जगह है जहाँ टीम सत्यापन करना बंद करते हैं और जल जाते हैं। स्कीमा सत्यापन, श्रृंखला और अर्थपूर्ण जांच, और एक बाधित मरम्मत लूप तीन परतें हैं, और वे अलग चीजें पकड़ते हैं: स्कीमा आकार को पकड़ता है, जांच बकवास मान को पकड़ती है, मरम्मत लूप बचाए जाने योग्य लोगों को पुनः प्राप्त करता है।

Junoफिर भी मान्य करें सख्त मोड विकृत आउटपुट को हटा देता है और गलत मान को पूरी तरह छोड़ देता है, तो सामग्री को मान्य करें, अकेले पार्स को नहीं। विफलता को वर्गीकृत करें: ट्रंकेशन एक बजट फिक्स है (अधिक `max_tokens`, पुनः प्रयास), एक अमान्य मान एक सामग्री मिस है कि एक अंधा पुनः प्रयास केवल पुनः उत्पादन करता है, इसलिए एक मरम्मत पथ बनाएँ जो खराब आउटपुट को वापस फीड करता है, और पुनः प्रयास को सीमित करें ताकि एक खराब इनपुट आपके बिल को लूप न कर सके। साफ लिफाफा ठीक वह जगह है जहाँ लोग जाँचना बंद करते हैं और जल जाते हैं।

दो पैटर्न: वर्गीकृत और निष्कर्षण

अधिकांश संरचित-आउटपुट कार्य दो आकारों में से एक है।

वर्गीकरण एक इनपुट को लेबल के एक निश्चित सेट में से एक में बांटता है। स्कीमा में एक enum आउटपुट को बिल्कुल उन लेबलों तक सीमित करता है, एक ही टोकन-प्रूनिंग ट्रिक का उपयोग करके: लेबल स्थिति पर, केवल अनुमत मानों की भविष्यवाणी की जा सकती है, इसलिए मॉडल एक श्रेणी का आविष्कार नहीं कर सकता है जो आपकी सूची में नहीं है।

python
# वर्गीकरण के लिए स्कीमा टुकड़ा
{"type": "string", "enum": ["billing", "technical", "general"]}

निष्कर्षण मुक्त पाठ से विशिष्ट फ़ील्ड खींचता है, जैसे पहले का संपर्क उदाहरण: एक नाम, एक तारीख, एक राशि, उत्पाद नाम की सूची। एक साथ, वर्गीकृत और निष्कर्षण वास्तविक AI सुविधाओं का एक बड़ा हिस्सा कवर करते हैं: समर्थन टिकट रूटिंग, सामग्री टैगिंग, ईमेल को रिकॉर्ड में बदलना, रसीद पढ़ना। दोनों एक अस्पष्ट टेक्स्ट जेनरेटर को एक विश्वसनीय घटक में बदल देते हैं जो आपका कोड बना सकता है।

Junoदो पैटर्न: वर्गीकृत और निष्कर्षण वर्गीकरण एक इनपुट को लेबल के एक निश्चित सेट से एक में बांटता है, `enum` के साथ बंद हो जाता है ताकि मॉडल आपकी सूची से एक श्रेणी का आविष्कार न कर सके। निष्कर्षण नाम वाली फ़ील्ड को मुक्त पाठ से एक रिकॉर्ड में खींचता है। दोनों एक अस्पष्ट टेक्स्ट जेनरेटर को एक विश्वसनीय घटक में बदल देते हैं, और एक साथ वे व्यावहारिक AI सुविधाओं का एक बड़ा हिस्सा कवर करते हैं।

लगभग सबकुछ जो आप संरचित आउटपुट के साथ बनाते हैं दो आकारों में से एक है, और उन्हें नाम देना आपको सही स्कीमा तक पहुँचने में मदद करता है।

वर्गीकरण एक इनपुट को एक निश्चित सेट से एक लेबल के लिए मैप करता है। enum पूरी नौकरी को ले जाता है: बाधित डिकोडिंग लेबल स्थिति पर आपकी सूचीबद्ध लेबलों को छोड़कर हर टोकन को मास्क करता है, इसलिए मॉडल उनमें से एक लौटाता है या और कुछ नहीं।

python
# वर्गीकरण: एक बंद सेट से एक लेबल
{"type": "string", "enum": ["billing", "technical", "general"]}

निष्कर्षण नाम वाली फ़ील्ड को मुक्त पाठ से एक रिकॉर्ड में खींचता है, संपर्क और टिकट उदाहरण। दोनों रचना करते हैं: एक एकल स्कीमा एक बार वर्गीकृत और निष्कर्षण कर सकता है, जो सबसे वास्तविक सुविधाएं हैं। बंद सेट को enum मिलते हैं; खुली मान एक टाइप की गई फ़ील्ड मिलती हैं।

सचेत करने के लिए निर्णय: जब एक मान वास्तव में एक निश्चित सेट (स्थिति, श्रेणी, प्राथमिकता) है, तो enum का उपयोग करें ताकि मॉडल दूर न चला जाए, और जब यह खुला है (एक नाम, एक सारांश), तो एक सादे टाइप की गई फ़ील्ड का उपयोग करें और स्वीकार करें कि आप मान को बहुत अधिक मान्य करने के लिए विश्वास कर रहे हैं। उन्हें मिलाना, एक enum जहाँ वास्तविक दुनिया के अधिक मामले हैं, या एक मुक्त फ़ील्ड जहाँ एक बंद सेट त्रुटियों को पकड़ा होता, ठीक वह जगह है जहाँ ये सुविधाएं शांति से ख़राब हो जाती हैं।

Junoदो पैटर्न: वर्गीकृत और निष्कर्षण दो आकार अधिकांश को कवर करते हैं: वर्गीकरण एक बंद सेट से एक लेबल के लिए मैप करता है (enum प्रवर्तन करता है) और निष्कर्षण नाम वाली फ़ील्ड को एक रिकॉर्ड में खींचता है, और एक स्कीमा दोनों को एक बार कर सकता है। जानबूझकर चुनें: निश्चित सेट के लिए enum ताकि मॉडल दूर न चला जाए, खुली मान के लिए सादे टाइप की गई फ़ील्ड जिसे आप मान्य करेंगे। एक enum जो एक वास्तविक-दुनिया मामले को याद करता है गलत लेबल का एक शांत स्रोत है।

संरचित आउटपुट दो पैटर्न में पतन होता है, और अंतर एक डिज़ाइन लीवर है, केवल शब्दावली नहीं। वर्गीकरण एक बंद सेट से एक लेबल के लिए इनपुट मैप करता है, एक enum द्वारा लागू किया जाता है जो बाधित डिकोडिंग आपके मानों के बीच एक कठोर पसंद तक घटाता है। निष्कर्षण मुक्त पाठ से टाइप किए गए फ़ील्ड को खींचता है। अधिकांश उत्पादन स्कीमा उन्हें जोड़ते हैं।

python
# वर्गीकरण: बाधित डिकोडिंग केवल इन टोकन को लेबल स्थिति पर अनुमति देता है
{"type": "string", "enum": ["billing", "technical", "general"]}

लीवर वह जगह है जहाँ आप बंद-सेट सीमा खींचते हैं, क्योंकि enum एक तीक्ष्ण किनारे वाली सही गारंटी है। एक मान जो वास्तव में बंद है (एक स्थिति, प्राथमिकता) enum में होना चाहिए ताकि मॉडल कुछ भी बाहर न उत्सर्जित कर सके, और यह एक खुली-सिरे की पीढ़ी को एक जांच में बदल देता है जिसे आपका डाउनस्ट्रीम कोड भरोसा कर सकता है।

लेकिन enum तब भी एक विकल्प को मजबूर करता है जब कोई भी फिट नहीं होता: यदि असली इनपुट किसी भी लेबल से मेल नहीं खाता है, तो मॉडल सबसे करीबी गलत को चुनने के लिए बाध्य है और यह बताने के बजाय कि यह फिट नहीं होता है। एक escape हatch के बिना enum "फिट नहीं होता है" को एक आत्मविश्वासी गलत लेबल में बदल देता है। तो किसी भी वर्गीकार के लिए अस्पष्ट असली इनपुट का सामना करते हुए, एक स्पष्ट escape hatch जोड़ें, एक other या unknown सदस्य, और इसे किसी अन्य जगह मार्ग का संकेत के रूप में पढ़ें।

एक ही सावधानी आत्मविश्वास पर लागू होती है: यदि निर्णय लेबल पर निर्भर करता है, तो मॉडल को आत्मविश्वास या एक छोटी तर्क फ़ील्ड भी उत्सर्जित करने दें, इसलिए एक सीमांत कॉल साफ-सुथरे enum मान में साफ नहीं किया गया। ये टूल उपयोग के समान प्रवृत्ति हैं, जहाँ मॉडल एक बंद सेट से एक टूल उठाता है और आप को एक ही "क्या अगर कोई भी फिट नहीं होता है" समस्या का सामना करना पड़ता है।

Junoदो पैटर्न: वर्गीकृत और निष्कर्षण वर्गीकरण एक `enum` द्वारा लागू एक बंद सेट है, निष्कर्षण मुक्त पाठ से टाइप किए गए फ़ील्ड हैं, और `enum` तीक्ष्ण किनारे वाली गारंटी है: यह तब भी एक पिक को मजबूर करता है जब कोई भी फिट न हो, "मेल नहीं खाता" को एक आत्मविश्वासी गलत लेबल में धोता है। एक `other` या `unknown` सदस्य जोड़ें और इसे मार्ग पर पढ़ें, और एक आत्मविश्वास फ़ील्ड उत्सर्जित करें जब निर्णय लेबल पर निर्भर करता है। टूल उपयोग में एक बंद सेट से एक टूल लेने के समान आकार।

व्यवहार में

एक अस्पष्ट समर्थन ईमेल को एक संरचित टिकट में बदलना, एक स्कीमा में वर्गीकरण और निष्कर्षण को जोड़ते हुए:

python
import json

response = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": "समर्थन ईमेल को एक टिकट में बदलें।"},
        {"role": "user", "content": email_text},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "ticket",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "category": {"type": "string", "enum": ["billing", "technical", "general"]},
                    "urgency": {"type": "string", "enum": ["low", "medium", "high"]},
                    "summary": {"type": "string"},
                },
                "required": ["category", "urgency", "summary"],
                "additionalProperties": False,
            },
        },
    },
)

ticket = json.loads(response.choices[0].message.content)
# {"category": "billing", "urgency": "high", "summary": "पिछले महीने की सदस्यता के लिए दोहरे शुल्क।"}

एक कॉल ईमेल को दो तरीकों से वर्गीकृत करता है और एक सारांश निकालता है, एक रिकॉर्ड लौटाता है जिसे आपका कोड मार्ग और स्टोर कर सकता है, आकार की गारंटी के साथ और मान अभी भी जांच के लायक हैं। अब तक सबकुछ टेक्स्ट में बहा है और टेक्स्ट से बाहर। अगला आप मॉडल को एक अलग भावना देते हैं: एम्बेडिंग में, टेक्स्ट संख्या बन जाता है जिसे आप अर्थ से तुलना कर सकते हैं, खोज और अपने स्वयं के दस्तावेजों के साथ काम करने की नींव।

Junoव्यवहार में एक कॉल एक सख्त स्कीमा के साथ एक ईमेल को दो तरीकों से वर्गीकृत कर सकता है और एक सारांश एक बार निकाल सकता है, एक रिकॉर्ड लौटा सकता है जिसे आपका कोड मार्ग और स्टोर कर सकता है। आकार की गारंटी है; मान अभी भी जांच के लायक हैं। टूल उपयोग बाद में इसी ट्रिक पर झुकता है: जो तर्क मॉडल टूल को भेजता है वह भी संरचित आउटपुट है।

एक असली सुविधा आमतौर पर एक स्कीमा में दोनों पैटर्न को जोड़ती है। यहाँ एक समर्थन ईमेल एक टिकट बन जाता है: एक एकल कॉल में दो वर्गीकरण और एक निष्कर्षण।

python
import json

response = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": "समर्थन ईमेल को एक टिकट में बदलें।"},
        {"role": "user", "content": email_text},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "ticket",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "category": {"type": "string", "enum": ["billing", "technical", "general"]},
                    "urgency": {"type": "string", "enum": ["low", "medium", "high"]},
                    "summary": {"type": "string"},
                },
                "required": ["category", "urgency", "summary"],
                "additionalProperties": False,
            },
        },
    },
)

ticket = json.loads(response.choices[0].message.content)
# {"category": "billing", "urgency": "high", "summary": "पिछले महीने की सदस्यता के लिए दोहरे शुल्क।"}

दोनों enum मार्गीय हैं, इसलिए category और urgency हमेशा मार्गीय हैं। summary एक खुली फ़ील्ड है, इसलिए यह विश्वास करने से पहले मान्य करने के लिए एक है। वह विभाजन, लागू लेबल साथ एक जांचे हुए मुक्त-पाठ फ़ील्ड, अधिकांश निष्कर्षण सुविधाओं का आकार है। अगला, एम्बेडिंग मॉडल को एक अलग भावना देता है: पाठ को संख्या में बदला जाता है जिसे आप अर्थ से तुलना कर सकते हैं, खोज और अपने स्वयं के दस्तावेजों के साथ काम करने की नींव।

Junoव्यवहार में एक सख्त स्कीमा दो तरीकों से वर्गीकृत कर सकता है और एक एकल कॉल में सारांश निकाल सकता है, एक रिकॉर्ड लौटा सकता है जिसे आप मार्ग और स्टोर कर सकते हैं। enum को लागू किया जाता है इसलिए लेबल सुरक्षित हैं; खुली `summary` फ़ील्ड है जिसे आप मान्य करें। लेबल लॉक और जांचे हुए मुक्त पाठ का वह मिश्रण एक निष्कर्षण सुविधा का रोज़मर्रा का आकार है।

रोज़मर्रा की उत्पादन आकार मिश्रित है: कुछ कुल्हाड़ी पर वर्गीकृत करें और मुक्त-पाठ फ़ील्ड निकालें, सब एक स्कीमा और एक कॉल में।

python
import json

response = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": "समर्थन ईमेल को एक टिकट में बदलें।"},
        {"role": "user", "content": email_text},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "ticket",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "category": {"type": "string", "enum": ["billing", "technical", "general"]},
                    "urgency": {"type": "string", "enum": ["low", "medium", "high"]},
                    "summary": {"type": "string"},
                },
                "required": ["category", "urgency", "summary"],
                "additionalProperties": False,
            },
        },
    },
)

ticket = json.loads(response.choices[0].message.content)
# {"category": "billing", "urgency": "high", "summary": "पिछले महीने की सदस्यता के लिए दोहरे शुल्क।"}

प्रवर्तन फ़ील्ड में असमान है, और वह डिज़ाइन बिंदु है। enum कठोर गारंटियाँ हैं, इसलिए category और urgency आगे जांच के बिना मार्ग देने के लिए सुरक्षित हैं। summary एक अबाधित स्ट्रिंग है, इसलिए यह बिल्कुल वह जगह है जहाँ एक मतिभ्रम या ऑफ-बेस मान एक साफ स्कीमा के पीछे छिप सकता है, और जो फ़ील्ड एक सत्यापन पास कमाता है। दो लागू लेबल एक खुले summary फ़ील्ड के साथ ट्रंकेशन के लिए सबसे अधिक उजागर स्कीमा भी है: एक लंबा उत्पन्न सारांश आपको max_tokens में चलाता है और पूरे ऑब्जेक्ट को अपार्सेबल में बदल देता है, इसलिए लेबल के लिए नहीं, मुक्त-पाठ फ़ील्ड के लिए बजट।

यह टूल उपयोग के समान तंत्र है: एक टूल कॉल एक फ़ंक्शन स्कीमा के विरुद्ध संरचित तर्क उत्सर्जित करने वाला मॉडल है, समान तरीके से बाधित, तो सत्यापन, मरम्मत, और enum-escape-hatch प्रवृत्ति यहाँ से सीधे एजेंटों को विश्वसनीय बनाने के लिए स्थानांतरित होती हैं। यहाँ से, एम्बेडिंग मॉडल को एक अलग मोड में बदल देते हैं: पाठ को वेक्टर के रूप में जिसे आप अर्थ से तुलना करते हैं, खोज की नींव और अपने स्वयं के दस्तावेजों में जवाब कर सकते हैं।

Junoव्यवहार में एक सख्त स्कीमा, दो लागू enum और एक खुली `summary`: लेबल को मार्ग देने के लिए सुरक्षित, मुक्त-पाठ फ़ील्ड एक मतिभ्रमित मान छिपाता है और लंबी पीढ़ी `max_tokens` में ट्रिप करता है जो ट्रंकेशन में बदल जाता है, इसलिए इसे विशेष रूप से बजट और मान्य करें। यह टूल उपयोग के समान तंत्र है, फ़ंक्शन स्कीमा के विरुद्ध args बाधित, तो हर आदत यहाँ, सत्यापन, मरम्मत, enum escape हatch, सीधे एजेंटों को ले जाती है।