0xBakeer

API

From docs/api.mdRepository last pushed 3 September 2026

ArchivedThis recipe stays as published and gets no more updates. The numbers below carry the date and build they were measured on.

Pages in this section

The server speaks the OpenAI chat-completions protocol on http://127.0.0.1:8000/v1. Any OpenAI-compatible client works; point it at that base URL with any (or no) API key.

Endpoints

Path What
GET /health {"status": "healthy"} once the model is loaded — ./run.sh serve waits on it
GET /v1/models lists deepseek-v4-flash-0731
POST /v1/chat/completions chat, streaming or not, tools, reasoning
POST /v1/completions raw completions (you supply the formatted prompt)
GET /v1/model the loaded model's parameters (context length, draft, etc.)

Plain chat

curl -s http://127.0.0.1:8000/v1/chat/completions \
  -H 'content-type: application/json' \
  -d '{
    "model": "deepseek-v4-flash-0731",
    "messages": [{"role": "user", "content": "Explain unified memory in three sentences."}]
  }' | jq -r '.choices[0].message.content'

No sampling parameters sent → DeepSeek's recommended temperature 1.0 / top_p 1.0.

Streaming

curl -sN http://127.0.0.1:8000/v1/chat/completions \
  -H 'content-type: application/json' \
  -d '{
    "model": "deepseek-v4-flash-0731",
    "stream": true,
    "stream_options": {"include_usage": true},
    "messages": [{"role": "user", "content": "Write a limerick about a lighthouse."}]
  }'

Chunks arrive one per draft step — around six tokens every ~150 ms — so text appears in small even bursts rather than one token at a time. The final chunk carries usage with prompt_tokens, completion_tokens, and the server's own completion_tokens_per_sec.

Sampling

"temperature": 0

Send your own temperature / top_p when you want them; unset means DeepSeek's 1.0 / 1.0. Speed does not hinge on this: code and structured output stream at 50–57 tok/s and free prose at ~30 tok/s whichever temperature you pick, because the speculative draft is accepted on predictable text and rejected on open-ended text. Use 0 where you would use greedy anyway (extraction, classification, strict formats) and the default for long open-ended writing, where greedy decoding can loop on this model.

Thinking

curl -s http://127.0.0.1:8000/v1/chat/completions \
  -H 'content-type: application/json' \
  -d '{
    "model": "deepseek-v4-flash-0731",
    "messages": [{"role": "user", "content": "Is 2^61 - 1 prime? Reason carefully."}],
    "chat_template_kwargs": {"thinking": true, "reasoning_effort": "high"}
  }' | jq '{reasoning: .choices[0].message.reasoning_content, answer: .choices[0].message.content}'

reasoning_effort: low (default when thinking is on), high, max. Streaming responses carry reasoning as delta.reasoning_content before the first delta.content. Budget for it: a high answer to a hard question is routinely several thousand reasoning tokens.

Clients that only know the OpenAI-style fields work too. Any of these turn thinking on, without chat_template_kwargs:

"reasoning_effort": "high"
"enable_thinking": true
"reasoning": {"effort": "high"}

reasoning_effort at the top level: none and low keep thinking off, medium turns it on with no effort text, high and max add DeepSeek's effort text; xhigh is accepted as max. An explicit chat_template_kwargs.thinking always wins over the derived value.

Tool calling

Standard OpenAI tools / tool_choice. The server parses the model's DSML block into tool_calls:

curl -s http://127.0.0.1:8000/v1/chat/completions \
  -H 'content-type: application/json' \
  -d '{
    "model": "deepseek-v4-flash-0731",
    "messages": [{"role": "user", "content": "What is the weather in Lisbon right now?"}],
    "tools": [{"type": "function", "function": {
      "name": "get_weather",
      "description": "Current weather for a city",
      "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
    }}]
  }' | jq '.choices[0] | {finish_reason, tool_calls: .message.tool_calls}'
{
  "finish_reason": "tool_calls",
  "tool_calls": [{"id": "…", "type": "function",
                  "function": {"name": "get_weather", "arguments": "{\"city\": \"Lisbon\"}"}}]
}

Send the result back as a {"role": "tool", "tool_call_id": …, "content": …} message and continue. In streaming mode the call arrives as delta.tool_calls. DeepSeek suggests top_p: 0.95 for agentic use. Note that with tools in the prompt the model is eager to use them — a note-taking tool offered alongside "write me a story" will get called — so attach tools to the requests that need them, not to every request.

Python

from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8000/v1", api_key="none")

r = client.chat.completions.create(
    model="deepseek-v4-flash-0731",
    messages=[{"role": "user", "content": "Summarise the attached RFC in five bullets.\n\n" + rfc_text}],
    temperature=0,
    extra_body={"chat_template_kwargs": {"thinking": True}},
)
print(r.choices[0].message.reasoning_content)
print(r.choices[0].message.content)

Long prompts

Up to 393,216 tokens per request. Prefill runs at roughly 550–800 tok/s, so a 100k-token prompt takes about two minutes before the first token and a 300k-token prompt about six. Set your client's timeout accordingly, and send long conversations in the same order each turn so the prefix cache serves the unchanged prefix.

Concurrency

max_batch_size: 1: one request generates at a time; the rest wait in a queue and are served in order. A client that sees a slow time-to-first-token while another request is running is seeing the queue, not the model — see configuration.md for max_batch_size: 2.