Challenge 9.4: Research Workflow
Wie baust Du ein End-to-End AI-System das selbststaendig recherchiert, zusammenfasst und einen qualitaetsgesicherten Bericht erstellt — und dabei Guardrails, Model Routing und alle bisher gelernten Konzepte nutzt?
OVERVIEW
Abschnitt betitelt „OVERVIEW“Drei Phasen: Research (Agent Loop mit Tools und Break Conditions), Processing (Workflow mit Context Engineering) und Quality (Guardrails und Model Router). Konzepte aus 8 verschiedenen Levels kommen zusammen.
Ohne Orchestrierung: Einzelne Bausteine die nicht zusammenspielen. Du hast Guardrails, aber sie sind nicht in die Pipeline integriert. Du hast einen Model Router, aber er wird nicht genutzt. Du hast Workflows, aber ohne Qualitaetssicherung. Das Ergebnis: ein fragiles System das in Production versagt.
Mit Orchestrierung: Eine durchgaengige Pipeline in der jede Phase auf die vorherige aufbaut. Research sammelt Daten mit Safeguards. Processing strukturiert die Ergebnisse mit Context Engineering. Quality sichert Guardrails und optimiert Kosten mit Model Routing. Das Ergebnis: ein Production-Ready System.
WALKTHROUGH
Abschnitt betitelt „WALKTHROUGH“Schicht 1: Die Pipeline-Architektur
Abschnitt betitelt „Schicht 1: Die Pipeline-Architektur“Diese Pipeline verbindet Konzepte aus dem gesamten Lernpfad. Hier ist die Übersicht, welches Level wo zum Einsatz kommt:
| Phase | Konzept | Level | Funktion |
|---|---|---|---|
| Research | Tool Calling | 3.1 | search-Tool für Datensammlung |
| Research | Custom Loop | 8.3 | Agent entscheidet selbst wann genug recherchiert ist |
| Research | Break Conditions | 8.4 | Max Iterations, Timeout, Cost Guard |
| Processing | Workflow | 8.1 | Sequentielle Steps: Zusammenfassen, Strukturieren |
| Processing | Context Engineering | 5.x | XML-strukturierte Prompts für praezise Outputs |
| Processing | Structured Output | 1.5 | Zod Schema für typisierte Metadaten |
| Quality | Guardrails | 9.1 | Input/Output-Validierung |
| Quality | Model Router | 9.2 | Optimales Modell pro Phase |
| Quality | Usage Tracking | 2.2 | Token-Kosten über die gesamte Pipeline |
Schicht 2: Research-Phase
Abschnitt betitelt „Schicht 2: Research-Phase“Die Research-Phase ist ein Custom Agent Loop mit Tools — das Muster aus Level 8.3 und 8.4:
import { generateText, tool } from 'ai';import { anthropic } from '@ai-sdk/anthropic';import { google } from '@ai-sdk/google';import { z } from 'zod';
// search-Tool — simuliert Websuche (in Production: echte API)const searchTool = tool({ description: 'Suche nach Informationen zu einem Thema', parameters: z.object({ query: z.string().describe('Der Suchbegriff'), }), execute: async ({ query }) => { console.log(` Suche: "${query}"`); // In Production: Web Search API, Datenbank, etc. return `Ergebnisse für "${query}": [Hier würden echte Suchergebnisse stehen]`; },});
async function researchPhase(topic: string) { const LIMITS = { maxIterations: 5, timeoutMs: 30_000, maxTokens: 5_000 }; let totalTokens = 0; let iterations = 0; let breakReason = 'complete'; let researchResult = 'Keine Ergebnisse gefunden.';
const messages: any[] = [ // ← any[] weil AI SDK Messages verschiedene Content-Typen haben { role: 'user', content: `Recherchiere gruendlich zum Thema: ${topic}.Nutze das search-Tool um Informationen zu sammeln.Wenn Du genug Informationen hast, fasse die Ergebnisse zusammen.`, }, ];
const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), LIMITS.timeoutMs);
try { while (true) { // Break Condition: Max Iterations if (iterations >= LIMITS.maxIterations) { breakReason = 'max-iterations'; break; } // Break Condition: Cost Guard if (totalTokens >= LIMITS.maxTokens) { breakReason = 'cost-limit'; break; }
iterations++; const result = await generateText({ model: google('gemini-2.5-flash'), // ← Guenstiges Modell für Research tools: { search: searchTool }, messages, abortSignal: controller.signal, });
totalTokens += result.usage.totalTokens; messages.push(...result.response.messages);
// Break Condition: LLM ist fertig (kein Tool Call mehr) if (result.finishReason === 'stop') { // result.text der letzten Iteration enthaelt den finalen Text — // sicherer als lastAssistant.content, das bei Tool-Calls ein Array ist researchResult = result.text || 'Keine Ergebnisse gefunden.'; break; } } } catch (error) { if (error.name === 'AbortError') { breakReason = 'timeout'; } else { throw error; } } finally { clearTimeout(timeout); }
console.log(`Research: ${iterations} Iterationen, ${totalTokens} Tokens, Grund: ${breakReason}`); return { result: researchResult, iterations, totalTokens, breakReason };}Drei Break Conditions schuetzen den Loop: Max Iterations (5), Timeout (30s), Cost Guard (5.000 Tokens). Das search-Tool wird vom LLM autonom genutzt — es entscheidet, welche Suchbegriffe es verwendet. Wenn das LLM finishReason: 'stop' zurueckgibt, hat es genug recherchiert.
Schicht 3: Processing-Phase
Abschnitt betitelt „Schicht 3: Processing-Phase“Die Processing-Phase nutzt den Workflow-Pattern aus Level 8.1 mit Context Engineering aus Level 5:
import { generateText, Output } from 'ai';import { anthropic } from '@ai-sdk/anthropic';import { z } from 'zod';
const ReportSchema = z.object({ title: z.string(), summary: z.string(), keyFindings: z.array(z.string()).min(3).max(7), conclusion: z.string(),});
async function processingPhase(researchResult: string, topic: string) { // Step 1: Zusammenfassen (Context Engineering — XML-strukturierter Prompt) const summary = await generateText({ model: anthropic('claude-sonnet-4-5-20250514'), system: `<role>Du bist ein Research-Analyst.</role><task>Fasse die Recherche-Ergebnisse in 5-7 Kernaussagen zusammen.</task><rules>- Jede Aussage in maximal 2 Saetzen- Nur Fakten, keine Spekulationen- Wenn Informationen fehlen, sage es explizit</rules>`, prompt: `<topic>${topic}</topic>\n<research>\n${researchResult}\n</research>`, });
console.log(`Zusammenfassung: ${summary.usage.totalTokens} Tokens`);
// Step 2: Strukturieren (Structured Output — Zod Schema) const structured = await generateText({ model: anthropic('claude-sonnet-4-5-20250514'), system: `Erstelle einen strukturierten Report aus der folgenden Zusammenfassung.`, prompt: summary.text, output: Output.object({ schema: ReportSchema }), });
console.log(`Strukturierung: ${structured.usage.totalTokens} Tokens`);
return { report: structured.output, totalTokens: summary.usage.totalTokens + structured.usage.totalTokens, };}Zwei sequentielle Steps: Erst zusammenfassen mit XML-strukturiertem Prompt (Context Engineering aus Level 5), dann in ein typisiertes Schema umwandeln (Structured Output aus Level 1.5). Jeder Step hat seinen eigenen System Prompt mit klarer Rolle.
Schicht 4: Quality-Phase
Abschnitt betitelt „Schicht 4: Quality-Phase“Die Quality-Phase wendet Guardrails aus Challenge 9.1 und Model Routing aus Challenge 9.2 an:
import { generateText } from 'ai';import { anthropic } from '@ai-sdk/anthropic';
type Guardrail = (text: string) => { ok: boolean; reason?: string };
// Output-Guardrailsconst notEmpty: Guardrail = (text) => text.length > 0 ? { ok: true } : { ok: false, reason: 'Output is empty' };
const maxLength: Guardrail = (text) => text.length <= 15_000 ? { ok: true } : { ok: false, reason: `Too long: ${text.length}` };
const noHallucination: Guardrail = (text) => { const markers = ['ich bin nicht sicher', 'ich weiss nicht', 'keine informationen']; const hasUncertainty = markers.some(m => text.toLowerCase().includes(m)); if (hasUncertainty) { console.warn('Warnung: Output enthaelt Unsicherheits-Marker'); } return { ok: true }; // Warnen, nicht blocken};
function runGuardrails(text: string, guardrails: Guardrail[]): void { for (const guard of guardrails) { const result = guard(text); if (!result.ok) throw new Error(`Quality check failed: ${result.reason}`); }}
// Vollstaendige Pipelineasync function researchPipeline(topic: string) { console.log(`\n=== Research Pipeline: "${topic}" ===\n`); const pipelineStart = Date.now();
// Phase 1: Research console.log('[Phase 1: Research]'); const research = await researchPhase(topic);
// Phase 2: Processing console.log('\n[Phase 2: Processing]'); const processing = await processingPhase(research.result, topic);
// Phase 3: Quality console.log('\n[Phase 3: Quality]'); const report = processing.report; const reportText = `${report.title}\n\n${report.summary}\n\n${report.keyFindings.join('\n')}\n\n${report.conclusion}`; runGuardrails(reportText, [notEmpty, maxLength, noHallucination]); console.log('Alle Quality-Checks bestanden.');
// Statistiken const totalTokens = research.totalTokens + processing.totalTokens; const durationMs = Date.now() - pipelineStart;
console.log(`\n=== Pipeline abgeschlossen ===`); console.log(`Dauer: ${durationMs}ms`); console.log(`Tokens gesamt: ${totalTokens}`); console.log(`Research-Iterationen: ${research.iterations}`); console.log(`Abbruchgrund: ${research.breakReason}`);
return { report, totalTokens, durationMs, breakReason: research.breakReason };}
// Ausfuehrenconst result = await researchPipeline('Edge Computing Trends 2026');console.log('\n--- Report ---');console.log(`Titel: ${result.report.title}`);console.log(`Zusammenfassung: ${result.report.summary}`);console.log(`Kernaussagen:`);for (const finding of result.report.keyFindings) { console.log(` - ${finding}`);}console.log(`Fazit: ${result.report.conclusion}`);Die Quality-Phase ist die letzte Verteidigungslinie. Guardrails prüfen den finalen Output auf Laenge, Inhalt und Qualität. Die gesamte Pipeline trackt Tokens und Dauer — wichtig für Production Monitoring.
Aufgabe: Baue eine Mini Research Pipeline: Suche, Zusammenfassung, Formatierung mit Guardrails.
Erstelle research-pipeline.ts und fuehre aus mit npx tsx research-pipeline.ts.
import { generateText, tool } from 'ai';import { anthropic } from '@ai-sdk/anthropic';import { z } from 'zod';
const model = anthropic('claude-sonnet-4-5-20250514');
// TODO 1: Definiere ein search-Tool (simuliert, gibt festen Text zurück)
// TODO 2: Baue Phase 1 — Research// - generateText mit search-Tool// - Maximal 3 Iterationen
// TODO 3: Baue Phase 2 — Summarize// - generateText das die Recherche in 3 Kernaussagen zusammenfasst
// TODO 4: Baue Phase 3 — Format + Guardrails// - Formatiere als kurzen Report// - Pruefe: nicht leer, max 5.000 Zeichen
// TODO 5: Logge Token-Verbrauch pro Phase und gesamtCheckliste:
- search-Tool definiert und genutzt
- Research-Phase mit Iterations-Limit
- Zusammenfassung nutzt Research-Output als Input
- Output-Guardrails prüfen den finalen Report
- Token-Verbrauch wird pro Phase und gesamt geloggt
Lösung anzeigen
import { generateText, tool } from 'ai';import { anthropic } from '@ai-sdk/anthropic';import { z } from 'zod';
const model = anthropic('claude-sonnet-4-5-20250514');
// search-Tool (simuliert)const searchTool = tool({ description: 'Suche nach Informationen', parameters: z.object({ query: z.string() }), execute: async ({ query }) => { console.log(` Suche: "${query}"`); return `Suchergebnisse für "${query}": AI wird in der Medizin für Diagnostik, Medikamentenentwicklung und personalisierte Therapie eingesetzt. Aktuelle Studien zeigen 30% schnellere Diagnosen durch AI-Unterstuetzung.`; },});
async function miniResearchPipeline(topic: string) { let totalTokens = 0; console.log(`\n=== Mini Research Pipeline: "${topic}" ===\n`);
// Phase 1: Research (max 3 Iterationen) console.log('[Phase 1: Research]'); const messages: any[] = [ // ← any[] weil AI SDK Messages verschiedene Content-Typen haben { role: 'user', content: `Recherchiere zum Thema: ${topic}. Nutze das search-Tool.` }, ];
let iterations = 0; while (iterations < 3) { iterations++; const result = await generateText({ model, tools: { search: searchTool }, messages, }); totalTokens += result.usage.totalTokens; messages.push(...result.response.messages); if (result.finishReason === 'stop') break; }
const researchText = messages .filter(m => m.role === 'assistant' && typeof m.content === 'string') .map(m => m.content) .join('\n');
console.log(` ${iterations} Iterationen, ${totalTokens} Tokens\n`);
// Phase 2: Summarize console.log('[Phase 2: Summarize]'); const summary = await generateText({ model, system: 'Fasse die Informationen in exakt 3 Kernaussagen zusammen. Jede in einem Satz.', prompt: researchText, }); totalTokens += summary.usage.totalTokens; console.log(` ${summary.usage.totalTokens} Tokens\n`);
// Phase 3: Format + Guardrails console.log('[Phase 3: Format + Quality]'); const report = await generateText({ model, system: 'Formatiere als kurzen Report mit Titel, Kernaussagen und Fazit.', prompt: summary.text, }); totalTokens += report.usage.totalTokens;
// Guardrails if (report.text.length === 0) throw new Error('Report ist leer'); if (report.text.length > 5_000) throw new Error('Report zu lang'); console.log(' Quality-Checks bestanden.');
console.log(`\n=== Fertig. Gesamt: ${totalTokens} Tokens ===\n`); console.log(report.text);
return { report: report.text, totalTokens };}
await miniResearchPipeline('AI in der Medizin');Erklärung: Drei Phasen — Research mit Tool-Loop (max 3 Iterationen), Summarize mit eigenem System Prompt, Format mit Guardrails. Token-Verbrauch wird über alle Phasen kumuliert. Die Pipeline laeuft von Anfang bis Ende durch, auch wenn der Research-Loop frueh abbricht.
Erwarteter Output (ungefaehr):=== Mini Research Pipeline: "AI in der Medizin" ===
[Phase 1: Research] Suche: "AI in der Medizin" 1 Iterationen, 342 Tokens
[Phase 2: Summarize] 187 Tokens
[Phase 3: Format + Quality] Quality-Checks bestanden.
=== Fertig. Gesamt: 891 Tokens ===
AI in der Medizin — Report...COMBINE
Abschnitt betitelt „COMBINE“Das ist das grosse Bild. Du hast jetzt alle Bausteine, um Production-Ready AI-Systeme zu bauen:
- Level 1: Text generieren, streamen, strukturieren — die Grundlagen
- Level 2: Token-Verbrauch verstehen und tracken — Kosten im Griff
- Level 3: Tools und Agents — AI die handeln kann
- Level 5: Context Engineering — praezise Prompts die konsistente Ergebnisse liefern
- Level 6: Evals — Qualität messen statt raten
- Level 8: Workflows — komplexe Aufgaben orchestrieren
- Level 9: Guardrails, Routing, Comparing — Production-Patterns
In der Boss Fight baust Du ein System das alles vereint.