Lernpfad
Große Sprachmodelle werden immer meinungsstärker, was ihre Art zu denken angeht. Mit den drei expliziten Denkmodi von DeepSeek V4, Non-think, Think High und Think Max, kannst du die Tiefe des Denkens jetzt direkt auf API-Ebene steuern – und die richtige Wahl hängt vollkommen von der Aufgabe ab.
In diesem Tutorial zeige ich dir, wie du mit Streamlit eine DeepSeek V4 Think Mode Arena baust. Die App schickt denselben Prompt parallel an alle drei Denkmodi und präsentiert einen Side-by-Side-Vergleich der Antworten, Latenz, Token-Nutzung, Kosten und der Tiefe der Reasoning-Traces. Am Ende hast du ein funktionsfähiges Tool, das Folgendes kann:
-
Alle drei DeepSeek V4 Denkmodi gleichzeitig mit parallelen API-Calls ausführen
-
Einklappbare Denk-Traces aus
<think>...</think>-Blöcken parsen und anzeigen -
Latenz, Ausgabetokens, Durchsatz und geschätzte Kosten pro Modus tracken
-
Einen Gewinner-Überblick über vier Dimensionen zeigen: schnellste, günstigste, effizienteste und von Menschen am besten bewertete Antwort
Der vollständige Code zu diesem Tutorial ist in meinem GitHub-Repository verfügbar.
Was ist DeepSeek V4?
DeepSeek V4 ist die neueste Generation der Mixture-of-Experts (MoE) Sprachmodelle von DeepSeek AI. Die Serie umfasst zwei Varianten:
- DeepSeek-V4-Pro: 1,6 T Gesamtparameter (49 B aktiviert) und ein Kontextfenster von 1 Mio. Tokens.
- DeepSeek-V4-Flash: Die kleinere Modellvariante mit 284 B Gesamtparametern (13 B aktiviert), ebenfalls mit einem 1M-Token-Kontextfenster.
Mehrere architektonische Verbesserungen unterscheiden V4 von seinen Vorgängern:

Abbildung: Architektur der DeepSeek V4 Serie (DeepSeek Technical report)
- Hybride Attention-Architektur (CSA / HCA): Der rechte Pfad (in der obigen Abbildung) in jedem Block beginnt mit Compressed Sparse Attention (CSA) und Heavily Compressed Attention (HCA). Anstatt in jeder Schicht auf jedes Token zu achten, komprimieren diese Mechanismen die Attention-Berechnung selektiv. In einem 1M-Token-Kontext benötigt DeepSeek-V4-Pro dadurch nur 27 % der Single-Token-Inference-FLOPs und 10 % des KV-Caches im Vergleich zu DeepSeek-V3.2. Die Attention-Ausgabe wird durch Pre-Block- und Post-Block-Mixing geleitet, bevor sie über die Residual-Verbindung wieder zum Haupt-Hidden-State addiert wird.
- DeepSeekMoE: Nach der Attention fließt derselbe Pfad in die DeepSeekMoE-Schicht, in der die Mixture-of-Experts-Komponente pro Token nur einen Teil der Parameter aktiviert. Dadurch verhalten sich die 284 B Gesamtparameter von V4-Flash zur Inferenzzeit wie ein 13B-Modell und die 1,6 T von V4-Pro wie ein 49B-Modell.
- Manifold-Constrained Hyper-Connections (mHC): Der linke Pfad (in der Abbildung) zeigt gestapelte Hidden-State-Repräsentationen, die unten und oben in jedem Block durch Residual Mixing fließen. Das sind die mHC-Schichten, bei denen ein Ersatz für Standard-Residual-Verbindungen Updates auf einer gelernten Mannigfaltigkeit einschränkt und so die Stabilität des Gradientsignals über tiefe Stacks verbessert, ohne an Ausdrucksstärke zu verlieren.
- Muon Optimizer: Muon (nicht in der Architektur-Grafik sichtbar) ersetzt AdamW für die Mehrheit der Parameter mit einer an zweite Ordnung angelehnten Update-Regel, die bei den V4-Trainingsskalen schneller konvergiert und stabilere Loss-Kurven liefert.
Beide Modelle unterstützen drei unterschiedliche Aufwandsmodi für das Denken: Non-think, Think High und Think Max, die wir in diesem Tutorial erkunden und vergleichen.
DeepSeek V4 Benchmark-Ergebnisse
Das DeepSeek-Team hat die Leistung des V4-Modells mit seinen Gegenstücken verglichen. Das kam dabei heraus:
Abbildung: Benchmark-Leistung der DeepSeek V4 Serie (DeepSeek Technical report)
Das Balkendiagramm links zeigt, wo V4-Pro-Max im Vergleich zu führenden Closed-Source-Modellen bei Wissens-, Reasoning- und Agentenaufgaben landet. Die beiden Diagramme rechts zeigen, warum die Effizienzgewinne zählen – und sie sind die überraschenderen Ergebnisse. DeepSeek-V4-Pro-Max (der Think Max Denkmodus) erzielt wettbewerbsfähige Ergebnisse gegenüber führenden Closed-Source-Modellen:
|
Benchmark |
DeepSeek-V4-Pro Max |
Claude Opus 4.6 Max |
Gemini-3.1-Pro High |
|
LiveCodeBench (Pass@1) |
93,5 |
88,8 |
91,7 |
|
Codeforces Rating |
3206 |
— |
3052 |
|
GPQA Diamond (Pass@1) |
90,1 |
91,3 |
94,3 |
|
SWE Verified (Resolved) |
80,6 |
80,8 |
80,6 |
Das Codeforces-Rating von 3206 platziert V4-Pro-Max auf Legendary-Grandmaster-Niveau – die Programmieraufgaben in unserer Arena sind also ein wirklich anspruchsvoller Stresstest.
Die drei Denkmodi verstehen
Bevor wir die App bauen, lohnt es sich zu verstehen, was die Modi konkret tun:
Non-think: Das Modell antwortet direkt, also ohne interne Gedankenkette. Ideal, wenn Geschwindigkeit wichtiger ist als Tiefe – etwa für Formatkonvertierung, einfache Nachschlagen-Aufgaben und Ein-Satz-Zusammenfassungen.Think High: Das Modell denkt schrittweise nach, bevor es sich auf eine Antwort festlegt. Ein guter Kompromiss aus Tiefe und Kosten für mäßig komplexe Aufgaben wie Debugging, Systemdesign und Planung.Think Max: Das Modell treibt das Reasoning aufs Maximum, erkundet mehrere Ansätze, prüft die Logik gründlich und legt sich erst fest, wenn es sicher ist.Think Maxeignet sich daher am besten für harte mathematische Beweise, komplexe Refactorings über mehrere Dateien oder Aufgaben, bei denen eine falsche, aber selbstbewusste Antwort schlimmer ist als eine langsamere, verifizierte.
Die zentrale Erkenntnis dieses Tutorials: Think Max gewinnt nicht immer. Bei trivialen Aufgaben verschwendet es Rechenzeit bei gleicher Qualität. Ziel der Arena ist es, basierend auf realer Latenz, Token-Zahlen, Kosten und Nutzerbewertungen sichtbar zu machen, welcher Modus sich pro Aufgabentyp wirklich lohnt.
Wenn du wissen willst, wie sich das Modell gegenüber anderen State-of-the-Art-LLMs schlägt, lies unsere Artikel Claude Opus 4.7 vs DeepSeek V4 und GPT-5.5 vs DeepSeek V4.
Tutorial: Eine Think Mode Arena mit DeepSeek V4 bauen
In diesem Tutorial bauen wir eine Streamlit-Anwendung, die Folgendes kann:
-
Einen Prompt und eine Aufgabenkategorie vom Nutzer entgegennehmen
-
Drei parallele API-Calls auslösen, je einen pro Denkmodus, mithilfe von Pythons
ThreadPoolExecutor -
Denk-Traces aus
<think>...</think>-Blöcken in der Modellausgabe parsen -
Latenz, Token-Zahlen und geschätzte Kosten pro Modus erfassen
-
Einen Side-by-Side-Vergleich mit Metriken, Bewertungssystem und Gewinner-Überblick präsentieren
Die komplette App besteht aus einer einzigen app.py-Datei – ohne externe Datenbanken oder Hintergrunddienste.
Der vollständige Code zu diesem Tutorial ist in meinem GitHub-Repository verfügbar.
Schritt 1: Projekt-Setup und Abhängigkeiten
Erstelle zuerst einen Projektordner und installiere die zwei benötigten Pakete:
mkdir deepseek-arena && cd deepseek-arena
pip install streamlit>=1.32.0 openai>=1.12.0
Die Bibliothek openai wird hier verwendet, weil DeepSeeks API OpenAI-kompatibel ist. Das heißt, wir können den OpenAI-Client einfach auf DeepSeeks Basis-URL zeigen lassen – ohne weitere Änderungen. Ein DeepSeek-spezifisches SDK ist nicht nötig.
Hole dir einen API-Schlüssel von platform.deepseek.com und setze ihn als Umgebungsvariable:
export DEEPSEEK_API_KEY="sk-..."
Sobald die Umgebung steht, geht es an die Konfiguration von Modellen und Modi.
Schritt 2: Konfiguration — Modelle, Modi und Preise
Bevor wir Logik schreiben, definieren wir Imports, Modell-IDs, Konfigurationen für die Denkmodi und Preis-Konstanten. Diese Dictionaries steuern das Verhalten der gesamten App – vom Modelldropdown über API-Parameter, die jeden Denkmodus steuern, bis zum UI-Farbschema und den Kostenschätzungen im Vergleichspanel.
import os
import time
import concurrent.futures
from dataclasses import dataclass
from typing import Optional, Dict
import streamlit as st
from openai import OpenAI
DEEPSEEK_BASE_URL = "https://api.deepseek.com/"
DEEPSEEK_API_KEY_ENV = "DEEPSEEK_API_KEY"
MODELS = {
"DeepSeek-V4-Flash (default)": "deepseek-v4-flash",
"DeepSeek-V4-Pro": "deepseek-v4-pro",
}
MODES: Dict[str, dict] = {
"Non-think": {
"icon": "",
"color": "#10b981",
"badge": "green",
"desc": "Fast, direct answers — no internal reasoning",
"thinking_type": "disabled",
"reasoning_effort": None,
},
"Think High": {
"icon": "",
"color": "#3b82f6",
"badge": "blue",
"desc": "Careful step-by-step reasoning before responding",
"thinking_type": "enabled",
"reasoning_effort": "high",
},
"Think Max": {
"icon": "",
"color": "#ef4444",
"badge": "red",
"desc": "Exhaustive reasoning — push analysis to the limit",
"thinking_type": "enabled",
"reasoning_effort": "max",
},
}
PRICING = {
"deepseek-v4-flash": {
"input_cache_hit": 0.0028,
"input_cache_miss": 0.14,
"output": 0.28,
},
"deepseek-v4-pro": {
"input_cache_hit": 0.003625,
"input_cache_miss": 0.435,
"output": 0.87,
},
}
Ein paar Designentscheidungen lohnen sich hier zu erklären:
-
Parameter für den Denkmodus: Jeder Eintrag in
MODESführt zwei API-Felder statt eines Systemprompts mit:thinking_typeundreasoning_effort(”high”,"max"oderNone).thinking_typewird überextra_body={"thinking": {"type": ...}}übergeben,reasoning_effortist ein Top-Level-Request-Parameter. Non-think setztthinking_typeauf "disabled"und lässtreasoning_effortaufNone, sodass überhaupt kein Thinking-Body gesendet wird. -
Flash als Standardmodell: Flash aktiviert 13 B Parameter pro Token gegenüber 49 B bei Pro – dadurch sind drei parallele Aufrufe günstig genug für wiederholte Experimente. Pro ist über das Dropdown verfügbar, wenn du Spitzenleistung brauchst.
Think Maxauf Pro verbraucht jedoch schnell Budget, daher ist es bewusst als Opt-in statt Standard gesetzt.
Hinweis: Die im Code genutzten Werte spiegeln V4-Pro zu seinem aktuellen Promo-Rabatt wider. Prüfe die aktuellen Preise immer unter api-docs.deepseek.com/quick_start/pricing, bevor du Kostenvergleiche veröffentlichst, da sich Basispreise und Rabatte nach einem neuen Modell-Release häufig ändern.
Schritt 3: Aufgabenvorlagen
Das Aufgabendesign ist der am meisten unterschätzte Teil beim Bau eines Reasoning-Vergleichs. Wenn alle Aufgaben schwer und offen sind, gewinnt Think Max immer – und die Demo lehrt nichts. Der Aufgabensatz muss die gesamte Schwierigkeitsbreite abdecken, damit jeder Modus mindestens eine Kategorie hat, in der er gewinnt.
TASKS = {
"Trivial / Lookup": {
"prompt": (
"Complete both tasks below:\n\n"
"Task A — Convert this JSON to YAML:\n"
'{"name": "Alice", "age": 30, "skills": ["Python", "ML", "LLMs"],\n'
' "address": {"city": "San Francisco", "zip": "94105"}}\n\n'
"Task B — Summarize this paragraph in exactly one sentence:\n"
'"Large language models have rapidly transformed natural language processing '
"by demonstrating unprecedented capabilities across translation, summarization, "
"reasoning, and code generation, driven by scale and alignment techniques like RLHF "
'that bring model outputs closer to human intent."'
),
"expected_winner": "Non-think",
"tip": "Non-think should dominate here. No reasoning is required.",
},
"Coding / Debugging": {
"prompt": (
"Find every bug in the Python code below, explain each bug clearly, "
"and provide a fully corrected version:\n\n"
"```python\n"
"def binary_search(arr, target):\n"
" left, right = 0, len(arr)\n"
" while left < right:\n"
" mid = (left + right) // 2\n"
" if arr[mid] == target:\n"
" return mid\n"
" elif arr[mid] < target:\n"
" left = mid\n"
" else:\n"
" right = mid - 1\n"
" return -1\n\n"
"print(binary_search([1, 3, 5, 7, 9], 7))\n"
"```"
),
"expected_winner": "Think High",
"tip": "Think High usually finds the bugs and explains them well.",
},
"System Design": {
"prompt": (
"Design a scalable vector search system for 100 million documents.\n\n"
"Address each of the following:\n"
"1. Indexing strategy and pipeline\n"
"2. ANN algorithm selection (HNSW vs IVF-PQ vs ScaNN — justify your choice)\n"
"3. Sharding and replication strategy\n"
"4. p99 query latency target (< 50 ms) — how do you hit it?\n"
"5. Real-time document update handling\n"
"6. Top 3 failure modes and their mitigations"
),
"expected_winner": "Think High",
"tip": "Think High often gives the best quality-per-dollar design answer.",
},
"Planning": {
"prompt": (
"Create a detailed 6-month roadmap for deploying an enterprise RAG system.\n\n"
"Include:\n"
"- Month-by-month phases with concrete, measurable milestones\n"
"- Top 5 risks and mitigation strategies\n"
"- Team roles and headcount required per phase\n"
"- Evaluation metrics for each phase (how do you know it's working?)\n"
"- Go / no-go production checklist"
),
"expected_winner": "Think High",
"tip": "Think High should produce a more structured, complete roadmap.",
},
"Math (IMO-style)": {
"prompt": (
"Solve this problem completely and verify your answer:\n\n"
"Find all positive integers n such that n² + 1 is divisible by n + 1.\n\n"
"Your answer must include:\n"
"1. A complete proof with clear logical steps\n"
"2. Verification with at least 3 concrete numerical examples\n"
"3. A rigorous argument for why your solution set is complete "
"(i.e., there are no other solutions)"
),
"expected_winner": "Think Max",
"tip": "Think Max earns its cost when thorough verification matters.",
},
}
Die fünf Aufgaben lassen sich klar den drei erwarteten Gewinnern zuordnen:
|
Aufgabe |
Erwarteter Gewinner |
Begründung |
|
Trivial / Lookup |
Non-think |
Kein Denk-Overhead nötig; Denkzeit ist hier reine Verschwendung |
|
Coding / Debugging |
Think High |
Eine methodische Runde Logik findet alle Bugs; Max bringt nur geringen Zusatznutzen |
|
System Design |
Think High |
Mehr Tiefe erhöht Qualität; totale Ausschöpfung liefert keine bessere Architektur |
|
Planning |
Think High |
Struktur schlägt reine Rechenleistung; ein Lernplan ist kein Beweis |
|
Math (IMO-style) |
Think Max |
Verifikation ist tragend; ein falscher Beweis ist schlimmer als ein langsamer, korrekter |
Jede Aufgabe führt außerdem ein Feld expected_winner. Die App zeigt es nach Eintreffen der Ergebnisse an, damit Nutzer prüfen können, ob der erwartete Gewinner bestätigt oder geschlagen wurde.
Schritt 4: Datenklasse
Mit den Aufgabenvorlagen brauchen wir nun eine Struktur, die die Ergebnisse jedes API-Calls hält. Statt rohe Response-Objekte durch die App zu reichen, definieren wir eine RunResult-Dataclass, die alle Metriken kapselt, die das Vergleichspanel benötigt.
@dataclass
class RunResult:
mode: str
answer: str = ""
thinking: str = ""
latency: float = 0.0
input_tokens: int = 0
output_tokens: int = 0
cost_usd: float = 0.0
error: Optional[str] = None
@property
def tokens_per_second(self) -> Optional[float]:
if self.latency > 0 and self.output_tokens > 0:
return self.output_tokens / self.latency
return None
@property
def thinking_word_count(self) -> int:
return len(self.thinking.split()) if self.thinking else 0
Das Feld thinking ist getrennt von answer, weil die DeepSeek V4 API die Chain-of-Thought im separaten Feld reasoning_content zurückgibt – auf derselben Ebene wie content. Durch die Trennung kann die UI einen einklappbaren Reasoning-Trace neben der sauberen Finalantwort rendern. So werden die Modusunterschiede unmittelbar greifbar, besonders bei Mathe, wo der Think Max-Trace tausende Wörter umfassen kann.
Die Property tokens_per_second misst den Generierungsdurchsatz unabhängig von der Promptlänge. Das ist hilfreich, wenn sich die Ausgabetoken stark unterscheiden. Beachte, dass Think Max naturgemäß mehr Tokens produziert – reine Latenzvergleiche können daher in die Irre führen, wenn man nicht auch die Generierungsrate sieht.
Schritt 5: Kostenhelfer
Bevor wir die API-Logik schreiben, definieren wir zwei kleine Helfer zwischen der Rohantwort des SDKs und RunResult. Sie sind leicht zu übersehen, aber relevant für korrekte Kostenschätzungen.
def get_cached_prompt_tokens(usage) -> int:
prompt_details = getattr(usage, "prompt_tokens_details", None)
if prompt_details is None:
return 0
cached_tokens = getattr(prompt_details, "cached_tokens", None)
if cached_tokens is not None:
return cached_tokens or 0
if isinstance(prompt_details, dict):
return prompt_details.get("cached_tokens", 0) or 0
return 0
def estimate_cost_usd(
model: str,
prompt_tokens: int,
completion_tokens: int,
cached_prompt_tokens: int,
) -> float:
pricing = PRICING.get(model, PRICING["deepseek-v4-flash"])
cached_tokens = min(cached_prompt_tokens, prompt_tokens)
uncached_tokens = max(prompt_tokens - cached_tokens, 0)
return (
cached_tokens / 1_000_000 * pricing["input_cache_hit"]
+ uncached_tokens / 1_000_000 * pricing["input_cache_miss"]
+ completion_tokens / 1_000_000 * pricing["output"]
)
Die Funktion get_cached_prompt_tokens() greift nicht direkt auf ein Feld zu, weil die Struktur prompt_tokens_details zwischen SDK-Versionen variieren kann. Sie prüft zuerst auf ein typisiertes Attribut, fällt dann auf Dict-Zugriff zurück und gibt ansonsten null zurück, statt eine Exception zu werfen. Das ist wichtig im ThreadPoolExecutor, wo ein stiller Fehler in einem Thread zu zu niedrigen Kostenschätzungen führen könnte, ohne sichtbar zu werden.
Der Helfer estimate_cost_usd() trennt die Prompttokens in Cache-Hit- und Cache-Miss-Anteile, bevor Preise angewendet werden. Da DeepSeek die Cache-Hit-Preise auf ein Zehntel der Miss-Rate gesenkt hat, ist der Unterschied zwischen Cold- und Warm-Prompt erheblich. Bei wiederholten Läufen kann Non-think dadurch fast kostenlos erscheinen – nicht, weil es weniger Tokens ausgibt, sondern weil sein kürzerer Prompt sehr wahrscheinlich warm im Cache ist.
Schritt 6: Parallele API-Ausführung
Das ist der architektonische Kern der Arena. Alle drei Modi starten gleichzeitig über einen ThreadPoolExecutor, sodass die gesamte Wandzeit der langsamsten Einzelantwort entspricht – nicht der Summe aller drei.
def call_mode(client: OpenAI, model: str, mode_name: str, user_prompt: str) -> RunResult:
result = RunResult(mode=mode_name)
mode_cfg = MODES[mode_name]
start = time.perf_counter()
try:
request_kwargs = {
"model": model,
"messages": [{"role": "user", "content": user_prompt}],
"max_tokens": 4096,
"extra_body": {"thinking": {"type": mode_cfg["thinking_type"]}},
}
if mode_cfg["reasoning_effort"]:
request_kwargs["reasoning_effort"] = mode_cfg["reasoning_effort"]
response = client.chat.completions.create(**request_kwargs)
result.latency = time.perf_counter() - start
message = response.choices[0].message
result.thinking = (getattr(message, "reasoning_content", None) or "").strip()
result.answer = (message.content or "").strip()
usage = response.usage
result.input_tokens = getattr(usage, "prompt_tokens", 0) or 0
result.output_tokens = getattr(usage, "completion_tokens", 0) or 0
result.cost_usd = estimate_cost_usd(
model=model,
prompt_tokens=result.input_tokens,
completion_tokens=result.output_tokens,
cached_prompt_tokens=get_cached_prompt_tokens(usage),
)
except Exception as exc:
result.latency = time.perf_counter() - start
result.error = str(exc)
return result
def run_parallel(client: OpenAI, model: str, prompt: str) -> Dict[str, RunResult]:
results: Dict[str, RunResult] = {}
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as pool:
futures = {
pool.submit(call_mode, client, model, mode_name, prompt): mode_name
for mode_name in MODES
}
for fut in concurrent.futures.as_completed(futures):
results[futures[fut]] = fut.result()
return results
Einige Konstruktionsdetails sind hier wichtig:
-
request_kwargsbedingt aufbauen: DerNon-think-Modus sendetthinking_type: "disabled"und keinen Schlüsselreasoning_effort.Think HighundThink Maxsendenthinking_type: "enabled"sowie ihre jeweilige Effort-Stufe. Die Abfrageif mode_cfg["reasoning_effort"]stellt sicher, dass der Parameter beiNon-thinkkomplett weggelassen wird, statt alsNonegesendet zu werden – das könnte sonst zu API-Validierungsfehlern führen. -
reasoning_contentdirekt lesen: Die Chain-of-Thought wird ausmessage.reasoning_contentpergetattr()mit Fallback auf einen leeren String gelesen. Das ist robuster, als<think>...</think>-Tags aus dem Content-String zu parsen. Es nutzt das offizielle Feld, handhabt Fälle ohne Trace (Non-think) und bricht nicht, falls das Wort "think" aus anderen Gründen im Output steht. -
Defensives
getattr()bei Usage-Feldern: Usage-Felder werden mitgetattr(..., 0) or 0gelesen statt direkt. Fehlt ein Feld in älteren SDKs oder in ungewöhnlichen Antworten, fällt der Wert auf null zurück, anstatt eineAttributeErrorauszulösen, die den gesamten Lauf scheitern ließe. -
Error-Handling: Wenn ein Call fehlschlägt, speichert die
RunResult-Dataclass den Fehlerstring statt zu werfen. Die UI prüftresult.errorund rendert eine informative Karte, ohne den gesamten Drei-Modi-Lauf zum Absturz zu bringen.
Schritt 7: Streamlit UI und CSS
Dieser Schritt deckt die Präsentation ab: Seitenlayout, CSS-Designsystem, die Ergebnis-Spalte pro Modus und die Tab-Struktur, die den Vergleich organisiert, ohne auf den ersten Blick zu überfrachten.
Die App nutzt st.set_page_config mit layout="wide", damit der Drei-Spalten-Vergleich genug horizontalen Platz hat:
def main():
st.set_page_config(
page_title="DeepSeek V4 Think Mode Arena",
layout="wide",
initial_sidebar_state="expanded",
)
inject_css()
Die Funktion inject_css() injiziert ein vollständiges Designsystem per st.markdown. Es nutzt einen warmen Pergamenthintergrund, Space Mono für Monospace-Überschriften und Metrik-Chips sowie DM Sans für Fließtext.
def render_mode_column(result: RunResult, mode_name: str):
cfg = MODES[mode_name]
badge_cls = f"mode-{cfg['badge']}"
st.markdown(
f'<div class="mode-header {badge_cls}">{mode_name}</div>',
unsafe_allow_html=True,
)
st.markdown(f'<div class="subtle-copy">{cfg["desc"]}</div>', unsafe_allow_html=True)
if result.error:
st.error(f"**API Error:** {result.error}")
return
chips = [
("Latency", f"{result.latency:.1f}s"),
("Output tokens", f"{result.output_tokens:,}"),
("Cost", f"${result.cost_usd:.5f}"),
]
if result.tokens_per_second:
chips.append(("Tok/s", f"{result.tokens_per_second:.0f}"))
chip_html = "".join(
f'<span class="metric-chip">{label} <span>{val}</span></span>'
for label, val in chips
)
st.markdown(chip_html, unsafe_allow_html=True)
if result.thinking:
with st.expander(f" Thinking trace — {result.thinking_word_count:,} words"):
preview = result.thinking[:5000]
if len(result.thinking) > 5000:
preview += "\n\n[… truncated for display …]"
st.text(preview)
elif mode_name != "Non-think":
st.caption("_No thinking trace emitted_")
st.markdown('<div class="answer-label">Final answer</div>', unsafe_allow_html=True)
st.markdown(result.answer if result.answer else "_No answer returned._")
Der Thinking-Trace-Expander macht den Modusunterschied besonders greifbar: Think Max kann bei harten Matheaufgaben tausende Wörter an Selbstkorrektur und Verifikation ausgeben, während Non-think oft gar keinen Trace hat.
Das Hauptlayout nutzt Streamlit-Tabs, um Inhalte zu trennen, statt alles in einen endlosen Scroll zu pressen:
overview_tab, answers_tab, ratings_tab = st.tabs(
["Overview", "Full Responses", "Ratings"]
)
Der Tab „Overview“ zeigt die Gewinnerzusammenfassung und die Metriktabelle. „Full Responses“ zeigt den Drei-Spalten-Vergleich mit Thinking-Traces. „Ratings“ enthält Slider für Nutzerbewertungen (1–5) pro Modus.
Schritt 8: Metriken und Bewertungen
Zum Schluss bauen wir zwei Komponenten für den Overview-Tab: eine flache Metriktabelle mit allen Dimensionen nebeneinander und eine Gewinnerzusammenfassung mit vier klaren Kategorien.
def render_metrics_table(results: Dict[str, RunResult], ratings: Dict[str, int]):
rows = []
for mode_name, res in results.items():
ok = not res.error
rows.append({
"Mode": mode_name,
"Latency (s)": f"{res.latency:.2f}" if ok else "—",
"Input Tokens": f"{res.input_tokens:,}" if ok else "—",
"Output Tokens": f"{res.output_tokens:,}" if ok else "—",
"Tok/s": f"{res.tokens_per_second:.0f}" if (ok and res.tokens_per_second) else "—",
"Est. Cost (USD)": f"${res.cost_usd:.5f}" if ok else "—",
"Thinking Words": f"{res.thinking_word_count:,}" if ok else "—",
"User Rating": f"{ratings.get(mode_name)}/5" if ratings.get(mode_name) else "—",
})
st.table(rows)
def render_winner_summary(results: Dict[str, RunResult], ratings: Dict[str, int], expected: str):
valid = {k: v for k, v in results.items() if not v.error}
fastest = min(valid, key=lambda k: valid[k].latency)
cheapest = min(valid, key=lambda k: valid[k].cost_usd)
most_efficient = max(
valid,
key=lambda k: valid[k].output_tokens / max(valid[k].cost_usd, 1e-9),
)
top_rated = max(ratings, key=ratings.get) if ratings else None
Kurz, was diese Funktionen leisten:
-
render_metrics_table()iteriert über alleRunResult-Objekte und baut je Modus eine Zeile. Die acht Spalten decken Zeit (Latenz, Tok/s), Umfang (Input- und Output-Tokens, Thinking-Wörter), Geld (geschätzte Kosten) und menschliches Urteil (Nutzerbewertung) ab. -
render_winner_summary()filtert zunächst fehlgeschlagene Läufe heraus, damit ein einzelner API-Fehler die Ergebnisse nicht verzerrt. Dann ermittelt es den Sieger in vier unabhängigen Dimensionen: Wandzeit, Rohkosten, Ausgabe-Effizienz und Nutzerwertung.
Die vier Kategorien bleiben bewusst getrennt statt zu einem Score gewichtet – die Frage, ob Latenz wichtiger ist als Kosten, ist eine Produktentscheidung, keine Framework-Entscheidung.
Außerdem zeigt die App den erwarteten Gewinner pro Aufgabe an und fordert zur Bestätigung auf:
st.markdown(
f"> **Expected winner for this task type:** {expected} — "
"does your result match? Rate answers to confirm.",
)
Schritt 9: App starten
Die gesamte App steckt in einer einzigen app.py mit zwei Abhängigkeiten – der Start erfolgt in zwei Befehlen:
# Set your API key
export DEEPSEEK_API_KEY="sk-..."
# Run
streamlit run app.py
Die App öffnet sich im Browser unter localhost:8501. Wähle eine Aufgabenvorlage im Dropdown, bearbeite optional den Prompt und klicke auf Run Arena. Ein Fortschrittsbalken aktualisiert sich, sobald ein Modus fertig ist. Ergebnisse liegen in st.session_state, damit du Tabs wechseln und bewerten kannst, ohne einen Re-Run auszulösen.

Hinweis zu Preisen: DeepSeek hat die V4 API-Preise seit dem Launch deutlich angepasst. V4-Pro ist aktuell im Promo-Rabatt, und die Cache-Hit-Preise wurden im April 2026 auf ein Zehntel der Miss-Rate gesenkt. Die in der App gezeigten Kosten spiegeln diese aktuellen Sätze wider, können sich aber ändern. Prüfe immer unter api-docs.deepseek.com/quick_start/pricing, bevor du ein Modell produktiv nutzt.
Fazit
In diesem Tutorial haben wir eine Streamlit-App gebaut, die denselben Prompt parallel über die drei Denkmodi von DeepSeek V4 laufen lässt und die Ergebnisse nach Latenz, Kosten, Tokennutzung, Tiefe der Thinking-Traces und menschlicher Bewertung vergleicht. Die wichtigsten Architekturentscheidungen waren:
-
ThreadPoolExecutorfür echte Parallelität – die gesamte Wandzeit entspricht der langsamsten Antwort statt der Summe aller drei -
Die API-Parameter
thinkingundreasoning_effortsorgen für saubere, explizite Modussteuerung im Einklang mit DeepSeeks API – statt fragilem Systemprompt-Steering -
Cache-bewusste Kostenschätzung teilt Eingabetokens in Cache-Hit und -Miss auf und liefert deutlich genauere Kosten, besonders bei wiederholten Läufen, wo Warm-Cache-Rabatte
Non-thinknahezu kostenlos erscheinen lassen können
Wenn du dieses Projekt erweitern willst, könntest du eine LLM-as-judge-Schicht hinzufügen (ein separates Modell wie Claude oder GPT-4 bewertet Antworten automatisch), Antworten per Prompthash cachen, um identische Anfragen nicht neu zu rechnen, oder eine Cross-Model-Achse einführen, die Flash Think Max gegen Pro Think High stellt – eine wirklich spannende Kostenparitätsfrage, die das V4-Paper aufwirft, aber nicht vollständig beantwortet.
DeepSeek V4 API Denkmodus-Arena: FAQs
Warum sollten wir OpenAI statt eines DeepSeek SDKs verwenden?
Die API von DeepSeek ist OpenAI-kompatibel. Wir können den OpenAI-Client daher mit einem DeepSeek API-Schlüssel auf https://api.deepseek.com zeigen. Das bedeutet auch: Die App funktioniert bei jedem OpenAI-kompatiblen Provider, der DeepSeek V4 hostet – es müssen nur Basis-URL und Modellstring angepasst werden.
Warum wird reasoning_effort beim Non-think-Modell weggelassen statt auf None gesetzt?
Die Abfrage if mode_cfg["reasoning_effort"] in call_mode() lässt den Parameter ganz weg, wenn er None ist, statt reasoning_effort=None zu senden. Manche API-Validatoren lehnen unbekannte Parameter mit expliziten Nullwerten ab. Das vollständige Weglassen ist daher das robustere Muster bei frisch eingeführten Endpunkten.
Warum erscheint der Thinking-Trace bei Think High manchmal nicht?
Der Trace wird aus message.reasoning_content gelesen. Gibt das Modell für einen Lauf ein leeres oder null Feld zurück – was bei kürzeren, weniger komplexen Prompts passieren kann, wenn Think High schnell konvergiert –, ist result.thinking ein leerer String.
Ich bin Google Developers Expertin für ML (Gen AI), dreifache Kaggle-Expertin und Women-Techmakers-Botschafterin mit über drei Jahren Erfahrung in der Tech-Branche. 2020 habe ich ein Health-Tech-Startup mitgegründet und absolviere derzeit einen Master in Informatik an der Georgia Tech mit Schwerpunkt Machine Learning.


