问题分类器(QuestionClassifier
)是Citu智能数据问答平台的核心组件,负责将用户问题分类为DATABASE
(数据库查询)或CHAT
(聊天对话)类型。本文档详细解释其基于规则的分类逻辑和评分机制。
graph TD
A[用户问题输入] --> B[提取当前问题]
B --> C[检查非业务实体词]
C --> D{包含非业务词?}
D -->|是| E[直接分类为CHAT<br/>置信度0.85]
D -->|否| F[计算各类评分]
F --> G[业务实体评分]
F --> H[系统指示词评分]
F --> I[查询意图评分]
F --> J[SQL模式评分]
F --> K[聊天关键词评分]
G --> L[组合评分逻辑]
H --> L
I --> L
J --> L
K --> L
L --> M[分类决策]
M --> N[返回分类结果]
问题分类器定义了 8种关键词类型,用于不同的分类判断:
序号 | 关键词类型 | 数据结构 | 权重/作用 | 数量 | 定义位置 |
---|---|---|---|---|---|
1 | 强业务关键词 | 字典(6个子类别) | 混合权重 | 65个 | classifier.py:49-79 |
2 | 查询意图关键词 | 列表 | +1分/词 | 25个 | classifier.py:81-87 |
3 | 非业务实体词 | 列表 | 立即CHAT(0.85) | ~80个 | classifier.py:91-122 |
4 | SQL模式 | 正则表达式列表 | +3分/匹配 | 2个 | classifier.py:126-129 |
5 | 聊天关键词 | 列表 | +1分/词 | 17个 | classifier.py:132-136 |
6 | 追问关键词 | 列表 | 上下文判断 | 16个 | classifier.py:139-143 |
7 | 话题切换关键词 | 列表 | 上下文判断 | 12个 | classifier.py:146-150 |
8 | 业务上下文文件 | 外部文本 | LLM分类辅助 | 1个文件 | tools/db_query_decision_prompt.txt |
关键概念区分:
graph TD
A[强业务关键词<br/>strong_business_keywords] --> B[业务实体词<br/>+2分/词<br/>5个子类别]
A --> C[系统查询指示词<br/>+1分/词<br/>特殊处理]
B --> D[核心业务实体]
B --> E[支付业务]
B --> F[经营品类]
B --> G[车流业务]
B --> H[地理路线]
C --> I[系统指示<br/>数据指示<br/>平台指示]
style B fill:#e1f5fe
style C fill:#fff3e0
包含关系说明:
代码实现逻辑:
# 在 _rule_based_classify 方法中
for category, keywords in self.strong_business_keywords.items():
if category == "系统查询指示词": # 系统指示词单独处理
continue
for keyword in keywords:
if keyword in question_lower:
business_score += 2 # 业务实体词权重更高
这是分类器的核心词库,分为6个业务类别:
用于识别数据查询意图,权重: +1分/词
使用正则表达式匹配SQL语句特征,权重: +3分/匹配
select|from|where|group by|order by|having|join|update
数据库|表名|表|字段名|SQL|sql|database|table
定义位置: agent/classifier.py
第91-122行
处理机制: 一旦匹配,直接分类为CHAT,置信度0.85(最高优先级判断)
具体分类:
定义位置: agent/classifier.py
第132-136行
处理机制: 倾向于聊天分类,权重: +1分/词
具体分类:
定义位置: agent/classifier.py
第139-143行
处理机制: 用于检测追问型问题,在渐进式分类中起上下文判断作用
具体分类:
定义位置: agent/classifier.py
第146-150行
处理机制: 检测明显的话题转换,避免错误继承上下文类型
具体分类:
定义位置: agent/tools/db_query_decision_prompt.txt
处理机制: 为LLM分类提供详细的业务范围描述
内容概要:
# 1. 业务实体评分 (business_score)
for 每个业务类别:
if 类别 != "系统查询指示词":
for 每个关键词:
if 关键词 in 问题:
business_score += 2
# 2. 系统指示词评分 (system_indicator_score)
for 每个系统查询指示词:
if 关键词 in 问题:
system_indicator_score += 1
# 3. 查询意图评分 (intent_score)
for 每个查询意图词:
if 关键词 in 问题:
intent_score += 1
# 4. SQL模式评分
for 每个SQL正则模式:
if 模式匹配:
business_score += 3
# 5. 聊天关键词评分 (chat_score)
for 每个聊天关键词:
if 关键词 in 问题:
chat_score += 1
系统指示词具有特殊的组合效应:
if system_indicator_score > 0 and business_score > 0:
# 系统指示词 + 业务实体 = 强组合效应
business_score += 3 # 组合加分
elif system_indicator_score > 0:
# 仅有系统指示词 = 中等业务倾向
business_score += 1
设计理念:
分类器的核心决策逻辑并非单一的规则判断,而是一个分为两个阶段的混合流程,旨在平衡效率与准确性。
此流程图准确地描述了代码中的两层决策逻辑:首先是高效的规则预分类,然后是根据置信度决定是否启动LLM二次研判的混合决策。
graph TD
subgraph "第一层:规则预分类 (_rule_based_classify)"
A["用户问题输入"] --> B{"包含非业务词?"};
B -- "是<br/>(王炸规则)" --> C["直接分类为CHAT<br/>置信度=0.85<br/>结束规则判断"];
B -- "否" --> D["业务/意图/聊天/SQL<br/>关键词评分计算"];
D --> E{"根据评分规则<br/>进行初步分类"};
E --> F["生成规则分类结果<br/>(类型 + 置信度)"];
end
subgraph "第二层:混合决策 (_hybrid_classify)"
F --> G{"规则置信度 ≥ 0.7?"};
G -- "是" --> H["🟢 毫不犹豫<br/>直接采纳规则结果"];
G -- "否" --> I["🟡 调用LLM<br/>进行二次分类"];
I --> J["比较规则与LLM的置信度"];
J --> K["择优选择置信度<br/>更高的结果"];
end
H --> L["最终分类结果"];
K --> L;
第一层:规则预分类 (_rule_based_classify
方法)
CHAT
并赋予0.85的高置信度,后续所有评分和判断流程都将被跳过。DATABASE
或CHAT
)以及对应的置信度,形成rule_result
。第二层:混合决策 (_hybrid_classify
方法)
_hybrid_classify
方法接收到第一层的rule_result
后,首先检查其置信度。如果置信度大于等于0.7
,表明规则分类已经非常有把握,系统会直接采纳该结果,不再调用LLM,从而实现高效决策。0.7
,说明情况比较模糊或规则不足以做出高可信度判断,系统会启动LLM进行更深层次的语义理解和分类,得到llm_result
。rule_result
和llm_result
的置信度,选择置信度更高的一方作为最终的分类结果。这种机制确保了即使规则分类的把握不大,也能通过LLM进行补足,同时在LLM判断不准时,仍能依赖保底的规则结果。0.7
作为高置信度阈值,是在API调用成本和决策速度之间取得的平衡。对于绝大多数意图明确的问题,可以通过高效的规则快速解决,避免了不必要的LLM调用。business_score
和intent_score
同时满足最低要求。这种设计的核心价值在于,它可以精准地阻挡那些“有查询意图,但查询对象并非业务范畴”的无效问题。例如,对于问题“分析汇总我这个月的花费”
,尽管“分析”、“汇总”有很高的意图分,但由于“花费”不是业务关键词,导致business_score
为0,无法通过任何数据库查询的门槛,从而被正确地识别为不确定问题,避免了错误的数据库查询。这套机制确保了只有意图和业务主体有效组合的问题才能被处理,大大提升了系统的鲁棒性。置信度范围 | 决策行为 | 代码位置 | 说明 |
---|---|---|---|
非业务词匹配 | 🔴 直接CHAT,置信度=0.85 | classifier.py:231-238 |
最高优先级,立即决策 |
≥ 0.7 | 🟢 毫不犹豫使用规则结果 | classifier.py:171-173 |
高置信度,不调用LLM |
< 0.7 | 🟡 规则+LLM双重判断 | classifier.py:175-182 |
取置信度更高者 |
问题: "统计服务区的微信支付金额"
规则分类: DATABASE, 置信度=0.9
决策: 直接使用规则结果,不调用LLM ✓
问题: "服务区情况"
规则分类: DATABASE, 置信度=0.6
LLM分类: DATABASE, 置信度=0.8
决策: 选择LLM结果 (0.8 > 0.6) ✓
问题: "苹果什么时候成熟"
非业务词: 苹果 ✓
决策: 直接CHAT,置信度=0.85,跳过所有其他判断 ✓
参数名 | 默认值 | 范围 | 说明 |
---|---|---|---|
high_confidence_threshold |
0.7 | 0.7-0.9 | 高置信度阈值,超过则直接使用规则结果 |
low_confidence_threshold |
0.4 | 0.2-0.5 | 低置信度阈值,低于则启用LLM辅助 |
max_confidence |
0.9 | 0.8-1.0 | 最大置信度上限,防止过度自信 |
base_confidence |
0.4 | 0.3-0.6 | 基础置信度,聊天分类的起始值 |
confidence_increment |
0.08 | 0.05-0.2 | 置信度增量步长 |
uncertain_confidence |
0.2 | 0.1-0.3 | 不确定分类的置信度 |
关键词类型 | 权重 | 用途 | 说明 |
---|---|---|---|
业务实体词 | +2分/词 | 规则评分 | 核心业务概念,强业务关键词的主要部分 |
系统指示词 | +1分/词 | 规则评分 | 系统查询指示,权重低于业务实体词 |
查询意图词 | +1分/词 | 规则评分 | 数据查询意图,辅助判断 |
SQL模式 | +3分/匹配 | 规则评分 | 技术查询特征,权重最高 |
聊天关键词 | +1分/词 | 规则评分 | 聊天交互意图 |
非业务实体词 | 立即CHAT(0.85) | 直接分类 | 最高优先级,跳过所有评分 |
追问关键词 | 无直接权重 | 上下文判断 | 检测追问型问题 |
话题切换关键词 | 无直接权重 | 上下文判断 | 检测话题转换 |
组合加分 | +3分 | 特殊逻辑 | 系统词+业务词组合效应 |
问题: "统计服务区的微信支付金额"
匹配:
- 业务实体: 服务区(+2), 微信支付(+2) → business_score=4
- 查询意图: 统计(+1) → intent_score=1
- 总分: 4+1=5
结果: DATABASE, 置信度=min(0.9, 0.8+5*0.05)=0.9
问题: "驿美运营公司档口数量"
匹配:
- 业务实体: 驿美运营公司(+2), 档口(+2) → business_score=4
- 查询意图: 无 → intent_score=0
结果: DATABASE, 置信度=min(0.9, 0.7+4*0.03)=0.82
问题: "苹果什么时候成熟"
匹配: 苹果(非业务词)
结果: CHAT, 置信度=0.85
问题: "怎么使用这个平台"
匹配:
- 聊天关键词: 怎么(+1), 使用方法(+1) → chat_score=2
- 业务实体: 无 → business_score=0
结果: CHAT, 置信度=min(0.9, 0.4+2*0.08)=0.56
问题: "请问一下"
匹配: 无关键词匹配
结果: UNCERTAIN, 置信度=0.2
def _extract_current_question_for_rule_classification(self, question: str) -> str:
"""提取当前问题用于规则分类,避免上下文干扰"""
if "\n[CURRENT]\n" in question:
current_start = question.find("\n[CURRENT]\n")
current_question = question[current_start + len("\n[CURRENT]\n"):].strip()
return current_question
return question.strip()
所有关键词匹配都转换为小写进行,确保大小写不敏感。
SQL模式使用正则表达式匹配,支持单词边界检查,避免子字符串误匹配。
本文档基于 agent/classifier.py 代码分析生成,版本日期: 2024年