Text Parts manuell streamen
Überblick
Abschnitt betitelt „Überblick“Normalerweise uebernimmt streamText das Schreiben von Text Parts automatisch. Aber manchmal brauchst Du mehr Kontrolle: mehrere LLM-Outputs kombinieren, eigenen Text einfuegen oder Text aus Nicht-LLM-Quellen streamen. In diesen Faellen schreibst Du Text Parts manuell über writer.write().
Ein Text-Part in der UI durchlaeuft einen Lifecycle: text-start oeffnet einen neuen Text-Part, dann folgen beliebig viele text-delta Parts mit den eigentlichen Text-Fragmenten, und text-end schliesst den Text-Part ab. Wenn Du writer.merge() verwendest, sendet streamText diese Lifecycle-Events automatisch. Bei rein manuellem Schreiben über writer.write() genuegt es, text-delta Parts zu senden — der Stream kuemmert sich um Start und Ende.
Du kannst manuelle Text-Deltas mit writer.merge() kombinieren — eigener Text vor, nach oder zwischen LLM-Streams.
Dieses Pattern ist besonders nuetzlich für Workflow-Szenarien, in denen mehrere LLM-Calls nacheinander ausgefuehrt werden und Du Ueberschriften oder Trennzeichen dazwischen einfuegen willst.
Einfaches Beispiel
Abschnitt betitelt „Einfaches Beispiel“import { createUIMessageStreamResponse } from 'ai';
export async function POST(req: Request) { return createUIMessageStreamResponse({ execute(writer) { // Manuell Text Parts schreiben writer.write({ type: 'text-delta', textDelta: 'Hello ' }); writer.write({ type: 'text-delta', textDelta: 'World!' }); }, });}Kombination mit streamText
Abschnitt betitelt „Kombination mit streamText“import { createUIMessageStreamResponse, streamText } from 'ai';import { anthropic } from '@ai-sdk/anthropic';
export async function POST(req: Request) { const { messages } = await req.json();
return createUIMessageStreamResponse({ async execute(writer) { // Eigener Text vor dem LLM-Stream writer.write({ type: 'text-delta', textDelta: '## Antwort\n\n' });
const result = streamText({ model: anthropic('claude-sonnet-4-5-20250514'), messages, });
writer.merge(result.toUIMessageStream()); await result;
// Eigener Text nach dem LLM-Stream writer.write({ type: 'text-delta', textDelta: '\n\n---\nGeneriert mit AI SDK', }); }, });}Mehrere LLM-Calls kombinieren
Abschnitt betitelt „Mehrere LLM-Calls kombinieren“import { createUIMessageStreamResponse, streamText } from 'ai';import { anthropic } from '@ai-sdk/anthropic';
export async function POST(req: Request) { return createUIMessageStreamResponse({ async execute(writer) { // Abschnitt 1: Zusammenfassung writer.write({ type: 'text-delta', textDelta: '## Zusammenfassung\n\n' });
const summary = streamText({ model: anthropic('claude-sonnet-4-5-20250514'), prompt: 'Fasse zusammen: ...', }); writer.merge(summary.toUIMessageStream()); await summary;
// Abschnitt 2: Analyse writer.write({ type: 'text-delta', textDelta: '\n\n## Analyse\n\n' });
const analysis = streamText({ model: anthropic('claude-sonnet-4-5-20250514'), prompt: 'Analysiere: ...', }); writer.merge(analysis.toUIMessageStream()); await analysis;
// Abschluss writer.write({ type: 'text-delta', textDelta: '\n\n---\nFertig.' }); }, });}Text-Part Lifecycle
Abschnitt betitelt „Text-Part Lifecycle“Wenn streamText über writer.merge() eingebunden wird, sendet es automatisch die vollständige Sequenz:
text-start— Oeffnet einen neuen Text-Parttext-delta(n-mal) — Sendet Text-Fragmente inkrementelltext-end— Schliesst den Text-Part ab
Bei manuellen writer.write()-Aufrufen mit text-delta wird der Lifecycle ebenfalls korrekt gehandhabt.
| Stream Part | Properties | Beschreibung |
|---|---|---|
text-start | — | Oeffnet einen neuen Text-Part |
text-delta | textDelta: string | Textfragment, wird an aktuellen Text-Part angehaengt |
text-end | — | Schliesst den aktuellen Text-Part ab |
step-start | messageId, request, warnings | Markiert den Beginn eines neuen Schritts |
step-finish | finishReason, usage, isContinued | Markiert das Ende eines Schritts |
Writer-Methoden
Abschnitt betitelt „Writer-Methoden“| Methode | Beschreibung |
|---|---|
writer.write({ type, ... }) | Schreibt einen einzelnen Stream Part |
writer.merge(stream) | Fuegt einen externen Stream (z.B. result.toUIMessageStream()) ein |
Siehe auch
Abschnitt betitelt „Siehe auch“- Challenge 7.1: Custom Data Parts — Streaming-Grundlagen
- Challenge 8.1: Workflows — Multi-Step Workflows mit kombinierten Streams