Tool Calling और Structured Outputs: वह अनुबंध जो टिकता है
24 calls, शून्य टूटा JSON, दो उपयोगी dates—फिर बेहतर description वाला वही endpoint, और schema क्या ठीक नहीं कर सकता।
इस पेज पर
एक model को flight-search tool दें और उससे Madrid से Berlin की flight ढूँढने को कहें। यह वापस आता है:
<tool_call>
{"name": "search_flights",
"arguments": {"from": "Madrid", "to": "Berlin", "date": "3rd October 2026"}}
</tool_call>JSON valid है। tool का नाम सही है। हर required field मौजूद है। और call बेकार है: कोई flight API "Madrid" स्वीकार नहीं करती जहाँ उसे airport code चाहिए, या "3rd October 2026" जहाँ उसे date चाहिए।
यही gap — syntactically perfect, semantically unusable — इस chapter का विषय है, और सबसे पहले यह स्थापित करना ज़रूरी है कि यह JSON की समस्या नहीं है। इस tool के साथ चौबीस requests में, model ने 24 valid tool calls और zero broken JSON बनाए। वह उस हिस्से में एक बार भी असफल नहीं हुआ जिसे हर कोई debug करता है।
model कुछ भी execute नहीं करता
सेक्शन का लिंक: model कुछ भी execute नहीं करताmechanics से पहले, वह वाक्य जो सबसे ज़्यादा भ्रम रोकता है: tool call एक request है, action नहीं।
model एक structured message emit करता है जो कहता है मैं चाहता हूँ कि search_flights इन arguments के साथ call हो। फिर वह रुक जाता है। आपका code वह message प्राप्त करता है, तय करता है कि उसे मानना है या नहीं, जो भी call करना है वह करता है, और result को एक और message की तरह वापस भेजता है। model ने आपकी database को कभी नहीं छुआ, कभी HTTP request नहीं की, कभी credentials नहीं थे।
अध्याय 30 में agent security के बारे में सब कुछ इसी विभाजन से निकलता है, और अध्याय 23 में agent design के बारे में भी सब कुछ: model प्रस्ताव रखता है और आपका code निर्णय करता है, और code ही वह जगह है जहाँ हर guarantee रहती है।
तो vocabulary हटाकर देखें, तो tool दो चीज़ें है:
एक schema। एक JSON Schema जो function का वर्णन करता है: उसका नाम, वह क्या करता है, और वह कौन-से arguments लेता है, उनके types और constraints के साथ। यही prompt में जाता है, और यही एकमात्र चीज़ है जिसे model कभी देखता है।
एक endpoint। आपके code में एक function जो वे arguments लेता है और कुछ return करता है। model उसे कभी नहीं देखता, कभी नहीं जानता कि वह किस language में है, और database query और hardcoded string में फर्क नहीं बता सकता।
आप request के साथ schemas भेजते हैं
सेक्शन का लिंक: आप request के साथ schemas भेजते हैंtool definitions prompt में जाती हैं, उस format में serialise होकर जिस पर model train हुआ था। वे हर single call पर tokens खर्च करती हैं — एक तथ्य जो इस chapter में आगे एक number के साथ लौटता है।
model text के बजाय call से जवाब देता है
सेक्शन का लिंक: model text के बजाय call से जवाब देता हैprose की जगह, response में structured request होती है, और API एक finish reason report करती है जो यही बताता है। reason मायने रखता है: इसी से आपका code जानता है कि user को answer दिखाने के बजाय tool चलाना है।
आपका code उसे चलाता है — या मना करता है
सेक्शन का लिंक: आपका code उसे चलाता है — या मना करता हैयह वह step है जिसमें कोई model नहीं है। arguments को schema के against validate करें, तय करें कि इस caller को यह करने की अनुमति है या नहीं, और execute करें।
आप result को message की तरह वापस भेजते हैं
सेक्शन का लिंक: आप result को message की तरह वापस भेजते हैंresult conversation में एक और turn बन जाता है, उसके लिए reserved role में। model उसे किसी भी अन्य context की तरह पढ़ता है।
model जवाब देता है, या दूसरे tool के लिए पूछता है
सेक्शन का लिंक: model जवाब देता है, या दूसरे tool के लिए पूछता हैयही Chapter 23 का loop है, और यही वजह है कि एक single request दर्जन भर round trips में बदल सकती है।
इसमें कुछ भी emergent नहीं है। जैसा अध्याय 11 ने स्थापित किया, tool calling एक trained behaviour है:1 post-training के दौरान model ने ठीक इसी shape की हजारों conversations देखीं। इसी वजह से format model-specific है, similar size के models के बीच reliability इतनी अलग होती है, और model ऐसा tool call कर सकता है जिसे उसने कभी नहीं देखा — shape train की गई थी, specific tool आपके prompt से आता है।
खराब schema की कीमत, मापी हुई
सेक्शन का लिंक: खराब schema की कीमत, मापी हुईयह वह tool है जिसे अधिकतर लोग पहली बार ऐसे लिखते हैं। ध्यान दें कि इसमें कुछ भी गलत नहीं है; यह बस thin है:
{
name: "search_flights",
description: "Search for flights.",
parameters: {
type: "object",
properties: {
from: { type: "string", description: "Airport." },
to: { type: "string", description: "Airport." },
date: { type: "string", description: "The date." },
},
required: ["from", "to", "date"],
},
}चौबीस requests, छह city pairs को date व्यक्त करने के चार तरीकों के साथ cross किया गया ("अगले महीने की 3 तारीख", "अगला Friday", "15 December", "कल"), greedy decoding ताकि results reproduce हों:
| tool call हुआ | broken JSON | date ISO में | airports IATA के रूप में | सब कुछ सही | |
|---|---|---|---|---|---|
| ऊपर वाला schema | 24/24 | 0 | 2/24 | 4/24 | 1/24 |
आखिरी तीन से पहले पहली दो columns पढ़ें। model हर बार सही tool call करता है और हर बार well-formed JSON बनाता है। failure पूरी तरह values में है, और values unusable हैं: "Madrid" की जगह MAD, "3rd October 2026" की जगह 2026-10-03।
इस पर ज़ोर देना ज़रूरी है क्योंकि इससे तय होता है कि कुछ टूटने पर आप कहाँ देखते हैं। instinct होता है JSON parser में retry जोड़ना, या model से valid JSON के लिए ज़्यादा सख्ती से कहना। यहाँ जो हुआ, उनमें से कोई भी उसे address नहीं करता।
अब केवल description बदलें
सेक्शन का लिंक: अब केवल description बदलेंवही endpoint। उसके पीछे वही code। वही model, वही prompts, वही decoding। सिर्फ schema में text बदलता है:
{
name: "search_flights",
description: "Search scheduled flights between two airports on a given day.",
parameters: {
type: "object",
properties: {
from: {
type: "string",
description: "Departure airport as a three-letter IATA code, e.g. MAD for Madrid. Never a city name.",
pattern: "^[A-Z]{3}$",
},
to: { /* same */ },
date: {
type: "string",
description: "Departure date as an ISO 8601 calendar date, YYYY-MM-DD. Resolve relative dates against today before calling.",
format: "date",
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
},
},
required: ["from", "to", "date"],
},
}| date FORMAT | date VALUE | airport FORMAT | airport VALUE | |
|---|---|---|---|---|
| thin schema | 2/24 | 1/24 | 4/24 | 4/24 |
| described schema | 24/24 | 12/24 | 16/24 | 8/24 |
date format 24 में से 2 से 24 में से 24 हो जाता है। Perfect, सिर्फ text change से, बिना code छुए और बिना retry logic के। अगर आप इस chapter से एक operational habit लेते हैं, तो वह यही है: जब tool गलत call होता है, fix लगभग हमेशा description में होता है, और यह system का सबसे सस्ता fix है।
अब दूसरी column पढ़ें, जो ज़्यादा important half है।
schema shape को constrain करता है। वह knowledge supply नहीं कर सकता।
सेक्शन का लिंक: schema shape को constrain करता है। वह knowledge supply नहीं कर सकता।date 24 में से 24 बार ISO format में है। वह सही दिन 24 में से 12 बार है।
तो अब आधी calls में perfectly formatted date है जो गलत date है। description ने model को बताया कि कौन-सी shape produce करनी है, और model ने उसे flawlessly produce किया — लेकिन "अगला Friday" को 2026-09-11 में बदलने के लिए आज की date जानना और calendar arithmetic करना पड़ता है, और कोई भी description यह supply नहीं करती। airports की कहानी भी वही है: format 4 से 16 हुआ, लेकिन value सिर्फ 4 से 8, क्योंकि MAD लिखने के लिए यह जानना पड़ता है कि Madrid का airport MAD है।
यही distinction इस chapter का load-bearing idea है:
schema form के बारे में contract है। यह model के output को parseable, typed और consistent बना सकता है। यह उसे true नहीं बना सकता, और good schema के बाद भी बचा हर failure mode knowledge failure है, format failure नहीं।
दोनों को अलग fixes चाहिए, और उन्हें confuse करना हफ्तों बर्बाद करता है। Format failures description में या नीचे दिए constrained decoding से fix होते हैं। Knowledge failures knowledge को prompt में डालकर fix होते हैं — system message में current date, airport lookup को एक second tool बनाना जिसे model पहले call करे, schema में enum जब set enumerate करने लायक छोटा हो। ध्यान दें कि तीनों में क्या common है: वे problem को model की memory से निकालकर उसके input में ले जाते हैं, जो अध्याय 24 का पूरा विषय है।
Structured outputs, और "constrained decoding" असल में क्या है
सेक्शन का लिंक: Structured outputs, और "constrained decoding" असल में क्या हैऊपर की हर चीज़ अब भी model के choosing पर निर्भर करती है कि वह सही shape produce करे। एक stronger guarantee उपलब्ध है, और यह अध्याय 17 का best payoff है।
याद करें generation कैसे काम करती है: हर step पर model vocabulary के हर token के लिए logit produce करता है, और sampler एक चुनता है। Constrained decoding बीच में एक step insert करता है। आपकी JSON Schema से derived grammar दिए जाने पर, यह compute करता है कि अगले कौन-से tokens legally आ सकते हैं, बाकी सभी के logits को negative infinity पर set करता है, और sampler को बचे हुए में से चुनने देता है।
अगर schema कहता है कि अगली चीज़ { ही होनी चाहिए, तो हर token जो { नहीं है उसकी probability zero है। "unlikely" नहीं: zero। model invalid JSON emit नहीं कर सकता क्योंकि invalid tokens sampling से पहले distribution से हटा दिए गए थे।
"structured outputs", "JSON mode" और "guided generation" के नीचे यही है, और यही उनकी दो properties समझाता है। guarantee उस हर चीज़ के लिए total है जिसे grammar express कर सकती है — types, required fields, enums, nesting — क्योंकि यह mechanically enforce होती है, politely request नहीं। और यह content के बारे में कुछ नहीं कहती: grammar "date" को date pattern match करने वाली string होने के लिए force कर सकती है, और उसे सही दिन होने के लिए force नहीं कर सकती। यह previous section वाली दीवार ही है, बस दूसरी तरफ से पहुँची हुई।
दो practical notes। यह free नहीं है: mask हर step पर compute करना पड़ता है, और complex grammars measurable latency खर्च करती हैं। और यह बदल देता है कि model क्या कर रहा है — अपने preferred token से दूर steer किया गया model perfect structure produce करते हुए भी worse content produce कर सकता है, इसी वजह से simple shapes के लिए "अच्छे से पूछो और validate करो" अब भी reasonable default है और constrained decoding अपनी cost तब कमाती है जब shape complex हो या consumer strict हो।
Side effects, और वह एक property जो मायने रखती है
सेक्शन का लिंक: Side effects, और वह एक property जो मायने रखती हैअध्याय 14 ने timeout के बाद retry को मापा था, जिसमें एक answer के लिए दो generations bill हुईं। tools के साथ वही failure worse हो जाता है, क्योंकि tool कुछ कर सकता है।
अगर आपका code charge_card call करता है, timeout होता है, और retry करता है, तो आपके पास दो charges हैं। model को इसका कोई अंदाज़ा नहीं कि यह सब हुआ; उसे एक tool result दिखता है। fix वही है जो किसी भी distributed system में होता है और यह model की problem नहीं है: call को key देकर operation को idempotent बनाइए, ताकि second execution first को recognise करे और work फिर से करने के बजाय उसका result return करे।
इससे निकलने वाला design rule साफ़-साफ़ कहना चाहिए। अपने tool catalogue में reads को writes से अलग रखें। read को freely retry किया जा सकता है, parallel run किया जा सकता है, और cache किया जा सकता है। write ऐसा नहीं कर सकता, और उसे key, permission check, और — ऐसी हर चीज़ के लिए जिसके होने से पहले user जानना चाहेगा — approval step carry करना चाहिए जो request और action के बीच human रखता है। वह approval step courtesy नहीं है: यह prompt injection और real consequence के बीच खड़ी कुछ गिनी-चुनी चीज़ों में से एक है — और, Chapter 30 मापता है, उनमें सबसे कमजोर।
कितने tools के बाद degradation शुरू होता है?
सेक्शन का लिंक: कितने tools के बाद degradation शुरू होता है?folklore कहता है कि बहुत सारे tools load करने से model गलत choose करता है। इसे repeat करने के बजाय measure करना बेहतर है, इसलिए: वही चौबीस requests, flight tool के साथ बढ़ते हुए दूसरे tools का set — जिसमें तीन deliberately confusable tools शामिल हैं (train timetables, ferry crossings, bus routes)।
| tools loaded | prompt tokens | search_flights चुना | date ISO में |
|---|---|---|---|
| 1 | 353 | 24/24 | 24/24 |
| 5 | 730 | 24/24 | 24/24 |
| 10 | 1,193 | 21/24 | 21/24 |
| 20 | 2,119 | 24/24 | 24/24 |
Selection degrade नहीं हुआ। बीस tools के साथ, जिनमें तीन plausibly confusable थे, half-billion-parameter model ने चौबीस में से चौबीस बार सही tool चुना। दस पर dip तीन calls हैं जिन्होंने अलग tool का नाम लिया, और बीस पर जाने के बाद वह survive नहीं करता।
यह negative result है और इसे वैसा ही report किया जाना चाहिए: इस task पर, इन tools के साथ, "too many tools" problem नहीं था। जो monotonic रूप से और छह गुना बढ़ा, वह prompt है: 353 tokens से 2,119, conversation की हर request पर paid, हमेशा के लिए, चाहे कोई tool use हो या नहीं।
तो folklore का honest version cost और context, accuracy नहीं के बारे में है। बीस tools हर message पर permanent tax हैं, और अध्याय 16 पहले ही दिखा चुका है कि forty turns में permanent prefix bill के साथ क्या करता है। जब लोग report करते हैं कि बहुत सारे tools quality को hurt करते हैं, तो mechanism आम तौर पर यह होता है कि definitions ने mattered context को crowd out कर दिया — जो Chapter 24 की problem है, Chapter 18 का costume पहने हुए। जो tools सचमुच एक-दूसरे के near-duplicates हैं, वे भी real problem हैं, और उनका fix fewer tools नहीं बल्कि better descriptions and namespaces है: उन्हें system से prefix करें (crm.search_customer, billing.search_customer) ताकि दो teams से merge हुए दो catalogues collide न करें, और model के पास discriminate करने के लिए कुछ हो।
तीन तरह के tool, और वह एक जो अगला हिस्सा खोलता है
सेक्शन का लिंक: तीन तरह के tool, और वह एक जो अगला हिस्सा खोलता हैtools को इस आधार पर sort करना मदद करता है कि वे world के साथ क्या करते हैं, क्योंकि हर एक के लिए engineering अलग होती है।
Data tools read करते हैं: search, fetch, query। Retryable, parallelisable, cacheable। वे fail तब होते हैं जब कुछ useful return नहीं करते, और उनका main risk यह है कि वे untrusted text को context में लाते हैं — जो Chapter 30 का पूरा attack surface है।
Action tools write करते हैं: send, create, charge, delete। key के बिना retryable नहीं, safely parallelisable नहीं, और यही वजह है कि approval flows मौजूद हैं।
Orchestration tools दूसरे models call करते हैं। ऐसा tool जिसकी implementation एक और agent है, अपने prompt, अपने tools और अपने loop के साथ — और calling model को यह बाकी दोनों जैसा ही दिखता है, क्योंकि schema और endpoint ही वह सब है जिसे वह कभी देखता है।
तीसरी kind कोई curiosity नहीं है। यही अध्याय 25 के agent-as-a-tool half के पीछे का mechanism है — दूसरी topology, handoff, conversation दे देती है और उसे कभी वापस नहीं लेती — और यह ठीक इसलिए काम करता है क्योंकि इस chapter में interface इतना narrow है कि पूरा agent उसके पीछे fit हो जाता है।
आगे यह कहाँ जाता है
सेक्शन का लिंक: आगे यह कहाँ जाता हैअब आपके पास एक model है जो चीज़ों के लिए ask कर सकता है, और एक contract है जो asking को parseable बनाता है। जो आपके पास नहीं है, वह है ऐसा कुछ जिसके बारे में वह ask कर सके, उससे परे जो उसके prompt में fit होता है।
production में सबसे common tool, बहुत बड़े margin से, ऐसे text body पर search है जिसे model ने training के दौरान कभी नहीं देखा: आपकी documentation, आपके tickets, आपके contracts। यह solved problem जैसा लगता है — उसे embed करें, nearest neighbours ढूँढें, उन्हें paste करें — और जो parts solved नहीं हैं वही तय करते हैं कि answer trustworthy है या नहीं: embedded होने से पहले text कैसे cut up होता है, कौन-सा similarity threshold इतना low है कि उसका मतलब मुझे नहीं पता हो, और citation claim से कैसे attach होता है ताकि reader उसे check कर सके।
अध्याय 19 retrieval है, और यह वह chapter है जहाँ गलत answer curiosity होना बंद करता है और liability बनना शुरू करता है।
Sources and method
सेक्शन का लिंक: Sources and methodइस chapter की measurements Qwen/Qwen2.5-0.5B-Instruct से आती हैं, greedy decoding के साथ, 24 generated requests पर जो छह city pairs को चार date phrasings के साथ cross करती हैं, tool definitions के लिए model के अपने chat template का use करते हुए। वे exactly reproduce होती हैं, और वे एक small model हैं: format/value split को mechanism की demonstration की तरह पढ़ें, current models क्या करते हैं उसके benchmark की तरह नहीं। frontier model "अगला Friday" को कहीं ज़्यादा बार correctly resolve करता है — और फिर भी schema से उसे ऐसा करने के लिए made नहीं किया जा सकता, यही वह part है जो generalise करता है।
ऊपर इस्तेमाल की गई JSON Schema vocabulary (type, properties, required, pattern, format, enum) उस JSON Schema draft में specified है जिसका नाम आपके provider की documentation देती है; useful subset छोटा है और providers में समान है, और जो differences मौजूद हैं — कौन-से keywords constrained decoding द्वारा enforce होते हैं बजाय केवल model को pass किए जाने के — उन्हें assume करने के बजाय provider की structured-output guide में पढ़ना बेहतर है।
technique के रूप में constrained decoding के लिए, guidance-style libraries और outlines project grammar-to-logit-mask construction को इस तरह document करते हैं जो Chapter 17 के sampler पर सीधे map करता है। और round trip खुद के लिए, सबसे clear specification tutorial नहीं बल्कि protocol है: अध्याय 26 उसे line by line पढ़ता है।
संदर्भ
सेक्शन का लिंक: संदर्भ-
Ouyang, L. et al. Training language models to follow instructions with human feedback. arXiv:2203.02155 (2022). वह paper जिसने post-training recipe को standard बनाया; tool call की shape वहाँ demonstrations से सीखी जाती है, बिल्कुल answer की shape की तरह। ↩