Custom Data Parts streamen
Überblick
Abschnitt betitelt „Überblick“Data Parts transportieren strukturierte Daten neben dem LLM-Text im selben Stream. Statt Fortschritt, Status oder Quellen in den Text einzubetten, sendest Du typisierte JSON-Objekte, die das Frontend direkt rendern kann.
Es gibt zwei Kategorien: Persistent Data Parts werden in message.parts gespeichert und bleiben Teil der Message-Historie. Transient Data Parts sind nur waehrend des Streams über den onData-Callback verfügbar und werden nicht persistiert.
Auf der Server-Seite nutzt Du createUIMessageStreamResponse (oder createUIMessageStream) mit einem execute-Callback. Der writer bietet eine write()-Methode für Custom Data Parts und writer.merge() fuegt den LLM-Stream ein.
Server-Beispiel
Abschnitt betitelt „Server-Beispiel“import { createUIMessageStreamResponse, streamText } from 'ai';import { anthropic } from '@ai-sdk/anthropic';
export async function POST(req: Request) { const { messages } = await req.json();
return createUIMessageStreamResponse({ execute(writer) { // Persistent Data Part (wird in message.parts gespeichert) writer.write({ type: 'data-weather', data: { city: 'Berlin', status: 'loading' }, });
const result = streamText({ model: anthropic('claude-sonnet-4-5-20250514'), messages, onFinish() { writer.write({ type: 'data-weather', data: { city: 'Berlin', status: 'success', temp: 22 }, }); }, });
writer.merge(result.toUIMessageStream()); }, });}Typsichere Data Parts
Abschnitt betitelt „Typsichere Data Parts“import type { UIMessage } from 'ai';
// Generics definieren die erlaubten Data Part Typentype MyUIMessage = UIMessage< never, // Metadata-Typ { weather: { city: string; status: 'loading' | 'success'; temp?: number }; notification: { message: string; level: 'info' | 'warning' }; }>;| Methode | Beschreibung |
|---|---|
createUIMessageStreamResponse({ execute }) | Erstellt eine Response mit UI Message Stream |
createUIMessageStream({ execute }) | Erstellt einen rohen UI Message Stream |
writer.write({ type: 'data-${NAME}', data }) | Schreibt ein Persistent Data Part |
writer.write({ type: 'data-${NAME}', data, id }) | Schreibt ein Data Part mit ID (für Reconciliation) |
writer.write({ ..., transient: true }) | Schreibt ein Transient Data Part (nicht persistiert) |
writer.merge(result.toUIMessageStream()) | Fuegt den LLM-Stream in den Writer ein |
Siehe auch
Abschnitt betitelt „Siehe auch“- Challenge 7.1: Custom Data Parts — Hands-on mit Data Parts
- Challenge 8.2: Streaming Custom Data to Frontend — Data Parts in Workflows
- Custom Data Parts im Frontend — Frontend-Konsum