Een character AI-app bouwen: architectuur, code en kostenberekening
Updated 2026-07-15
Een character AI-app bestaat uit vier componenten die verbonden zijn met een OpenAI-compatibel chat-endpoint: een persona-systeemprompt, een geheugenlaag, een moderatiepoort en een modelrouter. Je kunt een werkend prototype uitbrengen in minder dan 200 regels Python en het draaien voor ruim onder een dollar per maandelijks actieve gebruiker met de juiste modelkeuzes.
Kort antwoord: de architectuur met vier componenten
Je hoeft geen model te trainen of te fine-tunen. Elke serieuze companion-app op de markt vandaag, inclusief de apps die miljoenen gebruikers bedienen, is een dunne orkestratielaag boven gehoste LLM-API's. Het personage leeft in de prompt en de database, niet in de gewichten. De rest van deze gids bouwt elk component met werkende code tegen een standaard OpenAI-compatibel endpoint, en loopt daarna door de tokenberekening zodat je weet wat een maandelijks actieve gebruiker echt kost voordat je lanceert.
- Persona-prompt: een gestructureerde systeemprompt (500 tot 1,000 tokens) die bepaalt wie het personage is en hoe het spreekt.
- Geheugen: een rollend venster van recente beurten plus een periodiek vernieuwde samenvatting, zodat gesprekken de contextlimiet overleven.
- Moderatie: een leeftijdscontrole, een inputclassifier en contentbeleid afgestemd op het model waarnaar je routeert.
- Routering: een kleine functie die een goedkoop model kiest voor casual chat en een sterker model voor lange scènes.
Component 1: de persona-prompt
De persona-prompt is het product. Het is een systeembericht dat met elk verzoek meereist en bevat doorgaans vijf delen: identiteit (naam, leeftijd, achtergrondverhaal), persoonlijkheidskenmerken, spreekstijl met twee of drie voorbeeldzinnen, harde gedragsregels (nooit uit karakter vallen, antwoorden onder een lengtelimiet houden), en het huidige scenario. Houd het tussen 500 en 1,000 tokens. Kortere persona's dwalen af; veel langere verbranden inputbudget bij elk afzonderlijk bericht en verbeteren zelden de trouw. Sla persona's op als rijen in je database zodat gebruikers personages kunnen aanmaken en bewerken, wat de kernloop is van producten in de stijl van Character.AI. Hier is een compleet verzoek. Dezelfde vorm werkt met elke OpenAI-compatibele backend; dit voorbeeld gebruikt een multi-model gateway-endpoint zodat je modellen kunt wisselen door één string te veranderen:
curl https://api.apisrouter.com/v1/chat/completions \
-H "Authorization: Bearer $KEAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4-flash",
"messages": [
{"role": "system", "content": "You are Mira, a sarcastic starship engineer in her 30s. Personality: dry wit, fiercely loyal, hates small talk. Speech style: short technical sentences, occasional teasing. Example: \"The coupling is fried. Again. Did you touch it?\" Rules: never break character, never mention being an AI, keep replies under 120 words."},
{"role": "user", "content": "Mira, the reactor is making that noise again."}
],
"temperature": 0.9,
"max_tokens": 300,
"stream": true
}'Component 2: geheugen dat lange gesprekken overleeft
Companion-appsessies duren lang. Een geheugenstack met drie lagen houdt de context coherent zonder elke keer de volledige geschiedenis mee te sturen: Laag 1 is het rollend venster: de laatste 10 tot 14 ruwe beurten, letterlijk verstuurd. Laag 2 is de lopende samenvatting: elke ongeveer 20 beurten comprimeert een goedkoop model oudere berichten tot een alinea die namen, relatiestatus en open plotlijnen bijhoudt. Laag 3 zijn vastgepinde feiten: blijvende gebruikersdetails (naam, voorkeuren, eerdere gebeurtenissen die het personage zou moeten onthouden) die uit je database gehaald en als kort systeembericht ingevoegd worden. Dit is de volledige implementatie in Python met de officiële OpenAI SDK:
| Contextslot | Typische grootte | Ververscadans |
|---|---|---|
| Persona-systeemprompt | 500 tot 1,000 tokens | Statisch per personage |
| Vastgepinde gebruikersfeiten | 100 tot 200 tokens | Bij extractiegebeurtenissen |
| Lopende samenvatting | 300 tot 500 tokens | Elke ~20 beurten |
| Rollend venster (12 beurten) | ~1,800 tot 2,200 tokens | Elk bericht |
| Nieuw gebruikersbericht | ~100 tokens | Elk bericht |
from openai import OpenAI
client = OpenAI(
api_key="sk-...",
base_url="https://api.apisrouter.com/v1",
)
def build_context(persona, summary, pinned_facts, recent_turns, user_msg):
facts = "\n".join(f"- {f}" for f in pinned_facts)
return [
{"role": "system", "content": persona},
*([{"role": "system", "content": f"Facts to remember:\n{facts}"}]
if pinned_facts else []),
*([{"role": "system", "content": f"Story so far: {summary}"}]
if summary else []),
*recent_turns[-12:],
{"role": "user", "content": user_msg},
]
def refresh_summary(old_turns, prev_summary):
prompt = (
"Update this running summary of a roleplay chat. Keep names, "
"relationship state, and open plot threads. Max 150 words.\n\n"
f"Current summary: {prev_summary}\n\nNew messages: {old_turns}"
)
resp = client.chat.completions.create(
model="deepseek-v4-flash",
messages=[{"role": "user", "content": prompt}],
max_tokens=400,
)
return resp.choices[0].message.contentComponent 3: moderatie en contentbeleid
Moderatie in een companion-app heeft drie afzonderlijke taken, en ze door elkaar halen is de meest voorkomende lanceerfout. Ten eerste: bescherm je doelgroep. Als je app volwassen fictieve thema's toestaat, plaats ze dan achter een volwassen leeftijdscontrole en houd een aparte standaard voor alle leeftijden aan. App Store en Play Store review controleren dit allebei, en betalingsverwerkers geven er ook om. Ten tweede: screen inputs. Draai een goedkope classifierpas over gebruikersberichten voordat ze het personagemodel bereiken, en blokkeer categorieën die geen enkele provider toestaat: inhoud met minderjarigen, geloofwaardige schade in de echte wereld, en illegale instructies. Eén deepseek-v4-flash-aanroep met een ja/nee-rubriek kost een fractie van een cent en voegt minder dan een seconde latentie toe. Ten derde: match contentbeleid met model. Providers verschillen in fictie: het gepubliceerde beleid van xAI staat expliciet volwassen fictieve thema's toe voor volwassen gebruikers, DeepSeek en andere modellen afgeleid van open weights zijn communityfavorieten voor roleplay omdat hun gehoste beleid flexibel is voor fictie, terwijl het beleid van Anthropic expliciete inhoud verbiedt, wat Claude alleen geschikt maakt voor creatief schrijven voor alle leeftijden. Deze beleidsregels begrijpen voordat je verkeer routeert bespaart je weigeringsstormen in productie. Wat je ook bouwt, het moet de servicevoorwaarden van elke provider die je aanroept respecteren.
Component 4: modelroutering en de selectiematrix
De meeste berichten in een companion-app zijn korte casual beurten die een budgetmodel prima aankan. Een minderheid zijn lange emotionele scènes of creatieve setpieces waar prozakwaliteit het product is. Routeren op scènediepte verlaagt de kosten drastisch zonder dat gebruikers het merken:
| Model | API-model-ID | Tarief per 1M tokens (in/uit) | Geschiktheid voor companion-app |
|---|---|---|---|
| DeepSeek V4 Flash | deepseek-v4-flash | $0.126 / $0.252 | Standaard chatmodel. Communityfavoriet voor roleplay, beste waarde in de catalogus. |
| DeepSeek V4 Pro | deepseek-v4-pro | $0.3915 / $0.783 | Langere scènes, sterkere instructieopvolging, nog steeds goedkoop. |
| GLM-5 | glm-5 | $0.514 / $2.314 | Waardekeuze met sterk creatief schrijven. |
| Kimi K2.6 | kimi-k2.6 | Zie /pricing | Waardekeuze voor long-context sessies. MiMo is een vergelijkbare budgetoptie. |
| grok-4.5 | grok-4.5 | $1.60 / $4.80 | Volwassen fictieve thema's voor volwassen gebruikers volgens het gepubliceerde beleid van xAI. Contextvenster van 500K. |
| Claude Sonnet 4.6 | claude-sonnet-4-6 | $2.40 / $12.00 | Hoogste prozakwaliteit. Alleen creatief schrijven voor alle leeftijden; Anthropic verbiedt expliciete inhoud. |
| Gemini 3.5 Flash | gemini-3.5-flash | $1.20 / $7.20 | Snel, goed voor beeldbewuste functies zoals avatarreacties. |
ROUTES = {
"casual": "deepseek-v4-flash",
"scene": "deepseek-v4-pro",
"prose": "claude-sonnet-4-6", # alleen creatief schrijven voor alle leeftijden
}
def pick_model(user_msg: str, turns_in_scene: int) -> str:
if turns_in_scene > 6 or len(user_msg) > 400:
return ROUTES["scene"]
return ROUTES["casual"]Wat een maandelijks actieve gebruiker werkelijk kost
Tokenberekening vóór lancering is beter dan een facturatieverrassing erna. Met het contextbudget uit de geheugentabel: ruwweg 3,300 inputtokens en 250 outputtokens per bericht. Companion-appgebruikers zijn zware gebruikers; communitycijfers zetten betrokken gebruikers op tientallen berichten per dag, dus ga uit van ongeveer 40 berichten per dag over 20 actieve dagen, oftewel ongeveer 800 berichten per MAU per maand. Dat geeft 2.64M inputtokens en 0.2M outputtokens per MAU per maand. Vermenigvuldigd met catalogustarieven:
| Model | Inputkosten / MAU | Outputkosten / MAU | Totaal / MAU / maand |
|---|---|---|---|
| deepseek-v4-flash | $0.33 | $0.05 | $0.38 |
| deepseek-v4-pro | $1.03 | $0.16 | $1.19 |
| glm-5 | $1.36 | $0.46 | $1.82 |
| gemini-3.5-flash | $3.17 | $1.44 | $4.61 |
| grok-4.5 | $4.22 | $0.96 | $5.18 |
| claude-sonnet-4-6 | $6.34 | $2.40 | $8.74 |
| gpt-5.5 | $10.56 | $4.80 | $15.36 |
Eén endpoint voor elk model in de matrix
Je aanmelden voor vijf provideraccounts om één router te draaien is echte overhead: vijf keys, vijf factureringsdashboards, vijf sets ratelimits. Een multi-model gateway laat dat samensmelten. APIsRouter biedt elk model hierboven aan via de enkele OpenAI-compatibele base-URL https://api.apisrouter.com/v1, dus het routersnippet werkt ongewijzigd door alleen de modelstring te veranderen. Facturering is pay-as-you-go zonder abonnement, wereldwijde modellen draaien 20% onder de officiële prijzen met Chinese modellen onder hun officiële tarieven, en de no-signup checkout op /topup stuurt na betaling een key naar je e-mail, waarbij de eerste storting +100% saldo toevoegt. GET /v1/models met je key geeft de live modellijst terug, wat ook handig is om een modelkiezer in je eigen admin-UI te vullen.
Productietips die echt geld en pijn besparen
- Stream alles. Time-to-first-token is de metric die gebruikers voelen; een gestreamd antwoord in 2 seconden voelt sneller dan een compleet antwoord in 4 seconden.
- Houd het stabiele prefix stabiel. Persona en vastgepinde feiten moeten byte-identiek zijn tussen verzoeken, zodat backends die prefix caching ondersteunen dat kunnen benutten.
- Beperk max_tokens per route. Casual beurten hebben zelden meer dan 300 outputtokens nodig; een ongelimiteerd model dat uitweidt verdubbelt je outputrekening.
- Log kosten per gebruiker, niet alleen per verzoek. Een kleine fractie van zware gebruikers zal de uitgaven domineren; je moet ze zien om eerlijke gebruikstiers te ontwerpen.
- Bouw fallback in de router. Als het primaire model timeout heeft of weigert, probeer het één keer opnieuw op een zustermodel voordat je een fout toont.
- Beperk het rollend venster op tokens, niet op beurten, zodat één lange plak niet het budget opblaast.
- Behandel weigeringen in karakter. Zet een weigering om in een sierlijke in-verhaal-afleiding in plaats van ruwe API-tekst te tonen.
- Bewaar geen ruwe chats langer dan nodig, en zeg dat in je privacybeleid. Companion-chatlogs zijn van nature gevoelig.
Veelgestelde vragen
Hoeveel kost het om een character AI-app te bouwen?
Ontwikkelingskosten zijn vooral je tijd: een werkend prototype is een weekendproject omdat er geen modeltraining bij komt kijken. Draaikosten zijn het echte cijfer, en het schaalt met gebruik. Op een budgetmodel zoals deepseek-v4-flash kost een zware maandelijks actieve gebruiker ruwweg $0.38 aan tokens; op een premiummodel zoals gpt-5.5 kost dezelfde gebruiker ongeveer $15. Modelkeuze, niet infrastructuur, bepaalt je marge.
Welk AI-model is het beste voor een character AI-app?
De DeepSeek V4-familie is de communityfavoriet voor roleplay en de beste waarde: Flash voor casual chat, Pro voor langere scènes. GLM-5, Kimi K2.6 en MiMo zijn solide waardekeuzes. Grok past bij apps die volwassen fictieve thema's aan volwassenen serveren, volgens het gepubliceerde beleid van xAI. Claude Sonnet 4.6 schrijft het beste proza maar is alleen geschikt voor creatief schrijven voor alle leeftijden omdat Anthropic expliciete inhoud verbiedt.
Hoe onthouden character AI-apps eerdere gesprekken?
Via prompt-engineering, niet modelgeheugen. De app stuurt een rollend venster van recente berichten opnieuw mee, een periodiek gecomprimeerde samenvatting van oudere berichten, en een korte lijst vastgepinde feiten uit een database. Het model zelf is stateless; elk verzoek bevat alles wat het personage "onthoudt".
Moet ik mijn eigen model trainen om een AI-companion-app te bouwen?
Nee. Fine-tuning is duur, traag om te itereren en onnodig voor personageconsistentie. Een goed gestructureerde persona-prompt van 500 tot 1,000 tokens plus een geheugenlaag bereikt personagetrouw die gebruikers niet kunnen onderscheiden van een custom model, en laat je vrij onderliggende modellen wisselen zodra betere modellen uitkomen.
Hoe ga ik om met volwassen content in een companion-app?
Behandel het als een beleidsmatchingprobleem. Plaats volwassen fictieve thema's achter een volwassen leeftijdscontrole, screen inputs op categorieën die geen enkele provider toestaat, en route dat verkeer alleen naar modellen wiens gepubliceerde beleid fictie voor volwassenen toestaat, zoals Grok onder het beleid van xAI. Houd een standaard voor alle leeftijden op strengere modellen, en houd je aan de servicevoorwaarden van elke provider.
Kan ik de OpenAI SDK gebruiken voor een character AI-app met andere modellen?
Ja. DeepSeek, GLM, Kimi, Gemini, Claude en Grok zijn allemaal bereikbaar via OpenAI-compatibele endpoints, via hun eigen aanbieders of via een gateway. Je appcode blijft op de standaard chat.completions-interface en wisselt modellen door de modelstring te veranderen, wat precies is wat routering per bericht goedkoop maakt om te bouwen.