You set temperature: 0 and the output is still different every time. There is no error, no warning field, and no indication in the response that the parameter was discarded. It was.
The symptom
The report is always the same. A pipeline that relies on temperature: 0 for stable output works against deepseek-chat and stops working the moment the model name is changed to deepseek-reasoner. Output varies between identical calls. Setting top_p instead changes nothing. Setting both changes nothing. The requests all return 200.
Before going further, rule out the thing that is not this: if you are running the open weights locally rather than calling the API, your temperature is being honoured by your own server and the variation has a different cause. This page is about the hosted reasoning path.
What DeepSeek documents
DeepSeek’s reasoning-model guide lists the parameters the reasoning path does not support, and splits them into two groups with different behaviour — which is the detail that resolves the confusion.
Accepted, no effect (kept for client compatibility):
temperature
top_p
presence_penalty
frequency_penalty
Rejected with an error:
logprobs
top_logprobs
The stated reason for the first group is compatibility with existing software. An OpenAI-compatible client almost always sets a temperature; rejecting it would break every such client on the first request, so the server accepts the field and does not act on it. The second group returns an error because there is no sensible value to return, and silently omitting requested log probabilities would be worse than refusing.
The practical rule that falls out: on the reasoning path, a 200 does not mean your parameters were applied. That is not a statement about DeepSeek so much as about OpenAI-compatible APIs in general — the schema has no mechanism for reporting an ignored field — but this is the clearest documented instance of it.
Why the sampling is fixed
Reasoning quality depends on the sampling settings far more sharply than ordinary generation does, and the dependency is not monotonic: both ends of the range are bad. The R1 model card recommends a temperature range rather than a value, and warns that settings outside it produce repetition or incoherent output.
At temperature 0 a reasoning model becomes prone to loops. Having committed to an approach, the highest-probability continuation is frequently to restate or extend that approach, and with no randomness there is nothing to break the cycle — so the model can spend its entire output budget circling a step it cannot complete. At high temperature the trace becomes incoherent and the answer drifts from it. The useful band is narrow and the model was trained with it in mind.
Fixing the sampling server-side prevents a caller from configuring the model into either failure. The tradeoff is that determinism is not available at all on this path, and it would not be fully available even if temperature worked — batching and floating-point reduction order are independent sources of variation that no parameter reaches.
Two phases, one parameter
The question underneath most of the frustration here is narrower than it first appears: people are not really asking for a temperature control, they are asking for determinism, and it is worth being precise about why the parameter would not deliver it even if it worked.
A reasoning request has two phases and they are not separately addressable. The trace is generated first, then the answer is generated conditioned on the prompt and that trace. There is one temperature field in the request and two phases behind it, with no syntax for saying “explore while thinking, be greedy while answering” — which is what almost everybody actually wants. That is a limitation of the OpenAI-compatible schema this API implements rather than a decision DeepSeek made.
Now suppose the parameter did apply and you set it to 0. The trace becomes greedy, which is the configuration the model card warns against and the one most prone to looping. And the answer phase, whose input is a trace produced under those conditions, inherits whatever that trace became. You would have made the answer deterministic given the trace, and the trace is the part that varies — so the output as a whole would still change whenever anything upstream did. Determinism at the second phase is worth very little when the first phase is a search.
This is why the useful reframing is that the trace is not output you control. It is an intermediate computation the model performs, more like a query planner’s chosen plan than like text you wrote a template for. You control what goes in and you validate what comes out; the middle is the model’s business, and the parameters that would let you interfere with it are exactly the ones this endpoint does not honour.
One practical consequence worth stating: because the phases share a budget as well as a sampler, the only lever that reaches both is max_tokens. It is honoured, it bounds the trace and the answer together, and it is the single parameter on this path whose effect you can predict.
The open weights behave differently
Serve R1 yourself and every sampling parameter is yours: your inference server exposes them and applies them. Nothing suppresses temperature locally. That is a real difference between the hosted model and the weights of the same name, and it is worth knowing in both directions — a local deployment gives you the control, and it also gives you the ability to configure the model badly.
If you take that control, take DeepSeek’s own recommendations with it. The model card gives a suggested temperature range, a top_p value, the advice to avoid a system prompt, and the advice to force the response to begin with a thinking token because the model sometimes skips the pattern otherwise. Those are the settings the model was evaluated with, and the last one has direct consequences for parsing the trace.
Which parameters the hosted reasoning path accepts has changed across model versions, and a future release may honour settings that are ignored today. Verify against the reasoning-model guide rather than against this page if the answer matters to a design decision.
What you can still control
- Stop trying to make the trace stable. It is not a deliverable. Assert on
content, never onreasoning_content, and remove any snapshot test that captured one. - Use
max_tokens, which is honoured. It bounds the trace and the answer together, and it is the one lever on this path that reliably does something. Size it from a high percentile of observedreasoning_tokens. - Constrain the answer in the user turn. Format, length and language instructions still work — they just have to be placed where the model will act on them, which for a reasoning model is not the system message. That is its own problem with its own fix.
- Validate and retry rather than tightening parameters. If the answer must satisfy a checkable property, check it. One retry resolves most single-run variation, and a check is a stronger guarantee than any temperature ever was.
- Sample deliberately where correctness is worth it. Three runs and a majority vote turns the variation you cannot remove into an accuracy improvement, at three times the cost. Reserve it for decisions that justify the arithmetic.
- Route to the chat model when you need determinism.
temperature: 0is honoured on the non-reasoning name, and for a task that must be reproducible that is worth more than the reasoning is.
Top comments (0)