LLM 输出内容安全生产实战:用分级审核与灰度阈值降低误拦截
背景问题
很多团队接入大模型后,会先关注效果、成本和延迟,最后才补内容安全。这种顺序容易导致两个问题:第一,模型上线后才发现某些回答不适合直接展示;第二,安全策略一旦收紧,又会把正常用户请求误拦截,造成体验下降。
内容安全不是简单地在接口前加一个”是否违规”的布尔判断。更接近真实生产问题的是:哪些内容必须阻断,哪些内容可以降级回答,哪些内容要转人工复核,哪些内容只需要审计留痕;同时,系统还要区分输入风险、输出风险、用户年龄、业务类型、地区合规和历史行为。
OpenAI 的 Moderation 文档说明,moderation 模型可以检测文本和图片中的有害内容,并将结果用于过滤内容、路由到人工复核或对提交被标记内容的账户进行干预。Azure AI Content Safety 也强调,它面向应用中的用户生成内容和 AI 生成内容,提供文本和图像检测能力。AWS Bedrock Guardrails 和 Google Model Armor 则进一步把内容过滤、敏感信息保护、输入/输出拦截、审计和策略执行放到了生成式 AI 应用保护链路中。
本文不讨论”如何写一个完美的安全提示词”,而是讨论生产系统里更可落地的内容安全工程:分级审核、阈值灰度、误拦截治理、人工复核和上线检查。
核心原理
1. 从二分类改成风险分级
最常见的错误是把内容安全结果压缩成一个字段:blocked: true | false。这样做实现简单,但不利于治理。
生产系统更适合保留三类信息:
- category:命中的风险类别,例如骚扰、仇恨、成人、暴力、自伤、违法建议、敏感信息等。
- severity:风险等级,例如
low、medium、high、critical。 - confidence 或 score:分类器对该判断的置信度。
这样做的价值是把”检测”和”执行”拆开。检测模型只负责判断可能风险,业务策略负责决定动作。低风险内容可以提示用户调整表达;中风险内容可以改写或局部遮罩;高风险内容可以拒绝;边界样本可以进入人工复核。
| 风险等级 | 置信度区间 | 建议动作 |
|---|---|---|
| low | < 0.40 | 仅记录日志,正常返回 |
| medium | 0.40 - 0.70 | 安全改写或局部遮罩 |
| high | 0.70 - 0.90 | 转人工复核队列 |
| critical | > 0.90 | 直接阻断 |
2. 输入和输出都要检查
只检查用户输入不够,因为模型输出也可能引入新的风险。比如用户提出一个边界请求,输入本身不明显违规,但模型补全时扩展出了不适合展示的细节。Google Model Armor 的架构说明中也明确包含两个检查点:先检查 prompt,再检查模型生成的 response;如果需要,可以对 prompt 或 response 进行清洗后再继续。
建议将链路拆成四个检查位置:
- pre-input check:用户输入进入模型前。
- context check:系统拼接历史上下文、工具结果、检索内容后。
- post-output check:模型回答返回用户前。
- feedback check:用户举报、人工复核和申诉后。
其中第三个位置最容易被忽略,但对生产系统最关键。
3. 阈值应该按场景灰度,而不是一次性全局启用
内容安全分类器会产生误判。OpenAI 文档也提醒,moderation endpoint 的底层模型会持续升级,因此依赖 category_scores 的自定义策略可能需要随时间重新校准。这意味着阈值不能写死在代码里,也不应该所有业务共用一个全局阈值。
更稳妥的方式是建立策略矩阵:
policy_version: content-safety-2026-07-03
rules:
- scene: public_chat
category: violence
threshold:
block: 0.86
review: 0.62
log_only: 0.40
- scene: customer_support
category: self_harm
threshold:
block: 0.92
review: 0.55
safe_completion: 0.30
- scene: internal_knowledge_base
category: pii
threshold:
redact: 0.50
review: 0.75
同一个风险类别,在不同业务场景中可以有不同执行动作。例如公开社区内容应更保守,内部知识库问答可以优先脱敏和审计,而客服场景可能需要把部分高风险对话转人工。
工程落地
1. 推荐架构
一个可落地的内容安全链路通常包含以下模块:
- Policy Service:保存策略版本、阈值、场景、动作和灰度比例。
- Moderation Adapter:对接 OpenAI Moderation、Azure AI Content Safety、Bedrock Guardrails、Model Armor 或自研分类器。
- Decision Engine:把分类结果映射成
allow、block、redact、rewrite、review、log_only等动作。 - Review Queue:承接边界样本、用户申诉和人工复核结果。
- Audit Store:记录策略版本、模型版本、分类分数、执行动作和最终结果。
- Metrics Dashboard:观察拦截率、误拦截率、复核通过率、用户申诉率和各类别趋势。
关键点是:不要让业务服务直接写死分类器阈值。业务服务只传入场景、用户类型、输入、输出和上下文摘要,由策略服务返回最终动作。
2. 决策引擎示例
下面是一个简化的 TypeScript 伪代码,用于说明检测结果如何转成执行动作。
type ModerationResult = {
category: string;
score: number;
severity?: "low" | "medium" | "high" | "critical";
};
type SafetyAction = "allow" | "log_only" | "redact" | "review" | "block";
type PolicyRule = {
scene: string;
category: string;
logOnlyScore: number;
reviewScore: number;
blockScore: number;
redactScore?: number;
};
function decideAction(
scene: string,
results: ModerationResult[],
rules: PolicyRule[]
): SafetyAction {
let finalAction: SafetyAction = "allow";
for (const result of results) {
const rule = rules.find(
r => r.scene === scene && r.category === result.category
);
if (!rule) continue;
if (result.score >= rule.blockScore) return "block";
if (result.score >= rule.reviewScore)
finalAction = maxAction(finalAction, "review");
else if (rule.redactScore && result.score >= rule.redactScore)
finalAction = maxAction(finalAction, "redact");
else if (result.score >= rule.logOnlyScore)
finalAction = maxAction(finalAction, "log_only");
}
return finalAction;
}
function maxAction(a: SafetyAction, b: SafetyAction): SafetyAction {
const order: SafetyAction[] = ["allow", "log_only", "redact", "review", "block"];
return order.indexOf(a) >= order.indexOf(b) ? a : b;
}
这段代码只是骨架。真实系统还需要考虑用户年龄、地区政策、产品线、请求来源、模型类型、历史违规次数、是否命中敏感业务流程等因素。
3. 审计日志必须记录策略版本
内容安全问题排查时,团队常常只看到”某条消息被拦截”,却不知道为什么拦截。建议每次决策至少记录:
| 字段 | 说明 |
|---|---|
request_id / conversation_id | 请求或会话标识 |
policy_version | 当前生效的策略版本号 |
moderation_provider | 审核服务提供商 |
moderation_model | 审核模型版本 |
input_check_result | 输入检查结果 |
output_check_result | 输出检查结果 |
action | 最终执行动作 |
threshold_snapshot | 决策时刻的阈值快照 |
reviewer_result | 人工复核结果 |
appeal_result | 用户申诉结果 |
created_at | 时间戳 |
其中 policy_version 和 threshold_snapshot 很重要。没有这两个字段,后续很难回答”这个用户当时为什么被拦截""是否因为策略升级导致拦截率上升""旧版本策略是否需要回滚”。
4. 人工复核不是兜底,而是训练数据来源
人工复核队列不应该只作为客服补救手段。它更重要的价值是形成持续校准数据。
建议把复核样本分为四类:
- false positive:误拦截,后续应调低阈值或增加白名单上下文。
- false negative:漏拦截,后续应收紧阈值或补充规则。
- policy ambiguous:政策不清,需要业务和法务明确边界。
- model uncertain:分类器分数波动,需要多模型交叉验证或人工优先。
这类标注数据可以进入安全回归集,但不要把它和普通模型效果评估混在一起。内容安全回归集应按照风险类别、语言、地域、场景和用户群体分层维护。
适用场景
内容安全网关最适合以下场景:
- 面向公众开放的 AI 聊天、搜索、问答或写作产品。
- 企业客服、金融、医疗、教育等对输出边界敏感的场景。
- 支持用户上传图片、文档、网页、长文本并让模型生成总结的系统。
- 多模型平台或内部 LLM 平台,需要统一内容安全策略。
- 有人工运营、申诉、审计或合规要求的应用。
如果只是内部研发测试工具,也至少应保留 log_only 模式。Google Model Armor 文档中提到的 Inspect only 模式很适合灰度阶段:先记录潜在违规和命中分布,不立即阻断流量,等团队理解误拦截率后再切换到主动阻断。
常见误区
误区一:只要接入一个内容安全 API 就完成治理
API 只能提供检测结果,不能替你定义业务政策。真正的难点在于:哪些内容允许、哪些内容改写、哪些内容转人工、哪些内容必须拦截。
误区二:阈值越严格越安全
阈值过严会制造大量误拦截。误拦截会让用户绕过系统、换说法、投诉,甚至导致正常业务无法完成。内容安全不是简单追求拦截率,而是平衡风险、用户体验和人工成本。
误区三:所有场景共用一套规则
公开社区、内部知识库、客服工单、儿童产品、金融建议和代码助手的风险边界并不相同。统一规则容易在低风险场景过度拦截,在高风险场景又不够严格。
误区四:忽略多语言和隐晦表达
内容安全分类器在不同语言、方言、隐喻和群体相关表达上可能表现不一致。公开研究也提示,商业内容审核 API 可能同时存在过度审核和审核不足的问题。因此上线前需要准备多语言、多地区、多表达方式的测试集。
上线检查清单
- 是否同时检查用户输入、拼接上下文和模型输出。
- 是否将检测结果和执行策略解耦。
- 是否保存
policy_version、threshold_snapshot和moderation_model。 - 是否支持
log_only、review、redact、block等多种动作。 - 是否能按业务场景、地区、用户类型和产品线配置阈值。
- 是否建立人工复核和申诉流程。
- 是否统计误拦截率、漏拦截率、复核通过率和用户投诉率。
- 是否支持策略灰度、回滚和审计导出。
- 是否对图片、文档、工具返回内容和多轮上下文做边界说明。
- 是否明确哪些内容会被记录,记录多久,由谁可访问。
FAQ
内容安全应该放在网关层还是业务服务层?
建议放在统一策略层或平台层,但要允许业务传入场景参数。完全放在业务服务里容易形成规则碎片;完全放在网关里又可能不了解业务语义。更好的方式是平台提供统一检测、审计和策略执行,业务侧提供场景、用户类型和风险边界。
输出内容被拦截后应该直接返回错误吗?
不建议总是返回硬错误。可以按风险等级选择安全改写、局部遮罩、解释性拒绝、转人工、重新生成或仅提示用户修改输入。直接返回错误虽然简单,但容易破坏体验,也不利于收集可复核样本。
参考资料
- OpenAI Moderation Guide: https://developers.openai.com/api/docs/guides/moderation
- OpenAI Safety Best Practices: https://developers.openai.com/api/docs/guides/safety-best-practices
- Azure AI Content Safety Overview: https://learn.microsoft.com/en-us/azure/ai-services/content-safety/overview
- Amazon Bedrock Guardrails: https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html
- Google Cloud Model Armor Overview: https://docs.cloud.google.com/model-armor/overview
- BingoGuard: LLM Content Moderation Tools with Risk Levels: https://arxiv.org/abs/2503.06550
- Lost in Moderation: How Commercial Content Moderation APIs Over- and Under-Moderate Group-Targeted Hate Speech and Linguistic Variations: https://arxiv.org/abs/2503.01623