AI 智能客服系统实战:从架构设计到日均处理10万咨询
作者:重庆投肯小刚更新日期:2026年5月项目周期:3个月
一、项目背景与业务需求
1.1 客户背景
客户是一家拥有 2000+ 员工的电商企业,拥有 APP、PC 网站、微信小程序三个渠道。日均咨询量约 5 万条,高峰期(双十一、618)达 15 万条。原有客服团队 80 人,三班倒处理,仍有以下痛点:
- 响应慢:高峰期排队 30 分钟,用户流失率 40%
- 质量不稳定:新手客服培训周期 2 个月,答复质量参差不齐
- 人力成本高:客服人力成本(含工资、社保、管理)约 500 万/年
- 知识分散:产品知识、优惠规则、售后政策分散在 5 套系统中
1.2 核心需求
| 需求 | 量化目标 | 优先级 |
| 24小时自动回复 | 覆盖率 ≥ 85% | P0 |
| 响应时间 | 首次响应 < 5s | P0 |
| 意图识别准确率 | ≥ 90% | P0 |
| 转人工率 | ≤ 15% | P1 |
| 单次对话成本 | ≤ 0.1 元 | P1 |
| 多渠道统一 | APP/小程序/PC 统一知识库 | P2 |
二、系统架构设计
2.1 整体架构
┌──────────────────────────────────────────────────────────────────┐
│ 用户层 │
│ APP (Flutter) 小程序 (WeChat) PC Web │
└────────────────────┬──────────────────────────────────────────────┘
│ HTTPS / WebSocket
┌────────────────────▼──────────────────────────────────────────────┐
│ 接入层(Nginx) │
│ SSL 终止 / 负载均衡 /限流 / 健康检查 │
└────────────────────┬──────────────────────────────────────────────┘
│
┌────────────────────▼──────────────────────────────────────────────┐
│ 网关层(Spring Cloud Gateway) │
│ 路由 / 鉴权 / 渠道适配 / 请求去重 / 灰度发布 │
└────────────────────┬──────────────────────────────────────────────┘
│
┌────────────────────▼──────────────────────────────────────────────┐
│ 服务层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 对话管理服务 │ │ 意图识别服务 │ │ 知识库服务 │ │ 工单服务 │ │
│ │ (Dify) │ │ (LLM分类) │ │ (RAG) │ │ (人工协作) │ │
│ │ 端口:8081 │ │ 端口:8082 │ │ 端口:8083 │ │ 端口:8084 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└────────────────────┬──────────────────────────────────────────────┘
│
┌────────────────────▼──────────────────────────────────────────────┐
│ 数据层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ Redis │ │ PostgreSQL│ │ Milvus │ │ Kafka │ │ MinIO │ │
│ │ 会话缓存 │ │ 业务数据 │ │ 向量检索 │ │ 消息队列 │ │ 文件存储│ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └─────────┘ │
└──────────────────────────────────────────────────────────────────┘
2.2 核心模块职责
| 模块 | 技术选型 | 职责 |
| 对话管理 | Dify + Qwen2-72B | 对话流程编排、多轮对话状态管理、插件集成 |
| 意图识别 | FastAPI + Scikit-learn + LLM fallback | 12类意图分类、置信度阈值控制、转人工判断 |
| 知识库 | RAG(Milvus + Qwen2-72B) | 文档解析、语义检索、答案生成与引用 |
| 工单服务 | Spring Boot + PostgreSQL | 转人工处理、满意度评价、绩效统计 |
三、意图识别模块详细实现
3.1 12类意图分类体系
我们定义了 12 类日常高频意图,覆盖了 95% 以上的用户问题:
| 意图ID | 意图名称 | 示例问法 | 处理策略 |
| I001 | 订单查询 | 我的订单到哪了/查物流 | 直接调API |
| I002 | 退款售后 | 申请退款/质量问题 | RAG + 流程引导 |
| I003 | 优惠咨询 | 有什么优惠/领券 | RAG |
| I004 | 商品咨询 | 这款手机怎么样/有货吗 | RAG + 商品API |
| I005 | 账号问题 | 忘记密码/账户异常 | 流程引导 |
| I006 | 投诉建议 | 要投诉/反馈问题 | 转人工 |
| I007 | 物流异常 | 快递丢了/一直不派送 | RAG + 工单 |
| I008 | 发票相关 | 怎么开发票/电子发票 | RAG |
| I009 | 支付问题 | 支付失败/无法付款 | 流程引导 |
| I010 | 评价管理 | 怎么追评/删除评价 | RAG |
| I011 | 活动咨询 | 双十一活动规则 | RAG |
| I012 | 其他/寒暄 | 你好/在吗/谢谢 | 简单回复 |
3.2 两阶段意图识别方案
为兼顾准确率和响应速度,我们采用"规则 + ML + LLM"三层级联方案:
# 第一阶段:规则匹配(毫秒级,覆盖约 40% 请求)
# 维护一个正则表达式库,匹配常见句式
INTENT_RULES = {
"I001": [ # 订单查询
r"订单[到状].?[哪哪]了",
r"查.*物流",
r"快递[到走]哪",
r"订单号[是]?\d{10,}",
r"看看.*订单",
],
"I002": [ # 退款售后
r"申请退款",
r"想退[货钱]",
r"退款[流程怎么]",
r"不想要了",
r"商品.*问题.*退款",
],
"I003": [ # 优惠咨询
r"有什么优惠",
r"优惠券?[吗呢]",
r"打[折几]折",
r"满[减免].",
r"能便宜[吗点]",
],
}
def rule_based_intent(text: str) -> Optional[str]:
"""
第一阶段:正则规则匹配
毫秒级响应,零模型调用成本
"""
for intent_id, patterns in INTENT_RULES.items():
for pattern in patterns:
if re.search(pattern, text):
return intent_id
return None # 未匹配,进入第二阶段
# 第二阶段:TF-IDF + SVM 分类器(10-30ms,覆盖约 45% 请求)
# 用历史标注数据训练,零大模型调用成本
import joblib
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import LinearSVC
class IntentClassifier:
"""
基于 TF-IDF + Linear SVM 的意图分类器
训练数据:20,000 条人工标注的客服对话
"""
def __init__(self):
self.vectorizer = TfidfVectorizer(
max_features=5000, # 最多5000个特征词
ngram_range=(1, 2), # unigram + bigram
min_df=3, # 至少出现3次
max_df=0.8, # 最多出现在80%的文档中
sublinear_tf=True # 使用 1+log(tf) 而非原始tf
)
self.classifier = LinearSVC(
C=1.0, # 正则化参数
class_weight='balanced', # 类别权重(处理数据不平衡)
max_iter=5000
)
self.is_trained = False
def train(self, texts: List[str], labels: List[str]):
"""
训练意图分类器
Args:
texts: 分词后的文本列表
labels: 意图ID标签
"""
X = self.vectorizer.fit_transform(texts)
y = labels
self.classifier.fit(X, y)
self.is_trained = True
# 输出训练报告
from sklearn.metrics import classification_report
y_pred = self.classifier.predict(X)
print(classification_report(y, y_pred, digits=3))
def predict(self, text: str) -> Tuple[str, float]:
"""
预测意图类别和置信度
Returns:
(intent_id, confidence_score)
"""
X = self.vectorizer.transform([text])
pred = self.classifier.predict(X)[0]
# 获取置信度(decision_function 的 Platt scaling)
scores = self.classifier.decision_function(X)[0]
confidence = float(max(scores) / sum(scores)) # 简化的置信度
return pred, confidence
def load(self, model_path: str):
"""加载已保存的模型"""
data = joblib.load(model_path)
self.vectorizer = data['vectorizer']
self.classifier = data['classifier']
self.is_trained = True
def save(self, model_path: str):
"""保存模型"""
joblib.dump({
'vectorizer': self.vectorizer,
'classifier': self.classifier
}, model_path)
# 第三阶段:LLM 兜底(200-500ms,覆盖剩余 15% 复杂请求)
# 规则和 ML 分类器都无法高置信度判断时,调用大模型
INTENT_PROMPT = """你是一个电商客服意图分类器,请将用户问题分类到以下12个意图之一:
I001=订单查询(如:查物流、订单状态)
I002=退款售后(如:申请退款、商品问题)
I003=优惠咨询(如:优惠券、折扣活动)
I004=商品咨询(如:产品怎么样、有没有货)
I005=账号问题(如:忘记密码、账户异常)
I006=投诉建议(如:投诉、反馈问题)
I007=物流异常(如:快递丢失、一直不派送)
I008=发票相关(如:开发票、电子发票)
I009=支付问题(如:支付失败、无法付款)
I010=评价管理(如:追评、删除评价)
I011=活动咨询(如:活动规则、参与方式)
I012=其他/寒暄(如:你好、谢谢、再见)
用户问题:{user_input}
请输出JSON格式:{{"intent":"IXXX","confidence":0.XX,"reason":"分类理由"}}
只输出JSON,不要其他内容。"""
def llm_intent_classify(text: str, model: str = "qwen2-72b") -> dict:
"""
LLM 意图分类兜底方案
当规则和 ML 都无法高置信度判断时调用
"""
# 使用本地部署的 Qwen2-72B
response = ollama.chat(
model=model,
messages=[
{"role": "system", "content": INTENT_PROMPT},
{"role": "user", "content": text}
],
options={
"temperature": 0.1, # 低温度保证稳定分类
"num_predict": 200 # 限制输出长度
}
)
result = json.loads(response['message']['content'])
return result
# 完整的三层级联意图识别流程
def classify_intent(text: str) -> dict:
"""
三层级联意图识别
性能指标:
- 第一阶段(规则): < 1ms,覆盖 ~40% 请求
- 第二阶段(SVM): 10-30ms,覆盖 ~45% 请求
- 第三阶段(LLM): 200-500ms,覆盖 ~15% 请求
- 平均响应时间: ~15ms(整体)
"""
# 层1:规则匹配
intent = rule_based_intent(text)
if intent:
return {"intent": intent, "confidence": 0.99, "stage": "rule"}
# 层2:SVM 分类
intent, confidence = svm_classifier.predict(text)
if confidence > 0.85:
return {"intent": intent, "confidence": confidence, "stage": "svm"}
# 层3:LLM 兜底
result = llm_intent_classify(text)
return {
"intent": result["intent"],
"confidence": result["confidence"],
"stage": "llm",
"reason": result["reason"]
}
3.3 意图识别效果数据
上线后效果:
| 指标 | 上线前(纯人工) | 上线后(AI辅助) | 提升 |
| 平均响应时间 | 45s(高峰期排队) | 3.2s | ↓ 93% |
| 意图识别准确率 | N/A | 92.3% | - |
| 转人工率 | 100%(全人工) | 12.7% | ↓ 87.3% |
| 人工客服日均处理 | 625条/人 | 2800条/人 | ↑ 348% |
| 用户满意度 | 72% | 89% | ↑ 17pp |
| 单次咨询成本 | 8.5元 | 0.08元 | ↓ 99% |
四、RAG 知识库模块
4.1 知识库文档结构
知识库文档分类(总计 3.2万条知识条目):
├── 产品知识(8000条)
│ ├── 商品详情(名称、规格、价格、库存)
│ ├── SKU变体(颜色、尺寸、套餐)
│ └── 比对信息(与其他品牌对比)
├── 政策规则(5000条)
│ ├── 退换货政策(7天无理由、质量问题)
│ ├── 优惠券规则(满减、叠加、有效期)
│ ├── 会员权益(积分、等级、专属优惠)
│ └── 活动规则(双十一、618等)
├── 物流信息(6000条)
│ ├── 快递公司编码与联系方式
│ ├── 配送时效(分区、特殊地区)
│ └── 物流异常处理流程
├── 常见问题(10000条)
│ ├── TOP100 问题(覆盖80%咨询)
│ ├── 新手引导(如何下单、支付、查订单)
│ └── 账户问题(注册、登录、密码找回)
└── 接待策略(3000条)
├── 情绪安抚话术(投诉、差评处理)
├── 升级转人工标准
└── 禁止回复内容(不能承诺的优惠)
4.2 文档处理流水线
# 文档处理流水线:从原始文档到可检索向量
import pymupdf # PDF 解析
import pypandoc # Word 转换
from bs4 import BeautifulSoup # HTML 解析
import jieba # 中文分词
import hashlib # 内容去重
class DocumentProcessor:
"""
文档处理流水线:
1. 格式检测与解析(PDF/Word/HTML/TXT)
2. 内容清洗(去除噪音、提取正文)
3. 分块处理(基于语义/长度双维度)
4. 向量化(embedding)
5. 写入向量数据库
"""
def __init__(self, embedder, vector_db):
self.embedder = embedder
self.vector_db = vector_db
def process(self, file_path: str, category: str, metadata: dict = None):
"""
处理单个文档
Args:
file_path: 文件路径
category: 知识库分类(I001-I012)
metadata: 额外元数据(作者、日期、标签等)
"""
# 1. 检测文件格式并解析
content = self._parse_file(file_path)
# 2. 内容清洗
cleaned = self._clean_content(content)
# 3. 分块处理(递归字符分割 + 语义边界检测)
chunks = self._chunk_text(cleaned, max_tokens=500)
# 4. 生成向量并写入数据库
for i, chunk in enumerate(chunks):
chunk_hash = hashlib.md5(chunk.encode()).hexdigest()
# 检查是否已存在(去重)
if self._exists_in_db(chunk_hash):
continue
# 生成向量
embedding = self.embedder.encode(chunk)
# 写入向量数据库
self.vector_db.insert(
id=chunk_hash,
text=chunk,
vector=embedding,
metadata={
"category": category,
"source": file_path,
"chunk_index": i,
**metadata
}
)
def _parse_file(self, file_path: str) -> str:
"""根据文件格式选择解析器"""
ext = os.path.splitext(file_path)[1].lower()
parsers = {
'.pdf': self._parse_pdf,
'.docx': self._parse_docx,
'.doc': self._parse_doc,
'.html': self._parse_html,
'.txt': self._parse_txt,
}
parser = parsers.get(ext, self._parse_txt)
return parser(file_path)
def _parse_pdf(self, file_path: str) -> str:
"""解析 PDF 文件"""
text_parts = []
with pymupdf.open(file_path) as doc:
for page in doc:
text_parts.append(page.get_text())
return "\n".join(text_parts)
def _parse_docx(self, file_path: str) -> str:
"""解析 Word 文档"""
from docx import Document
doc = Document(file_path)
return "\n".join([p.text for p in doc.paragraphs])
def _parse_html(self, file_path: str) -> str:
"""解析 HTML 文件"""
with open(file_path, 'r', encoding='utf-8') as f:
soup = BeautifulSoup(f.read(), 'html.parser')
# 移除 script 和 style 标签
for tag in soup(['script', 'style', 'nav', 'footer']):
tag.decompose()
return soup.get_text(separator="\n", strip=True)
def _clean_content(self, text: str) -> str:
"""内容清洗"""
# 移除多余空白
text = re.sub(r'\n{3,}', '\n\n', text)
text = re.sub(r' {2,}', ' ', text)
# 移除特殊控制字符
text = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', text)
return text.strip()
def _chunk_text(self, text: str, max_tokens: int = 500) -> List[str]:
"""
智能分块:基于 token 数和语义边界双重限制
语义边界优先级:
1. 段落分隔(\n\n)—— 优先保证段落完整
2. 句子分隔(。)—— 次优先
3. 硬截断 —— 最后的兜底手段
"""
chunks = []
# 先按段落分割
paragraphs = text.split('\n\n')
current_chunk = []
current_token_count = 0
for para in paragraphs:
para_tokens = self._estimate_tokens(para)
# 如果单个段落就超过 max_tokens,进一步分割
if para_tokens > max_tokens:
if current_chunk:
chunks.append('\n\n'.join(current_chunk))
current_chunk = []
current_token_count = 0
# 递归分割长段落
sub_chunks = self._split_long_paragraph(para, max_tokens)
chunks.extend(sub_chunks)
elif current_token_count + para_tokens > max_tokens:
# 当前块满了,保存并新建
chunks.append('\n\n'.join(current_chunk))
current_chunk = [para]
current_token_count = para_tokens
else:
current_chunk.append(para)
current_token_count += para_tokens
if current_chunk:
chunks.append('\n\n'.join(current_chunk))
return [c.strip() for c in chunks if c.strip()]
def _estimate_tokens(self, text: str) -> int:
"""估算中文字符数(粗略:1中文≈1.5 token)"""
chinese = sum(1 for c in text if '\u4e00' <= c <= '\u9fff')
other = len(text) - chinese
return int(chinese * 1.5 + other * 0.25)
def _exists_in_db(self, chunk_hash: str) -> bool:
"""检查内容是否已存在(去重)"""
return self.vector_db.exists(chunk_hash)
五、对话管理模块(Dify 工作流)
5.1 对话流程设计
用户发消息
↓
【接入】Nginx → Gateway → 渠道适配
↓
【意图识别】三层级联(规则→SVM→LLM)
↓
意图分流
├── I001-I005(高频明确意图)
│ └── → 知识库检索(RAG)→ 生成答案 → 用户
│
├── I006/I009(投诉/支付问题)
│ └── → 高置信度判断:RAG+流程 | 低置信度:转人工
│
└── I012(寒暄)
└── → 简单回复 + 意图学习样本收集
↓
【满意度评价】每轮对话结束
↓
【数据统计】Kafka → 实时大屏 + 日报
5.2 Dify 工作流配置
Dify 工作流用于编排复杂对话逻辑,关键配置如下:
# Dify 工作流 JSON 配置(简化版)
# 实际通过 Dify 可视化界面配置,此处展示结构
workflow = {
"version": "1.0",
"nodes": [
{
"id": "node_start",
"type": "start",
"config": {
"inputs": {"user_message": "{{user.message}}"},
"outputs": {"message": "user_message"}
}
},
{
"id": "node_intent",
"type": "llm",
"config": {
"model": "qwen2-72b",
"prompt": INTENT_PROMPT,
"inputs": {"user_input": "{{node_start.message}}"},
"outputs": {"intent": "result.intent", "confidence": "result.confidence"}
}
},
{
"id": "node_router",
"type": "if-else",
"config": {
"condition": "{{node_intent.confidence}} > 0.75",
"true_branch": "node_rag", # 高置信 → RAG 检索
"false_branch": "node_human" # 低置信 → 转人工
}
},
{
"id": "node_rag",
"type": "rag-retrieval",
"config": {
"retrieval_strategy": "semantic",
"top_k": 5,
"score_threshold": 0.6,
"category_filter": "{{node_intent.intent}}"
}
},
{
"id": "node_answer",
"type": "llm",
"config": {
"model": "qwen2-72b",
"prompt": """根据以下参考知识回答用户问题。
如果知识不足以回答,请说"这个问题我需要转人工为您解答"。
参考知识:
{{node_rag.context}}
用户问题:{{node_start.message}}
要求:
- 直接给出答案,不要说"根据知识库"
- 如需引用,在答案末尾加"[来源:文件名]"
- 保持礼貌、简洁、口语化""",
"inputs": {
"context": "{{node_rag.context}}",
"message": "{{node_start.message}}"
}
}
},
{
"id": "node_human",
"type": "http-request",
"config": {
"url": "http://ticket-service:8084/api/transfer",
"method": "POST",
"body": {
"user_id": "{{user.id}}",
"message": "{{node_start.message}}",
"intent": "{{node_intent.intent}}",
"history": "{{conversation.history}}"
}
}
},
{
"id": "node_end",
"type": "end",
"config": {
"outputs": "{{node_answer.result}}"
}
}
],
"edges": [
{"from": "node_start", "to": "node_intent"},
{"from": "node_intent", "to": "node_router"},
{"from": "node_router", "to": "node_rag", "condition": "true"},
{"from": "node_router", "to": "node_human", "condition": "false"},
{"from": "node_rag", "to": "node_answer"},
{"from": "node_answer", "to": "node_end"},
{"from": "node_human", "to": "node_end"}
]
}
六、性能优化与生产保障
6.1 延迟优化措施
| 优化项 | 做法 | 效果 |
| 意图识别缓存 | 相同问题 5 分钟内不重复识别 | 节省 40% LLM 调用 |
| RAG 结果缓存 | Redis 缓存热门问题检索结果 1 小时 | P99 延迟从 800ms 降至 120ms |
| 模型量化 | Qwen2-72B 使用 INT4 量化 | 显存从 144GB 降至 40GB,吞吐量 ↑ 2.3x |
| 异步处理 | 非关键路径(评价收集、埋点)异步化 | 主流程 P99 降低 35% |
| 预热机制 | 每日 6:00 预加载模型到 GPU | 早高峰冷启动避免 0.5s 延迟 |
6.2 高可用保障
# Kubernetes 部署配置(关键部分)
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: customer-service-intent
spec:
replicas: 3 # 3副本保障高可用
selector:
matchLabels:
app: intent-service
template:
spec:
containers:
- name: intent
image: registry.example.com/customer-service:intent-v2.3
resources:
requests:
memory: "4Gi"
cpu: "2"
limits:
memory: "8Gi"
gpu.intel.com/gpu: "1" # 申请 1 个 GPU
env:
- name: OLLAMA_BASE_URL
value: "http://ollama-service:11434"
- name: REDIS_URL
value: "redis://redis:6379/0"
readinessProbe:
httpGet:
path: /health
port: 8082
initialDelaySeconds: 30
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8082
initialDelaySeconds: 60
periodSeconds: 10
nodeSelector:
gpu: "true" # 仅调度到有 GPU 的节点
---
apiVersion: v1
kind: Service
metadata:
name: intent-service
spec:
type: ClusterIP
selector:
app: intent-service
ports:
- port: 8082
targetPort: 8082
# HPA 自动扩缩容(基于请求量)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: intent-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: customer-service-intent
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
七、总结与经验
7.1 核心经验
- 三层级联意图识别比直接用 LLM 好:规则(0ms)+ ML(20ms)+ LLM(300ms)分工,平均延迟从 300ms 降到 15ms
- RAG 的分块策略比向量模型更重要:段落级分块(500 token)比句子级效果好,语义边界检测是关键
- 转人工率不是越低越好:初期设为 10%,后期发现 I006(投诉)类转人工率太低导致客诉上升,调整到 15% 后满意度提升
- 知识库维护比系统开发更费时:3个月项目,2个月在清洗和标注知识库
7.2 下一步优化方向
- 引入多模态:支持用户上传图片(商品图、截图)直接识别
- 主动服务:通过用户行为数据(浏览、加购未付款)主动触达
- 情感识别:在意图识别基础上增加情绪分析,对负向情绪自动升级