背景痛点:规则引擎的“天花板”
传统客服系统大多基于正则+规则树,上线初期看似“指哪打哪”,一旦业务扩张,痛点立刻暴露:
- 冷启动成本高:每新增一条业务线,就要写上百条规则,还要为长尾问题不断打补丁,维护人员疲于奔命。
- 长尾问题处理难:用户问法千奇百怪,规则覆盖不到就 fallback 到人工,导致人工队列越堆越长。
- 意图漂移:同一问题换个说法,规则就失效,用户反复被转接,满意度直线下降。
我们曾统计过,某电商大促期间,规则客服的意图识别准确率从 92% 跌到 74%,人工溢出率飙升至 38%,直接拉垮履约时效。痛定思痛,决定把“大模型”搬上生产线。
技术选型:GPT、Claude 还是本地小模型?
选型阶段,我们把“响应延迟、成本、数据隐私”做成三维雷达图,让数据说话:
| 维度 | GPT-3.5 | GPT-4 | Claude-v1 | 7B 本地模型 |
|---|---|---|---|---|
| 平均延迟 | 800 ms | 1.2 s | 900 ms | 350 ms |
| 每 1k 对话成本 | $0.002 | $0.03 | $0.0015 | 0(自有 GPU) |
| 数据隐私 | 需脱敏上传 | 需脱敏上传 | 需脱敏上传 | 本地闭环 |
| 多语言 | 优 | 优 | 良 | 依赖语料 |
| 微调自由度 | 受限 | 受限 | 受限 | 全量可控 |
结论:
- 首轮寒暄+FAQ 用 GPT-3.5,兼顾成本与效果。
- 高价值订单咨询接入 GPT-4,保证推理深度。
- 隐私场景(医疗、金融)走 7B 本地模型 + Lora 微调,延迟最低,且合规闭环。
核心实现:让大模型“听话”的三板斧
1. 对话状态机(DSM)
大模型天生“无状态”,我们用 Python 3.11 写了个轻量级状态机,支持可配置 DSL:
from typing import Dict, Optional from enum import Enum, auto import json class State(Enum): INIT = auto() AWAIT_INTENT = auto() AWAIT_SLOT = auto() HANDOFF = auto() class DSM: def __init__(self, uid: str): self.uid = uid self.state = State.INIT self.slots: Dict[str, str] = {} def transition(self, intent: str, slots: Dict[str, str]) -> State: if self.state == State.INIT: return State.AWAIT_INTENT if intent else State.INIT if self.state == State.AWAIT_INTENT and intent == "order_cancel": self.slots.update(slots) return State.AWAIT_SLOT if self.state == State.AWAIT_SLOT and "order_id" in self.slots: return State.HANDOFF return self.state状态转移图如下:
2. 意图识别增强:BERT+BiLSTM
虽然大模型也能 zero-shot,但为了让 3.5 更“省 token”,我们先用小模型兜底,top-1 置信 < 0.8 再走大模型。
import torch from torch import nn from transformers import BertModel import torch.nn.functional as F class IntentClassifier(nn.Module): def __init__(self, bert_name: str, num_intents: int, hidden_dim: int = 128): super().__init__() self.bert = BertModel.from_pretrained(bert_name) self.bilst = nn.LSTM(768, hidden_dim, batch_first=True, bidirectional=True) self.fc = nn.Linear(hidden_dim * 2, num_intents) def forward(self, input_ids, attn_mask): x = self.bert(input_ids=input_ids, attention_mask=attn_mask)[0] # [B, L, 768] x, _ = self.bilst(x) # [B, L, H*2] x = x.mean(dim=1) return self.fc(x)训练 30 epoch,F1 达到 0.95,比纯 BERT 提升 3.2%。
3. 对话历史压缩
大模型按 token 计费,我们把“用户重复句”“系统重复句”做 CRC32 去重,再用摘要模型二次压缩,平均节省 32% token。
from transformers import pipeline summarizer = pipeline("summarization", model="facebook/bart-large-cnn", max_length=60) def compress_history(dialog: list[str]) -> str: concat = " | ".join(dialog[-6:]) # 只取最近 6 轮 return summarizer(concat, min_length=20, do_sample=False)[0]["summary_text"]性能测试:把“理想”压成“现实”
压测环境:Gunicorn + FastAPI,4 核 8 G,GPU T4*1,并发 200。
| 指标 | GPT-3.5 | GPT-4 | 本地 7B |
|---|---|---|---|
| QPS | 42 | 18 | 78 |
| p99 延迟 | 1.1 s | 2.3 s | 450 ms |
| 错误率 | 0.4 % | 0.6 % | 0.2 % |
限流规避策略:
- 多轮对话里,非关键轮次走本地小模型,降低 3.5/4 调用频次。
- 对同一 session 做 token-bucket 限流,突发不超过 10 req/s。
- 自建“模型路由”层,按优先级排队,高优请求动态降级到 3.5。
避坑指南:上线后才懂的“血泪”
- 敏感词过滤误判
仅用关键字会误杀“枸杞”→“**”,我们引入双向最大匹配 + 白名单,召回提升 7%,误杀降到 0.1%。 - 上下文丢失补偿
偶发 Redis 超时导致 state 清空,客户端带 lastMsgId 回传,服务端做“断点续传”,用户无感。 - 模型蒸馏精度损失
用 GPT-4 生成 50w 伪标,蒸馏到 7B,KL 散度监控 > 0.05 自动回滚,保证线上 F1 下降 < 2%。
可复用完整链路代码(简化版)
# main.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel import uvicorn class ChatReq(BaseModel): uid: str text: str app = FastAPI() dsm_pool: Dict[str, DSM] = {} @app.post("/chat") def chat(req: ChatReq): dsm = dsm_pool.setdefault(req.uid, DSM(req.uid)) intent, slots = small_model_predict(req.text) # 伪代码 new_state = dsm.transition(intent, slots) if new_state == State.HANDOFF: return {"reply": "正在为您转接人工客服..."} return {"reply": generate_reply(intent, dsm.slots)}思考题
当大模型成本与用户体验呈指数级放大时,你会选择:
- 继续堆预算上 GPT-4,保证极致体验?
- 动态降级 + 小模型兜底,牺牲部分“聪明度”?
- 还是把对话拆成“意图识别→检索→生成”三段,彻底本地闭环?
欢迎在评论区留下你的解法,一起把“智能”和“成本”拉成平行线。