背景痛点:传统客服为什么总被用户吐槽?
做客服系统三年,我总结了一句话:“规则写不尽,用户问无穷。”
长尾问题覆盖率低
电商大促时,用户会问“满300减50能不能和店铺券叠加再叠加平台券?”规则引擎里没写,客服只能转人工,排队5分钟起跳。多轮对话“失忆”
传统方案把每句话当独立请求,用户刚说完订单号,下一秒问“那邮费呢”,系统又让他重输一遍,体验瞬间崩塌。意图漂移
“我要退货”和“我想退差价”只差两个字,关键词匹配直接翻车,后台日志里 40% 的误判都来自这种“近义词陷阱”。维护成本高
每上新业务,运营就要拉开发一起补正则、加同义词,发版一次两小时,夜里上线成了常态。
技术对比:规则 vs 机器学习 vs 模型
把三种路线放在一张表,数据来自我们去年 Q4 的 A/B 测试,样本 12w 条真实对话。
| 维度 | 规则引擎 | 传统ML(意图+槽位) | 大模型+Prompt |
|---|---|---|---|
| 首句准确率 | 78% | 86% | 93% |
| 长尾覆盖 | 45% | 68% | 91% |
| 开发周期 | 2-3 周 | 4-6 周 | 1 周 |
| 人力维护/月 | 5 人天 | 2 人天 | 0.5 人天 |
| 线上延迟 | 200 ms | 350 ms | 600 ms(可优化) |
| 扩展难度 | 高 | 中 | 低 |
结论:大模型在“准确率 + 维护成本”两项上碾压,但延迟和 Token 费用是硬伤,后面会给出缓解方案。
核心实现:30 分钟跑一个可扩展对话链
1. 环境准备
python>=3.9 pip install langchain openai redis fastapi uvloop2. 用 LangChain 快速搭链
以下代码可直接python main.py跑通,已带异常捕获与日志。
# main.py import os import logging from typing import Dict from langchain.chat_models import ChatOpenAI from langchain.chains import ConversationChain from langchain.memory import RedisChatMessageHistory from langchain.schema import HumanMessage, SystemMessage logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") class CustomerServiceBot: """ 基于 LangChain 的客服对话机器人, 支持多轮记忆 + Prompt 注入防御。 """ def __init__(self, session_id: str): self.session_id = session_id self.history = RedisChatMessageHistory( session_id, url=os.getenv("REDIS_URL", "redis://localhost:6379/0") ) self.llm = ChatOpenAI( model="gpt-3.5-turbo", temperature=0.2, max_tokens=512, request_timeout=30, ) self.chain = ConversationChain( llm=self.llm, memory=self.history, verbose=False, ) self.system_prompt = ( "你是官方客服助手,必须礼貌、简洁。禁止讨论政治、色情、暴力话题。" "若用户询问敏感内容,请回复:‘抱歉,无法回答。’" ) def invoke(self, user_input: str) -> Dict: """返回 {'reply': str, 'error': str}""" try: # 1. 输入过滤 if self._detect_injection(user_input): return {"reply": "输入包含可疑内容,请重新提问。", "error": None} # 2. 注入系统级 Prompt messages = [ SystemMessage(content=self.system_prompt), HumanMessage(content=user_input), ] response = self.chain.run(messages=messages) return {"reply": response, "error": None} except Exception as exc: logging.exception("LLM call failed") return {"reply": "系统繁忙,请稍后再试。", "error": str(exc)} def _detect_injection(self, text: str) -> bool: """简单启发式,可换成更严的模型检测""" suspicious = ["忽略前面", "system prompt", "你是", "现在你是"] return any(k in text for k in suspicious) if __name__ == "__main__": bot = CustomerServiceBot("test_user_10086") print(bot.invoke("满300减50能和店铺券叠加吗?"))3. 意图识别再加速
只靠大模型兜底,Token 费用会哭。先用小模型做“前置过滤”,命中置信度 >0.85 直接返回答案,不调用 LLM。
# intent_model.py import torch from transformers import BertTokenizer, BertModel import torch.nn as nn class BertBiLSTM(nn.Module): """ BERT 取 [CLS] 后接 BiLSTM + FC,适合多分类意图任务 """ def __init__(self, bert_dir: str, num_intents: int, hidden_dim=128): super().__init__() self.bert = BertModel.from_pretrained(bert_dir) self.lstm = 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): bert_out = self.bert(input_ids=input_ids, attention_mask=attn_mask).last_hidden_state cls_vec = bert_out[:, 0, :].unsqueeze(1) # [B,1,768] lstm_out, _ = self.lstm(cls_vec) logits = self.fc(lstm_out.squeeze(-1)) return logits训练技巧:
- 数据增强:用 ChatGPT 生成同义问法,再人工审核,训练集扩 2.3 倍。
- Focal Loss:解决长尾意图样本不均衡,误判率再降 4%。
- 半监督自训练:把线上置信 0.6~0.8 的样本打伪标签,每周迭代一次。
生产考量:别让 API 限流把你半夜叫醒
双层缓存
意图模型结果缓存 5 分钟,LLM 最终答案缓存 30 分钟,Key 用“意图+关键词”哈希,命中率 42%,省 30% Token。Token Throttling
采用“漏桶 + 短令牌桶”双算法:- 漏桶保证全局 800 req/min 不超。
- 短令牌桶允许突发 120 req/10s,应对大促洪峰。
代码片段:
from ratelimit import limits, sleep_and_retry @sleep_and_retry @limits(calls=120, period=60) def call_llm(messages: list) -> str: ...降级策略
触发限流 → 切换“预置 FAQ 文本 + 意图模型 Top1 答案”,用户仍能得到 80% 可用回复。敏感信息过滤
日志写盘前统一脱敏,用正则 + 命名实体识别双层方案:
import re from presid import IDCardRecognizer, PhoneRecognizer def desensitize(text: str) -> str: text = IDCardRecognizer.replace(text, "***") text = PhoneRecognizer.replace(text, "****") text = re.sub(r"\d{4}.\d{4}", "****", text) # 订单号 return text避坑指南:Prompt 注入与状态缓存
Prompt 注入防御
- 白名单指令:系统 Prompt 只接受固定模板,用户输入全部转义。
- 输出后处理:返回内容再跑一次“安全模型”,检测违规概率 >0.3 直接拦截。
- 随机前缀:在每次系统 Prompt 尾部加 8 位随机串,增大攻击者猜测难度。
Redis 缓存设计
多轮状态用 Hash 存,结构如下:
Key: cs:{user_id} Field | Value -------|------- turn | 5 intent | refund order | 123456设置 TTL=30 min,防止僵尸数据。大促前把 Redis 升到 16G+ 10w QPS 集群,避免 LRU 误删活跃对话。
- 版本隔离
Prompt 变更先灰度 5% 流量,对比负面反馈率 <0.5% 才全量。回滚能在 30s 内置灰。
性能调优清单(可直接打印贴墙)
- 开启
uvloop+httpx异步,延迟降 18%。 - LLM 输出
max_tokens按场景裁剪,售后场景 256 足够。 - 使用
gpt-3.5-turbo-1106最新版,价格再降 25%。 - 批量日志写盘,攒 2000 条或 5s flush 一次,磁盘 IO 降 60%。
- 监控看板必看三指标:P99 延迟、Token 费用、限流触发率。
互动时间
以上方案帮我们把误判率从 12% 压到 7%,但新的挑战也来了:
“如果用户故意诱导模型输出违规内容,你会怎么防?”
是继续加安全模型?还是把系统 Prompt 做成动态签名?欢迎留言聊聊你的做法,一起把智能客服做得既聪明又安全。