> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apiyi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Why does a reasoning model return empty content?

> Getting empty_response, or HTTP 200 with empty text? Usually max_tokens is consumed by thinking. Three checks and three fixes.

## Short answer

This is not an API failure — it is the **thinking budget eating the output budget**.

Reasoning models such as `gpt-6.1-sol` first generate a reasoning trace, then write the answer. Both parts **share** the `max_tokens` allowance. When the budget runs out during thinking, the answer is cut off before it starts, so you receive an empty result.

Raise `max_tokens` (1000 or more is a safe start), or lower the reasoning effort, and the problem disappears.

## What you will see

There are two common forms.

**One is an explicit error**, with HTTP status 429 or 500 (the `message` field may be localized, so a Chinese message is expected on some responses):

```json theme={null}
{
  "error": {
    "message": "上游返回了空响应。",
    "type": "shell_api_error",
    "code": "empty_response"
  }
}
```

**The other is HTTP 200 with empty content**:

```json theme={null}
{
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "" },
      "finish_reason": "length"
    }
  ],
  "usage": {
    "prompt_tokens": 1500,
    "completion_tokens": 300,
    "completion_tokens_details": { "reasoning_tokens": 300, "text_tokens": 0 }
  }
}
```

Look at the usage block: `completion_tokens` is 300, `reasoning_tokens` is 300, `text_tokens` is 0 — **the model generated 300 tokens, spent all of them thinking, and never wrote a single word of output.**

> [!NOTE]
>
> The call log shows the request as successful and billed, which is not a contradiction: the model did produce content (the reasoning trace), just no visible text.

## Why this happens

A reasoning model's output has two stages:

| Stage | Content | Returned to you |
| - | - | - |
| Thinking | reasoning tokens, internal deliberation | Some models expose it as `reasoning_content`; usually invisible |
| Answer | text tokens, the visible output | Yes |

`max_tokens` (or `max_completion_tokens`, `max_output_tokens`) limits **both stages combined**, not the length of the visible answer.

So if `max_tokens` is set to something small like 200–500 while the task needs substantial reasoning, the budget is exhausted during thinking. `finish_reason` becomes `length` and the content is empty.

## Three checks

**1. Step 1: read finish\_reason**

If it is `length`, the output was truncated — the model did not refuse to answer. If it is `stop` but the content is still empty, continue to steps 2 and 3.

**2. Step 2: read reasoning\_tokens in usage**

Find `usage.completion_tokens_details.reasoning_tokens` and compare it with `completion_tokens`. If the two are close or equal, most of the budget went into thinking.

**3. Step 3: read max\_tokens in your request**

If you explicitly set `max_tokens` to a small value (300, for example), that is almost certainly the cause. If you did not set it, check whether your SDK or framework filled in a small default.

This script prints all three signals at once:

```python theme={null}
import json
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.apiyi.com/v1")

resp = client.chat.completions.create(
    model="gpt-6.1-sol",
    messages=[{"role": "user", "content": "your question"}],
    max_tokens=2000,
)

choice = resp.choices[0]
usage = resp.usage
print("finish_reason:", choice.finish_reason)
print("content:", repr(choice.message.content)[:100])
print("completion_tokens:", usage.completion_tokens)
print("reasoning_tokens:", getattr(usage.completion_tokens_details, "reasoning_tokens", None))
```

## How to fix it

> [card] Raise max\_tokens
>
> The direct fix. Use 1000–2000 for ordinary chat and 4000 or more for heavy reasoning or long-form output. Reasoning overhead can be much larger than you expect.

> [card] Lower reasoning effort
>
> If the model supports `reasoning_effort`, drop it from `high` to `medium` or `low`. Thinking consumption falls noticeably.

> [card] Switch to streaming
>
> Set `stream` to `true`. The reasoning trace arrives as separate events, so you can see what the model is doing and the answer never silently disappears.

### Parameter reference by model family

| Model family | Output budget parameter | Reasoning effort parameter |
| - | - | - |
| OpenAI reasoning models (o series, GPT-5/6 series) | `max_completion_tokens` (Chat), `max_output_tokens` (Responses) | `reasoning_effort` |
| Claude thinking mode | `max_tokens` | `thinking.budget_tokens` |
| Gemini thinking mode | `maxOutputTokens` | `thinkingConfig.thinkingBudget` |

> [!WARNING]
>
> Some reasoning models reject `max_tokens` and require `max_completion_tokens`. A wrong parameter name may raise an error, or may be silently ignored so the model falls back to a default that does not match your intent.

## FAQ

> [accordion] Why does the log show success while I received an error?
>
> The log records that the upstream finished generating and settled billing. It does not check whether the visible text is empty. Generation succeeding and the answer being non-empty are two different things.

> [accordion] Will simply retrying help?
>
> Usually not. With the same prompt and the same `max_tokens`, the model will most likely spend the budget on thinking again. Changing the parameters is far more effective than retrying.

> [accordion] Am I billed for an empty response?
>
> Yes. Reasoning tokens are real consumption and are billed as output tokens. Check [call logs](https://docs.apiyi.com/en/faq/log-billing-explained.md) for the exact amount.

> [accordion] Does every model behave this way?
>
> No. Only reasoning models with a thinking stage have this problem. Ordinary non-reasoning models such as `gpt-4o` or `deepseek-chat` spend the whole `max_tokens` on visible output.

> [accordion] Does a large max\_tokens cost more?
>
> No. `max_tokens` is a ceiling, not actual consumption. The model stops when it finishes, and you pay for the tokens actually generated.

## Related

> [card] [What is max\_tokens?](https://docs.apiyi.com/en/faq/max-tokens.md)
>
> Parameter meaning, naming history, and per-model defaults

> [card] [Streaming vs non-streaming](https://docs.apiyi.com/en/faq/streaming-vs-non-streaming.md)
>
> Prefer streaming for long responses and reasoning models

> [card] [How to troubleshoot model errors](https://docs.apiyi.com/en/faq/model-error-troubleshooting.md)
>
> General triage for 400, 401, 429, and 503

> [card] [How to read billing in logs](https://docs.apiyi.com/en/faq/log-billing-explained.md)
>
> Confirm whether a request was billed, and how much


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.