大模型对话送审 — 核心知识点提炼

适用于 LLM 流式对话场景:用户输入 + 模型输出 异步送审,违规时中断响应链路。


一、核心概念

1.1 什么是「大模型对话送审」

在对话流程中,将用户提问模型流式生成的回答提交至内容审核服务,通过异步事件回调驱动业务侧中断输出、通知客户端、记录审计日志

送审对象:

阶段送审内容触发时机
输入送审用户问题发起 LLM 请求前
输出送审累积的回答文本每个流式 chunk 到达时

1.2 关键组件

组件职责
Audit Client / Service封装审核 API 调用、协程池、超时控制
AuditEvent Channel异步接收审核结果(通过 / 拒绝 / 异常)
IsAudit 开关控制当前会话是否启用审核
Audit Config审核参数、生效范围、违规类型过滤规则
interrupt / done Signal协程间协调:审核失败 vs 对话正常结束

1.3 审核结果类型

PASSED   → 审核通过,继续正常流程
REFUSED  → 审核不通过,触发打断
ERROR    → 审核服务异常,通常仅记录日志,不打断对话

1.4 典型错误响应

客户端收到统一错误标识(如 AUDIT_NOT_PASS),提示用户修改输入后重试。


二、实现原理 / 要点

2.1 整体流程

大模型审核服务对话 Handler客户端大模型审核服务对话 Handler客户端par[审核监听协程][流式输出协程]用户提问SubmitAudit(Question)发起流式请求Event(REFUSED)signal(interrupt)chunkSubmitAudit(accumulatedAnswer)推送内容审核失败 → 中断 + 提示

2.2 审核开关:按租户 / 应用灰度

审核通常非全局开启,通过配置白名单控制:

if config.IsAuditEnabled(appId) {
    req.IsAudit = true
}

支持热更新,无需重新部署即可调整生效范围。

2.3 Audit Client 初始化

核心配置项:

参数含义
max_worker_size审核任务协程池大小
worker_wait_timeout协程等待超时
event_buffer_size结果事件通道缓冲
http_timeout审核 API 超时
auditor := NewAuditor(
    WithMaxWorkerPoolSize(conf.MaxWorkers),
    WithHttpTimeout(conf.HttpTimeout),
)
result.AuditEvent = auditor.EventChannel

2.4 输入送审:语言识别

送审前识别文本语言,选择对应审核通道:

lang := DetectLanguage(question)  // zh / en / unknown
auditor.SubmitTextAudit(ctx, question, requestId, lang)

常见策略: 统计 Unicode 中文字符与英文字母数量,占比高者即为检测语言。

2.5 输出送审:流式增量 + 多语言处理

每个流式 chunk 到达时,提交累积全文

answerText += chunk.Text
auditText := answerText

// 非中文回答:拼接原问题,交由审核侧翻译后识别
if chunk.Language != "zh" {
    auditText = auditText + question
}
auditor.SubmitTextAudit(ctx, auditText, requestId, chunk.Language)

要点: 审核模型通常以中文为主,非中文输出需附带上下文(如原问题)才能完成有效识别。

2.6 异步协调:双 Signal 模式

用两个 channel 解耦「审核结果」与「流式输出」:

interrupt := make(chan struct{})  // 审核失败信号
done      := make(chan struct{})  // 对话完成信号

协程 1 — 监听审核事件:

for event := range auditEvent {
    if event.Result == REFUSED {
        if !shouldBlock(event.Reason) {  // 违规类型过滤
            continue
        }
        close(interrupt)
        auditor.Shutdown()
        writeAuditLog(event)
        return
    }
}

协程 2 — 等待打断或完成:

select {
case <-interrupt:
    output <- Output{Err: AuditNotPass, IsEnd: true}
case <-done:
    close(interrupt)
}

协程 3 — 流式输出(主逻辑):

defer close(done)
for chunk := range llmStream {
    submitAudit(chunk)
    output <- chunk
    if chunk.IsEnd {
        auditor.Shutdown()
    }
}

2.7 违规类型过滤

并非所有「审核不通过」都触发打断,可按违规类别配置白名单:

blockTypes := config.Get("filtered_content_types")
// 例:["politics", "porn", "fraud", "illegal"]

if !contains(blockTypes, event.Reason) {
    continue  // 非目标类型,忽略
}
close(interrupt)

注意: 匹配方式需与审核服务返回的 Reason 格式对齐(精确匹配 / 前缀匹配 / 包含匹配)。

2.8 客户端侧:审核失败处理

Handler 识别审核失败错误后,通常执行:

  1. 推送提示消息 — 告知用户内容不合规,请修改后重试
  2. 发送专用事件 — 携带 sensitive_content 等标识,供前端差异化展示
  3. 中断输出链路 — 停止流式推送、取消业务进程
  4. 发送结束包 — 若已开始分段输出,补发 isEnd=true 收尾

2.9 日志与监控

场景处理方式
审核不通过写审计日志 + 告警
审核通过Info 日志
审核异常Warn 日志,不打断对话

2.10 与主对话流程的关系

前置过滤(指令/无效输入检测)→ 发起 LLM 请求 → 流式输出
                                      ↑
                            审核并行运行(不阻塞 LLM 发起)
                                      ↓
                            审核失败 → 异步 interrupt 打断后续输出
  • 审核与 LLM 并行启动,输入送审不等待结果
  • 前置过滤(如指令识别)命中时直接返回,跳过审核
  • 审核失败通过 Signal 异步打断,而非同步阻塞 LLM 调用

三、总结 / 注意事项

3.1 设计要点

  1. 双端送审 — 输入 + 输出均覆盖,降低内容风险漏检
  2. 异步非阻塞 — 审核与流式生成并行,事件驱动打断
  3. 灰度可控 — 配置白名单 + 热更新,按应用 / 租户逐步放量
  4. 多语言适配 — 语言检测 + 非母语输出拼接上下文送审
  5. 精准过滤 — 仅对指定违规类型触发打断,减少误杀
  6. 资源释放 — 拒绝或正常结束时均关闭 Audit Client

3.2 注意事项

说明
审核异常不打断避免审核服务故障影响正常对话体验
违规类型匹配规则配置值须与审核服务返回格式一致
流式增量送审每 chunk 提交累积全文,审核侧需容忍重复提交
Shutdown 时机拒绝时立即释放;正常 IsEnd 时也需释放,防 goroutine 泄漏
interrupt 只 close 一次多处 close 会 panic,由唯一协程负责
测试代码隔离Mock 敏感词注入逻辑不应进入生产环境
配置热更新开关、违规类型、超时参数建议走配置中心,支持动态调整

3.3 可复用的模块划分

模块职责
Audit Client初始化、Submit、Shutdown、Event 通道
Chat Handler送审触发、事件监听、interrupt 协调
Stream Output流式推送、失败中断、结束包补发
Config开关白名单、审核参数、违规类型过滤
Language Utils语言检测、非中文翻译策略
Audit Logger审计日志、告警、监控指标
Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐