Configurando limites de detecção
Os limites de detecção definem o nível de confiança em que o Discuse sinaliza conteúdo, equilibrando falsos positivos e falsos negativos. No Discuse, esses limites são configurações do projeto definidas no painel (ou pela API de configurações), e a solicitação à API apenas alterna quais verificações serão executadas — ela não carrega limites numéricos. Este guia explica como esse equilíbrio funciona e como escolher valores para a sua plataforma.
Como funcionam os limites da Discuse
Cada verificação retorna uma pontuação de confiança de 0.0 a 1.0 e uma flag hit. A hit é definida quando a pontuação atinge ou excede o limite que você configurou para essa categoria no seu projeto. Os limites configuráveis são:
| Limite (configuração do projeto) | Aplica-se a |
|---|---|
threshold_sentiment |
Ponto de corte geral para sentimento negativo |
threshold_toxicity |
Texto tóxico |
threshold_profanity |
Linguagem ofensiva |
threshold_threat |
Ameaças |
threshold_insult |
Insultos |
threshold_spam |
Confiança do classificador de spam |
threshold_images |
Imagens explícitas (geral) |
threshold_images_porn |
Imagens pornográficas |
threshold_images_sexual |
Imagens sexualmente sugestivas |
Esses são os nomes expostos pela API de configurações do projeto; o objeto settings por requisição contém apenas alternâncias check_* de ativar/desativar, além de expected_language. Você altera os limites no painel, não por requisição.
O equilíbrio
Lower Threshold = More Strict
├── More content flagged
├── Higher false positive rate
├── Fewer harmful posts slip through
└── More user friction
Higher Threshold = More Permissive
├── Less content flagged
├── Lower false positive rate
├── More harmful posts may slip through
└── Better user experience
Visualizando o equilíbrio
False Positives ─────────────────────────►
Few Many
┌─────────────────────────────────────────┐
False Few │ ◄─── Ideal Zone │
Negatives │ (High threshold, │
│ low false rates) │
│ │ │
│ │ Your platform's │
│ │ optimal point → ● │
▼ │ │
Many │ Too permissive ──►│
└─────────────────────────────────────────┘
Threshold: 0.3 0.5 0.7 0.9
Quais limites são adequados para cada plataforma?
Os valores abaixo são pontos de partida expressos pelos nomes de limites do Discuse (threshold_toxicity, threshold_images_porn e assim por diante). Use-os como uma base para ajustar com seus próprios dados de falsos positivos, não como números garantidamente corretos. Um limite mais baixo sinaliza conteúdo de forma mais agressiva.
Plataformas de redes sociais
Plataformas sociais de uso geral precisam de moderação equilibrada:
const SOCIAL_MEDIA_THRESHOLDS = {
threshold_toxicity: 0.7,
threshold_profanity: 0.6,
threshold_threat: 0.5, // Lower (stricter) for threats
threshold_insult: 0.7,
threshold_spam: 0.75,
threshold_images_porn: 0.6,
threshold_images_sexual: 0.8 // More permissive for suggestive content
};
Plataformas profissionais / empresariais
Contextos empresariais geralmente exigem moderação mais rigorosa:
const PROFESSIONAL_THRESHOLDS = {
threshold_toxicity: 0.5,
threshold_profanity: 0.4,
threshold_threat: 0.3,
threshold_insult: 0.5,
threshold_spam: 0.6,
threshold_images_porn: 0.3,
threshold_images_sexual: 0.5
};
Comunidades de jogos
Plataformas de jogos podem tolerar mais provocações, mantendo rigor contra ameaças reais:
const GAMING_THRESHOLDS = {
threshold_toxicity: 0.8,
threshold_profanity: 0.85, // Banter allowed
threshold_threat: 0.5, // Still strict on real threats
threshold_insult: 0.8,
threshold_spam: 0.8,
threshold_images_porn: 0.6,
threshold_images_sexual: 0.9
};
Plataformas para crianças
Plataformas voltadas a menores exigem as configurações mais rigorosas:
const CHILDRENS_THRESHOLDS = {
threshold_toxicity: 0.3,
threshold_profanity: 0.2,
threshold_threat: 0.2,
threshold_insult: 0.3,
threshold_spam: 0.5,
threshold_images_porn: 0.1, // Maximum strictness
threshold_images_sexual: 0.2
};
Posso variar os limiares dinamicamente?
O Discuse armazena um conjunto de limiares por projeto, portanto variações por usuário ou por contexto ficam na sua aplicação. Os padrões abaixo calculam um limiar efetivo do seu lado; então você pode encaminhar para projetos diferentes (cada um com seus próprios limiares configurados) ou aplicar a comparação por conta própria com base nas pontuações retornadas pelo Discuse.
Níveis de confiança do usuário
Ajuste os limiares efetivos com base na reputação do usuário:
function getThresholds(user) {
const baseThresholds = PLATFORM_THRESHOLDS;
const trustMultipliers = {
new_user: 0.8, // Stricter (lower effective threshold)
basic_user: 1.0, // Standard
verified_user: 1.15, // Slightly more permissive
trusted_user: 1.3, // More permissive
moderator: 1.5 // Most permissive
};
const multiplier = trustMultipliers[user.trustLevel] || 1.0;
return Object.fromEntries(
Object.entries(baseThresholds).map(([key, value]) => [
key,
typeof value === 'number'
? Math.min(value * multiplier, 0.95)
: adjustNestedThresholds(value, multiplier)
])
);
}
Limiares baseados em contexto
Tipos diferentes de conteúdo podem exigir limiares diferentes:
const CONTEXT_THRESHOLDS = {
// Public posts visible to everyone
public_post: {
toxic: 0.6,
profanity: 0.5
},
// Direct messages between users
direct_message: {
toxic: 0.7, // Slightly more permissive
profanity: 0.6
},
// Comments on public content
comment: {
toxic: 0.55, // Stricter than posts
profanity: 0.5
},
// Profile information
profile: {
toxic: 0.5, // Strict for public-facing content
profanity: 0.4
}
};
function getContextThresholds(contentType) {
return CONTEXT_THRESHOLDS[contentType] || CONTEXT_THRESHOLDS.public_post;
}
Ajustes baseados em horário
Ajuste os limiares durante períodos de maior risco:
function getTimeAdjustedThresholds(baseThresholds) {
const hour = new Date().getHours();
const dayOfWeek = new Date().getDay();
// Stricter during off-hours when fewer moderators available
const isOffHours = hour < 6 || hour > 22;
const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
let multiplier = 1.0;
if (isOffHours) multiplier *= 0.85;
if (isWeekend) multiplier *= 0.9;
return adjustThresholds(baseThresholds, multiplier);
}
Implementação da configuração de limites
Configuração centralizada
// config/moderation.js — mirrors your Discuse project thresholds so app-side
// routing stays in sync with the values configured in the dashboard.
export const ModerationConfig = {
thresholds: {
threshold_toxicity: parseFloat(process.env.THRESHOLD_TOXICITY || '0.7'),
threshold_profanity: parseFloat(process.env.THRESHOLD_PROFANITY || '0.6'),
threshold_threat: parseFloat(process.env.THRESHOLD_THREAT || '0.5'),
threshold_insult: parseFloat(process.env.THRESHOLD_INSULT || '0.7'),
threshold_spam: parseFloat(process.env.THRESHOLD_SPAM || '0.75'),
threshold_images_porn: parseFloat(process.env.THRESHOLD_IMAGES_PORN || '0.6'),
threshold_images_sexual: parseFloat(process.env.THRESHOLD_IMAGES_SEXUAL || '0.8')
},
actions: {
high_confidence: 'auto_block', // score > 0.95
medium_confidence: 'human_review', // 0.7 - 0.95
low_confidence: 'allow_with_flag' // threshold - 0.7
}
};
Atualizações de limites em tempo de execução
Permita ajustes de limites sem reimplantação:
class ModerationService {
constructor() {
this.thresholds = defaultThresholds;
this.loadRemoteConfig();
}
async loadRemoteConfig() {
try {
const config = await fetch('/api/admin/moderation-config');
const data = await config.json();
this.thresholds = data.thresholds;
console.log('Loaded remote moderation config');
} catch (error) {
console.warn('Using default thresholds:', error);
}
}
async checkContent(content, context) {
const result = await callModerationAPI(content);
const thresholds = this.getThresholdsForContext(context);
return this.applyThresholds(result, thresholds);
}
}
Medindo a eficácia dos limiares
Métricas principais
const MODERATION_METRICS = {
// Accuracy
precision: 'True positives / (True positives + False positives)',
recall: 'True positives / (True positives + False negatives)',
f1_score: 'Harmonic mean of precision and recall',
// User impact
block_rate: 'Content blocked / Total content',
appeal_rate: 'Appeals filed / Content blocked',
appeal_success: 'Appeals won / Appeals filed',
// Operational
review_queue_size: 'Items waiting for human review',
review_time: 'Average time to human decision'
};
Limiares de teste A/B
Teste mudanças nos limiares em um subconjunto do tráfego:
async function moderateWithExperiment(content, userId) {
const experiment = getExperiment(userId, 'threshold_test');
const thresholds = experiment === 'control'
? CURRENT_THRESHOLDS
: EXPERIMENTAL_THRESHOLDS;
const result = await checkContent(content);
const decision = applyThresholds(result, thresholds);
// Log for analysis
await logExperiment({
experiment: 'threshold_test',
variant: experiment,
content_id: content.id,
scores: result,
decision: decision,
timestamp: Date.now()
});
return decision;
}
Analisando os resultados
-- Calculate precision and recall for each threshold variant
SELECT
variant,
COUNT(*) as total_decisions,
SUM(CASE WHEN blocked AND actually_harmful THEN 1 ELSE 0 END) as true_positives,
SUM(CASE WHEN blocked AND NOT actually_harmful THEN 1 ELSE 0 END) as false_positives,
SUM(CASE WHEN NOT blocked AND actually_harmful THEN 1 ELSE 0 END) as false_negatives,
SUM(CASE WHEN blocked AND actually_harmful THEN 1 ELSE 0 END) * 1.0 /
NULLIF(SUM(CASE WHEN blocked THEN 1 ELSE 0 END), 0) as precision,
SUM(CASE WHEN blocked AND actually_harmful THEN 1 ELSE 0 END) * 1.0 /
NULLIF(SUM(CASE WHEN actually_harmful THEN 1 ELSE 0 END), 0) as recall
FROM moderation_decisions
WHERE experiment = 'threshold_test'
GROUP BY variant;
Fluxo de ajuste de limiares
Etapa 1: Estabeleça uma linha de base
// Start with conservative thresholds
const INITIAL_THRESHOLDS = {
threshold_toxicity: 0.5,
threshold_profanity: 0.5,
threshold_spam: 0.6
};
Etapa 2: Colete dados
async function logModerationDecision(content, result, decision) {
await db.insert('moderation_log', {
content_id: content.id,
content_hash: hashContent(content.text),
scores: result.results,
thresholds_used: currentThresholds,
decision: decision,
user_trust_level: content.author.trustLevel,
created_at: Date.now()
});
}
Etapa 3: Analise as taxas de erro
Analise o conteúdo bloqueado e os recursos dos usuários para identificar:
- Falsos positivos: conteúdo seguro bloqueado incorretamente
- Falsos negativos: conteúdo prejudicial que não foi detectado
Etapa 4: Ajuste e repita
// Based on analysis, raise thresholds that fire too often
const ADJUSTED_THRESHOLDS = {
threshold_toxicity: 0.65, // Raised after false positives
threshold_profanity: 0.55,
threshold_spam: 0.7
};
Etapa 5: Monitore continuamente
Configure alertas para a eficácia dos limiares:
async function checkModerationHealth() {
const stats = await getModerationStats(last24Hours);
// Alert if false positive rate too high
if (stats.appealSuccessRate > 0.3) {
alert('High appeal success rate - thresholds may be too strict');
}
// Alert if harmful content is getting through
if (stats.reportedAfterApproval > threshold) {
alert('Increase in reported content - thresholds may be too permissive');
}
}
Resumo das melhores práticas
- Comece de forma conservadora: inicie com limites mais rigorosos e flexibilize-os com base nos dados.
- Use o contexto: diferentes superfícies (publicações públicas, DMs, perfis) exigem limites diferentes.
- Níveis de confiança importam: ajuste o limite efetivo de acordo com a reputação do usuário no seu app.
- Meça tudo: acompanhe precisão, recall e impacto sobre os usuários.
- Itere continuamente: a moderação nunca está "concluída".
- Documente as decisões: mantenha registros do motivo pelo qual os limites foram alterados.
- Tenha alternativas: encaminhe casos limítrofes para revisão humana.
Lembre-se: no Discuse, esses limites são configurações do projeto. Altere-os no painel ou pela API de configurações; o objeto settings por requisição apenas ativa ou desativa quais check_* são executados.
Próximos passos
- Guia de moderação de conteúdo com AI - Entendendo a moderação com AI
- Escalando a moderação de conteúdo - Implementação em alto volume
- Análise de texto - Detalhes de moderação específicos para texto