cheapaimodelSearch
All posts

How to set DeepSeek V4.1 Flash's reasoning effort on any OpenAI-compatible API

By Nicho

DeepSeek V4.1 Flash reasons before it answers. Unless you say otherwise, it reasons at high effort. You can change that with one request field, reasoning_effort. It's an ordinary field in the request body, so you can set it per request through any endpoint that passes it along, including ours. You don't need a different model ID.

This post covers the four levels, what each one cost in a test we ran on October 16, 2026, how to set the field from code and from common tools, and how to check that a third-party endpoint actually passes it through.

The short version

Add reasoning_effort next to model:

curl https://api.cheapaimodel.ai/v1/chat/completions \
  -H "Authorization: Bearer $CHEAPAIMODEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4-1-flash",
    "reasoning_effort": "low",
    "messages": [{"role": "user", "content": "Summarize this changelog in three bullets: ..."}]
  }'
Value What it does
none Turns reasoning off. The model answers right away.
low Short reasoning. DeepSeek suggests it for simple tasks.
high The default. DeepSeek suggests it for everyday agent work.
max The longest reasoning, for harder problems.

Leaving the field out is the same as sending high.

What each level cost

We sent one math question with a single correct answer to https://api.cheapaimodel.ai/v1: how many ordered pairs (a, b) of positive integers, both at most 100, make a² + b² divisible by 13? (The answer is 1,491.) Each level ran 8 times, except none, which ran 3 times. All requests were non-streaming.

Effort Avg. reasoning tokens Range Avg. time Correct
none 0 0 14.0 s 0 of 3
low 2,348 925–3,719 17.2 s 7 of 8
high 3,081 2,232–3,629 20.4 s 8 of 8
max 3,530 2,700–5,803 23.2 s 7 of 8

Reasoning tokens are billed as output tokens. At our V4.1 Flash price when we ran the test, $0.84 per million output tokens, an average request cost about $0.002 at low and $0.003 at max.

What stood out:

  • With reasoning off, the model was wrong every time. Twice it ignored "reply with just the number" and worked through the problem in its visible answer, which took about as long as reasoning would have.
  • high and max were close on this question. max spent clearly more only once, when it chose to think much longer (the 5,803-token run).
  • low used about a quarter fewer tokens than high and missed once.

One question isn't a benchmark. Before you pick a default, run a sample of your own prompts at two levels and compare usage.completion_tokens_details.reasoning_tokens and the answers.

Setting it from code

OpenAI Python SDK

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.cheapaimodel.ai/v1",
    api_key=os.environ["CHEAPAIMODEL_API_KEY"],
)

completion = client.chat.completions.create(
    model="deepseek-v4-1-flash",
    reasoning_effort="low",
    messages=[{"role": "user", "content": "Explain recursion in one sentence."}],
)

print(completion.choices[0].message.content)
print(completion.usage.completion_tokens_details.reasoning_tokens)

reasoning_effort is an ordinary argument. Its type hints include none from openai 2.8.0 and max from 2.45.0, so older versions still send those values but your type checker will complain. The reasoning text itself is in completion.choices[0].message.reasoning_content. It isn't part of the SDK's types, but the SDK keeps extra fields, so the attribute works.

OpenAI TypeScript SDK

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.cheapaimodel.ai/v1",
  apiKey: process.env.CHEAPAIMODEL_API_KEY,
});

const completion = await client.chat.completions.create({
  model: "deepseek-v4-1-flash",
  reasoning_effort: "max",
  messages: [{ role: "user", content: "Explain recursion in one sentence." }],
});

'none' and 'max' type-check from openai 6.46.0. reasoning_content isn't in the SDK's types either, so to read it, cast the message to the SDK's ChatCompletionMessage type intersected with { reasoning_content?: string }.

Responses API

The Responses API takes the same four values inside a reasoning object:

response = client.responses.create(
    model="deepseek-v4-1-flash",
    reasoning={"effort": "low"},
    input="Explain recursion in one sentence.",
)

print(response.output_text)
print(response.usage.output_tokens_details.reasoning_tokens)

With "effort": "none", the response has no reasoning item and reasoning_tokens is 0.

Turning reasoning off

There are two switches. reasoning_effort: "none" is the portable one. DeepSeek also has its own thinking object, which the OpenAI Python SDK sends through extra_body:

completion = client.chat.completions.create(
    model="deepseek-v4-1-flash",
    messages=[{"role": "user", "content": "..."}],
    extra_body={"thinking": {"type": "disabled"}},
)

In the TypeScript SDK, thinking isn't in the types. Add it with a // @ts-expect-error comment, which is what the SDK's README suggests for undocumented parameters. Don't use the per-request body option for this: it replaces the whole request body instead of adding a field.

Use one switch or the other. When we sent both, thinking won both ways: disabled with high didn't reason, and enabled with none did.

In frameworks

We pointed each library at a local server that records requests and checked the body it actually sent. Each one can send the field, but several have a default that doesn't.

LangChain (Python)

import os
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="deepseek-v4-1-flash",
    base_url="https://api.cheapaimodel.ai/v1",
    api_key=os.environ["CHEAPAIMODEL_API_KEY"],
    reasoning_effort="low",
)

llm.invoke("Explain recursion in one sentence.", reasoning_effort="max")  # per call
  • Send thinking with extra_body={"thinking": {...}}. Putting it in model_kwargs raises a TypeError.
  • Passing reasoning={"effort": ...} instead of reasoning_effort quietly switches ChatOpenAI to the Responses API.
  • ChatOpenAI discards reasoning_content. The token count survives in usage_metadata["output_token_details"]["reasoning"]. If you need the text, ChatDeepSeek from langchain-deepseek returns it in additional_kwargs["reasoning_content"].

LlamaIndex

import os
from llama_index.llms.openai_like import OpenAILike

llm = OpenAILike(
    model="deepseek-v4-1-flash",
    api_base="https://api.cheapaimodel.ai/v1",
    api_key=os.environ["CHEAPAIMODEL_API_KEY"],
    is_chat_model=True,
    additional_kwargs={"reasoning_effort": "low"},
)
  • Use additional_kwargs. The constructor also has a reasoning_effort= argument, but it's only sent for OpenAI's own reasoning models, so with V4.1 Flash it silently does nothing. It also rejects "max".
  • thinking goes one level down: additional_kwargs={"extra_body": {"thinking": {...}}}.

Vercel AI SDK

import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { generateText } from "ai";

const cheapaimodel = createOpenAICompatible({
  name: "cheapaimodel",
  baseURL: "https://api.cheapaimodel.ai/v1",
  apiKey: process.env.CHEAPAIMODEL_API_KEY,
});

const { text, reasoningText } = await generateText({
  model: cheapaimodel("deepseek-v4-1-flash"),
  prompt: "Explain recursion in one sentence.",
  providerOptions: { cheapaimodel: { reasoningEffort: "low" } },
});
  • The key under providerOptions is the name you gave the provider. Write reasoningEffort in camelCase: reasoning_effort there is silently dropped.
  • AI SDK 7 also has a top-level reasoning: "low" option that sends the same field.
  • thinking works under the same key: providerOptions: { cheapaimodel: { thinking: { type: "disabled" } } }.

LiteLLM

import os
import litellm

response = litellm.completion(
    model="openai/deepseek-v4-1-flash",
    api_base="https://api.cheapaimodel.ai/v1",
    api_key=os.environ["CHEAPAIMODEL_API_KEY"],
    reasoning_effort="low",
    messages=[{"role": "user", "content": "Explain recursion in one sentence."}],
)
  • Keep the openai/ prefix. With deepseek/, LiteLLM turns the effort into DeepSeek's on/off switch and drops the level, so low and max both become plain "thinking on".
  • On LiteLLM Proxy, set reasoning_effort under the model's litellm_params. A value the client sends overrides it.

In coding tools and apps

Most tools only send the field if you tell them to. If a tool sends nothing, DeepSeek runs at high.

Tool Where to set it Levels you can reach
Codex CLI model_reasoning_effort in config.toml all four
Continue requestOptions.extraBodyProperties on the model all four
Aider --reasoning-effort, after declaring the setting (below) all four
Open WebUI Model → Advanced Params → Reasoning Effort, set to Custom all four
Zed reasoning_effort on the model in available_models all four
OpenClaw the model's compat settings (below) all four
n8n OpenAI Chat Model → Options → Extra Body all four
Cline Reasoning Effort in the OpenAI Compatible settings, or --thinking none, low, high
Dify Reasoning effort, after setting Thinking Mode Support (below) none, low, high
Cursor not available with a custom base URL default only

Tested with Codex CLI 0.163.0, Continue CLI 1.5.47, Aider 0.86.2, Cline CLI 3.0.71, and OpenClaw 2026.10.4; read from source for Open WebUI 0.12.2, Zed 1.24.2, the Dify OpenAI-API-compatible plugin 0.0.68, and n8n 2.43.6.

Codex CLI only talks to custom providers through the Responses API, so it sends reasoning.effort. Also set model_reasoning_summary = "none". Otherwise Codex adds reasoning.summary, which V4.1 Flash on cheapaimodel rejects with a 400.

model_reasoning_effort = "low"
model_reasoning_summary = "none"

If you leave model_reasoning_effort unset, Codex's banner says "reasoning effort: none", but it sends no effort at all, so the model runs at high.

Continue has no effort option for OpenAI-compatible models, but it adds any body field you list:

models:
  - name: DeepSeek V4.1 Flash
    provider: openai
    model: deepseek-v4-1-flash
    apiBase: https://api.cheapaimodel.ai/v1
    apiKey: YOUR_API_KEY
    requestOptions:
      extraBodyProperties:
        reasoning_effort: low

Aider ignores --reasoning-effort for models it doesn't know and prints a warning. Declare the setting in .aider.model.settings.yml:

- name: openai/deepseek-v4-1-flash
  accepts_settings: ["reasoning_effort"]

Then run aider --model openai/deepseek-v4-1-flash --reasoning-effort low, or type /reasoning-effort low in the chat. Don't put the field in extra_params directly: Aider drops it there.

OpenClaw treats any custom base URL as a proxy and doesn't send an effort unless the model entry says it can. Add these fields to the entry from our OpenClaw guide:

{
  id: "deepseek-v4-1-flash",
  // ...the rest of the entry
  reasoning: true,
  compat: {
    supportsUsageInStreaming: true,
    supportsReasoningEffort: true,
    supportedReasoningEfforts: ["none", "low", "high", "max"],
  },
}

Then set a default in agents.defaults.models["cheapaimodel/deepseek-v4-1-flash"].params.thinking, for example "high". Without it, new sessions start at low, and OpenClaw rounds levels it doesn't list down, so medium becomes low.

n8n only shows its built-in Reasoning Effort option for OpenAI model names. Use Extra Body instead, and match the field to the API the node uses. With Use Responses API on, the default, write {"reasoning": {"effort": "low"}}. With it off, write {"reasoning_effort": "low"}.

Dify is the one to watch. With the default Thinking Mode Support, "Only Non-Thinking Mode", Dify sends no effort and only hides the reasoning from the reply. The model still reasons at high, and you still pay for those tokens. To actually turn reasoning off, choose a mode that includes thinking and set Reasoning effort to none.

Cursor doesn't send an effort for models behind a custom base URL, so they run at high.

On other OpenAI-compatible endpoints

Everything above applies to any provider that serves V4.1 Flash behind an OpenAI-compatible base URL. What varies is what the endpoint does with the field. Before you rely on it:

  1. Check that it arrives. Send the same prompt with none and with max. With none, reasoning_tokens should be 0 and the message should have no reasoning_content. If both requests come back looking the same, the endpoint is dropping the field and you're getting its default.
  2. Check the model list. Some gateways expose each level as its own model ID, for example with a -max or -none suffix. If yours does, use those IDs. cheapaimodel has one ID, deepseek-v4-1-flash, and the field decides.
  3. Check what a typo does. On cheapaimodel, "reasoning_effort": "turbo" returns 400 with "code": "InvalidParameter", so a mistake fails loudly. An endpoint that drops values it doesn't recognize will quietly run at the default instead.
  4. Stick to none, low, high, and max. DeepSeek's own API also accepts OpenAI's minimal, medium, and xhigh and maps them to the nearest level, but endpoints don't all map them the same way. In our tests, minimal behaved more like high than low.
  5. Don't assume the rules carry over. Providers that serve the same model differ in the details. DeepSeek's documentation says its API returns 400 for tool_choice: "required" in thinking mode and for tool conversations that drop reasoning_content. On cheapaimodel, both requests went through in our tests. Write your code to work under the stricter rules.

Three things that trip people up

max_tokens includes the reasoning

With reasoning_effort: "high" and max_tokens: 100, we got finish_reason: "length" and an empty content. All 100 tokens went to reasoning. If you cap output, leave room for it. When you don't set max_tokens, DeepSeek's API defaults to 64K in thinking mode and 128K at max.

Keep reasoning_content in tool conversations

When the model calls a tool, its message carries reasoning_content alongside tool_calls. DeepSeek's API requires you to send it back, unchanged, in every later request of that conversation. In the OpenAI Python SDK, appending the returned message object does that:

messages.append(completion.choices[0].message)

Libraries differ here. The OpenAI SDKs, LiteLLM with the openai/ prefix, and the Vercel AI SDK keep reasoning_content when you send the returned message back. LangChain's ChatOpenAI and ChatDeepSeek and LlamaIndex's OpenAILike leave it out of the next request. On cheapaimodel, leaving it out didn't cause an error in our test, but on an endpoint that enforces DeepSeek's rule, the request fails with a 400.

In conversations without tools, you don't need to send it back. DeepSeek ignores it.

Temperature doesn't steer reasoning

In thinking mode, temperature has no effect, and a top_p below 0.95 is treated as 0.95. To make answers faster or more careful, change the effort level instead.

Checking it on cheapaimodel

Open Logs in the console and click a request. If you sent reasoning_effort, the details show it under Reasoning effort. If the row isn't there, the request ran at the default, high.

Prices and context limits are on the DeepSeek V4.1 Flash model page. To get a key and make your first call, see the Quickstart. DeepSeek's own reference is its thinking mode guide.

All posts