समस्या निवारणगाइड
टूल कॉल के बाद 400: reasoning_content वापस भेजें
थिंकिंग मॉडल पर टूल-कॉल लूप का दूसरा अनुरोध 400 क्यों लौटाता है, पूरा संदेश जोड़ने वाला Python समाधान, और इसे कब छोड़ सकते हैं।

इस पृष्ठ पर
आपका एजेंट लूप पहले अनुरोध पर काम करता है और दूसरे पर 400 के साथ विफल हो जाता है। थिंकिंग मॉडल पर, एक प्रलेखित कारण एक गायब फ़ील्ड है: आप जो असिस्टेंट संदेश वापस भेजते हैं, उसने अपना reasoning_ खो दिया है। यदि यही कारण है, तो संदेश को ठीक वैसे ही जोड़ना जैसे API ने लौटाया था, इसे ठीक कर देता है।
DeepSeek की थिंकिंग-मोड गाइड (docs, 8 नवंबर 2026 को जाँचा गया) नियम को एक वाक्य में रखती है: जब अनुरोध में tools पैरामीटर हो, तो reasoning_ को सभी बाद के अनुरोधों में पूरा वापस भेजना होता है, जिनमें बिना टूल कॉल वाले टर्न भी शामिल हैं। अन्यथा API 400 लौटाता है। वही पेज कहता है कि थिंकिंग डिफ़ॉल्ट रूप से चालू है, एफ़र्ट high के साथ। इसलिए गैर-थिंकिंग मॉडल के लिए लिखा गया आपका लूप एक भी पंक्ति बदले बिना टूट सकता है।
अनुरोध एक और अनुरोध दो के बीच क्या होता है#
थिंकिंग मोड में चेन ऑफ़ थॉट reasoning_ में वापस आता है, जो content के समान स्तर पर एक फ़ील्ड है। लूप की कल्पना करें:
- आप प्रश्न और
toolsसूची भेजते हैं। - मॉडल
tool_callsके साथ उत्तर देता है (और उनके बगल मेंreasoning_)।content - आप टूल चलाते हैं और सब कुछ वापस भेजते हैं: इतिहास, असिस्टेंट संदेश, और परिणाम के साथ एक
toolसंदेश।
चरण 3 के अनुरोध पर 400 तब आता है जब उसमें असिस्टेंट संदेश में reasoning_ नहीं होता।

DeepSeek पेज 400 को केवल इस टूल-कॉल मामले के लिए प्रलेखित करता है और कोई त्रुटि पाठ नहीं देता, इसलिए जब आप जाँचें कि आपके पास यह समस्या है या नहीं, तो विशिष्ट संदेश नहीं, HTTP स्थिति देखें।
समाधान: संदेश को वैसे ही जोड़ें जैसे लौटाया गया#
सबसे सुरक्षित कदम है असिस्टेंट संदेश को दोबारा बनाना ही नहीं। इसे प्रतिक्रिया से लें और पूरा जोड़ें। यहाँ CheapTokens की ओर इंगित OpenAI Python SDK के साथ एक पूरा लूप है। मौसम टूल एक स्टब है, इसलिए आप इसे वैसे ही चला सकते हैं।
import json, 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"
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
def get_weather(city):
return {"city": city, "temp_c": 7} # stub
messages = [{"role": "user", "content": "Do I need a jacket in Oslo today?"}]
for _ in range(5): # hard step limit
resp = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
msg = resp.choices[0].message
messages.append(msg.model_dump(exclude_none=True)) # the whole message
if not msg.tool_calls:
print(msg.content)
break
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(get_weather(**args)),
})महत्वपूर्ण एक पंक्ति है messages.। SDK उन फ़ील्ड को रखता है जिनके बारे में उसे नहीं पता, इसलिए API ने संदेश पर जो कुछ भी रखा, reasoning_ सहित, वह उसके साथ वापस जाता है। अंतिम उत्तर भी जोड़ा जाता है, जो नियम माँगता है: पहले टूल कॉल के बाद, हर बाद का अनुरोध पिछले असिस्टेंट टर्न की रीज़निंग साथ ले जाता है।
टूल-कॉल की यांत्रिकी (स्कीमा, tool_call_id, आर्ग्युमेंट पार्सिंग) Function calling in Python with an OpenAI-compatible API में है। बेस URL, कुंजी और मॉडल आईडी CheapTokens docs page पर हैं; यहाँ उपयोग किया गया मॉडल DeepSeek page पर वर्णित है: 380K कॉन्टेक्स्ट और प्रति उत्तर अधिकतम 32,768 आउटपुट टोकन, जो लंबी थिंकिंग और उत्तर के लिए जगह छोड़ता है।
एक आम दोषी: हाथ से दोबारा बनाया गया संदेश#
फ़ील्ड खोने का एक आम तरीका है वह कोड जो प्रतिक्रिया ऑब्जेक्ट को जोड़ता नहीं बल्कि नया dict बनाता है। यह हानिरहित लगता है: role, content, tool calls। फ्रेमवर्क और रैपर भी ऐसा ही करते हैं जब वे इतिहास को अपने प्रारूप में संग्रहीत करते हैं। जिस एक फ़ील्ड के बारे में उन्होंने कभी सुना ही नहीं, वही गायब हो जाता है।

तुलना करें
हाथ से दोबारा बनाया गया बनाम पूरा जोड़ा गया
हाथ से दोबारा बनाया गया (टूटता है)
messages.append({
"role": "assistant",
"content": msg.content,
"tool_calls": [c.model_dump() for c in msg.tool_calls],
})पूरा जोड़ा गया (काम करता है)
messages.append(msg.model_dump(exclude_none=True))यदि आप फ्रेमवर्क उपयोग करते हैं और उस पंक्ति को छू नहीं सकते, तो जाँचें कि यह असिस्टेंट टर्न को कैसे संग्रहीत करता है। ऐसा इतिहास जो सीरियलाइज़र से गुज़रता है जो केवल content और tool_calls रखता है, उसमें वही बग है, बस एक परत नीचे।
जब आपको इसकी आवश्यकता नहीं#
हर थिंकिंग-मॉडल कॉल को अतिरिक्त सावधानी की आवश्यकता नहीं होती। बिना टूल वाली मल्टी-टर्न चैट के लिए, DeepSeek की गाइड कहती है कि reasoning_ को वापस भेजना आवश्यक नहीं है; यदि आप फिर भी भेजते हैं, तो इसे अनदेखा किया जाता है और पिछली रीज़निंग कॉन्टेक्स्ट में नहीं जोड़ी जाती। इसलिए सादी चैट इसे छोड़ती रह सकती है और कुछ नहीं टूटता।
अपना मामला चुनें
आपका मामला कौन सा है?
उत्तर देखने के लिए एक विकल्प चुनें
अनुरोध में tools है, मॉडल थिंक कर रहा है
हर टर्न पर पूरा असिस्टेंट संदेश जोड़ें, टूल टर्न और अंतिम उत्तर दोनों।
सादी चैट, कोई tools पैरामीटर नहीं
कोई सुधार आवश्यक नहीं। आप इतिहास से reasoning_ छोड़ सकते हैं, या भेज सकते हैं; इसे अनदेखा किया जाता है।
फ्रेमवर्क आपके लिए इतिहास बनाता है
वह जगह खोजें जहाँ यह असिस्टेंट संदेशों को सीरियलाइज़ करता है और सुनिश्चित करें कि reasoning_ बचा रहे। यदि ऐसा नहीं हो सकता, तो टूल भाग के लिए अपने स्वयं के लूप से API कॉल करें।
ध्यान में रखने योग्य एक दुष्प्रभाव: आप जो इतिहास दोबारा भेजते हैं वह हर अनुरोध पर इनपुट होता है, इसलिए लंबे लूप में लंबी रीज़निंग जुड़ती जाती है। थिंकिंग टोकन कैसे गिने जाते हैं, यह Reasoning effort and thinking tokens में शामिल है, और जब कोई अनुरोध मॉडल की सीमाओं से बढ़ जाए तो क्या करें, यह Request too long: 400 vs 413 में है।
यदि फिर भी 400 लौटता है#
इन्हें क्रम से देखें:
- विफल कॉल से ठीक पहले
messagesप्रिंट करें। क्या मॉडल से आए हर असिस्टेंट संदेश मेंreasoning_है, यदि प्रतिक्रिया में वह था?content - क्या आप कहीं संदेश दोबारा बनाते हैं: कोई हेल्पर, कोई इतिहास क्लास,
json.dumpsऔर वापस कुंजियों की निश्चित सूची के साथ? - क्या हर
tool_call_idके लिएtoolसंदेश मौजूद है, उसी id के साथ? - क्या वास्तव में लंबाई है? कॉन्टेक्स्ट सीमा से अधिक अनुरोध एक अलग 400 है, जो ऊपर के लेख में वर्णित है।
त्वरित जाँच
मॉडल के टूल माँगने के बाद आप क्या जोड़ते हैं?
उत्तर दिखाएँ
उत्तर: पूरा असिस्टेंट संदेश जैसे लौटाया गया, reasoning_content सहित
tool_calls वही हैं जिनका उत्तर आपके टूल संदेश देते हैं, और अनुरोध में टूल होने पर रीज़निंग को उनके साथ चलना होता है।
यही पूरा समाधान है: एक append, कोई पुनर्निर्माण नहीं। उदाहरण से स्टेप सीमा को अपने हर लूप में जोड़ें, ताकि एक खराब टर्न पाँच अनुरोधों का खर्च करे, पाँच सौ का नहीं।



