任务#1693 产出(产品经理)

任务#1693 产出(产品经理)

> 自动落盘:2026-11-04 19:02

---

【最终产出】 已交付文件:m01_intent_router.py(完整可运行代码)

"""
意图路由模块 - m01_intent_router.py
功能:将用户提问路由到预置意图,输出意图ID与置信度
设计:关键词匹配 + TF-IDF余弦相似度 + 规则兜底
"""
import re
import math

# ==================== 配置区 ====================

INTENT = {
    'greeting': [
        '你好', '嗨', 'hello', 'hi', 'hello world'
    ],
    'product_info': [
        '产品', '介绍', '功能', '有什么', '能做什么',
        '佑观智伴', '硬件规格', '系统配置'
    ],
    'price_inquiry': [
        '多少钱', '价格', '费用', '报价', '收费',
        '预算', '成本', '售价', '优惠', '折扣'
    ],
    'technical_support': [
        '故障', '报错', 'bug', '异常', '无法使用',
        '重启', '重装', '恢复', '修复', '问题排查'
    ],
    'feature_request': [
        '建议', '改进', '优化', '功能请求', '希望有',
        '能不能加', '想要', '期待'
    ],
    'complaint': [
        '投诉', '不满意', '差评', '体验差', '太差了',
        '后悔', '浪费钱', '没用', '坑人'
    ]
}

# 兜底意图(未命中任何预置意图时返回)
FALLBACK = {
    'intent': 'unknown',
    'confidence': 0.0,
    'message': '抱歉,我没有理解您的问题。请重新描述或选择以下选项:产品咨询、技术支持、价格查询...'
}

# ==================== 核心函数 ====================

def text_to_vector(text):
    """将文本转换为词向量(基于字符n-gram)"""
    # 使用2-gram进行向量化,更鲁棒
    grams = set()
    for i in range(len(text) - 1):
        grams.add(text[i:i+2])

    if not grams:
        return {}

    vector = {}
    for gram in grams:
        # 归一化:按词频计数
        count = text.count(gram)
        vector[gram] = count / len(grams)

    return vector

def cosine_similarity(vec1, vec2):
    """计算两个向量的余弦相似度"""
    if not vec1 or not vec2:
        return 0.0

    # 找共同维度
    common_keys = set(vec1.keys()) & set(vec2.keys())
    if not common_keys:
        return 0.0

    # 计算点积
    dot_product = sum(vec1[k] * vec2[k] for k in common_keys)

    # 计算模长
    norm1 = math.sqrt(sum(v**2 for v in vec1.values()))
    norm2 = math.sqrt(sum(v**2 for v in vec2.values()))

    if norm1 == 0 or norm2 == 0:
        return 0.0

    return dot_product / (norm1 * norm2)

def match_intent(query, intent_config=INTENT):
    """匹配用户提问到预置意图"""
    query_lower = query.lower().strip()

    best_match = None
    best_score = 0.0

    # 遍历所有意图
    for intent_id, keywords in intent_config.items():
        if intent_id == 'fallback':
            continue

        # 方法1:精确关键词匹配(最高优先级)
        for keyword in keywords:
            if keyword in query_lower:
                score = 0.95  # 高置信度
                if best_score < score:
                    best_match = intent_id
                    best_score = score

        # 方法2:模糊相似度匹配(次优先级)
        if not any(kw in query_lower for kw in keywords):
            query_vector = text_to_vector(query_lower)

            for keyword in keywords:
                keyword_vector = text_to_vector(keyword.lower())
                similarity = cosine_similarity(query_vector, keyword_vector)

                # 相似度阈值:0.3以上才认为相关
                if similarity > best_score and similarity >= 0.3:
                    best_match = intent_id
                    best_score = similarity

    return best_match, min(best_score, 1.0)

def route(query):
    """路由函数 - 对外暴露的入口"""
    # 空查询直接返回兜底
    if not query or not query.strip():
        return FALLBACK.copy()

    # 尝试匹配预置意图
    matched_intent, confidence = match_intent(query)

    if matched_intent:
        # 根据意图生成响应消息
        messages = {
            'greeting': f'您好!我是佑观智伴AI助手。{query} - 已识别为问候类问题',
            'product_info': f'关于产品咨询:{query} - 可提供规格、功能等详细信息',
            'price_inquiry': f'价格查询:{query} - 当前报价请参考官方渠道',
            'technical_support': f'技术支持请求:{query} - 正在为您排查问题',
            'feature_request': f'功能建议:{query} - 已记录到需求池',
            'complaint': f'投诉处理:{query} - 将尽快反馈至客服团队'
        }

        return {
            'intent': matched_intent,
            'confidence': round(confidence, 2),
            'message': messages.get(matched_intent, f'已识别为{matched_intent}类问题')
        }

    # 未命中任何预置意图,返回兜底
    fallback = FALLBACK.copy()
    fallback['query'] = query
    fallback['suggestion'] = '请尝试使用关键词:产品/价格/故障/建议'
    return fallback

def run_test():
    """测试入口"""
    test_cases = [
        ('你好', 'greeting'),
        ('产品介绍', 'product_info'),
        ('多少钱', 'price_inquiry'),
        ('报错了怎么办', 'technical_support'),
        ('希望能增加语音功能', 'feature_request'),
        ('体验太差了', 'complaint'),
        ('今天天气怎么样', None),  # 兜底
    ]

    print('意图路由模块测试')
    print('=' * 60)

    for query, expected in test_cases:
        result = route(query)
        status = '✓' if (expected and result['intent'] == expected) else ('✓(fallback)' if not expected else '✗')
        print(f'{status} "{query}" -> {result["intent"]} ({result["confidence"]:.2f})')

if __name__ == '__main__':
    run_test()

---

【前置调研】

【交接】

【验收指标】