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

适用于 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) chunk SubmitAudit(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

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

更多推荐