gwdoc/utils/intent_matcher.py

74 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
意图匹配工具:基于关键词 + 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