خرابیوں کا ازالہگائیڈ
LLM جواب پر json.JSONDecodeError: Python میں JSON نکالیں
ماڈل کے جواب پر json.loads ناکام؟ وجہ جاننے کے لیے exc.pos اور finish_reason پڑھیں، پھر raw_decode سے JSON نکالیں اور ایک بار دوبارہ کوشش کریں۔

اس صفحہ پر
آپ کا اسکرپٹ ماڈل سے JSON مانگتا ہے، json. کال کرتا ہے اور json. کے ساتھ مر جاتا ہے۔ عام طور پر ماڈل نے جواب دیا ہوتا ہے: اس نے JSON کو ```json fence, put a line of chat in front of it, or ran into max_tokens halfway through. Look at exc.pos and finish_reason to tell which one it is, pull the object out with JSONDecoder. میں لپیٹ دیا، اور اگر کچھ بچایا نہ جا سکے تو ایک بار دوبارہ کوشش کریں۔
تین طریقے جن سے جواب json.loads کو توڑ دیتا ہے#
Python کی json دستاویزات (Python 3.15 docs، 2 نومبر 2026 کو دیکھی گئی) کے مطابق JSONDecodeError، ValueError کی ذیلی کلاس ہے جس میں msg، doc، pos، lineno اور colno خصوصیات ہیں۔ یہاں جو اہم ہے وہ pos ہے: سٹرنگ میں وہ انڈیکس جہاں پارسنگ ناکام ہوئی۔
فرض کریں ایک اسکرپٹ گاہکوں کی ای میلز سے فیلڈز نکالتا ہے اور {"name": . مانگتا ہے۔ یہ تین سٹرنگز وہ جوابات ہیں جو اسے توڑ دیتے ہیں۔ انہیں Python شیل میں پیسٹ کریں:
import json
fenced = '```json\n{"name": "Anna", "age": 31}\n```'
chatty = 'Sure! Here is the JSON:\n{"name": "Anna", "age": 31}'
cut = '{"name": "Anna", "age": 31'
for reply in (fenced, chatty, cut):
try:
json.loads(reply)
except json.JSONDecodeError as exc:
print(exc.pos, len(reply))پہلی دو pos 0 پر ناکام ہوتی ہیں: پارسر نے بالکل پہلا حرف دیکھا، ایک بیک ٹک یا S، اور ہار مان لی۔ تیسری سٹرنگ کے آخر میں ناکام ہوتی ہے (pos برابر ہے len(reply) کے): جو کچھ اس نے پڑھا وہ ٹھیک تھا، پھر متن ختم ہو گیا۔ یہی فرق آپ کی تشخیص ہے۔ پوزیشن 0 کا مطلب ہے JSON غالباً موجود ہے، بس لپٹا ہوا ہے۔ پوزیشن آخر میں ہونے کا مطلب ہے جواب جلدی رک گیا۔

کٹے ہوئے جوابات: پارس کرنے سے پہلے finish_reason چیک کریں#
درمیان میں رک جانے والا جواب پارسنگ کا مسئلہ نہیں، لمبائی کا مسئلہ ہے۔ API آپ کو بتاتی ہے: چوائس میں finish_reason ہے، اور "length" کا مطلب ہے جواب max_tokens سے کاٹ دیا گیا (پوری کہانی AI answer cut off? Fix finish_reason "length" and max_tokens میں ہے)۔ کسی بھی استخراج سے پہلے اسے دیکھیں۔
اگر آپ یہ قدم چھوڑ دیں تو ایک خطرناک جال ہے۔ پہلا قابلِ پارس { تلاش کرنے والا اسکینر آدھے ادھورے بیرونی آبجیکٹ سے ایک مکمل اندرونی آبجیکٹ اٹھا سکتا ہے، اور آپ کا اسکرپٹ غلط ڈیٹا کے ساتھ بغیر کسی خرابی کے آگے بڑھتا رہتا ہے۔ آزمائیں:
خود آزمائیںآزمائیں: اس کٹے ہوئے جواب کے لیے "پہلا آبجیکٹ تلاش کریں" فنکشن کیا واپس کرتا ہے؟جواب دکھائیں
'{"user": {"name": "Anna"}, "age": 31' لیں۔ بیرونی آبجیکٹ کبھی بند نہیں ہوتا، لیکن اندرونی {"name": "Anna"} مکمل ہے، اس لیے نیچے دیا گیا ایکسٹریکٹر {'name': 'Anna'} واپس کرتا ہے۔ کوئی استثنا نہیں، غلط نتیجہ۔ اسی لیے finish_reason کی جانچ استخراج سے پہلے آتی ہے۔
اصل کٹے ہوئے جواب کا حل زیادہ گنجائش ہے: max_tokens بڑھائیں۔ DeepSeek-V4-Flash فی جواب زیادہ سے زیادہ 32,768 آؤٹ پٹ ٹوکنز کی اجازت دیتا ہے، GLM-5.3-Flash زیادہ سے زیادہ 8,192، اس لیے لمبی JSON فہرست کے لیے پہلے پر زیادہ جگہ ہے۔ ماڈلز کی تفصیلات the CheapTokens models page پر ہیں۔
متن سے JSON نکالیں#
باڑوں اور بے کار باتوں کے لیے، معیاری لائبریری میں پہلے سے ہی اوزار موجود ہے۔ اسی Python صفحے کے مطابق، JSONDecoder. ایسی سٹرنگ سے JSON دستاویز ڈی کوڈ کرتا ہے جو اسی سے شروع ہو اور آبجیکٹ کے ساتھ ساتھ وہ انڈیکس واپس کرتا ہے جہاں دستاویز ختم ہوئی۔ دستاویزات کہتی ہیں کہ یہ ایسی سٹرنگ پر استعمال کیا جا سکتا ہے جس کے آخر میں اضافی ڈیٹا ہو۔ اسے ضرورت ہے کہ دستاویز پہلے حرف سے شروع ہو، اس لیے پہلے آگے کا متن کاٹ دیں: { تلاش کریں، وہاں سے ڈی کوڈ کرنے کی کوشش کریں، اور ناکام ہونے پر اگلے { پر جائیں۔
import json
def extract_json(text):
"""Return the first JSON object found in text, or raise ValueError."""
decoder = json.JSONDecoder()
for i, ch in enumerate(text):
if ch == '{':
try:
obj, _end = decoder.raw_decode(text[i:])
return obj
except json.JSONDecodeError:
continue
raise ValueError('no JSON object in the reply')یہ باڑ کو سنبھالتا ہے (آگے کا ```json is skipped because it is not a {), the sentence before the object, and text after the closing brace. Expecting a list? Look for '[' instead. Don't look for both: a stray [1] "see note [1]" جیسے جملے میں درست JSON ہے اور جیت جائے گا۔
دو چیزیں یہ جان بوجھ کر نہیں کرتا۔ یہ کبھی متن میں ترمیم نہیں کرتا (کوئی regex نہیں جو بیک ٹکس حذف کرے، غائب بریکٹس کا کوئی اندازہ نہیں)، اس لیے آپ ٹوٹے ہوئے جواب کو درست لیکن غلط ڈیٹا میں تبدیل نہیں کر سکتے۔ اور جب تلاش کرنے کو کچھ نہ ہو تو یہ بلند آواز میں ناکام ہوتا ہے، جو نیچے دی گئی دوبارہ کوشش کو درکار ہے۔

سخت پرامپٹ کے ساتھ ایک بار دوبارہ کوشش کریں#
اگر جواب کٹ گیا یا اس میں کوئی آبجیکٹ نہیں، دوبارہ پوچھیں۔ ایک بار، لامتناہی لوپ میں نہیں۔ کٹے ہوئے جواب پر، دوسری کوشش کو زیادہ جگہ دیں؛ ورنہ صاف الفاظ میں بتائیں کہ آپ کیا چاہتے ہیں۔ یہ CheapTokens بیس URL (https:/) کے خلاف OpenAI Python SDK اور دستاویزات سے مکمل ماڈل آئی ڈی استعمال کرتا ہے؛ کلید ایک ماحولیاتی متغیر میں رکھی گئی ہے۔
import os
from openai import OpenAI
client = OpenAI(
base_url='https://api.cheaptokens.dev/v1',
api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'
STRICT = '\n\nReply with one JSON object only. No text before or after it, no code fence.'
def ask_json(prompt, max_tokens=800):
content = prompt
for attempt in (1, 2):
resp = client.chat.completions.create(
model=MODEL,
messages=[{'role': 'user', 'content': content}],
max_tokens=max_tokens,
)
choice = resp.choices[0]
if choice.finish_reason == 'length':
max_tokens *= 2 # cut off: more room next time
else:
try:
return extract_json(choice.message.content or '')
except ValueError:
pass # no object: try the stricter prompt
content = prompt + STRICT
raise ValueError('no valid JSON after one retry')ترتیب ہی اصل نکتہ ہے: پہلے finish_reason، دوسرا استخراج، اور صرف پھر دوبارہ کوشش۔ دوسری کوشش کے بعد خرابی اٹھائیں تاکہ بیچ جاب اس آئٹم کو لاگ کر کے آگے بڑھ سکے۔
دوبارہ کوشش کی لاگت کا اندازہ لگانا آسان ہے۔ فرض کریں 1,200 ان پٹ ٹوکنز اور 300 آؤٹ پٹ ٹوکنز کی درخواست (ایک مفروضہ، اپنے نمبر استعمال کریں): DeepSeek-V4-Flash پر $0.000048 یا GLM-5.3-Flash پر $0.000036۔ اگر 1,000 میں سے 30 درخواستوں کو دوسری کوشش درکار ہو، تو اضافی بل 30 × وہ درخواست ہے، DeepSeek-V4-Flash پر $0.0014۔ قیمتیں لائیو ہیں، وہ موجودہ قیمت کی فہرست سے آتی ہیں۔
ترتیب دیں
مرمت کے مراحل کو ترتیب دیں
آئٹمز کو گھسیٹیں یا تیروں کا استعمال کریں
- finish_reason چیک کریں: اگر یہ length کہے تو یہیں رکیں
- پہلا { تلاش کریں اور اس سے پہلے کا متن کاٹ دیں
- raw_decode سے ڈی کوڈ کریں اور آگے جو ہے نظر انداز کریں
- اگر کچھ نہ ملا، سخت پرامپٹ کے ساتھ ایک بار دوبارہ کوشش کریں
کون سی علامت، کون سی مرمت#
اوپر کے مراحل آپ کے ذہن میں تب تک سماتے ہیں جب تک اگلی عجیب خرابی نہ آئے۔ یہ ایک تلاش کی طرح ہے: جو اسکرین پر نظر آئے اسے تلاش کریں اور مرمت پڑھیں۔
اپنا کیس منتخب کریں
جو نظر آئے اسے چنیں
جواب دیکھنے کے لیے ایک آپشن منتخب کریں
json.loads pos 0 پر ناکام
جواب ایک باڑ یا جملے سے شروع ہوتا ہے۔ اسے extract_json سے گزار دیں؛ دوبارہ کوشش کی ضرورت نہیں۔
pos سٹرنگ کے آخر میں ہے
جواب جلدی رک گیا۔ finish_reason چیک کریں: اگر یہ length ہے، تو max_tokens بڑھائیں اور دوبارہ پوچھیں۔
خرابی درمیان میں کہیں ہے
ماڈل نے خود ٹوٹی ہوئی JSON لکھی (غائب کوما، آخری کوما، غیر محفوظ کوٹ)۔ اسے پیچ نہ کریں: سخت پرامپٹ کے ساتھ ایک بار دوبارہ کوشش کریں اور دوبارہ ناکام ہونے پر جواب لاگ کریں۔
json.loads کام کرتا ہے لیکن ایک کلید غائب ہے
پارسنگ ٹھیک ہے، مواد نہیں۔ پرامپٹ میں درست کلیدیں درج کریں اور پارسنگ کے بعد کوڈ میں انہیں چیک کریں۔
کیا API درست JSON پر مجبور کر سکتی ہے؟#
کبھی کبھی۔ OpenAI کی structured outputs گائیڈ دو موڈز بیان کرتی ہے: JSON موڈ (type: json_)، جو درست JSON واپس کرتا ہے لیکن اسکیما کی پیروی نہیں کرتا، اور Structured Outputs (type: json_، strict: true)، جو کرتا ہے؛ OpenAI جہاں ممکن ہو دوسرے کی سفارش کرتا ہے (ماخذ: developers.openai.com، 2 نومبر 2026 کو دیکھا گیا)۔ یہ OpenAI کے اپنے API آپشنز ہیں۔ کسی دوسرے اینڈ پوائنٹ کے ساتھ response_format پر انحصار کرنے سے پہلے، CheapTokens docs چیک کریں؛ اوپر دیا گیا استخراج اور دوبارہ کوشش سادہ چیٹ کمپلیشنز کے ساتھ کام کرتے ہیں اور کسی خاص پیرامیٹر کی ضرورت نہیں۔ درخواست کی طرف کے آپشنز پر مزید Get valid JSON from an LLM API: response_format and retries میں۔
پارسر شپ کرنے سے پہلے، چار چیزیں چیک کریں: متن پارس کرنے سے پہلے finish_reason پڑھا جاتا ہے، صرف ایک دوبارہ کوشش ہے (اور دوسری ناکامی آئٹم آئی ڈی کے ساتھ لاگ ہوتی ہے)، کوڈ پارسنگ کے بعد چیک کرتا ہے کہ متوقع کلیدیں موجود ہیں، اور max_tokens سب سے لمبی متوقع JSON کے لیے جگہ چھوڑتا ہے۔
اگلی بار جب json.loads پھینکا جائے، پہلے exc.pos اور finish_reason پرنٹ کریں۔ یہ دو نمبر عام طور پر جواب کی ایک سطر پڑھنے سے پہلے ہی بتا دیتے ہیں کہ کیا ہوا۔



