You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

类语义相似时,如何提升文本相似度匹配与分类性能?

FAQ同主题细粒度匹配优化方案

一、嵌入层优化:跳出全局语义陷阱

  • 改用专门优化句对相似度的预训练模型:比如sentence-transformers的all-MiniLM-L6-v2,这类模型通过对比学习训练,针对同主题下的细粒度语义区分做了优化,比通用BERT的CLS向量更适配FAQ匹配场景,无需微调即可直接使用。
  • 替换CLS向量为加权token嵌入聚合:原代码仅用CLS token,它容易被全局主题信息主导。可以计算所有token嵌入的加权平均,权重采用模型输出的注意力权重或TF-IDF权重,突出疑问词、核心动词这类关键信息的作用。

二、相似度分数的差异化处理

  • Min-Max归一化分数:把所有FAQ的相似度分数映射到0-1区间,放大最优解和其他解的差距,避免因整体分数偏高导致阈值难以设置。
  • 增加相对差异判断:除了绝对阈值,加入“最优分数与次优分数的差值”条件,比如只有当两者差值大于0.08时才返回匹配,否则弃权。这样能过滤掉多个FAQ相似度接近的模糊情况,提升匹配准确性。

三、规则辅助过滤:先缩小匹配范围

  • 疑问词类型过滤:提取用户输入和FAQ的疑问词(是什么/如何/为什么),先筛选出疑问类型一致的FAQ,再计算相似度。比如用户问“如何预防X”,直接排除所有问“X是什么”的FAQ,减少无效计算的同时提升匹配精度。
  • 核心实体匹配:提取输入和FAQ中的核心实体,优先保留实体一致的FAQ,再做语义相似度计算,进一步缩小候选范围。

四、优化后的代码示例

示例1:使用Sentence-Transformers模型+分数归一化

from sentence_transformers import SentenceTransformer, util
import numpy as np

def mapping(user_input: str, abstain_threshold: float,
            language_model='all-MiniLM-L6-v2', faqs_file='faqs.txt'):
    # 加载针对句相似度优化的预训练模型
    model = SentenceTransformer(language_model)
    
    # 读取FAQ列表
    with open(faqs_file, 'r') as f:
        faqs = [line.strip() for line in f]
    
    # 生成句向量
    user_emb = model.encode(user_input, convert_to_tensor=True)
    faq_embs = model.encode(faqs, convert_to_tensor=True)
    
    # 计算余弦相似度
    cos_scores = util.cos_sim(user_emb, faq_embs)[0].cpu().numpy()
    
    # 对分数做Min-Max归一化,放大差异
    normalized_scores = (cos_scores - cos_scores.min()) / (cos_scores.max() - cos_scores.min() + 1e-6)
    
    # 获取最优和次优分数
    sorted_indices = np.argsort(cos_scores)[::-1]
    max_score = cos_scores[sorted_indices[0]]
    second_max_score = cos_scores[sorted_indices[1]] if len(faqs) > 1 else 0
    
    # 双重判断:绝对阈值 + 相对差异
    if max_score >= abstain_threshold and (max_score - second_max_score) >= 0.08:
        return faqs[sorted_indices[0]]
    else:
        return None

示例2:增加疑问词规则过滤(兼容原模型)

from transformers import AutoTokenizer, AutoModel
import torch
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
import spacy

# 加载英文分词与词性标注模型
nlp = spacy.load("en_core_web_sm")

def get_question_category(text):
    doc = nlp(text.lower())
    for token in doc:
        # 匹配疑问词对应的词性
        if token.tag_ in ("WDT", "WP", "WRB"):
            if token.text in ["what", "who", "which"]:
                return "definition"
            elif token.text in ["how", "way", "method"]:
                return "procedure"
            elif token.text in ["why", "reason", "cause"]:
                return "explanation"
    return "other"

def mapping(user_input: str, abstain_threshold: float,
            language_model='distilbert-base-uncased', faqs_file='faqs.txt'):
    # 加载模型和分词器
    tokenizer = AutoTokenizer.from_pretrained(language_model)
    model = AutoModel.from_pretrained(language_model)

    # 读取FAQ列表
    with open(faqs_file, 'r') as f:
        faqs = [line.strip() for line in f]
    
    # 先过滤同类型的FAQ
    user_category = get_question_category(user_input)
    filtered_faqs = []
    original_indices = []
    for idx, faq in enumerate(faqs):
        if get_question_category(faq) == user_category:
            filtered_faqs.append(faq)
            original_indices.append(idx)
    
    # 如果没有同类型FAQ,保留全部
    if not filtered_faqs:
        filtered_faqs = faqs
        original_indices = list(range(len(faqs)))

    # 分词与张量转换(原逻辑,仅针对过滤后的FAQ)
    user_input_tokens = tokenizer.encode(user_input, add_special_tokens=True)
    faq_tokens = [tokenizer.encode(faq, add_special_tokens=True) for faq in filtered_faqs]

    max_len = max(len(tokens) for tokens in faq_tokens + [user_input_tokens])
    user_input_tokens = user_input_tokens + [0] * (max_len - len(user_input_tokens))
    faq_tokens = [tokens + [0] * (max_len - len(tokens)) for tokens in faq_tokens]

    user_input_tensor = torch.tensor(user_input_tokens).unsqueeze(0)
    faq_tensors = [torch.tensor(tokens).unsqueeze(0) for tokens in faq_tokens]

    # 生成嵌入
    with torch.no_grad():
        user_input_embedding = model(user_input_tensor)[0][:, 0, :]
        faq_transformer_embeddings = [model(faq_tensor)[0][:, 0, :] for faq_tensor in faq_tensors]

    # 计算相似度
    faq_similarity_scores = []
    for faq_emb in faq_transformer_embeddings:
        similarity = cosine_similarity(user_input_embedding, faq_emb)[0][0]
        faq_similarity_scores.append(similarity)

    # 找到最优匹配
    max_score_index = np.argmax(faq_similarity_scores)
    max_score = faq_similarity_scores[max_score_index]
    best_match = faqs[original_indices[max_score_index]]
    
    # 阈值判断(可增加相对差异条件)
    if max_score >= abstain_threshold:
        return best_match
    else:
        return None

内容的提问来源于stack exchange,提问作者cookie1986

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 18:47:19