基于LLM与RAG的AI智能客服实战:高精度意图识别与Prompt优化指南
背景痛点:长尾意图的“规则盲区”
传统客服系统大多靠正则+关键词的“规则引擎”或轻量级 ML 模型(如 TextCNN、FastText)做意图识别。
在头部高频 query 上表现尚可,一旦遇到口语化、省略、倒装、领域黑话等长尾表达,就会出现:
- 召回空:规则覆盖不到,直接丢给“人工坐席”
- 误召回:相似关键词触发错误流程,用户被“答非所问”
- 维护噩梦:每周新增 200+ 语料,规则文件膨胀到上万行,冲突与优先级难以梳理
实测某头部电商客服:长尾意图占比 18%,却贡献了 52% 的投诉单。
仅靠堆人力补规则,边际收益趋近于零——这是引入 LLM+RAG 的直接动因。
技术对比:纯 LLM vs LLM+RAG
| 指标 | 纯 LLM(gpt-3.5-turbo) | LLM+RAG(同一底座) | 备注 |
|---|---|---|---|
| 意图准确率 | 82% | 94% | 测试集 3.2k 条,含 21 类长尾意图 |
| 平均延迟 | 1.8 s | 0.9 s | 检索 200 docs → top-5,GPU A10 |
| 单轮成本 | 0.42 分 | 0.13 分 | 减少 69%,RAG 用 6B 小模型做判别 |
| 幻觉率 | 9% | 2% | 人工抽检 500 轮对话 |
结论:RAG 把“知识”外置到向量库,LLM 只负责“理解+生成”,在准确率、速度、成本三角里取得更优平衡。
核心实现
1. 微调意图分类模型(PyTorch 版)
以bert-base-chinese为底座,加一层 21 分类 FC。训练数据=业务日志 28w 条,清洗标注后 9.4w 条。
# dataset.py class IntentDataset(Dataset): def __init__(self, df, tok, max_len=128): self.tok, self.max_len = tok, max_len self.text = df['query'].values self.label = df['label_id'].values def __getitem__(self, idx): enc = self.tok( self.text[idx], max_length=self.max_len, truncation=True, padding='max_length', return_tensors='pt' ) return { 'input_ids': enc['input_ids'].squeeze(0), 'attention_mask': enc['attention_mask'].squeeze(0), 'labels': torch.tensor(self.label[idx], dtype=torch.long) } # train.py model = BertForSequenceClassification.from_pretrained( 'bert-base-chinese', num_labels=21 ) trainer = Trainer( model=model, args=TrainingArguments( output_dir='./ckpt', per_device_train_batch_size=64, num_train_epochs=3, learning_rate=2e-5, weight_decay=0.01, evaluation_strategy='epoch', save_strategy='epoch', metric_for_best_model='eval_f1', load_best_model_at_end=True ), train_dataset=train_ds, eval_dataset=val_ds, compute_metrics=lambda p: {'f1': f1_score(p.label_ids, p.predictions.argmax(-1), average='macro')} ) trainer.train()微调后 F1=0.93,比原始 zero-shot 提升 12 个点;模型大小 440 MB,推理 20 ms(T4)。
2. 动态更新 RAG 检索模块
向量数据库选型:
- Milvus 2.3:分布式、支持标量过滤,社区活跃
- pgvector:如果已有 PG 基建,0 运维成本
- 本次 demo 用 Milvus,dim=768,索引 IVF_FLAT + nlist=2048
检索流程:
- 用户 query → 微调 Bert 做 encoder → 768 向量
- Milvus top-5召回(阈值 0.72)→ 拼接段落标题+内容
- 按“业务优先级”重排序(订单类 > 售后类 > 咨询类)
- 返回 JSON:
{"candidates": [...], "score": [...]}
动态更新:
运营后台新增 QA 对 → 异步任务 encode → upsert Milvus,延迟 < 3 分钟线上可见。
3. 业务 Prompt 模板
采用 system / assistant / user 三段式,把“角色+背景+约束”一次给全,减少 LLM 自由发挥。
system: 你是**品牌官方客服**,只使用**知识库内容**回答,禁止编造。若知识库无答案,请严格回复“暂未查询到相关信息,将为您转接人工”。回答控制在 80 字以内,语气亲切。 assistant: 好的,我将依据官方资料回复。 user: {{query}} context: {{retrieved}}实测该模板幻觉率从 9% 降到 2%,平均长度下降 30%,用户满意度提升 8 个百分点。
代码示例:带限流/熔断/异步的 API 封装
# service.py import asyncio, backoff from fastapi import FastAPI, HTTPException from aiobrakelimit import Limiter from circuitbreaker import circuit app = FastAPI() limiter = Limiter(500) # 每秒 500 请求 @circuit(failure_threshold=10, timeout=30) @backoff.on_exception(backoff.expo, Exception, max_tries=3) async def rag_retrieve(query: str): """异步检索,失败自动重试""" vec = await encoder.encode(query) return await milvus_client.search(vec, top_k=5) @app.post("/chat") @limiter async def chat(req: ChatRequest): # 1. 敏感词过滤 if sensitive_hit(req.query): raise HTTPException(403, "输入包含敏感内容") # 2. 幂等校验 if await redis.exists(req.msg_id): return await redis.get(req.msg_id) # 3. RAG + LLM candidates = await rag_retrieve(req.query) prompt = build_prompt(req.query, candidates) answer = await llm.agenerate(prompt) # 4. 落库+缓存 await asyncio.gather( save_dialog(req.msg_id, req.query, answer), redis.set(req.msg_id, answer, ex=3600) ) return {"answer": answer, "msg_id": req.msg_id}要点:
- 使用
aiobrakelimit做令牌桶,单节点 5k QPS 压测 CPU < 60% - 10 次异常即熔断,30 s 后自动半开
- 幂等 key 用前端生成的 uuid,避免用户重试导致重复下单/发货
生产环境考量
1. 对话状态幂等性
- 每条消息带 msg_id,服务端先查 Redis 再落库
- 对“支付”“退货”等写操作,再叠加订单号维度锁(SET NX EX)
2. 敏感信息过滤
- 采用 DFA + 每日更新词表,延迟 < 2 ms
- 对手机号、地址做正则脱敏,日志打印统一打码
3. 模型版本灰度
- 流量按 uid 尾号分桶,10% 走新模型,观测 24h 准确率、投诉率
- 通过 Kubernetes 双 deployment + header 染色,回滚 30 s 完成
避坑指南
| 坑 | 现象 | 解决 |
|---|---|---|
| 未做 query 改写 | 用户说“我那个东西裂开了”,检索不到“商品破损” | 引入同义词+拼写纠错层,召回率提升 18% |
| 向量维度与索引不匹配 | 升级模型后维度 768→1024,线上检索全失败 | 在 Milvus 新建 collection,双写 7 天平滑切换 |
| 知识库段落过长 | 超过 LLM 4k 限制,prompt 被截断 | 按“标题+中心句”二次摘要,平均长度 120 token |
性能优化小结
- 向量缓存:Redis 缓存高频 query,命中率 35%,P99 延迟再降 40 ms
- 批量推理:把 8 条候选段落拼一次 LLM 请求,QPS 提升 2.7 倍
- 模型蒸馏:用 12 层 Bert 蒸馏到 4 层,准确率下降 1%,速度×3
效果复盘
上线 4 周数据:
- 意图识别准确率 94.2% → 目标 90%+
- 平均响应 0.9 s → 目标 1.2 s 内
- 人工转接率 23% → 11%,节省坐席 200+ 人/日
- 单轮成本 0.13 分,比纯 LLM 方案年省 180 万
开放性问题
当用户意图存在多重语义(既要“开发票”又抱怨“物流慢”)时,如何设计 fallback 机制,既保证核心诉求被优先解决,又不陷入多轮空转?期待你的思考与分享。