Multi-turn gesprekken ontwerpen: een AI die de draad vasthoudt
Een van de grootste uitdagingen in prompt-engineering en AI-applicatieontwikkeling is het creëren van een natuurlijke flow. Grote taalmodellen (LLM's) zijn van nature stateless: ze vergeten alles zodra een API-call is afgerond. Aan ons als developers de taak om de illusie van een continu gesprek te bouwen. Hoe zorg je voor een multi-turn architectuur die robuust, kostenefficiënt en gebruiksvriendelijk is?
1. Staat bijhouden: de basis van je architectuur
Om een model geheugen te geven, moet de backend de gespreksgeschiedenis (de state) bijhouden en bij elke nieuwe iteratie terugsturen. Voor webapplicaties betekent dit meestal opslag in een database of in de memory van de actieve sessie.
Het gevaar? Het context window van het model is beperkt (en dure tokens stapelen zich snel op). Een naïeve aanpak stuurt simpelweg de hele array van eerdere berichten mee. Een betere strategie is de Sliding Window-techniek, waarbij je bijvoorbeeld alleen de laatste 5 tot 10 beurten instuurt via je API-endpoints, plus een eventuele vaste systeem-prompt die de persona en basisregels definieert.
2. Verwijzen naar eerdere beurten in de praktijk
Wanneer een gebruiker zegt: "Maak die header rood in plaats van blauw", moet het systeem weten om welke code het gaat. Stel, je bouwt een webapplicatie waarbij je modellen zoals DeepSeek of Claude aanroept via een framework (zoals OpenRouter). Als de gebruiker een component refineert, moet de context de actuele code bevatten.
User (Turn 1): "Schrijf een Python script voor database backup."
AI (Turn 1): [Genereert script]
User (Turn 2): "Voeg logging toe aan de excepties."
Als het model bij Turn 2 niet het eerdere Python script in zijn context heeft, faalt het of genereert het slechts losse log-regels. Zorg dat de payload naar de LLM gestructureerd blijft met duidelijke role: user en role: assistant objecten.
3. Samenvatten: token-limieten overleven
Wat doe je bij gesprekken van 50+ beurten? Het constant meesturen van de hele geschiedenis vreet je compute en budget op. De oplossing is asynchrone summarization.
Wanneer de geschiedenis een bepaalde token-limiet bereikt (bijv. 4000 tokens), laat je een kleiner, goedkoper model op de achtergrond een samenvatting schrijven van de oudste beurten. De nieuwe context-payload ziet er dan zo uit:
[
{"role": "system", "content": "Je bent een expert..."},
{"role": "system", "content": "Samenvatting eerdere context: De gebruiker bouwt een frontend app en heeft zojuist de authenticatie-module afgerond."},
{"role": "user", "content": "Laten we nu de CSS aanpakken."},
]
Voor enterprise applicaties of complexe systemen kun je deze samenvattingen opslaan in een vector-database. Als een gebruiker vraagt: "Wat zei je gisteren ook alweer over die API-keys?", haal je via embeddings de specifieke beurt terug. Lees hier meer over het implementeren van RAG en vector search.
4. Wanneer opnieuw beginnen? (Context Reset)
Zelfs de beste summarization lijdt onder "context drift"—het model raakt in de war door te veel diverse informatie in één draad. Het is cruciaal om zowel in de UI als in de backend een harde reset te faciliteren.
- Voor de gebruiker: Bied een prominente "Nieuw onderwerp" of "Wis geheugen" knop.
- Voor de backend: Bouw een intent-classifier in. Als het systeem detecteert dat de gebruiker plots overgaat van 'Python debuggen' naar 'een recept voor pannenkoeken', kan de applicatie automatisch de state splitsen of een schone context starten met de melding: "Ik zie dat we een nieuw onderwerp aansnijden. Zal ik met een schone lei beginnen?"
