Zum Hauptinhalt springen
Lektion 3 von 12 · KI-Logik mit Mistral: reasoning_effort, Small 4 und Large 4

Denk-Blöcke: Lesen der Modell-Argumentation

Lektion 3 von 12 Aktualisiert am 2. November 2026 Entwickler
Auf dieser Seite
  1. Zwei Antwortformen
  2. Anatomie eines Denk-Blocks
  3. Parsen der Antwort in Python
  4. Anzeige der Argumentation in einer Schnittstelle
  5. Streaming in drei Phasen
  6. Kernaussagen

Lektion am 2. November 2026 überarbeitet basierend auf dem Abschnitt Handling thinking chunks der Mistral-Dokumentation. Die vorherige Version las die Argumentation aus einem text-Feld im Denk-Block: Dieses Feld existiert nicht; die Argumentation ist eine Liste von Text-Blöcken.

Zwei Antwortformen

Bei reasoning_effort="high" ist das Feld message.content einer Antwort kein String mehr, sondern eine Liste von Blöcken. Bei reasoning_effort="none" ist es wieder ein einfacher String, ohne Spur einer Argumentation. Robuster Code behandelt immer beide Formen: Das ist die goldene Regel dieser Lektion.

Anatomie eines Denk-Blocks

In der Liste treten zwei Block-Typen auf:

  • ThinkChunk (type: "thinking") trägt die Argumentationsspur. Sein thinking-Feld ist selbst eine Liste von TextChunk-Fragmenten;
  • TextChunk (type: "text") trägt die endgültige Antwort in seinem text-Feld.

Hier ist die Form einer Antwort von Mistral Small 4, entnommen aus dem offiziellen Beispiel (Texte abgekürzt):

{
  "model": "mistral-small-2603",
  "usage": {"prompt_tokens": 77, "completion_tokens": 1114, "total_tokens": 1191},
  "choices": [{
    "finish_reason": "stop",
    "message": {
      "role": "assistant",
      "content": [
        {"type": "thinking", "thinking": [
          {"type": "text", "text": "Okay, let's try to figure out John's age..."}
        ]},
        {"type": "text", "text": "Let's denote the ages of the sisters as follows..."}
      ]
    }
  }]
}

Das Objektmodell des Python-SDK folgt dieser Struktur exakt: ThinkChunk.thinking enthält die Argumentations-Blöcke, und jeder TextChunk gibt seinen Inhalt über .text aus.

Parsen der Antwort in Python

Der offizielle Code unterscheidet Blöcke mit isinstance, nachdem er den Fall des einfachen Strings ausgeschlossen hat:

from mistralai.client.models import TextChunk, ThinkChunk

content = chat_response.choices[0].message.content

if isinstance(content, str):          # reasoning_effort="none"
    print(content)
else:
    for chunk in content:
        if isinstance(chunk, ThinkChunk):
            print("--- reasoning ---")
            for inner in chunk.thinking:
                if isinstance(inner, TextChunk):
                    print(inner.text)
            print("--- end of reasoning ---")
        elif isinstance(chunk, TextChunk):
            print(chunk.text)

In einer Anwendung möchten Sie eine Funktion, die Argumentation und Antwort getrennt zurückgibt. Wir nennen sie separate und verwenden sie später im Kurs erneut:

from mistralai.client.models import TextChunk, ThinkChunk

def separate(content):
    """Return (reasoning, answer) for content that is either a string or a list of chunks."""
    if isinstance(content, str):
        return "", content
    reasoning, answer = [], []
    for chunk in content or []:
        if isinstance(chunk, ThinkChunk):
            reasoning.extend(i.text for i in chunk.thinking if isinstance(i, TextChunk))
        elif isinstance(chunk, TextChunk):
            answer.append(chunk.text)
    return "".join(reasoning), "".join(answer)

reasoning, answer = separate(chat_response.choices[0].message.content)

Anzeige der Argumentation in einer Schnittstelle

Das Trennen der beiden Teile ermöglicht es Ihnen, zu entscheiden, was der Benutzer sieht. Drei gängige Ansätze:

  • Verbergen der Argumentation und Anzeigen nur der Antwort, für einen für Endnutzer bestimmten Assistenten;
  • Einklappen der Argumentation in einen Block, den der Benutzer öffnen kann, falls er möchte, für ein Expertentool;
  • Anzeigen der vollen Argumentation, für einen pädagogischen Tutor, bei dem der Prozess genauso wichtig ist wie das Ergebnis.
def render_html(content, show_reasoning=False):
    reasoning, answer = separate(content)
    html = f"<div class='answer'>{answer}</div>"
    if show_reasoning and reasoning:
        html = (
            "<details><summary>View model reasoning</summary>"
            f"<pre>{reasoning}</pre></details>" + html
        )
    return html

In einem echten Projekt sollten Sie den Text vor der Einfügung in HTML ent escaped werden (beispielsweise mit html.escape): Sowohl Argumentation als auch Antwort sind generierter Text und keine vertrauenswürdige Markup.

Streaming in drei Phasen

Beim Streaming ändert sich die Form von delta.content, während die Antwort entsteht:

  1. Argumentationsphase: delta.content ist eine Liste, die einen ThinkChunk enthält;
  2. Übergang: eine einzelne Liste, die sowohl den schließenden ThinkChunk als auch den ersten TextChunk enthält;
  3. Antwortphase: delta.content ist ein einfacher String.

Der folgende Code, angepasst aus dem offiziellen Beispiel, zeigt beide Phasen, indem er eine Statusflag verfolgt:

import os
from mistralai.client import Mistral
from mistralai.client.models import TextChunk, ThinkChunk

client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
in_reasoning = False

for event in client.chat.stream(
    model="mistral-large-4-0",
    messages=[{"role": "user", "content": "What is 17 × 23?"}],
    reasoning_effort="high",
):
    delta = event.data.choices[0].delta.content
    if not delta:
        continue
    if isinstance(delta, str):            # answer phase
        if in_reasoning:
            print("\n--- end of reasoning ---")
            in_reasoning = False
        print(delta, end="", flush=True)
        continue
    for chunk in delta:                   # reasoning phase and transition
        if isinstance(chunk, ThinkChunk):
            if not in_reasoning:
                print("--- reasoning ---")
                in_reasoning = True
            for inner in chunk.thinking:
                if isinstance(inner, TextChunk):
                    print(inner.text, end="", flush=True)
        elif isinstance(chunk, TextChunk):
            if in_reasoning:
                print("\n--- end of reasoning ---")
                in_reasoning = False
            print(chunk.text, end="", flush=True)

Streaming ändert das Erlebnis: Statt auf einen langen Argumentationsprozess zu warten, während der Bildschirm eingefroren ist, sieht der Benutzer das Modell bei der Arbeit oder zumindest einen Aktivitätsindikator, falls Sie die Argumentation verbergen.

Kernaussagen

  • content ist ein String bei none, eine Liste von Blöcken bei high: Behandeln Sie immer beide
  • ThinkChunk.thinking ist eine Liste von TextChunk; die endgültige Antwort lebt in einem oberstufigen TextChunk
  • Eine separate-Funktion, die (reasoning, answer) zurückgibt, vereinfacht den Rest Ihres Codes
  • Beim Streaming: Argumentationsliste, gemischter Übergang, dann Antwort-Strings
  • Ent escaped Sie sowohl Argumentation als auch Antwort, bevor Sie sie anzeigen