API اور SDKگائیڈ
LLM API سے درست JSON حاصل کریں: response_format اور دوبارہ کوششیں
ایک کاپی کرنے کے قابل Python درخواست جو پارس کے قابل JSON واپس کرتی ہے، ایک json.loads ریپر جو خالی یا کٹے ہوئے جوابات سنبھالتا ہے، اور JSON ٹوٹنے کی وجوہات کی چیک لسٹ۔

اس صفحہ پر
چیٹ ماڈل سے JSON حاصل کرنے کے لیے تین کام کریں: response_ پاس کریں، پرامپٹ میں لفظ "json" اور ساخت کی ایک مثال ڈالیں، اور max_tokens کو پورے آبجیکٹ کے لیے کافی زیادہ رکھیں۔ پھر جواب پر کبھی آنکھ بند کر کے بھروسا نہ کریں: چیک کریں کہ یہ خالی نہیں ہے، finish_reason چیک کریں، اور صرف اس کے بعد json.loads کال کریں۔
یہ مختصر ورژن ہے۔ اس گائیڈ کا باقی حصہ ایک بہت عام کام کے لیے ایک مکمل اسکرپٹ ہے: ای میل سے فیلڈز نکالنا۔ مثالیں base URL https:/ اور ماڈل id deepseek- استعمال کرتی ہیں (docs)۔
کام: ایک ای میل اندر، ایک قطار باہر#
فرض کریں آپ کی اسکرپٹ سپورٹ ای میلز پڑھتی ہے اور ہر ایک کو ایک ریکارڈ میں بدلنا ہے: بھیجنے والا، تاریخ، رقم، اور بھیجنے والا کیا چاہتا ہے۔ یہ لیں:
ہائے، میں Lumen Ltd سے Anna Petrova ہوں۔ 14 اکتوبر کو میں نے انوائس #3381 کی 1,250 EUR ادائیگی کی، لیکن رسید اب بھی اسے غیر ادا شدہ دکھاتی ہے۔ براہ کرم جمعہ سے پہلے اسے ٹھیک کریں۔
آپ یہ واپس چاہتے ہیں، اور کچھ نہیں:
{"sender": "Anna Petrova", "date": "2026-10-14", "amount": 1250, "currency": "EUR", "action": "fix receipt status"}ایک سادہ "فیلڈز نکالیں" پرامپٹ آپ کو ایک دوستانہ جملہ، ایک کوڈ فینس، یا دونوں دے سکتا ہے۔ آپ کا json.loads پہلے بیک ٹک پر ہی اٹک جاتا ہے۔ یہی وہ مسئلہ ہے جسے response_format اور ایک اچھا پرامپٹ مل کر حل کرتے ہیں۔
Python اور curl میں وہی درخواست
Python
import json
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"
SYSTEM = """Extract fields from the email and answer with json only.
Example of the json format:
{"sender": "Jane Roe", "date": "2026-01-31", "amount": 99.5, "currency": "USD", "action": "short phrase"}
Use null for a field that is not in the email."""
resp = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": email_text},
],
response_format={"type": "json_object"},
max_tokens=1000,
temperature=0,
)
print(resp.choices[0].message.content)curl
curl https://api.cheaptokens.dev/v1/chat/completions \
-H "Authorization: Bearer $CHEAPTOKENS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-ai/DeepSeek-V4-Flash-0731",
"messages": [
{"role": "system", "content": "Extract fields from the email and answer with json only. Example: {\"sender\": \"Jane Roe\", \"amount\": 99.5}"},
{"role": "user", "content": "Hi, this is Anna Petrova from Lumen Ltd. I paid invoice #3381 for 1,250 EUR..."}
],
"response_format": {"type": "json_object"},
"max_tokens": 1000
}'JSON Output کے لیے DeepSeek API ریفرنس (27 اکتوبر 2026 کو چیک کیا گیا؛ صفحے پر کوئی اشاعت کی تاریخ نہیں ہے) ان قواعد کو بیان کرتا ہے جن کی یہ درخواست پیروی کرتی ہے: response_format کو json_object پر سیٹ کریں، سسٹم یا یوزر پرامپٹ میں کہیں لفظ "json"، اور ہدف کی ساخت کی ایک مثال۔ مثال کے بغیر ماڈل کو آپ کے فیلڈ ناموں کا اندازہ لگانا پڑتا ہے، اور وہ اگلی ای میل پر مختلف اندازہ لگائے گا۔
فلیگ سے زیادہ مثال کیوں اہم ہے#
response_format API سے JSON آبجیکٹ واپس کرنے کو کہتا ہے۔ یہ ماڈل کو نہیں بتاتا کہ کون سا آبجیکٹ۔ اسے ایسے سمجھیں جیسے کسی ساتھی سے کہیں "مجھے ایک اسپریڈشیٹ بھیجیں" بغیر یہ بتائے کہ کون سے کالم۔ آپ کو ایک اسپریڈشیٹ ملتی ہے، بس آپ کی نہیں۔
پرامپٹ میں مثال کالم ہیڈر کی قطار ہے۔ دو عادات اسے بہتر بناتی ہیں:
- اصل شکل دکھائیں، بشمول اقسام:
1250ایک نمبر ہے،"2026-10-14"ایک مقررہ تاریخ فارمیٹ میں ایک سٹرنگ ہے۔ - بتائیں کہ جب کوئی فیلڈ غائب ہو تو کیا کرنا ہے (اوپر
null)۔ ورنہ ماڈل خلا بھرنے کے لیے ایک قدر ایجاد کر لیتا ہے۔
response_format کو ایک مضبوط اشارہ سمجھیں، ضمانت نہیں۔ ماڈلز کبھی کبھی پھر بھی خالی سٹرنگ واپس کرتے ہیں، یا آبجیکٹ کو نثر میں لپیٹ دیتے ہیں۔ اسی لیے اگلا حصہ موجود ہے۔
محفوظ طریقے سے پارس کریں: خالی، کٹا ہوا، یا صرف ٹوٹا ہوا#
عملی طور پر تین ناکامیاں سامنے آتی ہیں، اور ہر ایک مختلف نشان چھوڑتی ہے:
- خالی مواد۔ DeepSeek دستاویزات کہتی ہیں کہ JSON موڈ کبھی کبھار خالی مواد واپس کر سکتا ہے اور پرامپٹ کو دوبارہ لکھنے کا مشورہ دیتی ہیں۔ آپ کی طرف یہ
message.contentکے""یاNoneہونے، اورjson.loads("")کےExpecting value: line 1 column 1 (char 0)اٹھانے کی صورت میں نظر آتا ہے۔ - کٹا ہوا۔
max_tokensآبجیکٹ کے بیچ میں ختم ہو گیا۔finish_reasonlengthہے، اور متن سٹرنگ کے بیچ میں ختم ہوتا ہے۔ اس بارے میں مزید AI جواب جملے کے بیچ میں کیوں رک جاتا ہے میں۔ - JSON نہیں۔ آبجیکٹ سے پہلے ایک جملہ، یا اس کے گرد ایک فینس۔

پہلی اور تیسری کا حل زیادہ پختہ پرامپٹ کے ساتھ دوبارہ کوشش ہے۔ دوسری کے لیے، اسی حد کے ساتھ دوبارہ کوشش کچھ نہیں بدلتی، اس لیے ریپر اٹھتا ہے اور آپ کو max_tokens بڑھانے کو کہتا ہے:
def ask_json(email_text: str, retries: int = 1) -> dict:
user = email_text
for attempt in range(retries + 1):
resp = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": user},
],
response_format={"type": "json_object"},
max_tokens=1000,
temperature=0,
)
choice = resp.choices[0]
if choice.finish_reason == "length":
raise ValueError("JSON cut off by max_tokens: raise the limit")
text = (choice.message.content or "").strip()
if text:
try:
return json.loads(text)
except json.JSONDecodeError:
pass
# empty or not JSON: ask again, more firmly
user = email_text + "\n\nReply with one json object only, in the format of the example."
raise ValueError("no valid JSON after retry")ایک اسکرپٹ کے لیے ایک دوبارہ کوشش کافی ہے۔ اگر یہ دو بار ناکام ہو، ای میل id لاگ کریں اور آگے بڑھیں؛ تیسری یکساں درخواست شاذ و نادر ہی مدد کرتی ہے۔
جوڑے ملائیں
کون سی علامت کس وجہ کی طرف اشارہ کرتی ہے؟
بائیں طرف کسی آئٹم پر ٹیپ کریں، پھر اس کا جوڑا
- finish_reason "length" ہےmax_tokens آبجیکٹ کے لیے بہت کم ہے
- content ایک خالی سٹرنگ ہےJSON موڈ نے کچھ واپس نہیں کیا؛ پرامپٹ دوبارہ لکھیں اور دوبارہ کوشش کریں
- بیک ٹک والے حرف پر JSONDecodeErrorماڈل نے JSON کو کوڈ فینس میں لپیٹ دیا
- ای میلز کے درمیان فیلڈ نام مختلف ہیںپرامپٹ میں ساخت کی کوئی مثال نہیں ہے
صرف نحو نہیں، شکل چیک کریں#
json.loads صرف یہ ثابت کرتا ہے کہ متن درست JSON ہے۔ یہ ثابت نہیں کرتا کہ اس میں وہ فیلڈز ہیں جو آپ نے مانگے تھے۔ پارس کرنے کے فوراً بعد ایک سستا چیک شامل کریں:
REQUIRED = {"sender", "date", "amount", "currency", "action"}
data = ask_json(email_text)
missing = REQUIRED - data.keys()
if missing:
raise ValueError(f"missing fields: {sorted(missing)}")یہاں سے ڈکٹ سیدھا ڈیٹا بیس کی قطار یا اسپریڈشیٹ میں جاتا ہے۔ اگر آپ کو ماڈل سے اپنے فنکشنز کال کروانے ہیں بجائے ایک مقررہ ریکارڈ بھرنے کے، تو یہ ایک مختلف ٹول ہے: Python میں فنکشن کالنگ دیکھیں۔

ای میلز کے ایک بیچ کی لاگت#
مختصر اخراج سستی قسم کی درخواست ہے: چند سو ٹوکن اندر، چند درجن باہر۔ فرض کریں روزانہ 1,000 ای میلز تقریباً 400 ان پٹ ٹوکنز (پرامپٹ، مثال اور ای میل) اور تقریباً 80 آؤٹ پٹ ٹوکنز (JSON) کے ساتھ۔ DeepSeek-V4-Flash پر یہ روزانہ $0.014 ہے، اور جدول دیگر ماڈلز پر وہی بوجھ دکھاتا ہے:
| ماڈل | ان پٹ $/1M | آؤٹ پٹ $/1M | فی درخواست | 1,000 درخواستیں | OpenRouter، 1,000 درخواستیں |
|---|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.000011 | $0.0112 | $0.0226 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.000014 | $0.014 | $0.0315 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.000032 | $0.032 | $0.216 |
فی درخواست 400 ان پٹ اور 80 آؤٹ پٹ ٹوکنز۔ فی 1M ٹوکنز کی قیمتیں موجودہ ہیں اور ہمارے ٹیرف کے ساتھ تبدیل ہوتی ہیں؛ OpenRouter کالم اسی ورک لوڈ کے لیے حوالہ جاتی قیمتیں دکھاتا ہے۔
مجموعی طور پر، ان پٹ اور آؤٹ پٹ کو ملا کر، DeepSeek-V4-Flash اس بوجھ کے لیے OpenRouter کی حوالہ قیمت سے سستا نکلتا ہے۔ یہ فی جواب 32,768 آؤٹ پٹ ٹوکنز تک کی بھی اجازت دیتا ہے، لہٰذا لائن آئٹمز کی لمبی فہرست اس طرح نہیں کٹے گی جیسے چھوٹی حد کے ساتھ ہوتی، اور قیمت کسی بھی گھنٹے میں یکساں ہے۔ GLM-5.3-Flash (zai-) اسی API ایڈریس پر ایک اور آپشن ہے: 8,192 آؤٹ پٹ ٹوکنز تک، جو فی ای میل ایک ریکارڈ کے لیے کافی ہے۔ موجودہ قیمتیں قیمتوں کے صفحے پر ہیں؛ DeepSeek ماڈل صفحہ پر یہاں استعمال ہونے والے ماڈل کی تفصیلات ہیں۔
فوری جانچ#
فوری جانچ
آپ کا JSON ایک سٹرنگ کے بیچ میں کٹا ہوا ہے۔ آپ سب سے پہلے کیا دیکھتے ہیں؟
جواب دکھائیں
جواب: finish_reason اور max_tokens
کٹا ہوا آبجیکٹ finish_reason کے length پر سیٹ ہونے کے ساتھ ختم ہوتا ہے۔ حد تک پہنچ گئی، اس لیے max_tokens بڑھائیں؛ temperature یا ایڈریس بدلنے سے مدد نہیں ملتی۔
اگر آپ نے ابھی تک کوئی درخواست نہیں بھیجی، تو اپنی پہلی API درخواست سے شروع کریں، پھر واپس آ کر اوپر کا کوڈ استعمال کریں۔



