Zum Hauptinhalt springen
Lektion 9 von 14 · Mistral API: Schnellstart

Erster Aufruf und Streaming in TypeScript

Lektion 9 von 14 Aktualisiert am 3. November 2026 Entwickler
Auf dieser Seite
  1. Ihren ersten Aufruf senden
  2. Streaming
  3. Mehrfachwechsel-Gespräche
  4. Generierung anpassen und Fehler behandeln
  5. Kernaussagen

Lektion aktualisiert am 3. November 2026 nach der Kompilierung von Beispielen im strengen Modus mit dem SDK @mistralai/mistralai 3.5.0 und TypeScript 7.0.2. Das SDK-Typ content als string | ContentChunk[]: Mehrfachwechselgespräche und Streaming-Schleifen kompilierten ohne eine typeof content === 'string'-Prüfung nicht. Das Konfigurationsbeispiel kombinierte zuvor temperature und topP, was die API-Dokumentation nicht empfiehlt, gemeinsam zu ändern. Die Fehlerbehandlung nutzt nun die MistralError-Klasse des SDKs, und die Express-Route validiert die Frage, bevor sie die API aufruft. Quellen: Mistral TypeScript SDK (README) · chat completion parameters.

Ihren ersten Aufruf senden

Nun, da das SDK installiert ist, werden wir praktisch. Die Methode chat.complete() des TypeScript-SDKs ist dem Python-SDK exakt gleichwertig: gleiche Parameter, gleiche Antwortstruktur, abgesehen von der Namenskonvention. Wenn Sie den Python-Kursen gefolgt sind, befinden Sie sich auf vertrautem Terrain; nur die asynchrone Syntax von JavaScript ist neu.

import 'dotenv/config';
import { Mistral } from '@mistralai/mistralai';

const client = new Mistral({
  apiKey: process.env.MISTRAL_API_KEY,
});

async function main() {
  const response = await client.chat.complete({
    model: 'mistral-small-latest',
    messages: [
      {
        role: 'user',
        content: 'Erklären Sie das Konzept einer Closures in JavaScript in drei Sätzen.',
      },
    ],
  });

  console.log(response.choices[0]?.message?.content);
}

main();

Die Fragezeichen in response.choices[0]?.message?.content sind nicht nur zur Schau: In den SDK-Typen sind message und content optional, und choices[0] existiert nicht, wenn die Liste leer zurückkommt. Der sichere Zugriff gibt undefined zurück, anstatt eine Ausnahme zu werfen. Beachten Sie auch, dass content nicht immer ein String ist: Das SDK typisiert es als string | ContentChunk[], da eine Antwort als Liste von Fragmenten (Text, thinking-Begründung, Referenzen usw.) eintreffen kann.

Das Antwortformat verstehen

Das Antwortformat ist dem des Python-SDKs identisch. Das Parsen hilft Ihnen zu verstehen, wofür Sie zahlen und warum eine Antwort gestoppt wurde. Das folgende Beispiel extrahiert Text, Stoppgrund und Tokenanzahl einzeln; das Tippen zeigt Ihrem Editor, dass er jedes Feld vorschlägt, was beweist, dass die Typisierung ihre Arbeit tut.

async function analyserReponse() {
  const response = await client.chat.complete({
    model: 'mistral-small-latest',
    messages: [
      { role: 'user', content: 'Was ist die Hauptstadt Frankreichs?' },
    ],
    maxTokens: 100,
  });

  // Antworttext
  const texte = response.choices[0]?.message?.content;

  // Stoppgrund
  const finRaison = response.choices[0]?.finishReason;

  // Token-Statistiken
  const tokensEntree = response.usage?.promptTokens;
  const tokensSortie = response.usage?.completionTokens;

  console.log(`Antwort: ${texte}`);
  console.log(`Tokens: ${tokensEntree} Eingabe + ${tokensSortie} Ausgabe`);
  console.log(`Stopp: ${finRaison}`);
}

Beachten Sie die Groß-/Kleinschreibung: Wo Python max_tokens, finish_reason und prompt_tokens auslegt, verwendet TypeScript maxTokens, finishReason und promptTokens. Dies ist der häufigste Fehler beim manuellen Portieren eines Python-Beispiels – und der Compiler wird dies sofort markieren.

Streaming

Streaming ist für Web-Oberflächen unerlässlich: Ohne es starrt der Nutzer mehrere Sekunden lang auf einen eingefrorenen Bildschirm; mit ihm erscheint Text Wort für Wort, und die wahrgenommene Latenz kollabiert. Das TypeScript-SDK stellt den Stream als asynchronen Generator bereit, den Sie mit for await...of durchlaufen:

async function streamReponse() {
  const stream = await client.chat.stream({
    model: 'mistral-small-latest',
    messages: [
      {
        role: 'user',
        content: 'Beschreiben Sie die fünf wichtigsten Designmuster in JavaScript.',
      },
    ],
  });

  for await (const chunk of stream) {
    const content = chunk.data.choices[0]?.delta.content;
    if (typeof content === 'string') {
      process.stdout.write(content);
    }
  }
  console.log();
}

Zwei Details verdienen Ihre Aufmerksamkeit. Der Inhalt befindet sich in chunk.data, nicht direkt in chunk: Dies ist die Event-Wrapper des SDKs seit Version 1.0. Und die typeof content === 'string'-Prüfung filtert sowohl Fragmente ohne Inhalt aus, die Ihre Ausgabe mit undefined verschmutzen würden, als auch Listen von Fragment-Inhalten, die process.stdout.write nicht akzeptiert: Ohne sie verweigert der strenge Modus die Kompilierung.

Den Stream über Express auslagern

Ein Stream, der den Terminal nie verlässt, hilft niemandem. Hier ist die Vorgehensweise, ihn an einen Browser über Server-Sent Events von einer Express-API weiterzuleiten. Die Frage wird vor jedem Aufruf validiert, um eine leere Anfrage an die API zu vermeiden. Die drei Header öffnen den Kanal, jedes Fragment wird als JSON in einem data:-Event zurückgesendet, und ein [DONE]-Marker signalisiert dem Client, die Verbindung zu schließen.

import express from 'express';
import { Mistral } from '@mistralai/mistralai';

const app = express();
const client = new Mistral({ apiKey: process.env.MISTRAL_API_KEY });

app.get('/api/chat', async (req, res) => {
  const question = typeof req.query.q === 'string' ? req.query.q : '';
  if (!question) {
    res.status(400).json({ error: 'Fehlender q-Parameter' });
    return;
  }

  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  const stream = await client.chat.stream({
    model: 'mistral-small-latest',
    messages: [{ role: 'user', content: question }],
  });

  for await (const chunk of stream) {
    const content = chunk.data.choices[0]?.delta.content;
    if (typeof content === 'string' && content) {
      res.write(`data: ${JSON.stringify({ text: content })}\n\n`);
    }
  }

  res.write('data: [DONE]\n\n');
  res.end();
});

app.listen(3000, () => console.log('Server auf Port 3000'));

Mehrfachwechsel-Gespräche

Die Verwaltung der Historie folgt demselben Prinzip wie in Python: Das Modell hat kein Gedächtnis, daher pflegen Sie ein Array von Nachrichten und senden das Ganze bei jedem Wechsel erneut. In TypeScript verhindert die Deklaration eines expliziten Message-Typs, dass eine nicht existente Rolle oder ein fehlerhaftes Objekt eingeschleust wird – ein Fehler, den die API sonst als 400 zurückgeben würde.

import { Mistral } from '@mistralai/mistralai';

type Message = {
  role: 'system' | 'user' | 'assistant';
  content: string;
};

const client = new Mistral({ apiKey: process.env.MISTRAL_API_KEY });

const historique: Message[] = [
  {
    role: 'system',
    content: 'Sie sind ein erfahrener TypeScript-Assistent. Antworten Sie auf Englisch.',
  },
];

async function poserQuestion(frage: string): Promise<string> {
  historique.push({ role: 'user', content: frage });

  const response = await client.chat.complete({
    model: 'mistral-small-latest',
    messages: historique,
  });

  const contenu = response.choices[0]?.message?.content;
  const reponse = typeof contenu === 'string' ? contenu : '';
  historique.push({ role: 'assistant', content: reponse });

  return reponse;
}

async function main() {
  console.log(await poserQuestion('Was ist ein generischer Typ?'));
  console.log(await poserQuestion('Zeigen Sie mir ein konkretes Beispiel.'));
  console.log(await poserQuestion('Wie füge ich Einschränkungen hinzu?'));
}

main();

Die typeof contenu === 'string'-Prüfung ist kein Luxus: Das content-Feld der Antwort kann eine Liste von Fragmenten sein, während Ihr Message-Typ einen String erwartet. Beachten Sie dann die dritte Frage: „Wie füge ich Einschränkungen hinzu?” macht nur Sinn, weil die beiden vorherigen Austausche noch im Array sind. Entfernen Sie die Zeile, die die Antwort des Assistenten zur Historie hinzufügt, und Sie werden sehen, wie das Modell den Faden beim zweiten Wechsel verliert.

Generierung anpassen und Fehler behandeln

Erweiterte Parameter sind dem Python-SDK identisch – nur die Groß-/Kleinschreibung ändert sich. Eine niedrige temperature für ein strukturiertes Ergebnis und ein maxTokens, der auf die erwartete Länge kalibriert ist, liefern vorhersehbarere Antworten. Stellen Sie temperature oder topP ein, nicht beide: Dies ist die Empfehlung der API-Dokumentation, die eine temperature zwischen 0 und 0,7 empfiehlt.

const response = await client.chat.complete({
  model: 'mistral-large-latest',
  messages: [
    { role: 'user', content: 'Entwerfen Sie eine Architektur für eine B2B SaaS.' },
  ],
  temperature: 0.5,
  maxTokens: 1000,
});

Schließlich kann jeder Netzwerkauftrag fehlschlagen: ungültiger Schlüssel, überschrittener Kontingenz, Ausfall. Umhüllen Sie den Aufruf immer in einen try/catch und prüfen Sie den Fehlertyp, bevor Sie seine Eigenschaften lesen, sonst verweigert TypeScript die Kompilierung. Alle HTTP-Fehler, die die API zurückgibt, leiten sich von MistralError ab, das statusCode und body auslegt; Netzwerkausfälle (ConnectionError, RequestTimeoutError usw.) leiten sich nicht davon ab, bleiben aber Error-Instanzen.

import * as errors from '@mistralai/mistralai/models/errors';

try {
  const response = await client.chat.complete({
    model: 'mistral-small-latest',
    messages: [{ role: 'user', content: 'Hallo!' }],
  });
  console.log(response.choices[0]?.message?.content);
} catch (error) {
  if (error instanceof errors.MistralError) {
    // API-Fehlerantwort: 401 Schlüssel abgelehnt, 429 Limit erreicht...
    console.error(`Mistral API Fehler ${error.statusCode}: ${error.message}`);
  } else if (error instanceof Error) {
    // Keine API-Antwort: Netzwerk ausgefallen, Zeitüberschreitung überschritten...
    console.error(`Fehler: ${error.message}`);
  }
}

Kernaussagen

  • client.chat.complete() ist asynchron – verwenden Sie await
  • Streaming verwendet for await...of auf dem Ergebnis von client.chat.stream()
  • TypeScript-Typisierung fängt Parameterfehler zur Kompilierzeit ab
  • SSE-Integration mit Express ist für Echtzeit-Web-Oberflächen unkompliziert
  • Gesprächshistorie wird mit einem typisierten Message[]-Array verwaltet
  • content ist entweder ein String oder eine Liste von Fragmenten: Testen Sie typeof content === 'string', bevor Sie ihn als Text verwenden
  • SDK-HTTP-Fehler leiten sich von MistralError ab (statusCode, body)