# 9.2 输出内容安全审核

输出层是防止有害内容泄露的最后屏障。本节介绍输出安全审核的实践方法。

## 9.2.1 输出安全的重要性

即使输入防护完善，输出仍可能包含问题：

* 模型生成有害内容
* 泄露敏感信息
* 产生误导性内容
* 违反合规要求

**输出审核流程**

{% @mermaid/diagram content="flowchart LR
A\["模型输出"] --> B\["有害内容检测"]
B --> C\["敏感信息过滤"]
C --> D\["事实验证"]
D --> E\["格式检查"]
E --> F\["最终输出"]" %}

图 9-3：输出安全的重要性流程图

## 9.2.2 有害内容检测

检测并过滤有害内容：

**内容分类**

| 类别   | 示例    | 处理方式  |
| ---- | ----- | ----- |
| 违法内容 | 犯罪指南  | 完全拒绝  |
| 仇恨言论 | 歧视性言语 | 完全拒绝  |
| 暴力内容 | 暴力描写  | 根据上下文 |
| 成人内容 | 不适宜内容 | 年龄限制  |
| 误导信息 | 虚假声明  | 警告标记  |

**检测实现**

```python
class ContentModerator:
    def __init__(self):
        self.classifier = load_moderation_model()
        self.rules = load_moderation_rules()

    def check(self, content: str) -> ModerationResult:
        # ML 模型检测

        scores = self.classifier.predict(content)

        # 规则检测

        rule_matches = self.check_rules(content)

        # 综合判断

        if self.should_block(scores, rule_matches):
            return ModerationResult(blocked=True,
                                    reason=self.get_reason(scores, rule_matches))

        return ModerationResult(blocked=False)

    def should_block(self, scores: dict, rules: list) -> bool:
        for category, score in scores.items():
            if score > self.thresholds[category]:
                return True
        return len(rules) > 0
```

## 9.2.3 输出过滤器

对检测到的问题内容进行处理：

```python
class OutputFilter:
    def filter(self, content: str, issues: list) -> str:
        if self.should_completely_block(issues):
            return self.get_rejection_message()

        filtered = content
        for issue in issues:
            if issue.type == "sensitive_info":
                filtered = self.redact(filtered, issue)
            elif issue.type == "harmful_content":
                filtered = self.remove_section(filtered, issue)
            elif issue.type == "uncertain_claim":
                filtered = self.add_disclaimer(filtered, issue)

        return filtered

    def redact(self, content: str, issue: Issue) -> str:
        # 用占位符替换敏感信息

        return content.replace(issue.match, "[已过滤]")

    def add_disclaimer(self, content: str, issue: Issue) -> str:
        # 添加免责声明

        disclaimer = "\n\n[注意：以上内容可能包含不确定信息，请自行验证]"
        return content + disclaimer
```

## 9.2.4 幻觉检测

检测模型编造的虚假信息：

{% @mermaid/diagram content="flowchart TB
A\["模型输出"] --> B\["事实提取"]
B --> C\["知识库验证"]
B --> D\["一致性检查"]
B --> E\["置信度分析"]
C --> F\["幻觉评分"]
D --> F
E --> F" %}

图 9-4：幻觉检测流程图

**检测方法**

| 方法    | 描述        |
| ----- | --------- |
| 知识库验证 | 与可信知识源对比  |
| 自我一致性 | 多次生成对比    |
| 溯源检查  | 验证引用的来源   |
| 置信度分析 | 模型输出的不确定性 |

**幻觉检测的局限与实践建议**

各种幻觉检测方法在实际应用中都存在固有的局限，企业不应依赖任何单一检测手段：

* **知识库验证的局限**：知识库本身可能不完整、过时或存在偏差，导致将真实但罕见的信息误判为幻觉。例如，最新发生的时事、小众领域的专业知识或新兴技术可能不在知识库中，但模型的输出仍然是准确的。这种“基准漂移”使得基于知识库的验证容易产生误报。
* **一致性检查的局限**：LLM 的输出具有内在的随机性，受 `temperature`、`top-k`、`top-p` 等采样参数的影响。同一输入在不同推理运行下的多次输出可能存在合理的差异，而非都是错误。此外，对于创意类、开放式的任务，“多次输出有分歧”本身是正常现象，不应视为幻觉信号。
* **置信度分析的局限**：许多模型的置信度评分存在“校准问题”（calibration issue），即模型报告的置信度与实际准确度不匹配。高置信度分数不等于高准确度，低置信度也不一定意味着答案是错误的。这种校准偏差使得单纯依赖置信度得分来判定幻觉往往不可靠。

**推荐的务实方案**

1. **多方法融合**：结合多种检测方法（知识库验证、自我一致性、来源溯源等），而不是依赖单一手段，通过多维信号的交叉验证提高可信度。
2. **分级审核阈值**：根据输出内容的风险等级设置不同的审核触发点。对于医疗、法律、金融等高风险领域，设置更激进的疑似幻觉阈值，主动触发人工复核；对于低风险的信息类查询，可以设置更宽松的阈值。
3. **与下游业务集成**：不要将幻觉检测结果作为“通过/失败”的二值决策，而是作为“可信度评分”注入到应用流程中，让业务逻辑根据不同场景灵活处理（例如在金融建议前添加免责声明、在医疗诊断建议中触发医生审核）。
4. **持续的标注与改进**：收集真实业务场景中被标注为幻觉或准确的输出样本，定期重新训练或调整检测模型的阈值，使其逐步适应特定领域的实际情况。

## 9.2.5 多级审核

根据内容敏感度实施分级审核：

```python
class MultiLevelReviewer:
    def review(self, content: str, context: dict) -> ReviewResult:
        # 第一级：自动审核

        auto_result = self.auto_review(content)
        if auto_result.decision == "pass":
            return auto_result
        if auto_result.decision == "block":
            return auto_result

        # 第二级：增强审核

        if auto_result.decision == "escalate":
            enhanced_result = self.enhanced_review(content, context)
            if enhanced_result.decision in ["pass", "block"]:
                return enhanced_result

        # 第三级：人工审核队列

        return self.queue_for_human_review(content, context)
```

**分级策略**

| 级别 | 方法    | 延迟 | 成本 |
| -- | ----- | -- | -- |
| L1 | 规则匹配  | 低  | 低  |
| L2 | ML 模型 | 中  | 中  |
| L3 | 增强模型  | 中高 | 中高 |
| L4 | 人工审核  | 高  | 高  |

## 9.2.6 实时与异步审核

**实时审核**

```python

# 同步模式：等待审核完成

def generate_with_moderation(prompt: str) -> str:
    response = model.generate(prompt)
    moderation = moderator.check(response)

    if moderation.blocked:
        return "抱歉，我无法提供这个请求的回答。"

    return moderation.filtered_content
```

**异步审核**

```python

# 异步模式：流式输出 + 后台审核

async def stream_with_moderation(prompt: str):
    review_buffer = ""
    pending_chunks = []

    async for chunk in model.stream(prompt):
        pending_chunks.append(chunk)
        review_buffer += chunk

        # 不提前释放未经完整审核的 chunk；按窗口审核后再批量放行。
        if len(review_buffer) >= CHECK_INTERVAL:
            full_check = await moderator.full_check(review_buffer)
            if full_check.blocked:
                yield "[内容已被过滤]"
                return

            yield "".join(pending_chunks)
            pending_chunks.clear()
            review_buffer = review_buffer[-OVERLAP_CHARS:]

    # 流结束时仍要审核不足一个窗口的尾部内容。
    if pending_chunks:
        final_check = await moderator.full_check(review_buffer)
        if final_check.blocked:
            yield "[内容已被过滤]"
            return
        yield "".join(pending_chunks)
```

## 9.2.7 审核日志与改进

记录审核结果用于改进：

```python
import hashlib

class AuditLogger:
    def log(self, input: str, output: str, moderation: ModerationResult):
        record = {
            "timestamp": datetime.now(),
            "input_hash": hashlib.sha256(input.encode("utf-8")).hexdigest(),  # 生产环境建议改为带密钥的 HMAC
            "output_hash": hashlib.sha256(output.encode("utf-8")).hexdigest(),
            "decision": moderation.decision,
            "categories": moderation.categories,
            "scores": moderation.scores,
            "latency_ms": moderation.latency_ms
        }
        self.store(record)

    def analyze_trends(self, period: str) -> TrendReport:
        records = self.query(period)
        return TrendReport(
            total_requests=len(records),
            block_rate=self.calc_rate(records, "blocked"),
            top_categories=self.top_categories(records),
            false_positive_rate=self.calc_fp_rate(records)
        )
```

## 9.2.8 开源工具推荐

以下开源工具可帮助快速落地输出内容审核能力：

| 工具                | 核心能力                                                                                                                                              | 适用场景                    |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| Guardrails AI     | 在模型外围建立 validator / input-output guards 框架，可强制要求输出符合指定 JSON 结构、不包含特定有害词汇；若用于事实性校验，通常需要 grounding context / metadata（如 ProvenanceLLM 一类 validator） | 构建输出格式约束和特定场景下的事实性校验流水线 |
| Llama Guard（Meta） | 不仅可用于输入安全分类，同样适用于输出侧，判断模型回复是否触及暴力、犯罪、色情、仇恨等违规类别                                                                                                   | 输出安全分类网关，可与输入侧共享同一模型实例  |
| LangKit（WhyLabs）  | 提供文本质量与安全指标的开源工具包，涵盖毒性、越狱/拒答相似度、regex 命中等 profile/metric，更偏监控与可观测性而非独立阻断网关                                                                        | 输出质量监控和安全指标的持续可观测性建设    |

输出审核是保护用户和维护系统声誉的关键环节。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yeasy.gitbook.io/ai_security_guide/di-san-bu-fen-fang-yu-pian/09_io_protection/9.2_output_moderation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
