DeepSeek Tool Calls with Thinking: reasoning_content Management
Combine DeepSeek's tool calls with thinking mode. The mandatory reasoning_content passback in tool loops, strict mode for JSON schema enforcement, and error handling patterns to avoid 400 errors.
DeepSeek supports tool calls in thinking mode — a feature introduced in V3.2 that combines structured function calling with chain-of-thought reasoning. The model can reason about which tool to call, interpret tool results, and continue reasoning across multiple tool call sub-turns. But the reasoning_content management in tool loops follows strict rules that will 400-error if you get them wrong.
The Tool Call + Thinking Flow
User: "What's the weather in Tokyo and should I bring an umbrella?"
Model (turn 1.1):
reasoning: "I need to get tomorrow's date first, then call get_weather."
tool_call: get_date()
Tool result: "2026-06-13"
Model (turn 1.2):
reasoning: "Tomorrow is June 13. Now I'll call get_weather for Tokyo."
tool_call: get_weather(location="Tokyo", date="2026-06-13")
Tool result: "Rainy, 15°C"
Model (turn 1.3):
reasoning: "It's rainy and cool. The user should definitely bring an umbrella."
content: "Yes, bring an umbrella! Tomorrow will be rainy with temperatures around 15°C."
The Critical Rule: Mandatory reasoning_content Passback
In tool-call turns, reasoning_content MUST be passed back to the API in all subsequent requests. Failure to do so returns a 400 error.
# CORRECT: Always pass the full message object
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages,
tools=tools,
reasoning_effort="high",
extra_body={"thinking": {"type": "enabled"}}
)
message = response.choices[0].message
# This single line handles reasoning_content + content + tool_calls correctly:
messages.append(message)
# Execute tool
tool_result = execute_tool(message.tool_calls[0])
messages.append({
"role": "tool",
"tool_call_id": message.tool_calls[0].id,
"content": tool_result
})
# Continue — reasoning_content from the previous message is automatically passed
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages,
tools=tools,
reasoning_effort="high",
extra_body={"thinking": {"type": "enabled"}}
)
The Full Tool Call Loop
def run_with_tools(messages, tools, tool_handler):
"""Complete tool call loop with reasoning management."""
while True:
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages,
tools=tools,
reasoning_effort="high",
extra_body={"thinking": {"type": "enabled"}}
)
message = response.choices[0].message
messages.append(message) # Includes reasoning_content, content, tool_calls
# No tool calls → final answer reached
if not message.tool_calls:
return message.content, message.reasoning_content
# Execute all tool calls
for tool_call in message.tool_calls:
result = tool_handler(tool_call.function.name, tool_call.function.arguments)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
strict Mode (Beta)
Strict mode enforces JSON schema compliance on tool call outputs. Useful when tool outputs must match exact schemas:
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"strict": True, # Enable strict mode
"description": "Get weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name"
}
},
"required": ["location"],
"additionalProperties": False # Required in strict mode
}
}
}]
# Must use beta endpoint for strict mode
client = OpenAI(
base_url="https://api.deepseek.com/beta",
api_key="<key>"
)
Supported JSON Schema Types in Strict Mode
| Type | Supported Constraints |
|---|---|
object | properties, required, additionalProperties: false |
string | pattern (regex), format (email, hostname, ipv4, ipv6, uuid) |
number/integer | minimum, maximum, const, multipleOf |
array | items schema |
enum | Value list |
anyOf | Multiple schema alternatives |
$ref/$def | Reusable schema modules |
Common Errors
Error 1: 400 — Missing reasoning_content
HTTP 400: "reasoning_content is required for tool call turns"
Fix: Always use messages.append(response.choices[0].message)
Never manually construct the assistant message dict in tool-call loops.
Error 2: 400 — strict mode schema validation
HTTP 400: "Schema validation failed"
Fix: Ensure all object properties are in 'required' array.
Set 'additionalProperties: false' on all objects.
Check that parameter names match between schema and function definition.
Error 3: Tool calls with non-thinking mode
Tool calls work in both thinking and non-thinking mode.
If you don't need reasoning, omit the thinking parameter for simpler tool loops.
Non-thinking mode doesn't require reasoning_content management.
When to Use Tool Calls with Thinking
| Scenario | Recommendation |
|---|---|
| Complex multi-tool chains | Thinking mode — reasoning helps select the right tools |
| Simple single-tool calls | Non-thinking mode — faster, cheaper |
| Tools with ambiguous results | Thinking mode — model reasons about results |
| Deterministic tool workflows | Non-thinking mode — no reasoning benefit |
| Production with strict schema | Thinking + strict mode — reliable structured outputs |
Note:
Pro Move: For LangChain agent workflows, verify that your framework correctly handles reasoning_content in multi-step tool chains. Many frameworks built for OpenAI drop non-standard fields. Test with a simple 2-step tool chain before deploying complex agents.
Note:
Streaming + Tool Calls: When streaming with tool calls, reasoning_content and tool_calls arrive in separate chunks. You must accumulate the full message (reasoning + content + tool_calls) before appending to the messages list. The non-streaming convenience of messages.append(response.choices[0].message) doesn't work in streaming mode — you must manually construct the full message object.
Related Pages
- OpenAI-Compatible API — SDK configuration and migration patterns for both OpenAI and Anthropic formats.
- Multi-Turn Reasoning — The
reasoning_contentmanagement rules that apply to all multi-turn thinking, including tool-call loops.
Related Articles
UX & Design: ChatGPT Prompts for Designers
A curated collection of ChatGPT prompts for UX designers — research, UI design, design systems, user testing, portfolios, and more.
Claude Domain Applications: Specialized Use Cases
Applied Claude prompting for document analysis, code review, data extraction, creative writing, and academic research. Domains where Claude's unique strengths — nuance, honesty, and long-form coherence — give it an edge.
3D Glassmorphism Icon Transformation
Discover how classic 2D icons are reimagined as stunning 3D glassmorphism objects, blending nostalgia with futuristic neon-lit design for next-gen digital experiences.