74 lines
2.8 KiB
Python
74 lines
2.8 KiB
Python
"""
|
||
意图匹配工具:基于关键词 + embedding 语义相似度的两层确认意图判断
|
||
|
||
策略:
|
||
第一层:关键词子串匹配(零延迟,覆盖 90%+ 常见表达)
|
||
第二层:embedding 语义相似度匹配(兜底,捕获罕见/创意表达)
|
||
"""
|
||
|
||
from typing import List, Optional
|
||
|
||
# ──────────────────────────────────────────────
|
||
# 确认意图短语表(信息充足 / 开始行动)
|
||
# ──────────────────────────────────────────────
|
||
CONFIRM_PHRASES: List[str] = [
|
||
# 直接确认
|
||
"确认", "是的", "对", "好的", "没问题", "行", "可以", "OK",
|
||
# 信息充足
|
||
"足够", "够了", "齐了", "信息完整", "不用补充", "不需要补充",
|
||
"就这些", "没有了", "信息够了", "不用再加了", "信息齐了",
|
||
# 开始行动
|
||
"开始诊断", "开始操作", "开始吧", "继续", "开始",
|
||
# 复合确认
|
||
"确认并继续", "正确", "没错", "对的", "是的开始", "就这样",
|
||
]
|
||
|
||
# 预计算的短语 embedding 缓存
|
||
_phrase_embeddings: Optional[List[List[float]]] = None
|
||
|
||
|
||
async def _ensure_phrase_embeddings() -> None:
|
||
"""确保确认短语的 embedding 已预计算(懒加载,仅首次调用时执行)"""
|
||
global _phrase_embeddings
|
||
if _phrase_embeddings is not None:
|
||
return
|
||
from modelsAPI.model_api import OpenaiAPI
|
||
_phrase_embeddings = await OpenaiAPI.get_embeddings_batch_async(CONFIRM_PHRASES)
|
||
print(f"[intent_matcher] 确认短语 embedding 预计算完成,共 {len(CONFIRM_PHRASES)} 条")
|
||
|
||
|
||
async def is_confirmation_intent(user_query: str, threshold: float = 0.78) -> bool:
|
||
"""
|
||
判断用户输入是否为确认意图
|
||
|
||
Args:
|
||
user_query: 用户输入文本
|
||
threshold: embedding 语义相似度阈值(默认 0.78)
|
||
|
||
Returns:
|
||
True 表示用户表达了确认/信息充足的意图
|
||
"""
|
||
if not user_query or not user_query.strip():
|
||
return True
|
||
|
||
# 第一层:关键词子串匹配(零延迟)
|
||
if any(kw in user_query for kw in CONFIRM_PHRASES):
|
||
return True
|
||
|
||
# 第二层:embedding 语义相似度匹配(兜底)
|
||
await _ensure_phrase_embeddings()
|
||
from modelsAPI.model_api import OpenaiAPI
|
||
|
||
query_embedding = await OpenaiAPI.get_embeddings_async(user_query)
|
||
similarities = OpenaiAPI.cosine_similarity_batch(query_embedding, _phrase_embeddings)
|
||
max_sim = max(similarities) if similarities else 0.0
|
||
|
||
if max_sim >= threshold:
|
||
matched_phrase = CONFIRM_PHRASES[similarities.index(max_sim)]
|
||
print(f"[intent_matcher] embedding 兜底命中: sim={max_sim:.3f}, "
|
||
f"matched='{matched_phrase}', query='{user_query}'")
|
||
return True
|
||
|
||
return False
|
||
|