Antwoord: bouw “ai web” als een server-first pipeline. Routeer requests naar een AI-API (tool calling of responses), haal context op (RAG of domeindata), valideer output strikt (schema’s), en stream resultaten naar de client. Gebruik Next.js Route Handlers (of equivalent), een toollaag voor externe calls, en een state-strategie (conversation of eigen sessiestaat). Onderstaande gids geeft een werkbaar referentiepatroon met codevoorbeelden.
AI web in 10 minuten, met het juiste model voor denken
Als je “ai web” technisch benadert, gaat het niet om “een AI chatbot in je UI”. Het gaat om een request, context, en contract loop:
- Request contract: wat stuurt de client naar de server, en wat mag de server teruggeven (tekst, JSON, events)?
- Context: welke domeingegevens, documenten, user intent, permissions moeten meedoen?
- AI contract: welk schema verwacht je terug, en hoe constrain je gedrag?
- Tooling: welke externe acties moet het model uitvoeren, via een toollaag?
- State: conversation state beheren, of client- of server-gedreven context injecteren.
Voor API’s is dit de moderne richting: de meeste “new” AI integraties bewegen naar tools en function calling binnen één endpoint. OpenAI noemt bijvoorbeeld de Responses API als basis, inclusief tool-achtige interacties en streaming. (openai.com)
Referentie-architectuur voor ai web (server-first)
Dit is het patroon dat je in de praktijk het snelst productief maakt en het makkelijkst te debuggen is.
Componenten
- Client: geeft user input + sessie-id. Ontvangt een stream met events.
- Backend route: valideert input, start een AI request, pusht output naar de client.
- Context provider: haalt documenten op, runt retrieval, checkt permissions.
- Tool layer: implementeert tools (fetch, search, database reads, ticket aanmaken, etc.).
- Output validator: forceert schema, of rerankt wanneer output niet klopt.
- Observability: logt request id, latency per stap, tool calls, en schema-validatie fouten.
Route handlers als knooppunt
Als je Next.js gebruikt, zet je de AI-call in een Route Handler in de App Router. Next.js documenteert dat Route Handlers request handlers zijn die je kunt combineren met streaming responses. (nextjs.org)
Doel: API key en domeinlogica nooit naar de browser.
State strategie
- Stateless (meestal startpunt): injecteer relevante context per request. Eenvoudig, makkelijker te schalen.
- Conversation state: als je meerdere turns nodig hebt, gebruik je conversation IDs of beheerde server state.
- Hybrid: korte conversation state, plus retrieved context per turn.
Let op tool-streaming en “edge cases” bij SDK’s. OpenAI statusmeldingen tonen bijvoorbeeld incidenten rond Responses API streaming in bepaalde omgevingen. Bouw daarom retry en foutafhandeling in. (status.openai.com)
API ontwerp: contracts, schema’s, en tool calling
Dit is waar ai web meestal faalt. Niet in de UI, maar in output betrouwbaarheid.
Maak het contract expliciet
Werk met twee lagen:
- Server contract (wat client stuurt en krijgt): JSON schema voor input, events voor output.
- AI contract (wat je terug wil): JSON met een vast schema, of een strikt gedefinieerde response vorm.
Praktisch: retourneer altijd machine-bruikbare output als JSON, en laat “human text” optioneel of afgeleid zijn van die JSON.
Tool calling als integratiepunt
Je wil dat het model keuzes maakt over welke tool het moet aanroepen, maar jij wil deterministische tool implementaties.
Implementatie aanpak:
- Definieer tools met names, argument schema, en allowed side effects.
- Routeer tool calls naar backend functies.
- Serialiseer tool resultaten naar een compact formaat voor het model.
- Valideer output opnieuw, vooral bij “planner” tools.
De Responses API van OpenAI is expliciet ontworpen rond tools en structured interacties. (openai.com)
Output validatie en repair
Minimaliseer “heuristiek” in je frontend. Gebruik:
- JSON schema validatie op backend
- Fallback: bij invalid JSON, rerun met “repareer naar schema” prompt, of terugval naar “raw text + waarschuwing”
- Observability: log schema errors met sample van het afwijkende output
Voorbeeld: Next.js Route Handler die ai web streamt
Doel: één endpoint, stream events naar de client, en strikt schema voor de eindoutput.
1) Endpoint contract
Client POST naar bijvoorbeeld /api/ai met:
- message: string
- sessionId: string
- mode: “json” of “text” (optioneel)
2) Next.js Route Handler skeleton
Next.js Route Handlers zijn request handlers in de App Router. (nextjs.org)
Voorbeeld, conceptueel. Je past de AI SDK call aan op jouw provider.
import { NextResponse } from 'next/server';
export async function POST(req) {
const body = await req.json();
const message = body?.message;
const sessionId = body?.sessionId;
if (typeof message !== 'string' || message.trim().length === 0) {
return NextResponse.json({ error: 'message_required' }, { status: 400 });
}
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
const send = (obj) => {
controller.enqueue(encoder.encode(JSON.stringify(obj) + 'n'));
};
try {
send({ event: 'start', sessionId });
// 1) Context laden (RAG, permissies, user data)
// 2) AI request starten met tools + output schema
// 3) Terwijl AI tool calls en tekst deltas binnenkomen, send events
// Placeholder output
send({ event: 'delta', data: 'Hallo, dit is een voorbeeld.' });
const final = {
schemaVersion: 1,
answer: 'OK',
confidence: 0.72,
citations: []
};
send({ event: 'final', data: final });
} catch (e) {
send({ event: 'error', message: (e && e.message) ? e.message : 'unknown_error' });
} finally {
controller.close();
}
}
});
return new NextResponse(stream, {
headers: {
'Content-Type': 'application/x-ndjson; charset=utf-8'
}
});
}
3) Client consumer (NDJSON events)
async function runAi(message) {
const res = await fetch('/api/ai', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message, sessionId: 's1' })
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buf = '';
while (true) {
const { value, done } = await reader.read();
if (done) break;
buf += decoder.decode(value, { stream: true });
const lines = buf.split('n');
buf = lines.pop();
for (const line of lines) {
if (!line.trim()) continue;
const evt = JSON.parse(line);
if (evt.event === 'delta') {
console.log('delta', evt.data);
}
if (evt.event === 'final') {
console.log('final', evt.data);
}
if (evt.event === 'error') {
console.error('ai error', evt.message);
}
}
}
}
Context en RAG voor ai web: wat je echt nodig hebt
RAG is niet “een vector database aansluiten”. RAG is een pipeline met aandacht voor permissions, snippets, en schema output.
Minimale RAG pipeline
- Intent detectie: is het een retrieval vraag, een actie vraag, of een code vraag?
- Permission filter: haal alleen content waar de user toegang heeft.
- Retrieval: top-k, eventueel met reranking.
- Snippet format: maak een compact contextblok (bron id, excerpt, score, tijdstempel).
- Prompt assembly: voeg context toe met expliciete instructies over gebruik en onbekendheid.
Context kan ook tool resultaten zijn
Je hoeft niet alles in RAG te stoppen. Veel “ai web” use cases werken met tools:
- Zoek user data in DB, geef gestructureerde records terug
- Vraag status op van een externe service, geef JSON terug
- Voer berekeningen uit in code, laat het model alleen redeneren over resultaten
Outputcitatie en bronverantwoordelijkheid
Als je context gebruikt, wil je vaak citations. Maak citations onderdeel van je schema, niet een vrije tekst bijzin. Dan kun je consistent renderen en debuggen.
Architectuurpatronen die je problemen besparen
Gebruik patronen die falen voorspelbaar maken.
Pattern 1: Planner, Executor, Verifier
- Planner: kiest een plan en welke tools nodig zijn.
- Executor: voert tools uit en levert tool results terug.
- Verifier: valideert dat eindoutput klopt met schema en constraints.
In code betekent dit vaak: één route, meerdere interne stappen, met retries op verifier.
Pattern 2: Idempotency voor side effects
Als tools writes doen (tickets aanmaken, betalingen initiëren), voeg idempotency keys toe. Maak tooling deterministisch in zoverre mogelijk.
Pattern 3: Token budget en truncation
Maak een harde “context budget” regel, zodat je niet random extra tekst injecteert. Truncation moet expliciet zijn, anders krijg je flakey output.
Pattern 4: Streaming als eersteklas feature
Streaming is geen afterthought. Door NDJSON events of SSE te gebruiken, kun je UI updates doen, tijdouts afhandelen, en observability granularer maken.
Let ook op echte incidenten bij streaming. OpenAI status kan issues melden voor SDK streaming in bepaalde situaties. (status.openai.com)
Frameworkkeuzes: Next.js, async verwerking, en “waar gaat de request heen”
Je hoeft niet alles te migreren, maar je wil een framework dat je AI workflow niet tegenwerkt.
Next.js App Router route handlers
Next.js Route Handlers zijn bedoeld als server-side request handlers en werken met streaming responses. (nextjs.org)
HTTP transport: NDJSON, SSE, of chunked text
- NDJSON: makkelijk te parsen, events zijn JSON lines.
- SSE: browservriendelijk, handig voor tekst events.
- Chunked text: snel, maar minder contractueel.
Voor technische teams is NDJSON vaak het meest onderhoudbaar.
AI provider variaties
Providers verschillen in supported features. Dit kan gaan over file inputs, tool types, of streaming behavior. Zie bijvoorbeeld community en support cases over verschillen in supported document types bij Responses API in varianten. (learn.microsoft.com)
Conclusie: behandel provider capabilities als configuratie, niet als aanname in je code.
Stappenplan: van “werkt” naar “productierijp”
Als je weinig tijd hebt, volg dit volgorde. Dan voorkom je vroegtijdig refactor-werk.
Stap 1: één endpoint, één schema
- Maak één route die AI output als JSON schema teruggeeft.
- Laat de client alleen renderen op basis van dat schema.
Stap 2: voeg tools toe, maar met contract
- Definieer tool argument schema’s.
- Tool implementaties blijven “pure” of idempotent.
Stap 3: context pipeline integreren
- Voeg permissions filter toe.
- Injecteer alleen relevante snippets.
- Maak citations onderdeel van het schema.
Stap 4: streaming + retries
- Stream events voor delta en final.
- Retry alleen waar dat veilig is (geen duplicate writes).
Stap 5: observability die je later dankbaar maakt
- Log tool calls met input, output size, en latency.
- Log schema validatie errors met een hash van de input.
- Track kosten per request (token usage, retries, tool count).
Veelgemaakte fouten bij ai web
- Geen contract: vrije tekst als “output format”, daarna hard werken om die te parsen.
- API key in de browser: altijd server-side houden.
- Geen permissions checks: RAG of DB reads lekken onbedoeld data.
- Geen tool grenzen: model kan te brede tools kiezen, of side effects te vaak uitvoeren.
- Te grote context: token budget explodeert, output degradeert.
Relevante achtergrond: wat is AI precies, en waar passen tools in?
Als je definities en ontwikkelingen ook als referentie wil meenemen in je projectdocumentatie, gebruik dit interne stuk als uitgangspunt: AI: Definitie, Toepassingen en Ontwikkelingen.
Conclusie
AI web is een engineering probleem, geen UI probleem. Bouw een server-first pipeline met een expliciet contract, tool calling met deterministische toollaag, RAG of tool resultaten voor context, en output validatie met schema’s. Gebruik Route Handlers als knooppunt, stream events naar de client voor snelheid en debuggability, en ontwerp retries en idempotency voor edge cases.
Als je dit patroon implementeert, heb je een ai web basis die je iteratief kunt uitbreiden met meer tools, betere retrieval, en strengere verifiers, zonder dat je steeds de fundamenten opnieuw moet slopen.

Geef een reactie