Verantwoord een volwassen chatbotproduct runnen: een checklist voor bouwers
Een volwassen chatbot is een echt product, en echte producten dragen verantwoordelijkheden. De API geeft je een model dat geen wettelijke volwassen inhoud weigert, wat betekent dat leeftijdcontroles, huisregels, rapportage en misbruikcontroles in jouw app zitten, niet in het model. Deze checklist loopt door elke laag met werkende code, zodat je met vertrouwen kunt lanceren.
Bijgewerkt
Belangrijkste punten
- Het platform is alleen voor volwassenen; verifieer de leeftijd bij je ingang en houd de check server-side.
- Schrijf je eigen contentbeleid en een rapportpad, omdat de openheid van het model je regels niet vervangt.
- Seksuele inhoud met minderjarigen wordt altijd geblokkeerd met een 403; ontwerp hier een duidelijke, rustige UX voor.
- Beperk het gebruik per gebruiker en houd de API-sleutel op je server; één sleutel wordt gedeeld door al je verkeer.
Wie is verantwoordelijk voor wat
Denk aan de stack in twee lagen. De API levert wettelijke volwassen inhoud, fictie en controversiële onderwerpen zonder weigering, voor gebruikers van 18 jaar en ouder. Alles rondom het model, de mensen die er toegang toe hebben, de regels die ze aangaan en wat er gebeurt als er iets misgaat, is aan jou. Deze scheiding is bevrijdend, maar alleen als jij je deel serieus neemt.
Hier is een korte tabel met verantwoordelijkheden om aan de muur te hangen.
| Verantwoordelijkheidsgebied | Platform | Jouw app |
|---|---|---|
| Seksuele inhoud met minderjarigen | Altijd geblokkeerd (403) | Leg het uit, beëindig de scène, voorkom omwegen |
| Leeftijd van je gebruikers | Alleen volwassenen volgens de voorwaarden | Grens en verifieer bij je ingang |
| Huisregels buiten de wet | Niet van toepassing | Schrijf, publiceer en handhaaf ze |
| Misbruik per gebruiker | 300 verzoeken per minuut per sleutel | Limieten per gebruiker en per dag |
| Geheime sleutel | Geeft het uit | Houd het op je server |
Dit is technische begeleiding, geen juridisch advies; regels verschillen per plaats, dus controleer de vereisten waar je gebruikers wonen.
Leeftijdsgrenzen die daadwerkelijk grenzen
Een banner met een "Ik ben 18"-knop is het minimum, en een vastgestelde minderjarige kan erop klikken. Het maakt nog steeds uit, omdat het een bevestigde verklaring registreert en je beleid eerlijk houdt. De sleutel ligt waar je het afdwingt. Als de controle alleen de chat in de browser verbergt, kan iedereen je endpoint direct aanroepen. Laat de server weigeren te praten totdat er een getekend marker bestaat.
import crypto from "node:crypto";
// Minimal 18+ gate: the user must confirm before the chat routes work.
// Replace the confirmation with a real verification step when your market requires it.
const SECRET = process.env.GATE_SECRET; // random string kept on the server
function sign(value) {
return crypto.createHmac("sha256", SECRET).update(value).digest("hex");
}
export function issueAdultCookie(res, userId) {
const stamp = String(Date.now());
const payload = `${userId}.${stamp}`;
res.cookie("adult_ok", `${payload}.${sign(payload)}`, {
httpOnly: true, sameSite: "strict", secure: true, maxAge: 30 * 24 * 3600 * 1000,
});
}
export function requireAdult(req, res, next) {
const raw = req.cookies?.adult_ok || "";
const [userId, stamp, sig] = raw.split(".");
if (!sig || sign(`${userId}.${stamp}`) !== sig) {
return res.status(403).json({ state: "age_required" });
}
req.userId = userId;
next();
}Voeg requireAdult voor elke chat-route toe. Voeg strengere verificatie toe wanneer je markt of risiconiveau dit vereist, zoals een leeftijdcontrole van een derde partij, en houd de marker kort genoeg zodat je de prompt kunt aanpassen. Richt je nooit op studenten of scholen in je marketing en plaats de poort voordat er volwassen inhoud wordt getoond, inclusief voorbeelden en voorbeeldgesprekken.
Je eigen contentbeleid schrijven
Het model weigert wettelijk volwassen materiaal niet, dus jij beslist wat je product toelaat. Een beleid van één pagina is meer dan genoeg. Beschrijf wat welkom is, wat in je community niet is toegestaan ook al is het wettelijk (bijvoorbeeld pesten van echte mensen of doxxing), hoe gebruikers problemen kunnen melden en welke acties je onderneemt: waarschuwingen, tijdelijke stiltes, verbanningen.
- Publiceer het waar gebruikers zich aanmelden, in duidelijke taal.
- Spiegel het in je system prompt. Een regel zoals "Alle karakters zijn volwassenen; beëindig elke scène die niet-consensueel wordt of echte, benoemde mensen omvat" houdt de bot afgestemd op je regels.
- Maak handhaving saai. Bepaal drempels van tevoren zodat moderators niet improviseren.
- Beoordeel het beleid elk kwartaal naarmate je product evolueert.
Een rapportpad dat gebruikers kunnen vinden
Geef elk bericht een kleine meldcontrole en zorg dat het werkt zonder een inlog-omweg. Als iemand een antwoord meldt, vang dan het minimum aan informatie dat je nodig hebt om actie te ondernemen: de gebruikers-id, de bericht-id, een korte reden en een tijdstempel. Stuur het naar een wachtrij die je moderatoren bewaken.
app.post("/api/report", requireAdult, express.json(), (req, res) => {
const { messageId, reason } = req.body;
// Store only what you need to act on: who, which message, why, when.
queueForModerator({ userId: req.userId, messageId, reason: String(reason).slice(0, 500), at: Date.now() });
res.json({ ok: true });
});Houd je beloftes smal. Vertel gebruikers precies wat een rapport triggert, en sla alleen op wat je eigen beleid en geldende regels vereisen. Beoordeel hoe lang je rapporten bewaart, en verwijder ze op een schema. Erken elk rapport aan de persoon die het indiende, zelfs met een één-regel bedankje, omdat gebruikers stoppen met rapporteren als er niets lijkt te gebeuren. Volg hoe snel je moderators items sluiten, en stel een doel in dat je echt kunt halen.
Ontwerpen voor de 403-minorenblokkade
Seksuele inhoud met minderjarigen wordt altijd geblokkeerd, ook in fictie en roleplay, en de API antwoordt met een 403 en de code content_blocked. Probeer het niet opnieuw en probeer niet om te herformuleren namens de gebruiker. Behandel het in plaats daarvan als een productmoment dat een duidelijk ontwerp verdient.
- Vertaal het op de server naar een staat die je UI kent, zodat ruwe upstreamtekst het scherm nooit bereikt.
- Zeg wat er gebeurde in één rustige zin en noem de regel.
- Beëindig of reset de scène. "Doorgaan toch" ondermijnt het doel.
- Log de gebeurtenis met de gebruikers-id zodat herhaalde pogingen je eigen handhaving kunnen triggeren.
- Gok niet over intentie. Sommige blokkades komen door dubbelzinnige formulering; de neutrale boodschap werkt voor beide gevallen.
// server: translate upstream outcomes into states your UI understands
if (upstream.status === 403) {
return res.status(403).json({
state: "content_blocked",
message: "That request breaks our rules, so we can't continue this scene.",
});
}
if (upstream.status === 402) return res.status(503).json({ state: "paused" });
if (upstream.status === 503) return res.status(503).json({ state: "busy" });// browser: show a calm, specific message for each state
const MESSAGES = {
content_blocked: "This scene can't continue. Sexual content involving minors is never allowed. Start a new chat any time.",
age_required: "Please confirm you are 18 or older to use the chat.",
slow_down: "You're sending messages quickly. Give it a few seconds.",
daily_limit: "You've reached today's message allowance. Come back tomorrow.",
paused: "Chat is briefly unavailable. We're on it.",
busy: "The service is busy. Try again in a moment.",
};
async function send(messages) {
const res = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages }),
});
if (!res.ok) {
const info = await res.json().catch(() => ({}));
showBanner(MESSAGES[info.state] || "Something went wrong.");
if (info.state === "content_blocked") endCurrentScene();
return null;
}
return res;
}
Per-gebruiker misbruik- en rate limits
Je enkele API-sleutel staat 300 verzoeken per minuut toe in totaal, gedeeld door alle gebruikers. Eén gescript account kan iedereen anders verhongeren, dus handhaaf zelf limieten voor eerlijk gebruik, aanzienlijk onder dat plafond. Het voorbeeld beperkt elke gebruiker tot 12 berichten per minuut en geeft elk een dagelijks tokenbudget gemeten aan de hand van de usage-figuur in het laatste streamblok.
const WINDOW_MS = 60_000;
const PER_USER_PER_MIN = 12; // your product rule, far below the key's 300
const DAILY_TOKEN_BUDGET = 60_000; // per user, tracked from the usage chunk
const hits = new Map(); // userId -> array of timestamps
const spent = new Map(); // userId -> tokens used today
export function userLimit(req, res, next) {
const now = Date.now();
const recent = (hits.get(req.userId) || []).filter((t) => now - t < WINDOW_MS);
if (recent.length >= PER_USER_PER_MIN) {
return res.status(429).json({ state: "slow_down" });
}
if ((spent.get(req.userId) || 0) >= DAILY_TOKEN_BUDGET) {
return res.status(429).json({ state: "daily_limit" });
}
recent.push(now);
hits.set(req.userId, recent);
next();
}
export function recordUsage(userId, totalTokens) {
spent.set(userId, (spent.get(userId) || 0) + totalTokens);
}Voor productie, sla tellers op in een gedeelde opslag in plaats van procesgeheugen zodat limieten herstarten overleven en werken over meerdere servers. Voeg een bescheiden max_tokens toe op elk verzoek om het ergste geval te begrenzen, en houd 402 in de gaten op je eigen saldo. Een gratis proeftegoed van $0,50 voor 7 dagen is een leuke manier om deze controles te testen voordat echt verkeer aankomt.
Houd de sleutel op de server
Stuur de sleutel nooit in front-end bundles, mobiele apps of openbare repositories. Sla het op als een omgevingsvariabele of in een secret manager, laad het alleen in je backend en sluit het uit van logs en foutmeldingen. Als je vermoedt dat het is blootgesteld, genereer het opnieuw vanuit je account; de oude sleutel werkt onmiddellijk niet meer, dus heb een deploy klaar. Onthoud dat er één sleutel per account is, wat een schone proxy-laag nog waardevoller maakt. De web chat tutorial toont het patroon van begin tot eind, en de docs lijst de foutcodes op die je wrapper moet mappen.
Pre-launch checklist
Loop deze lijst door de dag voordat je de deuren opent. Elk item kost enkele minuten en voorkomt een klasse van problemen die pijnlijk is om op te lossen nadat gebruikers zijn aangekomen.
- Probeer de poort te breken. Roep je chatroute aan met curl en zonder cookie. Het moet 403 antwoorden met
age_required, nooit een modelantwoord. - Trigger elke staat. Simuleer de upstream om 402, 403, 429 en 503 om de beurt terug te geven, en bevestig dat elk de juiste banner toont en nooit ruwe fouttekst lekt.
- Lees je eigen beleid hardop voor. Als een moderator een zaak binnen een minuut niet kan beoordelen aan de hand van het beleid, verscherp dan de formulering.
- Test de rapportknop vanaf een telefoonscherm. Een besturing die moeilijk te bereiken is telt niet als een rapporteringspad.
- Zoek in je repository naar de sleutel. Kijk in front-end mappen, build output, voorbeeldconfiguraties en commitgeschiedenis. Regenereren als je het ergens openbaar vindt.
- Stel alerts in. Bel jezelf op een 402, op een piek van 403-blokkades van één gebruiker en op een sprong in dagelijks tokengebruik.
- Bereid de pauze schakelaar voor. Een enkele vlag die chat gracieus uitzet is onbetaalbaar tijdens een incident.
Veiligheid is nooit af, en dat geldt ook voor de lijst; voeg items toe telkens wanneer een incident je iets nieuws leert, en deel ze met iedereen die volgend aan je team toevoegt. Bekijk de lijst opnieuw wanneer je functies toevoegt zoals afbeeldingsuploads in je eigen UI, groepsrooms of openbaar personage delen, omdat elk van deze nieuwe paden voor misbruik opent. Voor hulp bij het vormgeven van de personages zelf, lees de persona design guide, en houd de basis van je integratienotities in de docs bij de hand naarmate je team groeit.
Vragen en antwoorden
Is een selectievakje genoeg voor leeftijdverificatie?
Het is een minimum en registreert een verklaring, maar het is eenvoudig te omzeilen. Handhaaf het op de server en voeg sterkere verificatie toe waar je risico of lokale regels daarom vragen.
Wat moet mijn app doen bij een 403 content_blocked?
Probeer het niet opnieuw. Vertaal het naar een rustige in-app-bericht, beëindig of reset de scène en log het gebeurtenis voor je eigen handhaving.
Kan ik gebruikers eerlijk mijn API-sleutelcapaciteit laten delen?
Ja, door per-gebruiker rate en dagelijkse tokenlimieten op je server toe te voegen. De sleutel zelf is beperkt tot 300 verzoeken per minuut in totaal.
Handhaaft het model mijn huisregels?
Nee. Het weigert geen wettelijke volwassen inhoud, dus je beleid, systeem prompt en moderatie flow moeten dat werk doen.
Je sleutel is nog maar één formulier verwijderd
Maak een account aan, kopieer de sleutel, wijzig de base URL. Dat is de hele basis-URL.