ModelSiteAPI

DeepSeek Models

Scenario-based examples for deepseek-v4.1-flash / deepseek-v4-flash-0731 / deepseek-v4-pro: chat, thinking, tool calls, JSON output, prefix completion, caching, image input

DeepSeek models are called through /v1/chat/completions or /v1/messages. The platform passes the request body through: vendor-specific parameters are forwarded unchanged and the upstream model decides whether they take effect. This page is organised by scenario, following the scenarios in DeepSeek's official documentation (thinking mode, tool calls, JSON output, chat prefix completion, FIM completion, context caching, multi-round chat). What is supported is decided by the upstream we actually connect to, not by the official site.

Every scenario carries an evidence label:

  • Tested (live test account, 2026-10-19): called for real on production; responses come from real output (id and timestamps replaced with placeholders).
  • Per official docs (not tested): checked against the official documentation only, no real request.

Supported models

Model idDescriptionContext windowMax outputCapability tags
deepseek-v4.1-flashV4.1 Flash, thinking / non-thinking1,000,000384,000chat, streaming, tools, thinking, cache
deepseek-v4-flash-0731V4 Flash (0731 build)1,000,000384,000chat, streaming, tools, thinking, cache
deepseek-v4-proV4 Pro, stronger reasoning1,000,000384,000chat, streaming, tools, thinking, cache
  • DeepSeek's own API names the models deepseek-flash and deepseek-v4-pro; on ModelSite use the model ids in the table.
  • Capability tags are whatever GET /v1/models returns. None of the three has the vision tag; see Image input.

The platform never turns thinking on for you. It does not inject thinking, reasoning_effort, a thinking budget or temperature by default. If you omit them the upstream default applies (officially thinking is on and reasoning_effort defaults to high). Pass thinking explicitly on every request when you need deterministic behaviour.

Scenario overview

ScenarioOfficial docs cover itOur statusExample
Basic and multi-round chatYesSupportedBasic chat
StreamingYesSupportedStreaming
Thinking mode (switch, effort, reading the reasoning)YesSupportedThinking mode
Tool calls (non-thinking)YesSupportedTool calls
Tool calls in thinking modeYesPartly supported: tested on deepseek-v4.1-flash, not on the other twoThinking + tool calls
JSON outputYesSupportedJSON output
Chat prefix completion (Beta)YesPartly supported: tested on deepseek-v4-pro, no Beta endpoint needed; other two models not testedPrefix completion
Context cachingYesSupported (automatic, no parameter)Context caching
Image inputThe official pricing page lists Flash as supporting itPartly supported: deepseek-v4.1-flash read an image in testing, but the platform does not list it as a vision model and makes no promiseImage input
Anthropic-format callsYes (official Anthropic compatibility page)SupportedAnthropic format
FIM completion (Beta, /completions)YesNot integrated: the platform has no /v1/completions endpointNone
Strict-mode tool calls (strict, Beta)YesNot integrated: the official feature depends on a Beta endpoint that the platform does not offer; we have not verified whether the upstream recognises strictNone

Basic chat

Evidence: tested (live test account, 2026-10-19), deepseek-v4-flash-0731.

When to use: a single question, or multi-round chat by sending the history along. The API is stateless, so append each assistant reply to messages before the next round.

Request

from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

messages = [{"role": "user", "content": "Which is the highest mountain in the world? Answer in one short sentence."}]
resp = client.chat.completions.create(
    model="deepseek-v4-flash-0731",
    messages=messages,
    max_tokens=200,
    extra_body={"thinking": {"type": "disabled"}},
)
print(resp.choices[0].message.content)

# Multi-turn: append the reply to history, then ask the next question
messages.append({"role": "assistant", "content": resp.choices[0].message.content})
messages.append({"role": "user", "content": "And the second highest?"})
resp = client.chat.completions.create(
    model="deepseek-v4-flash-0731",
    messages=messages,
    max_tokens=200,
    extra_body={"thinking": {"type": "disabled"}},
)

Response

{
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Mount Everest, at 8,848.86 meters (29,031.7 feet) above sea level, is the highest mountain in the world.",
        "refusal": null
      },
      "finish_reason": "stop"
    }
  ],
  "created": 1760000000,
  "id": "chatcmpl-xxxx",
  "model": "deepseek-v4-flash-0731",
  "object": "chat.completion",
  "system_fingerprint": "fp_xxxx",
  "usage": {
    "prompt_tokens": 19,
    "completion_tokens": 32,
    "total_tokens": 51,
    "prompt_tokens_details": {
      "cached_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  }
}

Notes

  • When max_tokens is omitted the default and the counting rule come from the upstream and differ by model: for deepseek-v4.1-flash the upstream default is 128K, thinking is counted, and overflow is truncated without an error; the other two are unverified. The official API defaults to 8K non-thinking, 64K thinking, and errors on overflow. Always pass max_tokens explicitly, and leave room for thinking on thinking models.
  • A longer history means more input tokens; repeated prefixes hit the cache automatically, see Context caching.

Streaming

Evidence: tested (live test account, 2026-10-19), deepseek-v4-pro.

When to use: show output as it is generated. Pass stream: true and read SSE chunks; reasoning arrives in delta.reasoning_content, the answer in delta.content; accumulate them separately.

Request

from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

stream = client.chat.completions.create(
    model="deepseek-v4-pro",
    messages=[{"role": "user", "content": "数到五,用逗号分隔。"}],
    max_tokens=100,
    stream=True,
    extra_body={"thinking": {"type": "disabled"}},
)
reasoning, content = "", ""
for chunk in stream:
    if not chunk.choices:
        continue
    d = chunk.choices[0].delta
    if getattr(d, "reasoning_content", None):
        reasoning += d.reasoning_content
    elif d.content:
        content += d.content
print(content)

Response (middle chunks elided with ...)

data: {"choices":[{"index":0,"delta":{"role":"assistant","content":"1"}}],"created":1760000000,"id":"chatcmpl-xxxx","model":"deepseek-v4-pro","object":"chat.completion.chunk","service_tier":"default"}

data: {"choices":[{"index":0,"delta":{"role":"assistant","content":","}}],"created":1760000000,"id":"chatcmpl-xxxx","model":"deepseek-v4-pro","object":"chat.completion.chunk","service_tier":"default"}

...

data: {"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop"}],"created":1760000000,"id":"chatcmpl-xxxx","model":"deepseek-v4-pro","object":"chat.completion.chunk","service_tier":"default","usage":{"prompt_tokens":13,"completion_tokens":13,"total_tokens":26,"prompt_tokens_details":{"cached_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}}}

data: {"choices":[],"created":1760000000,"id":"chatcmpl-xxxx","model":"deepseek-v4-pro","object":"chat.completion.chunk","service_tier":"default","usage":{"prompt_tokens":13,"completion_tokens":13,"total_tokens":26,"prompt_tokens_details":{"cached_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}}}

data: [DONE]

Notes

  • If stream_options is not set the gateway adds include_usage itself and usage appears at the end of the stream; both the last chunk that has choices and the following chunk with empty choices carry usage, so check whether choices is empty before reading it.
  • Reasoning and answer are separate fields in the stream; do not concatenate reasoning_content into the answer.

Thinking mode

Evidence: tested (live test account, 2026-10-19), deepseek-v4.1-flash (OpenAI format).

When to use: maths, reasoning and complex coding that benefit from step-by-step thought. For simple Q&A, translation and tool loops, turn thinking off: faster and cheaper.

All three models have a thinking and a non-thinking mode: thinking switches it, reasoning_effort sets the depth. thinking is not an OpenAI standard field, so the Python SDK takes it in extra_body; reasoning_effort is standard and is passed directly.

Request

from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

# Enable thinking explicitly and set the effort
resp = client.chat.completions.create(
    model="deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "9.11 和 9.9 哪个大?一句话回答。"}],
    max_tokens=1500,
    reasoning_effort="low",
    extra_body={"thinking": {"type": "enabled"}},
)
msg = resp.choices[0].message
print(getattr(msg, "reasoning_content", None))  # the reasoning
print(msg.content)                              # the final answer

# Disable thinking
resp = client.chat.completions.create(
    model="deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "用一句话解释量子纠缠"}],
    extra_body={"thinking": {"type": "disabled"}},
)

Response: the reasoning is in message.reasoning_content, the answer in message.content; the number of thinking tokens is usage.completion_tokens_details.reasoning_tokens and is included in completion_tokens.

{
  "id": "xxxxxxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "deepseek-v4.1-flash",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "按数值比较,9.9 比 9.11 大。",
        "refusal": null,
        "reasoning_content": "我们需要回答中文问题:“9.11 和 9.9 哪个大?一句话回答。” 需要注意可能是版本号? 一般数字比较:9.11 < 9.9? 因为 9.11 = 9.11,9.9=9.90,所以 9.9 大。但如果像软件版本号,9.11 > 9.9 因为 minor 11 > 9。问题没指定。通常数学数字比较:9.9 大。一句话回答。需要简洁。问“9.11 和 9.9 哪个大?” 应该回答“按数值比较,9.9 比 9.11 大。” 一句话。注意如果版本号则 9.11 更大,但通常直接问哪个大,按十进制。可以加“按数值”。一句话。最终。"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 46,
    "completion_tokens": 200,
    "total_tokens": 246,
    "prompt_tokens_details": {
      "cached_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 183,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "service_tier": "default"
}

Notes

  • Use only low, high and max for reasoning_effort; the default is high. Other values (none, minimal, medium, xhigh, ultra) map differently across models, do not depend on them: the upstream docs for deepseek-v4.1-flash say none disables thinking, minimal maps to low, medium and xhigh map to high, ultra maps to max; for deepseek-v4-pro they say none and minimal disable thinking, medium maps to low, xhigh maps to high; deepseek-v4-flash-0731 is unverified. To turn thinking off use thinking: {"type": "disabled"}.
  • Sampling: temperature has no effect in thinking mode (no error); on deepseek-v4.1-flash top_p below 0.95 is raised to 0.95 in thinking mode and fixed at 1.0 otherwise; do not send frequency_penalty or presence_penalty. top_k is ignored upstream. The platform does not range-check, so out-of-range values go to the upstream unchanged.
  • thinking accepts only enabled / disabled; adaptive (a Claude-only value) is not forwarded.
  • reasoning_content in history: in multi-round chat without tools the upstream ignores it; for the case with tools see Thinking + tool calls.

Tool calls

Evidence: tested (live test account, 2026-10-19), deepseek-v4-pro, thinking off.

When to use: let the model decide to call functions you define. The model does not run functions: it returns tool_calls, your code runs them, puts each result back as a role: "tool" message (with the matching tool_call_id) and you call the model once more for the final answer.

First request

from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get weather of a location, the user should supply a location first.",
        "parameters": {
            "type": "object",
            "properties": {"location": {"type": "string", "description": "The city and state, e.g. San Francisco, CA"}},
            "required": ["location"],
        },
    },
}]
messages = [{"role": "user", "content": "How is the weather in Hangzhou?"}]
resp = client.chat.completions.create(
    model="deepseek-v4-pro", messages=messages, tools=tools, max_tokens=300,
    extra_body={"thinking": {"type": "disabled"}},
)
msg = resp.choices[0].message
messages.append(msg)  # put the assistant message with tool_calls back into history

First response: finish_reason is tool_calls; function.arguments is a JSON string that you must parse yourself.

{
  "id": "xxxxxxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "deepseek-v4-pro",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "I'll check the current weather in Hangzhou for you.\n\n",
        "refusal": null,
        "tool_calls": [
          {
            "id": "call_xxxx",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"location\": \"Hangzhou, China\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 306,
    "completion_tokens": 59,
    "total_tokens": 365,
    "prompt_tokens_details": {
      "cached_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "service_tier": "default"
}

Second round: run the function, put the result into the history and request again (keep sending tools).

for call in msg.tool_calls:
    result = "24℃, cloudy"  # the real result of your function
    messages.append({"role": "tool", "tool_call_id": call.id, "content": result})

resp = client.chat.completions.create(
    model="deepseek-v4-pro", messages=messages, tools=tools, max_tokens=300,
    extra_body={"thinking": {"type": "disabled"}},
)
print(resp.choices[0].message.content)

Second response

{
  "id": "xxxxxxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "deepseek-v4-pro",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "The weather in Hangzhou is currently **24℃ and cloudy**.",
        "refusal": null
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 381,
    "completion_tokens": 13,
    "total_tokens": 394,
    "prompt_tokens_details": {
      "cached_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "service_tier": "default"
}

Notes

  • tool_choice accepts none, auto, required or a named function. Whether a forced call works in thinking mode depends on the model (next section); when you must force a tool, turning thinking off is the safest option.
  • Only function tools are supported.
  • The Chat Completions format cannot insert tool-call messages in the middle of a conversation (official note; use the Anthropic format for that).
  • Anthropic-format tool_choice: auto maps to auto, any to required, tool to a named function; none maps to none; disable_parallel_tool_use: true maps to parallel_tool_calls: false.

Thinking + tool calls

Evidence: tested (live test account, 2026-10-19) on deepseek-v4.1-flash only; deepseek-v4-pro and deepseek-v4-flash-0731 per official docs (not tested).

When to use: agent flows that should reason before deciding which function to call. Enable thinking, pass tools, and loop until the response has no more tool_calls.

Request (first round)

resp = client.chat.completions.create(
    model="deepseek-v4.1-flash",
    messages=messages,            # same as above: the user asks about Hangzhou weather
    tools=tools,
    max_tokens=1500,
    reasoning_effort="low",
    extra_body={"thinking": {"type": "enabled"}},
)
msg = resp.choices[0].message     # contains reasoning_content and tool_calls
messages.append(msg)              # put the whole assistant message (with reasoning_content) back

First response: both reasoning_content and tool_calls are present.

{
  "id": "xxxxxxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "deepseek-v4.1-flash",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "",
        "refusal": null,
        "tool_calls": [
          {
            "id": "call_xxxx",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"location\": \"Hangzhou\"}"
            }
          }
        ],
        "reasoning_content": "The user wants to know the weather in Hangzhou. Let me call the get_weather function."
      },
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 321,
    "completion_tokens": 61,
    "total_tokens": 382,
    "prompt_tokens_details": {
      "cached_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 20,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "service_tier": "default"
}

Second response: put the whole assistant message above (with reasoning_content) and the role: "tool" result back into the history and request again.

{
  "id": "xxxxxxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "deepseek-v4.1-flash",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "The weather in Hangzhou is currently **24℃ and cloudy** — mild and comfortable, with no precipitation expected. It's a good day to be outside, though you might want a light layer if it gets breezy.",
        "refusal": null,
        "reasoning_content": "The tool returned 24℃, cloudy. Let me report that."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 378,
    "completion_tokens": 60,
    "total_tokens": 438,
    "prompt_tokens_details": {
      "cached_tokens": 256
    },
    "completion_tokens_details": {
      "reasoning_tokens": 14,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "service_tier": "default"
}

Notes

  • Passing back reasoning_content: DeepSeek officially requires the history's assistant reasoning_content to be passed back in full whenever tools is present, and returns 400 otherwise. The deepseek-v4.1-flash upstream we connect to did not error when we left it out in testing (the second round returned normally without it). That is lenient upstream behaviour, not a promise: always pass it back. The platform forwards reasoning_content in history unchanged, and in the Anthropic format a thinking content block in history is converted to reasoning_content.
  • Forced tool calls: the official API returns 400 for tool_choice: "required" and named functions in thinking mode; the upstream docs for deepseek-v4.1-flash say required is supported in thinking mode; the other two models are unverified.
  • In this scenario the second response shows usage.prompt_tokens_details.cached_tokens of 256: the prefix hit the automatic cache.

JSON output

Evidence: tested (live test account, 2026-10-19), deepseek-v4.1-flash, thinking off.

When to use: stable, directly parseable JSON, for example information extraction. Set response_format: {"type": "json_object"}; the prompt must contain the word "json" and an example of the expected format.

Request

import json
from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

system_prompt = """Parse the question and answer from the exam text and output them as JSON.
Example input: "Which is the highest mountain? Mount Everest."
Example JSON: {"question": "Which is the highest mountain?", "answer": "Mount Everest"}"""

resp = client.chat.completions.create(
    model="deepseek-v4.1-flash",
    messages=[
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": "Which is the longest river in the world? The Nile River."},
    ],
    response_format={"type": "json_object"},
    max_tokens=512,
    extra_body={"thinking": {"type": "disabled"}},
)
print(json.loads(resp.choices[0].message.content))

Response

{
  "id": "xxxxxxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "deepseek-v4.1-flash",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "{\"question\": \"Which is the longest river in the world?\", \"answer\": \"The Nile River\"}",
        "refusal": null
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 89,
    "completion_tokens": 21,
    "total_tokens": 110,
    "prompt_tokens_details": {
      "cached_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "service_tier": "default"
}

Notes

  • Set max_tokens high enough, otherwise the JSON may be cut off; the official docs warn that empty content is occasionally returned, so handle an empty result in code.
  • Use json_object only. json_schema is marked Beta in the upstream docs and per-model support is unverified.

Prefix completion

Evidence: tested (live test account, 2026-10-19) on deepseek-v4-pro only; deepseek-v4.1-flash and deepseek-v4-flash-0731 per official docs (not tested).

When to use: make the model continue from a beginning you supply, for example forcing a code block to start the output. Officially this is a Beta feature that needs the https://api.deepseek.com/beta endpoint; on ModelSite you do not change the endpoint, use the same /v1/chat/completions: the last message has role assistant and "prefix": true, and content is the beginning to continue.

Request

from openai import OpenAI

client = OpenAI(base_url="https://api.modelsite.ai/v1", api_key="sk-ms-xxxxxxxx")

resp = client.chat.completions.create(
    model="deepseek-v4-pro",
    messages=[
        {"role": "user", "content": "Please write quick sort code"},
        {"role": "assistant", "content": "```python\n", "prefix": True},
    ],
    stop=["```"],
    max_tokens=400,
    extra_body={"thinking": {"type": "disabled"}},
)
print(resp.choices[0].message.content)

Response (content truncated; max_tokens ran out this time so finish_reason is length)

{
  "id": "xxxxxxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "deepseek-v4-pro",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "def quick_sort(arr):\n    \"\"\"\n    Quick sort implementation using Lomuto partition scheme.\n    \n    Args:\n        arr: List of comparable elements\n    \n    Retur…",
        "refusal": null
      },
      "finish_reason": "length"
    }
  ],
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 400,
    "total_tokens": 412,
    "prompt_tokens_details": {
      "cached_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "service_tier": "default"
}

Notes

  • How we know the prefix was used: asked the same question without a prefix, the model opens with explanatory prose ("Here's a clean implementation..."); with the prefix it starts directly with code, and the input token count grows by the prefix. The response contains only the continuation, not the prefix you sent.
  • The last message must be an assistant message with prefix: true. stop is optional and cuts the output at a delimiter.
  • This is a DeepSeek Beta capability and may change; it has been tested on deepseek-v4-pro only.

Context caching

Evidence: tested (live test account, 2026-10-19), deepseek-v4.1-flash.

When to use: multi-round chat, or repeated questions over the same long document. Caching is automatic, has no request parameter, is best-effort rather than guaranteed, and only the input prefix is cached. Put stable content (system prompt, document) first and changing content last so that it can hit.

How to see a hit: usage.prompt_tokens_details.cached_tokens. For example in the second response of "Thinking + tool calls" above, prompt_tokens is 378 and cached_tokens is 256.

Notes

  • The upstream docs for deepseek-v4.1-flash give a 256-token minimum for implicit caching, and building a cache takes a few seconds.
  • DeepSeek's official API also returns prompt_cache_hit_tokens / prompt_cache_miss_tokens; these two fields did not appear in the real responses, so rely on cached_tokens.
  • A cache_control marker on content blocks has no effect on DeepSeek; the platform strips it before forwarding, so do not use it.

Image input

Evidence: tested (live test account, 2026-10-19) on deepseek-v4.1-flash only; the other two models were not tested.

None of the three models has the vision capability tag, so the platform has not opened DeepSeek as a vision model, and this scenario can only be "partly supported":

  • deepseek-v4.1-flash: tested with a solid red 64x64 PNG; the model answered the colour correctly and returned normally with no error. This is upstream behaviour, not a platform commitment, and image-input billing has not been checked separately, so do not use it in production.
  • deepseek-v4-pro: officially no image support; not tested.
  • deepseek-v4-flash-0731: the model catalog marks vision as unsupported; not tested.

For stable image understanding choose a model whose capability tags include vision (see the Qwen page).

Anthropic format

Evidence: tested (live test account, 2026-10-19), deepseek-v4-pro.

When to use: your client is the Anthropic SDK or something like Claude Code that only speaks /v1/messages. See the Messages page for usage and authentication (the SDK needs auth_token, not api_key).

Request

from anthropic import Anthropic

client = Anthropic(base_url="https://api.modelsite.ai", auth_token="sk-ms-xxxxxxxx")

resp = client.messages.create(
    model="deepseek-v4-pro",
    max_tokens=1500,
    thinking={"type": "enabled", "budget_tokens": 1024},
    messages=[{"role": "user", "content": "9.11 和 9.9 哪个大?一句话回答。"}],
)
for block in resp.content:
    if block.type == "thinking":
        print("thinking:", block.thinking)
    elif block.type == "text":
        print("answer:", block.text)

Response

{
  "id": "msg_xxxx",
  "type": "message",
  "role": "assistant",
  "content": [
    {
      "type": "thinking",
      "thinking": "我们需要回答用户中文问题“9.11 和 9.9 哪个大?一句话回答。”需要一句话。注意陷阱?9.11和9.9作为数字比较,9.9大。但要注意可能是日期?但通常数字。用户要求一句话回答。我们可以说“9.9更大。”需要一句话。确保不要解释太多。用中文。"
    },
    {
      "type": "text",
      "text": "9.9 更大。"
    }
  ],
  "model": "deepseek-v4-pro",
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 20,
    "output_tokens": 84,
    "reasoning_tokens": 77
  }
}

Notes

  • budget_tokens is not a hard budget: the official Anthropic compatibility doc says it is ignored. To control depth add the top-level field reasoning_effort to the body (extra_body in the Python SDK); the platform forwards it unchanged. Disable thinking with thinking: {"type": "disabled"}.
  • The reasoning comes back as a thinking content block; usage.reasoning_tokens is the number of thinking tokens.
  • top_k is forwarded and ignored upstream; stop_sequences maps to stop; metadata.user_id maps to user.

Parameter quick reference

ParameterNotes
thinkingenabled / disabled; auto is forwarded but DeepSeek only recognises the first two; adaptive is not forwarded
reasoning_effortUse only low / high / max
max_tokens / max_completion_tokensNot rewritten and no default injected; when both are sent only max_completion_tokens is forwarded
temperature, top_pMostly ineffective in thinking mode, see Thinking mode
frequency_penalty, presence_penaltyDo not send (the deepseek-v4.1-flash upstream says unsupported)
stopUp to 16 strings (upstream docs for deepseek-v4.1-flash; the others per official docs, unverified)
logprobs, top_logprobsUpstream docs say supported, top_logprobs up to 20; not tested
stream_options.include_usageAdded by the gateway when a streaming request omits it
response_formattext / json_object; json_schema unverified
n (above 1), service_tier, store, metadata, user_id, etc.Forwarded unchanged; whether the upstream recognises them is unverified
Unknown top-level fields, keys in extra_bodyForwarded flat, unchanged
developer roleConverted to system

Also: the reasoning object (OpenRouter style, reasoning.effort, reasoning.exclude, ...) is handled by the platform itself; reasoning.exclude: true or include_reasoning: false removes the reasoning from the response, thinking tokens are still billed.

Official docs

On this page