Vercel AI SDK mit Claude Code 2026

Das Vercel AI SDK ist das Standard-Framework für KI-Anwendungen in Next.js und Node.js — provider-agnostisch, streaming-first, mit Tool Calling und Structured Outputs. Claude Code generiert vollständige AI-Integrationen: Chat-Apps, RAG-Systeme und Agenten mit dem AI SDK.

1. AI SDK Grundlagen — streamText, generateText, generateObject, Provider Setup

Das Vercel AI SDK (Version 4.x) vereinheitlicht alle großen KI-Provider hinter einer konsistenten API. Claude Code kennt das SDK in- und auswendig: Es generiert sofort produktionsreife Integrationen, wählt die richtigen Funktionen für den Use-Case und konfiguriert Provider korrekt — inklusive Error Handling und TypeScript-Typen.

generateText()Einmalige Textantwort, kein Streaming
streamText()Token-für-Token Streaming Response
generateObject()Typsicheres JSON via Zod-Schema
streamObject()Partial JSON streaming in Echtzeit

SETUP Installation & Provider-Konfiguration

Claude Code beginnt jede AI-SDK-Integration mit dem korrekten Package-Setup und der Provider-Konfiguration:

# Installation: Core SDK + Provider-Packages npm install ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google @ai-sdk/groq zod # TypeScript-Typen sind automatisch enthalten # Node.js 18+ oder Edge Runtime erforderlich

CORE generateText() — Einfache Textgenerierung

Die grundlegendste Funktion: Eine Anfrage, eine vollständige Antwort. Claude Code nutzt generateText() für Batch-Verarbeitung, Background-Jobs und alle Use-Cases ohne UI-Streaming.

import { generateText } from 'ai'; import { anthropic } from '@ai-sdk/anthropic'; // Einfachste Form: Text generieren mit Claude const { text, usage, finishReason } = await generateText({ model: anthropic('claude-3-5-sonnet-20241022'), prompt: 'Erkläre den Unterschied zwischen useEffect und useLayoutEffect in React.', }); console.log(text); // usage.promptTokens, usage.completionTokens, usage.totalTokens console.log(`Tokens: ${usage.totalTokens}`); // Mit System-Prompt und strukturierter Nachricht const { text: codeReview } = await generateText({ model: anthropic('claude-3-5-sonnet-20241022'), system: 'Du bist ein erfahrener TypeScript-Entwickler. Gib präzises, konstruktives Feedback.', messages: [ { role: 'user', content: 'Review diesen Code: const x = data?.items.map(i => i.id)' } ], maxTokens: 512, temperature: 0.3, });

STREAM streamText() — Streaming-Grundlagen

streamText() gibt einen ReadableStream zurück. Claude Code verwendet es direkt in API-Routes und kann verschiedene Ausgabeformate aus demselben Stream ableiten:

import { streamText } from 'ai'; import { openai } from '@ai-sdk/openai'; const result = await streamText({ model: openai('gpt-4o'), prompt: 'Schreibe eine kurze Geschichte über einen KI-Entwickler.', onChunk({ chunk }) { // Jedes Token einzeln verarbeiten if (chunk.type === 'text-delta') { process.stdout.write(chunk.textDelta); } }, onFinish({ text, usage, finishReason }) { console.log(`\nFertig. Tokens: ${usage.totalTokens}`); }, }); // Stream in verschiedene Formate konvertieren const textStream = result.textStream; // AsyncIterable<string> const fullText = await result.text; // Promise<string> — wartet auf Ende const dataStream = result.toDataStream(); // Für useChat Hook const textResponse = result.toTextStreamResponse(); // Native Response
Claude Code Workflow-Tipp: Beschreibe deinen Use-Case ("Chat-UI mit Streaming" vs. "Batch-Verarbeitung von 100 Dokumenten") — Claude Code wählt automatisch zwischen streamText() und generateText() und fügt das korrekte Error Handling hinzu.
FunktionRückgabeBest für
generateText(){ text, usage, finishReason }Batch, Background, Scripts
streamText()StreamTextResult mit textStreamChat-UIs, Echtzeit-Output
generateObject(){ object: T }Strukturierte Extraktion
streamObject()partialObjectStreamLive-Form-Befüllung

2. Streaming in Next.js — useChat Hook, StreamingTextResponse, RSC mit AI SDK

Das AI SDK ist für Next.js App Router optimiert. Der useChat-Hook übernimmt State-Management, Message-History und Streaming komplett — Claude Code generiert vollständige Chat-Komponenten, die sofort funktionieren.

NEXT.JS API Route mit streamText()

Die Server-Seite: Eine Next.js API Route streamt Tokens direkt an den Client. Claude Code erstellt diese Route mit korrektem Edge-Runtime-Flag und CORS-Handling:

// app/api/chat/route.ts import { streamText, convertToCoreMessages } from 'ai'; import { anthropic } from '@ai-sdk/anthropic'; export const runtime = 'edge'; // Optional: Edge Runtime für niedrigere Latenz export async function POST(req: Request) { const { messages } = await req.json(); const result = await streamText({ model: anthropic('claude-3-5-sonnet-20241022'), system: 'Du bist ein hilfreicher KI-Assistent für Entwickler. Antworte auf Deutsch.', messages: convertToCoreMessages(messages), // UI Messages → Core Messages maxTokens: 2048, temperature: 0.7, }); // toDataStreamResponse() sendet im AI SDK Data Stream Protocol // Kompatibel mit useChat Hook out-of-the-box return result.toDataStreamResponse(); }

HOOK useChat — Frontend Chat-Komponente

Auf der Client-Seite übernimmt useChat alles: HTTP-Requests, Streaming, Message-State, Loading-States und Error Handling. Claude Code generiert vollständige, produktionsreife Chat-UIs:

// app/chat/page.tsx — Client Component 'use client'; import { useChat } from 'ai/react'; import { useRef, useEffect } from 'react'; export default function ChatPage() { const { messages, // Message[] — vollständige Chat-History input, // string — aktueller Input-Wert handleInputChange, // onChange Handler handleSubmit, // onSubmit Handler isLoading, // boolean — wartet auf Response error, // Error | undefined stop, // Stream abbrechen reload, // Letzte Nachricht neu generieren } = useChat({ api: '/api/chat', initialMessages: [ { id: '1', role: 'assistant', content: 'Hallo! Wie kann ich dir helfen?' } ], onError: (error) => console.error('Chat Error:', error), onFinish: (message) => console.log('Fertig:', message.content.length, 'Zeichen'), }); const messagesEndRef = useRef<HTMLDivElement>(null); useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); return ( <div className="flex flex-col h-screen max-w-2xl mx-auto"> <div className="flex-1 overflow-y-auto p-4 space-y-4"> {messages.map((message) => ( <div key={message.id} className={message.role === 'user' ? 'text-right' : 'text-left'}> <div className={`inline-block p-3 rounded-lg max-w-[80%] ${ message.role === 'user' ? 'bg-indigo-600 text-white' : 'bg-gray-100 text-gray-900' }`}> {message.content} </div> </div> ))} {isLoading && ( <div className="text-gray-400 animate-pulse">KI denkt nach...</div> )} <div ref={messagesEndRef} /> </div> <form onSubmit={handleSubmit} className="p-4 border-t flex gap-2"> <input value={input} onChange={handleInputChange} placeholder="Nachricht eingeben..." className="flex-1 border rounded-lg px-4 py-2 focus:outline-none" disabled={isLoading} /> {isLoading ? <button type="button" onClick={stop}>Stop</button> : <button type="submit" disabled={!input.trim()}>Senden</button> } </form> </div> ); }

RSC React Server Components mit AI SDK

Für Server Components ohne Client-State: Das AI SDK unterstützt direktes Streaming aus RSCs über createStreamableUI() und createAI():

// app/report/page.tsx — Server Component (RSC) import { streamText } from 'ai'; import { anthropic } from '@ai-sdk/anthropic'; // Direkt in Server Component — kein useChat nötig export default async function ReportPage({ searchParams }: { searchParams: { topic?: string } }) { const topic = searchParams.topic || 'KI-Trends 2026'; const { text } = await generateText({ model: anthropic('claude-3-5-haiku-20241022'), prompt: `Erstelle einen kompakten Report über: ${topic}`, maxTokens: 800, }); return ( <article className="prose max-w-2xl mx-auto py-8"> <h1>{topic}</h1> <div dangerouslySetInnerHTML={{ __html: text }} /> </article> ); }

3. Tool Calling / Function Calling — tool(), CoreTool, ToolResult, multi-step

Tool Calling ist der Kern moderner KI-Agenten: Das Modell entscheidet selbstständig, welche Tools es wann aufruft. Das Vercel AI SDK macht dies typesafe mit Zod-Schemas. Claude Code generiert vollständige Tool-Definitionen inklusive Input-Validierung, Error Handling und multi-step Agenten-Loops.

TOOL Tool-Definition mit tool() und Zod

Jedes Tool besteht aus Beschreibung, Input-Schema (Zod) und Execute-Funktion. Claude Code erstellt typesafe Tools mit vollständigen JSDoc-Kommentaren:

import { generateText, tool } from 'ai'; import { anthropic } from '@ai-sdk/anthropic'; import { z } from 'zod'; // Tool-Definitionen — typesafe mit Zod const tools = { getWeather: tool({ description: 'Aktuelles Wetter für eine Stadt abrufen', parameters: z.object({ city: z.string().describe('Stadtname auf Deutsch'), country: z.string().optional().describe('ISO-Ländercode, z.B. DE'), }), execute: async ({ city, country }) => { // Echter API-Call zu einem Wetter-Service const location = country ? `${city},${country}` : city; const response = await fetch( `https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41¤t=temperature_2m,weathercode` ); const data = await response.json(); return { city: location, temperature: data.current.temperature_2m, unit: '°C', condition: data.current.weathercode < 3 ? 'Sonnig' : 'Bewölkt', }; }, }), searchDatabase: tool({ description: 'Produkte in der Datenbank suchen', parameters: z.object({ query: z.string().describe('Suchbegriff'), limit: z.number().min(1).max(20).default(5), category: z.enum(['electronics', 'clothing', 'food']).optional(), }), execute: async ({ query, limit, category }) => { // Datenbankabfrage (Prisma, Supabase, etc.) const results = await db.product.findMany({ where: { name: { contains: query, mode: 'insensitive' }, ...(category && { category }), }, take: limit, select: { id: true, name: true, price: true, stock: true }, }); return { results, total: results.length }; }, }), };

MULTI-STEP maxSteps — Agenten-Loop mit mehreren Tool-Calls

Mit maxSteps läuft das Modell automatisch mehrere Runden: Tool aufrufen → Ergebnis verarbeiten → nächstes Tool → finale Antwort. Claude Code baut vollständige Agenten-Loops:

import { generateText, tool } from 'ai'; import { anthropic } from '@ai-sdk/anthropic'; import { z } from 'zod'; const { text, steps, toolCalls, toolResults } = await generateText({ model: anthropic('claude-3-5-sonnet-20241022'), tools, maxSteps: 5, // Max 5 Tool-Call-Runden system: 'Du bist ein hilfreicher Assistent mit Zugriff auf Wetter und Datenbank.', prompt: 'Wie ist das Wetter in Berlin heute und zeige mir 3 Winterjacken aus dem Shop?', onStepFinish({ text, toolCalls, toolResults, finishReason, usage }) { // Jeden Schritt beobachten console.log(`Step: ${finishReason}, Tools: ${toolCalls.length}`); toolCalls.forEach(tc => { console.log(` → ${tc.toolName}(${JSON.stringify(tc.args)})`); }); }, }); // steps[] enthält jeden einzelnen Schritt mit allen Details console.log(`Gesamtschritte: ${steps.length}`); console.log(`Alle Tool-Calls: ${toolCalls.length}`); console.log(`Finale Antwort: ${text}`); // Tool-Calls inspizieren for (const step of steps) { if (step.stepType === 'tool-result') { console.log(`Tool: ${step.toolName} → ${JSON.stringify(step.result)}`); } }

STREAMING streamText mit Tools — Live Tool-Call Feedback

Tool Calling funktioniert auch mit streamText(). Der Stream enthält Tool-Call-Events neben Text-Chunks — perfekt für Agenten-UIs mit Live-Feedback:

// API Route mit streamText + Tools import { streamText, tool, convertToCoreMessages } from 'ai'; import { z } from 'zod'; export async function POST(req: Request) { const { messages } = await req.json(); const result = await streamText({ model: anthropic('claude-3-5-sonnet-20241022'), messages: convertToCoreMessages(messages), maxSteps: 3, tools: { calculator: tool({ description: 'Mathematische Berechnungen durchführen', parameters: z.object({ expression: z.string().describe('Mathematischer Ausdruck, z.B. "2 * (3 + 4)"'), }), execute: async ({ expression }) => { // Sicheres Evaluieren (in Produktion: math.js oder ähnliches nutzen) try { const result = eval(expression.replace(/[^0-9+\-*/.() ]/g, '')); return { result, expression }; } catch { return { error: 'Ungültiger Ausdruck', expression }; } }, }), }, }); return result.toDataStreamResponse({ // Tool-Calls im Data Stream inkludieren sendUsage: true, }); }
Wichtig bei Tool Calling: Setze immer ein vernünftiges maxSteps-Limit (5-10). Ohne Limit kann ein Modell theoretisch endlos Tool-Calls machen. Claude Code fügt diesen Guard automatisch ein und warnt, wenn er fehlt.

4. Structured Outputs — generateObject() mit Zod-Schema, partialObjectStream

generateObject() ist der typsichere Weg, strukturierte Daten aus KI-Modellen zu extrahieren. Das Modell liefert garantiert valides JSON, das dem Zod-Schema entspricht — kein manuelles Parsing, keine Fehler durch Halluzinationen außerhalb der Struktur. Claude Code nutzt dies für Daten-Extraktion, Content-Generierung und API-Backends.

SCHEMA generateObject() — Typsicheres JSON aus dem Modell

Das Zod-Schema definiert exakt, was das Modell zurückgeben soll. Claude Code erstellt komplexe verschachtelte Schemas und wählt den richtigen Output-Mode:

import { generateObject } from 'ai'; import { anthropic } from '@ai-sdk/anthropic'; import { z } from 'zod'; // Schema für Produktbeschreibungs-Extraktion const ProductSchema = z.object({ name: z.string().describe('Produktname'), category: z.enum(['electronics', 'software', 'service']), targetAudience: z.array(z.string()).describe('Zielgruppen als Liste'), features: z.array(z.object({ title: z.string(), description: z.string(), importance: z.enum(['high', 'medium', 'low']), })).min(3).max(8), pricing: z.object({ model: z.enum(['one-time', 'subscription', 'usage-based']), startingPrice: z.number().optional(), currency: z.string().default('EUR'), }), seoKeywords: z.array(z.string()).max(10), }); type Product = z.infer<typeof ProductSchema>; const { object: product } = await generateObject({ model: anthropic('claude-3-5-sonnet-20241022'), schema: ProductSchema, prompt: `Analysiere dieses Produkt und extrahiere alle Informationen: "Claude Code ist Anthropics offizielles CLI für Claude, das KI-Entwicklern hilft, Code zu schreiben, zu debuggen und zu deployen. Es integriert sich direkt in das Terminal und unterstützt alle gängigen Editoren."`, }); // TypeScript kennt den exakten Typ dank Zod-Inferenz console.log(product.name); // string console.log(product.features[0]); // { title: string, description: string, importance: ... } console.log(product.pricing.model); // 'one-time' | 'subscription' | 'usage-based'

ARRAY generateObject mit Array-Output

Für Listen strukturierter Objekte: output: 'array' generiert ein Array mit Items, die alle dem Schema entsprechen — ideal für Batch-Generierung:

import { generateObject } from 'ai'; import { z } from 'zod'; const { object: blogIdeas } = await generateObject({ model: anthropic('claude-3-5-haiku-20241022'), output: 'array', // Array statt einzelnes Objekt schema: z.object({ title: z.string().describe('SEO-optimierter Blog-Titel'), slug: z.string().describe('URL-freundlicher Slug ohne Sonderzeichen'), keywords: z.array(z.string()).max(5), estimatedReadTime: z.number().describe('Geschätzte Lesezeit in Minuten'), outline: z.array(z.string()).describe('H2-Abschnitte als Liste'), }), prompt: 'Generiere 5 Blog-Post-Ideen über Vercel AI SDK und Next.js 15 für deutschsprachige Entwickler.', }); // blogIdeas ist ein typisiertes Array blogIdeas.forEach((idea, i) => { console.log(`${i + 1}. ${idea.title} (${idea.estimatedReadTime} min)`); console.log(` URL: /blog/${idea.slug}`); });

PARTIAL streamObject() — partialObjectStream für Live-Updates

streamObject() gibt ein partialObjectStream zurück: Jeder Chunk enthält den bisherigen validen Teilzustand des Objekts — perfekt für Live-Form-Befüllung und Progressive Disclosure in UIs:

import { streamObject } from 'ai'; import { anthropic } from '@ai-sdk/anthropic'; import { z } from 'zod'; const ResumeSchema = z.object({ name: z.string(), summary: z.string(), skills: z.array(z.string()), experience: z.array(z.object({ company: z.string(), role: z.string(), duration: z.string(), achievements: z.array(z.string()), })), }); const { partialObjectStream, object: finalResume } = await streamObject({ model: anthropic('claude-3-5-sonnet-20241022'), schema: ResumeSchema, prompt: 'Erstelle einen Lebenslauf für eine Senior TypeScript-Entwicklerin mit 8 Jahren Erfahrung.', }); // Jeder Partial-Update enthält den aktuellen Zustand for await (const partial of partialObjectStream) { // partial.name kann undefined sein bevor es generiert wird if (partial.name) console.log(`Name: ${partial.name}`); if (partial.skills?.length) { console.log(`Skills bisher: ${partial.skills.join(', ')}`); } // In einer UI: React State aktualisieren → sofortiges Feedback updateUIState(partial); } // Am Ende: vollständiges, validiertes Objekt const resume = await finalResume; console.log(`Komplett: ${resume.name}, ${resume.experience.length} Jobs`);

5. Multi-Provider — OpenAI, Anthropic (Claude), Google Gemini, Groq wechseln

Der größte Vorteil des Vercel AI SDK: Provider-Agnostizität. Jeder Provider wird hinter derselben API abstrahiert. Claude Code kann Anwendungen schreiben, die Provider dynamisch wechseln — nach Kosten, Geschwindigkeit, Verfügbarkeit oder Fähigkeiten.

SETUP Alle Provider konfigurieren

Jeder Provider braucht nur ein Package und einen API-Key in der Umgebungsvariable. Claude Code konfiguriert alle Provider korrekt und fügt TypeScript-Typen hinzu:

// lib/ai-providers.ts — Zentrale Provider-Konfiguration import { openai, createOpenAI } from '@ai-sdk/openai'; import { anthropic, createAnthropic } from '@ai-sdk/anthropic'; import { google, createGoogleGenerativeAI } from '@ai-sdk/google'; import { createGroq } from '@ai-sdk/groq'; import { createMistral } from '@ai-sdk/mistral'; // Standard-Instanzen (lesen API-Keys aus Env-Variablen) // OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, GROQ_API_KEY // Custom Instanzen mit Optionen const customOpenAI = createOpenAI({ apiKey: process.env.OPENAI_API_KEY, organization: process.env.OPENAI_ORG_ID, baseURL: 'https://api.openai.com/v1', // Oder Azure OpenAI Endpoint }); const customAnthropic = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY, // headers: { 'anthropic-beta': 'prompt-caching-2024-07-31' }, // Beta Features }); const groq = createGroq({ apiKey: process.env.GROQ_API_KEY, // Groq ist extrem schnell — ideal für Low-Latency Use-Cases }); // Provider-Modell-Map für einfaches Wechseln export const models = { // Anthropic Claude — beste Reasoning + Code-Qualität claudeSonnet: anthropic('claude-3-5-sonnet-20241022'), claudeHaiku: anthropic('claude-3-5-haiku-20241022'), claudeOpus: anthropic('claude-opus-4-5'), // OpenAI — breite Tool-Unterstützung, Vision gpt4o: openai('gpt-4o'), gpt4oMini: openai('gpt-4o-mini'), o3: openai('o3'), // Google Gemini — großes Context Window, Multimodal gemini25Pro: google('gemini-2.5-pro-preview-05-06'), gemini20Flash: google('gemini-2.0-flash'), // Groq — Ultra-low Latency (Llama, Mixtral) llama3: groq('llama3-70b-8192'), mixtral: groq('mixtral-8x7b-32768'), } as const;

ROUTING Dynamisches Provider-Routing nach Use-Case

Claude Code baut intelligente Router-Funktionen, die den optimalen Provider für jeden Use-Case wählen — nach Kosten, Latenz und Fähigkeiten:

// lib/model-router.ts — Intelligentes Provider-Routing import { models } from './ai-providers'; import { LanguageModelV1 } from 'ai'; type UseCase = | 'chat' // Allgemeiner Chat | 'code' // Code-Generierung und Review | 'extraction' // Daten-Extraktion (schnell + günstig) | 'reasoning' // Komplexe Reasoning-Aufgaben | 'realtime' // Ultra-low Latency | 'longContext'; // Sehr lange Dokumente export function selectModel(useCase: UseCase): LanguageModelV1 { const modelMap: Record<UseCase, LanguageModelV1> = { chat: models.claudeHaiku, // Schnell + günstig für Standard-Chat code: models.claudeSonnet, // Claude = beste Code-Qualität extraction: models.gpt4oMini, // Günstig für strukturierte Extraktion reasoning: models.claudeOpus, // Beste Reasoning-Fähigkeiten realtime: models.llama3, // Groq = schnellste Inferenz longContext: models.gemini25Pro, // Gemini = 1M Token Context Window }; return modelMap[useCase]; } // Fallback-Kette bei Provider-Ausfall export async function generateWithFallback( prompt: string, primaryUseCase: UseCase, ) { const fallbackChain: LanguageModelV1[] = [ selectModel(primaryUseCase), models.gpt4o, // Erster Fallback models.gemini20Flash, // Zweiter Fallback ]; for (const model of fallbackChain) { try { const { text } = await generateText({ model, prompt, maxRetries: 1 }); return text; } catch (error) { console.warn(`Provider fehlgeschlagen, nächster Fallback...`, error); } } throw new Error('Alle Provider fehlgeschlagen'); }
ProviderStärkenPackageEnv-Key
Anthropic ClaudeCode, Reasoning, Instruktionen@ai-sdk/anthropicANTHROPIC_API_KEY
OpenAITool Calling, Vision, GPT-4o@ai-sdk/openaiOPENAI_API_KEY
Google Gemini1M Context, Multimodal@ai-sdk/googleGOOGLE_GENERATIVE_AI_API_KEY
GroqUltra-fast Inferenz, Llama@ai-sdk/groqGROQ_API_KEY
MistralEuropäisch, DSGVO-konform@ai-sdk/mistralMISTRAL_API_KEY

6. AI SDK + RAG — embedMany(), cosineSimilarity(), Vektor-Store-Integration

Retrieval-Augmented Generation (RAG) verbindet KI-Modelle mit eigenen Wissensdatenbanken. Das Vercel AI SDK bietet native Embedding-Funktionen — embed() und embedMany() — die sich nahtlos in Vektor-Stores wie Pinecone, Supabase pgvector oder Qdrant integrieren. Claude Code baut vollständige RAG-Pipelines in einem Schritt.

EMBED embedMany() — Dokumente vektorisieren

Der erste Schritt jeder RAG-Pipeline: Dokumente in Vektoren umwandeln. Claude Code generiert Chunking-Strategien und Embedding-Pipelines mit optimalem Batch-Processing:

import { embedMany, embed } from 'ai'; import { openai } from '@ai-sdk/openai'; // Embedding-Modell (1536 Dimensionen für text-embedding-3-small) const embeddingModel = openai.embedding('text-embedding-3-small'); // Alternativ: anthropic.textEmbeddingModel('voyage-3') für Claude-Ökosystem // Dokument-Chunking-Strategie function chunkDocument(text: string, chunkSize = 512, overlap = 50): string[] { const words = text.split(' '); const chunks: string[] = []; for (let i = 0; i < words.length; i += chunkSize - overlap) { const chunk = words.slice(i, i + chunkSize).join(' '); if (chunk.trim()) chunks.push(chunk); } return chunks; } // Batch-Embedding für ein gesamtes Dokument async function indexDocument(documentText: string, documentId: string) { const chunks = chunkDocument(documentText); // embedMany() vektorisiert alle Chunks in einem API-Call const { embeddings, usage } = await embedMany({ model: embeddingModel, values: chunks, }); console.log(`${chunks.length} Chunks, ${usage.tokens} Tokens verbraucht`); // In Vektor-Store speichern (Supabase pgvector Beispiel) const records = chunks.map((chunk, i) => ({ document_id: documentId, chunk_index: i, content: chunk, embedding: embeddings[i], // number[] — Vektor metadata: { charCount: chunk.length, wordCount: chunk.split(' ').length, }, })); await supabase .from('document_chunks') .insert(records); return { chunks: chunks.length, tokens: usage.tokens }; }

SEARCH cosineSimilarity() — Semantische Suche

Das AI SDK exportiert cosineSimilarity() für die Ähnlichkeitsberechnung. Claude Code implementiert die vollständige Suche inklusive Re-Ranking und Score-Threshold:

import { embed, cosineSimilarity } from 'ai'; import { openai } from '@ai-sdk/openai'; const embeddingModel = openai.embedding('text-embedding-3-small'); // Semantische Suche ohne Datenbank — direkt mit cosineSimilarity() async function semanticSearch( query: string, documents: Array<{ id: string; text: string }>, topK = 5, threshold = 0.7, ) { // Query vektorisieren const { embedding: queryEmbedding } = await embed({ model: embeddingModel, value: query, }); // Alle Dokumente vektorisieren und Ähnlichkeit berechnen const { embeddings } = await embedMany({ model: embeddingModel, values: documents.map(d => d.text), }); // cosineSimilarity() aus dem AI SDK nutzen const scored = documents.map((doc, i) => ({ ...doc, score: cosineSimilarity(queryEmbedding, embeddings[i]), })); // Nach Score sortieren, Threshold anwenden, Top-K nehmen return scored .filter(d => d.score >= threshold) .sort((a, b) => b.score - a.score) .slice(0, topK); } // Mit pgvector (Supabase) — effizient für große Datensätze async function searchWithPgVector(query: string, topK = 5) { const { embedding } = await embed({ model: embeddingModel, value: query, }); // Supabase RPC für Vektor-Suche (cosine distance) const { data } = await supabase.rpc('match_documents', { query_embedding: embedding, // number[] match_threshold: 0.7, match_count: topK, }); return data; // Array von Chunks mit similarity score }

RAG Vollständige RAG-Pipeline mit generateText()

Die komplette RAG-Pipeline: Suche → Context zusammenstellen → Antwort generieren. Claude Code erstellt dies mit Prompt-Engineering für optimale Antwortqualität:

import { embed, generateText, streamText } from 'ai'; import { anthropic } from '@ai-sdk/anthropic'; import { openai } from '@ai-sdk/openai'; interface RAGOptions { query: string; topK?: number; includeScores?: boolean; } async function ragQuery({ query, topK = 5, includeScores = false }: RAGOptions) { // Step 1: Query Embedding const { embedding } = await embed({ model: openai.embedding('text-embedding-3-small'), value: query, }); // Step 2: Semantische Suche im Vektor-Store const relevantChunks = await searchWithPgVector(embedding, topK); // Step 3: Context aus gefundenen Chunks zusammenstellen const contextText = relevantChunks .map((chunk, i) => `[Quelle ${i + 1}] ${chunk.content}`) .join('\n\n'); // Step 4: RAG-Prompt erstellen const ragPrompt = `Du bist ein hilfreicher Assistent. Beantworte die Frage ausschließlich basierend auf den folgenden Quellen. Wenn die Antwort nicht in den Quellen enthalten ist, sage das ehrlich. QUELLEN: ${contextText} FRAGE: ${query} ANTWORT:`; // Step 5: Antwort generieren mit Claude const result = await streamText({ model: anthropic('claude-3-5-sonnet-20241022'), prompt: ragPrompt, maxTokens: 1024, }); return { stream: result.textStream, sources: includeScores ? relevantChunks : relevantChunks.map(c => c.id), chunksUsed: relevantChunks.length, }; } // API Route für RAG Chat export async function POST(req: Request) { const { query } = await req.json(); const { stream } = await ragQuery({ query, topK: 5 }); return new Response(stream); }
RAG-Performance-Tipp: Claude Code empfiehlt Hybrid-Search (Vektor + Keyword) für beste Ergebnisse. embedMany() ist batched und kosteneffizient — nie einzeln pro Chunk embedden. Für Produktions-RAG: Pinecone oder Supabase pgvector mit HNSW-Index für O(log n) Suche.

ADVANCED RAG mit Tool Calling — Agentisches RAG

Die nächste Stufe: Das Modell entscheidet selbst, wann es suchen muss und formuliert optimierte Such-Queries. Claude Code baut Self-Querying RAG-Agenten:

import { generateText, tool } from 'ai'; import { anthropic } from '@ai-sdk/anthropic'; import { z } from 'zod'; // Agentisches RAG: Modell wählt selbst Such-Strategie const { text, steps } = await generateText({ model: anthropic('claude-3-5-sonnet-20241022'), system: `Du bist ein Research-Assistent mit Zugriff auf eine Wissensdatenbank. Nutze das search_knowledge_base Tool um relevante Informationen zu finden. Suche mehrmals mit verschiedenen Queries wenn nötig. Synthetisiere dann eine umfassende Antwort.`, prompt: 'Was sind die Vor- und Nachteile von Vercel AI SDK im Vergleich zu LangChain.js?', maxSteps: 4, tools: { searchKnowledgeBase: tool({ description: 'Semantische Suche in der Wissensdatenbank', parameters: z.object({ query: z.string().describe('Optimierter Such-Query für semantische Suche'), filter: z.object({ category: z.enum(['docs', 'blog', 'tutorials']).optional(), dateAfter: z.string().optional(), }).optional(), }), execute: async ({ query, filter }) => { // Embedding + Vektor-Suche const results = await searchKnowledgeBase(query, filter); return { results: results.map(r => ({ content: r.content, source: r.url, score: r.similarity, })), query, }; }, }), }, });

AI-Integration-Modul im Kurs

Im Claude Code Mastery Kurs: vollständiges AI-Integration-Modul — Vercel AI SDK, LangChain.js, OpenAI SDK und Anthropic SDK für moderne KI-Anwendungen. Hands-on-Projekte: Chat-App, RAG-System, Tool-Calling-Agent, Multi-Provider-Routing.

14 Tage kostenlos testen →