Executando um produto de chatbot adulto com responsabilidade: Checklist para desenvolvedores
Um chatbot adulto é um produto real, e produtos reais trazem responsabilidades. A API oferece um modelo que não recusa conteúdo adulto lícito, o que significa que as verificações de idade, regras internas, relatórios e controles de abuso ficam no seu app, não no modelo. Este checklist percorre cada camada com código funcional, para você lançar com confiança.
Atualizado
Pontos principais
- A plataforma é apenas para adultos; verifique a idade na sua porta e mantenha a verificação no servidor.
- Escreva sua própria política de conteúdo e um caminho para relatórios, porque a abertura do modelo não substitui suas regras.
- Conteúdo sexual envolvendo menores é sempre bloqueado com 403; projete uma UX clara e calma para isso.
- Limite o uso por usuário e mantenha a chave de API no seu servidor; uma chave é compartilhada por todo o seu tráfego.
Quem é responsável pelo quê
Pense na pilha em duas camadas. A API serve conteúdo adulto lícito, ficção e tópicos controversos sem recusar, para usuários com 18 anos ou mais. Tudo ao redor do modelo, as pessoas que podem acessá-lo, as regras que elas concordam e o que acontece quando algo dá errado é seu. Essa divisão é libertadora, mas apenas se você levar sua parte a sério.
Aqui está uma tabela curta de responsabilidades para manter à vista.
| Preocupação | Plataforma | Seu app |
|---|---|---|
| Conteúdo sexual envolvendo menores | Sempre bloqueado (403) | Explique, encerre a cena, impeça contornamentos |
| Idade dos seus usuários | Apenas adultos pelos termos | Bloqueie e verifique na sua entrada |
| Regras internas além da lei | Não aplicadas | Escreva, publique e aplique-as |
| Abuso por usuário | 300 requisições por minuto por chave | Limites por usuário e por dia |
| Chave secreta | Emitida por | Mantenha no seu servidor |
Esta é uma orientação de engenharia, não aconselhamento jurídico; as regras variam conforme a região, então verifique os requisitos onde seus usuários vivem.
Verificação de idade que realmente bloqueia
Um banner com um botão "Tenho 18 anos" é o mínimo, e um menor determinado pode clicar nele. Ainda importa, porque registra uma afirmação afirmativa e mantém sua política honesta. A chave é onde você aplica. Se a verificação apenas esconder o chat no navegador, qualquer pessoa pode chamar seu endpoint diretamente. Faça o servidor recusar falar até que exista um marcador assinado.
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();
}Adicione requireAdult na frente de cada rota de chat. Adicione verificação mais rigorosa quando seu mercado ou nível de risco exigir, como uma verificação de idade de terceiros, e mantenha o marcador de curta duração para que você possa reenviar o prompt. Nunca direcione estudantes ou escolas em seu marketing, e coloque o controle antes que qualquer conteúdo adulto seja exibido, incluindo pré-visualizações e conversas de exemplo.
Escrevendo sua própria política de conteúdo
O modelo não recusa material adulto lícito, então você decide o que seu produto permite. Uma política de uma página é suficiente. Cubra o que é bem-vindo, o que é proibido na sua comunidade mesmo que seja legal (por exemplo, assédio a pessoas reais ou doxxing), como os usuários podem relatar problemas e quais ações você toma: avisos, silêncios temporários, banimentos.
- Publique-a onde os usuários fazem o cadastro, em linguagem clara.
- Espelhe-a no seu system prompt. Uma linha como "Todos os personagens são adultos; encerre qualquer cena que se torne não consensual ou envolva pessoas reais e nomeadas" mantém o bot alinhado com suas regras.
- Torne a aplicação entediante. Defina limites antecipadamente para que os moderadores não improvisem.
- Revise a política a cada trimestre conforme seu produto evolui.
Um caminho de relatórios que os usuários possam encontrar
Dê a cada mensagem um pequeno controle de relatório, e faça-o funcionar sem um desvio de login. Quando alguém relatar uma resposta, capture o mínimo necessário para agir: o id do usuário, o id da mensagem, um motivo curto e um carimbo de tempo. Encaminhe para uma fila que seus moderadores acompanham.
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 });
});Mantenha suas promessas restritas. Diga aos usuários exatamente o que um relatório aciona, e armazene apenas o que sua própria política e regras aplicáveis exigem. Revise por quanto tempo você mantém os relatórios e exclua-os em um cronograma. Reconheça cada relatório à pessoa que o enviou, mesmo com um agradecimento de uma linha, porque os usuários param de relatar quando parece que nada acontece. Acompanhe a rapidez com que seus moderadores fecham itens e defina uma meta que você possa realmente cumprir.
Projetando para o bloqueio 403 de menores
Conteúdo sexual envolvendo menores é sempre bloqueado, também em ficção e roleplay, e a API responde com 403 e o código content_blocked. Não tente novamente e não tente reformular em nome do usuário. Em vez disso, trate isso como um momento de produto que merece um design claro.
- Traduza-o no servidor para um estado que sua UI conhece, para que texto bruto do upstream nunca chegue à tela.
- Diga o que aconteceu em uma frase calma e nomeie a regra.
- Encerre ou redefina a cena. Oferecer "continuar mesmo assim" desfaz o propósito.
- Registre o evento com o ID do usuário para que tentativas repetidas possam acionar sua própria aplicação de regras.
- Não adivinhe a intenção. Alguns bloqueios vêm de redação ambígua; a mensagem neutra funciona para ambos os casos.
// 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;
}
Controle de abuso e limites por usuário
Sua chave de API única permite 300 requisições por minuto no total, compartilhadas por todos os usuários. Uma conta automatizada pode esgotar a cota de todos os outros, então imponha limites de uso justo por conta própria, bem abaixo desse teto. O exemplo limita cada usuário a 12 mensagens por minuto e concede a cada um uma cota diária de tokens medida a partir do valor de usage no bloco final do streaming.
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);
}Para produção, armazene contadores em um armazenamento compartilhado em vez de memória de processo para que os limites sobrevivam a reinicializações e funcionem em vários servidores. Adicione um max_tokens modesto em cada requisição para limitar o pior caso, e monitore 402 no seu saldo. Um crédito de teste grátis de $0,50 por 7 dias é uma boa maneira de testar esses controles antes que o tráfego real chegue.
Mantenha a chave no servidor
Nunca envie a chave em bundles de front-end, aplicativos móveis ou repositórios públicos. Armazene-a como uma variável de ambiente ou em um gerenciador de segredos, carregue-a apenas no seu backend e exclua-a de logs e relatórios de erro. Se você suspeitar de exposição, regenere-a na sua conta; a chave antiga para de funcionar imediatamente, então tenha um deploy pronto. Lembre-se que há uma chave por conta, o que torna uma camada de proxy limpa ainda mais valiosa. O tutorial de chat web mostra o padrão de ponta a ponta, e a documentação lista os códigos de erro que seu wrapper deve mapear.
Lista de verificação pré-lançamento
Passe por esta lista no dia anterior à abertura. Cada item leva minutos e evita uma classe de problemas que é dolorosa de corrigir após a chegada dos usuários.
- Tente quebrar o portão. Chame sua rota de chat com curl e sem cookie. Deve responder 403 com
age_required, nunca uma resposta do modelo. - Acione todos os estados. Simule o upstream para retornar 402, 403, 429 e 503 em sequência, e confirme que cada um mostra o banner certo e nunca vaza texto de erro bruto.
- Leia sua própria política em voz alta. Se um moderador não consegue decidir um caso a partir dela em um minuto, refine o texto.
- Teste o botão de relatório de uma tela de celular. Um controle que é difícil de alcançar não conta como um caminho de relatório.
- Pesquise seu repositório pela chave. Procure em pastas de front-end, saída de build, configurações de exemplo e histórico de commits. Regere-a se você encontrá-la em qualquer lugar público.
- Configure alertas. Notifique-se em um 402, em um pico de bloqueios 403 de um único usuário e em um aumento no uso diário de tokens.
- Prepare o interruptor de pausa. Uma única flag que desliga o chat de forma graciosa é inestimável durante um incidente.
Segurança nunca está completa, e nem a lista; adicione itens sempre que um incidente ensinar algo novo, e compartilhe-os com quem entrar na sua equipe a seguir. Revisite a lista quando adicionar recursos como uploads de imagem na sua própria UI, salas de grupo ou compartilhamento público de personagens, porque cada um abre novos caminhos para abuso. Para ajuda na formação dos próprios personagens, leia o guia de design de persona, e mantenha o básico das suas notas de integração na documentação à mão conforme sua equipe cresce.
Perguntas e respostas
Uma caixa de seleção é suficiente para verificação de idade?
É o mínimo e registra uma declaração, mas é fácil de contornar. Aplique no servidor e adicione verificação mais forte onde seu risco ou regras locais exigirem.
O que meu app deve fazer ao receber um 403 content_blocked?
Não tente novamente. Traduza para uma mensagem calma no app, encerre ou redefina a cena e registre o evento para sua própria aplicação de regras.
Posso permitir que os usuários compartilhem a capacidade da minha chave de API de forma justa?
Sim, adicionando limites de taxa e de tokens diários por usuário no seu servidor. A própria chave é limitada a 300 requisições por minuto no total.
O modelo aplica minhas regras internas?
Não. Ele não recusa conteúdo adulto lícito, então sua política, system prompt e fluxo de moderação têm que fazer esse trabalho.
Sua chave está a um formulário de distância
Crie uma conta, copie a chave, altere a base URL. Essa é toda a configuração.