一、核心背景与痛点
1. 万能 Prompt 的局限
当用户发送不同意图的请求(如 "我要退钱""你们态度太差了我要投诉")时,仅用一个万能 Prompt 会导致模型 "自信地出错":该共情时询问订单号,该查物流时解释退款政策,无法精准匹配不同场景的需求。
2. 单层路由的短板
实现的 "最小路由"(意图识别 + 阈值 + 兜底)在实际应用中存在三大问题:
- 意图类别增多时,关键词表维护爆炸,易出现互相污染;
- 多意图冲突频发(如 "我要退货且投诉快递员"),置信度常不足;
- 查询物流、退款进度等场景需调用工具查库,仅靠文本回复无法满足需求。
二、核心概念解析
1. 四大基础概念
| 概念 | 定义 | 核心作用 |
|---|---|---|
| 意图(Intent) | 用户请求的业务需求类型标签(如退款、投诉、查询物流等) | 区分不同处理逻辑,匹配对应语气、流程和工具 |
| 链路(Chain) | 由 "LLM+Prompt + 输出格式" 组成的处理流程 | 为每个意图提供专业的标准化处理步骤 |
| 阈值(Threshold) | 分类器对意图识别的置信度临界值 | 防止误判,低于阈值则进入兜底流程 |
| 兜底(Fallback) | 系统不确定时的安全链路 | 将模糊请求转化为澄清性问题,避免出错 |
2. 路由核心原则
- 先决策后生成:先通过分类器判断意图,再分发到对应链路处理;
- 不确定不装懂:置信度不足时,通过兜底流程澄清需求,而非强行回应;
- 分层处理:复杂场景采用两级路由,平衡覆盖度与精准度。
三、基础路由(单层路由)实现
1. 核心流程
- 输入规范化(Normalize):去噪、切分、大小写统一;
- 意图分类(Classify):基于关键词表识别意图,计算置信度;
- 链路分发:根据置信度与阈值判断,分发到对应业务链或兜底链。
2. 代码示例(基础版)
import re
# 1. 输入规范化:去噪、切分、小写转换
def normalize_input(text: str) -> str:
# 去除多余空格和特殊符号(保留关键标点)
text = re.sub(r'\s+', ' ', text.strip())
# 仅保留中文、英文、数字和核心标点
text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9\s,。!?、]', '', text)
return text.lower()
# 2. 关键词表定义
INTENT_KEYWORDS = {
"refund": ["退款", "退钱", "退货", "取消订单", "不想要了"],
"complaint": ["投诉", "差评", "态度差", "欺骗", "举报"],
"query": ["查询", "物流", "进度", "订单号", "在哪里"]
}
# 3. 意图分类与置信度计算
def classify_intent(text: str) -> tuple[str, float, str]:
normalized_text = normalize_input(text)
score_dict = {intent: 0 for intent in INTENT_KEYWORDS}
# 关键词匹配计分
for intent, keywords in INTENT_KEYWORDS.items():
for keyword in keywords:
if keyword in normalized_text:
score_dict[intent] += 1
total_score = sum(score_dict.values())
if total_score == 0:
return "fallback", 0.0, "未命中任何关键词"
# 计算置信度(最高得分/总得分)
best_intent = max(score_dict, key=score_dict.get)
confidence = score_dict[best_intent] / total_score
reason = f"命中关键词:{[k for k in INTENT_KEYWORDS[best_intent] if k in normalized_text]}"
return best_intent, confidence, reason
# 4. 业务链路定义
def refund_chain() -> str:
return "🔹 退款处理流程:\n1. 请提供订单号和支付方式;\n2. 为您核实退款资格;\n3. 告知手续费及到账时效"
def complaint_chain() -> str:
return "🔹 投诉处理流程:\n1. 非常抱歉给您带来不佳体验!\n2. 请描述具体问题和时间线;\n3. 我们将升级处理并尽快反馈"
def query_chain() -> str:
return "🔹 查询处理流程:\n1. 请提供订单号;\n2. 为您查询相关信息;\n3. 同步最新进度"
def fallback_chain() -> str:
return "🔍 为了更好地帮助您,请选择需求类型:\n1. 退款 2. 投诉 3. 查询(物流/订单等)"
# 5. 路由主函数
def basic_router(text: str, threshold: float = 0.6) -> str:
intent, confidence, reason = classify_intent(text)
print(f"意图:{intent} | 置信度:{confidence:.2f} | 理由:{reason}")
if confidence >= threshold:
if intent == "refund":
return refund_chain()
elif intent == "complaint":
return complaint_chain()
elif intent == "query":
return query_chain()
return fallback_chain()
# 测试
if __name__ == "__main__":
test_cases = [
"我要退款,昨天买的东西不想要了",
"你们客服态度太差了,我要投诉",
"我的快递到哪了?查一下物流",
"货不对版,差评!还要退货"
]
for case in test_cases:
print(f"\n用户输入:{case}")
print(f"机器人回复:{basic_router(case)}")
3. 常见错误演示
- 未设阈值:直接分发链路,导致低置信度请求误判(如 "货不对版" 可能被误判为查询);
- 去噪过度:删除所有标点符号,丢失 "!""?" 等情绪信号;
- 无兜底链:未命中关键词时直接返回 "无法理解",用户体验差。
四、进阶路由(两级路由)实现
1. 核心优化目标
解决单层路由的三大痛点,实现:
- 类别扩容:支持更多意图类别,避免关键词表污染;
- 多意图处理:通过澄清、拆分、主次策略解决冲突;
- 工具调用:识别需查库的场景,标记
need_tool。
2. 两级路由逻辑
- 一级路由(Domain):粗分类(如售后、投诉、查询、VIP 服务);
- 二级路由(Intent):细分类(如售后下的退款、退货、取消订单);
- 策略层:判断多意图优先级、是否调用工具。
3. 代码示例(进阶版)
import re
# 1. 两级关键词表(Domain→Intent)
DOMAIN_INTENT_MAP = {
"after_sales": { # 售后域
"refund": ["退款", "退钱", "不想要了"],
"return_goods": ["退货", "寄回", "换货"],
"cancel_order": ["取消订单", "订单作废"]
},
"complaint": { # 投诉域
"service_complaint": ["态度差", "服务烂", "客服不专业"],
"product_complaint": ["质量差", "货不对版", "瑕疵"]
},
"query": { # 查询域
"logistics": ["物流", "快递", "运输", "送达时间"],
"refund_progress": ["退款进度", "到账时间", "退款状态"],
"order_info": ["订单号", "订单详情", "购买记录"]
}
}
# 风险优先级(高→低)
RISK_PRIORITY = ["complaint", "after_sales", "query"]
# 2. 一级路由:Domain分类
def classify_domain(text: str) -> tuple[list[str], list[float]]:
normalized_text = normalize_input(text) # 复用基础版的normalize_input函数
domain_scores = {domain: 0 for domain in DOMAIN_INTENT_MAP}
# 计算各域得分
for domain, intents in DOMAIN_INTENT_MAP.items():
for keywords in intents.values():
for keyword in keywords:
if keyword in normalized_text:
domain_scores[domain] += 1
# 筛选得分>0的域,按风险优先级排序
valid_domains = [d for d in RISK_PRIORITY if domain_scores[d] > 0]
valid_scores = [domain_scores[d]/sum(domain_scores.values()) for d in valid_domains]
return valid_domains, valid_scores
# 3. 二级路由:Intent分类
def classify_intent_advanced(domain: str, text: str) -> tuple[str, float]:
normalized_text = normalize_input(text)
intents = DOMAIN_INTENT_MAP[domain]
intent_scores = {intent: 0 for intent in intents}
for intent, keywords in intents.items():
for keyword in keywords:
if keyword in normalized_text:
intent_scores[intent] += 1
total_score = sum(intent_scores.values())
best_intent = max(intent_scores, key=intent_scores.get)
confidence = intent_scores[best_intent] / total_score if total_score > 0 else 0.0
return best_intent, confidence
# 4. 工具路由判断
def need_tool(intent: str) -> tuple[bool, str]:
tool_intents = {
"logistics": ("物流查询接口", "需订单号"),
"refund_progress": ("退款系统接口", "需订单号+支付方式"),
"order_info": ("订单查询接口", "需订单号")
}
return tool_intents.get(intent, (False, ""))
# 5. 进阶路由主函数
def advanced_router(text: str, threshold: float = 0.5) -> str:
# 一级Domain分类
domains, domain_scores = classify_domain(text)
if not domains:
return fallback_chain() # 复用基础版的fallback_chain函数
# 处理多域冲突(取优先级最高且置信度达标者)
main_domain = None
main_domain_confidence = 0.0
for domain, score in zip(domains, domain_scores):
if score >= threshold:
main_domain = domain
main_domain_confidence = score
break
if not main_domain:
# 多域置信度均不达标,澄清优先级最高的域
return f"🔍 您的需求涉及{domains[0]}相关,是否需要先处理{domains[0]}业务?(如退款/投诉/查询)"
# 二级Intent分类
intent, intent_confidence = classify_intent_advanced(main_domain, text)
need_tool_flag, tool_info = need_tool(intent)
# 生成回复
response = f"📌 业务类型:{main_domain}→{intent}\n"
if need_tool_flag:
response += f"🔧 需调用工具:{tool_info}\n"
# 业务逻辑补充
if main_domain == "after_sales" and intent == "refund":
response += "流程:提供订单号→核实资格→告知到账时效"
elif main_domain == "complaint" and intent == "service_complaint":
response += "流程:道歉→记录问题→升级处理(24小时内反馈)"
elif main_domain == "query" and intent == "logistics":
response += "流程:提供订单号→调用物流接口→返回实时进度"
return response
# 测试
if __name__ == "__main__":
test_cases = [
"我要退货,而且你们客服态度特别差",
"查询我的退款进度,订单号123456",
"货不对版,要求换货并投诉质量问题"
]
for case in test_cases:
print(f"\n用户输入:{case}")
print(f"机器人回复:{advanced_router(case)}")
五、关键注意事项
- 阈值调整:需平衡精准度与覆盖率,过高易频繁兜底,过低易误判;
- 链路设计:每个链路需明确流程步骤,避免冗余,同时保留灵活性;
- 可观测性:输出意图、置信度、理由等日志,便于调试链路错误;
- 兜底设计:兜底不是 "无法理解",而是通过选择题、补充信息等方式引导用户明确需求。