API ও SDKগাইড
একটি LLM API থেকে বৈধ JSON পান: response_format এবং পুনরায় চেষ্টা
একটি কপিযোগ্য Python অনুরোধ যা পার্সযোগ্য JSON ফেরত দেয়, একটি json.loads র্যাপার যা খালি বা কাটা উত্তর পরিচালনা করে, এবং JSON কেন ভাঙে তার একটি চেকলিস্ট।

এই পৃষ্ঠায়
একটি চ্যাট মডেল থেকে JSON পেতে তিনটি কাজ করুন: response_ পাস করুন, প্রম্পটে "json" শব্দটি এবং কাঠামোর একটি উদাহরণ দিন, এবং পুরো অবজেক্টের জন্য max_tokens যথেষ্ট উচ্চ সেট করুন। তারপর উত্তরটি কখনো অন্ধভাবে বিশ্বাস করবেন না: এটি খালি নয় কিনা পরীক্ষা করুন, finish_reason পরীক্ষা করুন, এবং তারপরেই json.loads কল করুন।
এটি সংক্ষিপ্ত সংস্করণ। এই গাইডের বাকি অংশটি একটি খুব সাধারণ কাজের জন্য একটি সম্পূর্ণ স্ক্রিপ্ট: একটি ইমেইল থেকে ফিল্ড বের করা। উদাহরণগুলি বেস URL https:/ এবং মডেল আইডি deepseek- ব্যবহার করে (ডকস)।
কাজটি: একটি ইমেইল ভিতরে, একটি সারি বাইরে#
ধরুন আপনার স্ক্রিপ্ট সাপোর্ট ইমেইল পড়ে এবং প্রতিটিকে একটি রেকর্ডে পরিণত করতে হবে: প্রেরক, তারিখ, পরিমাণ, এবং প্রেরক কী চান। এই একটি নিন:
হাই, আমি লুমেন লিমিটেড থেকে আনা পেত্রোভা। ১৪ অক্টোবর আমি ১,২৫০ EUR এর জন্য ইনভয়েস #৩৩৮১ পরিশোধ করেছি, কিন্তু রসিদটি এখনও unpaid দেখাচ্ছে। অনুগ্রহ করে শুক্রবারের আগে এটি ঠিক করুন।
আপনি এটি ফেরত চান, এবং আর কিছু নয়:
{"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 আউটপুটের জন্য DeepSeek API রেফারেন্স (২৭ অক্টোবর ২০২৬ পরীক্ষিত; পৃষ্ঠাটিতে কোনো প্রকাশের তারিখ নেই) এই অনুরোধ যে নিয়মগুলি অনুসরণ করে তা বলে: 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_reasonহলlength, এবং টেক্সট মাঝ-স্ট্রিং-এ শেষ হয়। এই সম্পর্কে আরও কেন একটি 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")একটি স্ক্রিপ্টের জন্য একটি পুনরায় চেষ্টা যথেষ্ট। যদি এটি দুবার ব্যর্থ হয়, ইমেইল আইডি লগ করুন এবং এগিয়ে যান; একটি তৃতীয় অভিন্ন অনুরোধ খুব কমই সাহায্য করে।
জোড়া মেলান
কোন লক্ষণ কোন কারণের দিকে ইঙ্গিত করে?
বাম দিকের একটি আইটেমে ট্যাপ করুন, তারপর তার জোড়ায়
- 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-এ ফাংশন কলিং দেখুন।

ইমেইলগুলির একটি ব্যাচের খরচ কত#
একটি সংক্ষিপ্ত এক্সট্রাকশন হল সস্তা ধরনের অনুরোধ: কয়েকশ টোকেন ভিতরে, কয়েক ডজন বাইরে। ধরুন প্রতিদিন ১,০০০ ইমেইল প্রায় ৪০০ ইনপুট টোকেন (প্রম্পট, উদাহরণ এবং ইমেইল) এবং প্রায় ৮০ আউটপুট টোকেন (JSON)। DeepSeek-V4-Flash-এ এটি প্রতিদিন $0.014, এবং টেবিলটি অন্যান্য মডেলগুলিতে একই লোড দেখায়:
| মডেল | ইনপুট $/১ মিলিয়ন | আউটপুট $/১ মিলিয়ন | প্রতি অনুরোধে | ১,০০০টি অনুরোধ | OpenRouter, ১,০০০টি অনুরোধ |
|---|---|---|---|---|---|
| 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 |
প্রতি অনুরোধে ৪০০ ইনপুট এবং ৮০ আউটপুট টোকেন। প্রতি 1M টোকেনের দাম বর্তমান এবং আমাদের ট্যারিফের সাথে পরিবর্তিত হয়; OpenRouter কলামটি একই ওয়ার্কলোডের জন্য রেফারেন্স মূল্য দেখায়।
মোট, ইনপুট এবং আউটপুট একসাথে গণনা করলে, DeepSeek-V4-Flash এই লোডের জন্য OpenRouter-এর রেফারেন্স মূল্যের চেয়ে সস্তা হয়। এটি প্রতি উত্তরে ৩২,৭৬৮ আউটপুট টোকেন পর্যন্ত অনুমতি দেয়, তাই লাইন আইটেমের একটি দীর্ঘ তালিকা ছোট সীমার মতো কাটা হবে না, এবং মূল্য যেকোনো সময় একই। GLM-5.3-Flash (zai-) একই API ঠিকানায় আরেকটি বিকল্প: ৮,১৯২ আউটপুট টোকেন পর্যন্ত, যা প্রতি ইমেইলে একটি রেকর্ডের জন্য যথেষ্ট। বর্তমান মূল্য মূল্য পৃষ্ঠা-এ; DeepSeek মডেল পৃষ্ঠা-এ এখানে ব্যবহৃত মডেলের বিবরণ রয়েছে।
দ্রুত চেক#
দ্রুত যাচাই
আপনার JSON একটি স্ট্রিংয়ের মাঝখানে কাটা। আপনি প্রথমে কী দেখবেন?
উত্তর দেখান
উত্তর: finish_reason এবং max_tokens
একটি কাটা অবজেক্ট finish_reason length-এ সেট করে শেষ হয়। সীমা হিট হয়েছে, তাই max_tokens বাড়ান; তাপমাত্রা বা ঠিকানা পরিবর্তন সাহায্য করে না।
যদি আপনি এখনও একটি অনুরোধ পাঠাননি, আপনার প্রথম API অনুরোধ দিয়ে শুরু করুন, তারপর ফিরে আসুন এবং উপরের কোডটি প্রতিস্থাপন করুন।



