Embeddings 模型技术实践:从语义检索到智能客服意图路由

举报
yd_54922183 发表于 2026/10/18 04:24:43 2026/10/18
【摘要】 Embeddings 模型技术实践,以智能客服意图路由为例

一、什么是 Embeddings 模型?

在自然语言处理领域,我们经常需要判断两段文本之间的语义关系。

例如:

  • 用户搜索“怎么把买的东西退掉”,系统需要找到“商品退货及退款操作流程”。
  • 用户向客服发送“我的快递怎么还没到”,系统需要将其识别为“物流查询”意图。
  • 两个用户分别提交“账户无法登录”和“输入密码后一直进不去”,系统需要发现它们可能属于相同的问题。
  • 面对数十万条客服历史对话,系统希望自动发现不同类型的问题及其分布。

这些任务的共同特点是:系统需要理解文本之间的语义关系,而不仅仅是比较关键词是否相同。

Embeddings(嵌入)模型就是解决这一问题的重要技术。

与大语言模型(LLM)生成文字不同,文本 Embeddings 模型将输入文本转换为固定维度的数值向量,使计算机可以通过数学运算比较文本之间的语义相似程度。

例如:

输入文本 A:
"我想把买来的耳机退掉"

输入文本 B:
"如何办理商品退货退款?"

输入文本 C:
"今天北京的天气怎么样?"

经过 Embeddings 模型编码:

文本 A → [0.12, -0.08, 0.32, ...]
文本 B → [0.15, -0.06, 0.29, ...]
文本 C → [-0.23, 0.41, 0.07, ...]

这里的数值仅用于展示数据形式,不是真实模型的输出。

如果模型训练得足够好,那么 A 和 B 的向量应该具有较高的语义相似度,而 A 和 C 的相似度通常较低。

1.1 Embeddings 模型的核心工作原理

我们可以将 Embeddings 模型抽象为一个函数:

[
f(x) \rightarrow \mathbf{v}\in\mathbb{R}^{d}
]

其中:

  • (x):输入的文本。
  • (f):Embeddings 模型。
  • (\mathbf{v}):输出的文本向量。
  • (d):向量维度,例如 384、512、1024 或 1536。

假设模型输出维度为 512,那么无论输入是一句话还是一段文章,都会得到一个包含 512 个数值的向量,前提是输入没有超过模型支持的长度范围。

这个向量并不是文本的压缩副本,也无法通过简单的逆向转换直接恢复原始文字。它是模型学习得到的一种语义表示。

1.2 如何计算文本相似度?

最常见的方法是余弦相似度(Cosine Similarity)。

对于向量 A 和 B:

[
\operatorname{sim}(A,B)=
\frac{A\cdot B}{|A||B|}
]

余弦相似度衡量的是两个向量在空间中的方向接近程度。

理论范围为 -1 到 1:

余弦相似度 数学含义
接近 1 向量方向非常接近
接近 0 向量近似正交
接近 -1 向量方向相反

但必须注意,余弦相似度不是语义一致的概率。

在部分 Embeddings 模型中,大量不相关文本的余弦相似度也可能明显大于 0。

因此,不能简单规定“相似度超过 0.8 就一定属于同一类别”。

这种阈值需要根据模型和实际业务数据进行验证。

1.3 Embeddings、LLM 和决策模型有什么不同?

对比维度 Embeddings 模型 生成式 LLM 决策模型
核心输出 数值向量 自然语言或结构化文本 预定义答案及概率
主要任务 语义表示与相似性计算 理解、推理、内容生成 分类、评分、路由
是否直接产生自然语言回答 否 是 通常否
是否直接输出分类概率 否 需额外设计和校准 部分模型支持
是否适合大规模预计算 是 通常不适合 视任务而定
典型应用 搜索、聚类、推荐、候选召回 问答、总结、复杂推理 意图识别、审核与决策

值得强调的是:

Embeddings 模型并不直接告诉我们某段文本属于哪个类别,而是提供一种可以用来计算相似度的表示。

要完成分类任务,还需要额外设计类别表示、相似度比较及分类策略。


二、主流纯文本 Embeddings 模型与调用方式

2.1 常见模型选择

当前比较有代表性的纯文本 Embeddings 模型包括:

模型 向量维度 主要特点
BGE-small-zh-v1.5 512 中文模型,小型,适合本地部署及快速实验
BGE-base-zh-v1.5 768 中文语义检索,可作为中等规模基线
BGE-M3 1024 多语言,支持密集、稀疏和多向量检索
Qwen3-Embedding-0.6B 最高 1024 多语言,支持指令与可配置输出维度
Qwen3-Embedding-4B 最高 2560 较大规模的多语言文本向量模型
text-embedding-3-small 默认 1536 托管 API,支持调整输出维度
text-embedding-3-large 默认 3072 托管 API,适合测试更高容量的表示能力

这里的维度、模型参数量和实际分类准确率是不同概念。

维度更高,并不必然意味着效果更好。

例如,一个针对中文文本优化的 512 维模型,在特定中文客服数据集上,完全可能优于某个更高维但训练领域不同的模型。

选择 Embeddings 模型时,建议优先考虑:

  1. 中文语义表示质量。
  2. 文本长度和截断限制。
  3. 向量维度与存储成本。
  4. 单条文本推理延迟。
  5. 批量编码吞吐量。
  6. 本地部署或 API 部署的需求。

接下来两个实践案例,我们统一使用:

BAAI/bge-small-zh-v1.5

该模型输出 512 维向量,适合演示中文语义检索及基础分类任务。

它不是当前所有任务中性能最好的模型,选择它主要是为了让示例容易理解和复现。

2.2 Embeddings API 的基本形式

对于托管式 Embeddings 服务,常见的调用方式是:

POST /v1/embeddings

请求体一般包括模型名称和输入文本。

例如:

{
  "model": "text-embedding-3-small",
  "input": [
    "我想查询订单物流",
    "如何申请商品退款"
  ]
}

接口返回的数据主要是向量,而不是回答文本。

简化后的响应结构如下:

{
  "object": "list",
  "data": [
    {
      "object": "embedding",
      "index": 0,
      "embedding": [0.012, -0.031, 0.024]
    },
    {
      "object": "embedding",
      "index": 1,
      "embedding": [-0.041, 0.017, 0.036]
    }
  ],
  "model": "text-embedding-3-small"
}

这里的三个数值只是为了简化展示,实际返回的是完整维度的向量。

如果需要使用托管 API,可以将 POST /v1/embeddings 与服务提供商给出的 API 基础地址组合起来。

不过,本文将以本地模型为主,避免 API 网络请求及密钥管理对学习过程造成干扰。

2.3 Python 环境准备

安装 Sentence Transformers:

pip install -U sentence-transformers numpy

加载模型:

from sentence_transformers import SentenceTransformer

model = SentenceTransformer(
    "BAAI/bge-small-zh-v1.5"
)

text = "我想查询订单物流"

vector = model.encode(
    text,
    normalize_embeddings=True
)

print("向量维度:", vector.shape)
print("前五个数值:", vector[:5])

输出结构类似:

向量维度:(512,)
前五个数值:[...]

其中 normalize_embeddings=True 表示对向量执行 L2 归一化,使其长度为 1。

这样,两个归一化向量的点积,就等于它们的余弦相似度。

需要注意,第一次通过模型名称加载模型时,通常需要下载权重文件。后续可以使用本地模型目录,在断网环境中运行。


三、实践案例一:基于 Embeddings 的企业知识库语义检索

3.1 案例背景

这是 Sentence Transformers 官方 Semantic Search 实践所介绍的典型应用方向。

假设我们正在开发一个企业内部知识库。

知识库中保存着大量业务制度、操作手册和常见问题解答。

例如:

文档1:
员工可以通过企业办公平台提交差旅报销申请。
申请时需要上传有效的发票和出差审批单。

文档2:
员工离职后,应在规定时间内办理设备归还,
包括笔记本电脑、工牌及其他办公资产。

文档3:
如遇企业邮箱无法登录,可以先检查账户密码,
若仍无法登录,应联系IT服务台处理。

文档4:
员工年度带薪休假天数根据入职时间及累计工作
年限确定,具体规则参照公司休假管理制度。

现在,用户输入:

我出差回来,机票和酒店费用要怎么报?

传统关键词搜索可能找不到理想答案,因为搜索词使用的是“出差”“机票”“酒店费用”,而知识库中使用的是“差旅报销”“发票”“审批单”。

虽然两者存在明显的语义联系,但字面表达并不完全一致。

Embeddings 语义检索的目标,就是让系统根据语义关系找到最相关的文档。

3.2 整体技术流程

知识库文档
    │
    ▼
文本清洗与分块
    │
    ▼
Embeddings 模型
    │
    ▼
文档向量集合
    │
    ▼
向量索引或向量数据库
    │
    │
    │         用户输入查询
    │              │
    │              ▼
    │        Embeddings 模型
    │              │
    │              ▼
    └──────── 向量相似度检索
                   │
                   ▼
              返回 Top-K
                   │
                   ▼
           相关知识库文本片段

这里有一个非常重要的架构特点:

知识库文档不需要在每次查询时重新计算 Embeddings。

它们可以预先计算并持久化保存。

只有新查询需要实时进行编码。

因此,在线检索的主要过程可以简化为:

[
q \rightarrow f(q) \rightarrow TopK
]

其中,(f(q)) 表示查询文本的向量表示。

3.3 完整 Python 实践

先构造一个简单的知识库:

from sentence_transformers import SentenceTransformer
import numpy as np

# 1. 加载 Embeddings 模型
model = SentenceTransformer(
    "BAAI/bge-small-zh-v1.5"
)

# 2. 模拟企业知识库
documents = [
    {
        "id": 1,
        "title": "差旅报销",
        "content": (
            "员工出差结束后,可以通过企业办公平台"
            "提交差旅报销申请。机票、酒店住宿费用"
            "按照财务制度报销,需要提供有效发票"
            "及出差审批单。"
        )
    },
    {
        "id": 2,
        "title": "离职设备归还",
        "content": (
            "员工离职前需要归还公司设备,包括"
            "笔记本电脑、工牌和其他办公资产。"
        )
    },
    {
        "id": 3,
        "title": "邮箱账户问题",
        "content": (
            "如果企业邮箱无法登录,可以先检查"
            "账户密码,仍无法解决时联系IT服务台。"
        )
    },
    {
        "id": 4,
        "title": "年假管理",
        "content": (
            "员工年度带薪休假天数根据累计工作"
            "年限确定,具体以休假管理制度为准。"
        )
    }
]

# 3. 需要编码的文档正文
passages = [
    doc["content"]
    for doc in documents
]

# 4. 为知识库预先生成向量
doc_vectors = model.encode(
    passages,
    normalize_embeddings=True,
    batch_size=32
)

# 5. 用户输入查询
query = "我出差回来,机票和酒店费用要怎么报?"

# BGE 中文检索模型推荐的查询指令
instruction = (
    "为这个句子生成表示以用于检索相关文章:"
)

# 6. 生成查询向量
query_vector = model.encode(
    instruction + query,
    normalize_embeddings=True
)

# 7. 计算余弦相似度
scores = doc_vectors @ query_vector

# 8. 获取排名前三的文档
top_k = 3

top_indices = np.argsort(scores)[::-1][:top_k]

for rank, index in enumerate(top_indices, start=1):

    doc = documents[index]

    print(f"排名:{rank}")
    print(f"标题:{doc['title']}")
    print(f"相似度:{scores[index]:.4f}")
    print(f"内容:{doc['content']}")
    print("-" * 40)

3.4 如何解读结果?

对于上述查询,我们希望模型把“差旅报销”排在前面。

最终输出格式如下:

排名:1
标题:差旅报销
相似度:运行后得到的实际数值
内容:员工出差结束后,可以通过企业办公平台...

排名:2
标题:其他知识库文档
相似度:运行后得到的实际数值
...

排名:3
标题:其他知识库文档
相似度:运行后得到的实际数值
...

这里没有填入人为编造的相似度,因为真实数值必须由实际模型推理获得。

上述代码的核心只有三步:

# 文档编码
doc_vectors = model.encode(
    passages,
    normalize_embeddings=True
)

# 查询编码
query_vector = model.encode(
    instruction + query,
    normalize_embeddings=True
)

# 相似度计算
scores = doc_vectors @ query_vector

这就是一个最小化的语义检索系统。

3.5 扩展:将语义检索与 RAG 结合

Embeddings 模型只能返回相关文档,无法直接基于这些文档生成完整回答。

如果希望实现类似智能知识库问答的效果,就可以在其后接入 LLM。

用户问题
   │
   ▼
Embeddings 查询编码
   │
   ▼
向量检索 Top-K
   │
   ▼
检索到相关文档
   │
   ▼
可选:Reranker 精细排序
   │
   ▼
问题 + 检索文档
   │
   ▼
LLM 生成回答
   │
   ▼
返回答案

这就是典型的 RAG(Retrieval-Augmented Generation,检索增强生成)架构。

这里有两个角色:

Embeddings 模型负责找到资料。

生成式 LLM 负责理解资料并组织回答。

在实际系统中,如果知识库较大,通常还需要:

  • 使用文本分块避免超出模型输入长度。
  • 使用 FAISS、Milvus 等建立向量索引。
  • 将向量与文档 ID、来源、权限信息关联。
  • 对检索结果执行重排序。
  • 使用混合检索补充关键词、编号和专业术语匹配。

值得注意的是,RAG 的最终效果不仅取决于 Embeddings 模型,还取决于分块、召回、重排序和生成模型。


四、实践案例二:基于 Embeddings 的智能客服意图识别与路由

4.1 案例背景

第二个案例参考 OpenAI 开发者文档中 Zero-shot Classification with Embeddings 的经典方法。

该方法的核心思想是:

将文本与类别描述分别编码为向量,通过比较相似度完成零样本分类。

假设我们正在开发一个电商智能客服系统。

用户可能表达以下意图:

意图类别 用户表达示例
退款退货 我要把商品退掉
物流查询 我的快递到哪里了
修改订单 我想修改收货地址
优惠价格 这个商品有没有优惠券
发票业务 我想申请电子发票

传统关键词分类器可以根据“退款”“快递”“发票”等关键词进行匹配。

但用户实际表达可能具有明显的多样性。

例如:

买来的东西不喜欢,能不能把钱退给我?

这句话并未直接使用“退货退款”作为固定标签名称,但其语义与退款退货高度相关。

Embeddings 模型可以用于解决这种类别表达与用户表达不一致的问题。

4.2 核心原理:类别语义匹配

首先,为每一个意图类别定义一段文字描述。

例如:

类别:退款退货

描述:
用户希望取消订单、退回已经购买的商品、
获得退款或者办理售后退货。

然后对每个类别描述生成 Embeddings。

退款退货 ──> 类别向量 A

物流查询 ──> 类别向量 B

修改订单 ──> 类别向量 C

优惠价格 ──> 类别向量 D

发票业务 ──> 类别向量 E

用户输入新文本:

我买的耳机不想要了,能退钱吗?

通过相同的模型编码:

用户文本
    │
    ▼
Embeddings 模型
    │
    ▼
用户文本向量
    │
    ▼
与所有类别向量比较
    │
    ▼
类别相似度排名
    │
    ▼
输出候选意图类别

这种分类方式不需要先训练一个专门的意图分类头,因此可以作为零样本意图分类的基线。

4.3 完整 Python 实践

from sentence_transformers import SentenceTransformer
import numpy as np

# 1. 加载模型
model = SentenceTransformer(
    "BAAI/bge-small-zh-v1.5"
)

# 2. 定义意图类别及语义描述
intent_definitions = {

    "退款退货": (
        "用户希望取消已经支付的订单、"
        "退回购买的商品、申请售后退款"
        "或者要求商家退还货款。"
    ),

    "物流查询": (
        "用户希望查询快递物流信息、"
        "配送进度、发货时间、包裹位置"
        "或者预计送达时间。"
    ),

    "修改订单": (
        "用户希望修改已经提交的订单,"
        "包括收货地址、联系电话、"
        "商品规格或收件人信息。"
    ),

    "优惠价格": (
        "用户希望了解优惠券、折扣活动、"
        "商品价格、满减优惠或者价格保护。"
    ),

    "发票业务": (
        "用户希望申请发票、补开发票、"
        "修改发票抬头或查询开票信息。"
    )
}

# 3. 提取类别信息
intent_names = list(intent_definitions.keys())

intent_texts = list(intent_definitions.values())

# 4. 预先计算类别向量
intent_vectors = model.encode(
    intent_texts,
    normalize_embeddings=True
)


def classify_intent(text, top_k=3):
    """
    对文本进行意图相似度排序。

    返回候选意图,不把相似度
    直接解释为分类概率。
    """

    # 编码用户文本
    text_vector = model.encode(
        text,
        normalize_embeddings=True
    )

    # 计算所有类别的相似度
    scores = intent_vectors @ text_vector

    # 按相似度从高到低排序
    indices = np.argsort(scores)[::-1][:top_k]

    results = []

    for index in indices:
        results.append({
            "intent": intent_names[index],
            "similarity": float(scores[index])
        })

    return results


# 5. 模拟用户输入
user_text = "买来的耳机我不想要了,能退钱吗?"

# 6. 意图识别
results = classify_intent(user_text)

for item in results:
    print(
        f"{item['intent']}: "
        f"{item['similarity']:.4f}"
    )

这段代码完成了一个基础的零样本意图分类系统。

输入是一段文本,输出是最相近的三个意图及其相似度。

4.4 如何将相似度排名转化为业务路由?

假设某次实际运行得到以下分数:

以下分数仅用于解释逻辑,不代表实际模型测量结果。

退款退货:0.91
修改订单:0.73
优惠价格:0.65

系统可以认为“退款退货”是首选候选类别。

但这不等于模型有 91% 的正确概率。

对于生产环境,可以进一步设计:

  1. 最高相似度达到业务阈值。
  2. 第一类别和第二类别具有足够大的相似度差距。
  3. 不满足条件的请求进入更强的分类模型或人工审核。

例如:

results = classify_intent(user_text, top_k=2)

best = results[0]
second = results[1]

# 以下阈值为演示值,实际应在验证集上调优
min_similarity = 0.85
min_margin = 0.08

margin = (
    best["similarity"]
    - second["similarity"]
)

if (
    best["similarity"] >= min_similarity
    and margin >= min_margin
):
    action = f"自动路由到:{best['intent']}"
else:
    action = "进入进一步意图识别流程"

print(action)

这种方法可以把 Embeddings 模型从单纯的相似度计算器,变成智能客服系统中的候选意图召回器或轻量路由模块。

不过,自动化阈值应根据误分类代价、拒识率以及实际标签分布确定。

4.5 扩展:多意图识别怎么办?

实际客服场景经常不是单意图。

例如:

我要把昨天买的耳机退掉,另外上周买的键盘快递到哪里了?

这句话至少包含两个意图:

  • 退款退货
  • 物流查询

如果仅仅选择最高相似度类别,就会丢失另一个意图。

此时,我们可以采用两个阶段:

第一阶段:Embeddings 召回候选意图。

例如:

输入:
我要把昨天买的耳机退掉,
另外上周买的键盘快递到哪里了?

Embeddings 候选召回:
1. 退款退货
2. 物流查询
3. 修改订单

第二阶段:使用多标签分类器或者决策模型进行判定。

用户文本
    │
    ▼
Embeddings 模型
    │
    ▼
候选意图 Top-K
    │
    ▼
多标签分类模型 / 决策模型
    │
    ▼
最终意图集合
    │
    ├── 退款退货
    └── 物流查询

这样做的优势是:可以先用轻量 Embeddings 模型缩小候选集合,再由更擅长精确分类的模型完成最终判断。

当然,也可以尝试对每个类别分别设定相似度阈值,直接输出多个标签。

但这种方法存在明显问题:

  • 不同类别的相似度分布可能不一致。
  • 类别之间可能语义高度重叠。
  • 文本包含某个关键词,并不意味着用户具有对应意图。
  • 一个“其他”类别通常没有清晰统一的语义中心。

因此,对于复杂的多标签系统,直接对所有类别使用相同的余弦相似度阈值,往往不是最稳妥的做法。

更合理的方案是通过业务标注数据,为不同类别分别评估阈值,或者引入监督式多标签分类器。

4.6 当意图类别达到数百个时

对于大型客服系统,可能存在:

  • 数十个一级意图。
  • 数百个二级意图。
  • 部分二级意图之间只有非常细微的区别。

此时,可以使用一种分层架构:

用户对话文本
     │
     ▼
Embeddings 模型
     │
     ▼
一级意图候选召回
     │
     ▼
关联二级意图候选召回
     │
     ▼
精细分类模型
     │
     ▼
多标签意图集合

需要强调,一级意图和二级意图不一定必须分开召回。也可以直接把全部二级意图编码后进行统一 Top-K 检索,再根据层级关系组织输出。

这取决于业务标签体系和各类意图的语义相似程度。

对于 100~200 个左右的类别,仅仅计算一次查询向量与全部预先编码类别向量的点积,通常并不是主要计算瓶颈。

真正需要关注的往往是:

  • 用户文本的 Embeddings 推理时间。
  • 候选意图召回率。
  • 相似类别之间的区分能力。
  • 最终分类阶段的端到端延迟。

所以,在规模不大的意图分类系统中,Embeddings 更值得被优化的是表示质量和候选召回效果,而不只是向量检索速度。


五、工程实践:如何提高 Embeddings 系统的效果?

5.1 区分对称检索与非对称检索

Embeddings 检索并不总是相同的任务。

对称检索(Symmetric Search)

输入和匹配对象具有相似的文本形式。

例如:

句子 A:
我想退货。

句子 B:
这件商品能退款吗?

这种情况下,可以使用相同的编码方式。

非对称检索(Asymmetric Search)

查询往往很短,而待检索内容可能是一段完整的说明文字。

例如:

查询:
差旅怎么报销?

文档:
员工完成出差任务后,应通过财务报销
系统提交申请,并上传差旅审批记录...

对于非对称检索,部分 Embeddings 模型会针对 Query 和 Document 使用不同的指令或编码机制。

例如,BGE 中文模型推荐给短查询添加:

为这个句子生成表示以用于检索相关文章:

但通常不需要给文档添加该指令。

不同模型的要求不一样。

对于 Sentence Transformers,部分支持专门查询和文档提示词的模型,可以通过:

query_vector = model.encode_query(
    query,
    normalize_embeddings=True
)

document_vectors = model.encode_document(
    documents,
    normalize_embeddings=True
)

使用模型自身配置的查询与文档编码方式。

但具体模型是否配置了这些指令,需要查看对应的模型说明。对于本文使用的 BGE 模型,手动添加官方建议的查询指令是一种明确可控的实现方式。

5.2 Embeddings 不等于语义逻辑推理

考虑两句话:

A:用户已经完成实名认证。

B:用户尚未完成实名认证。

它们包含大量相同的词汇,主题也高度一致。

Embeddings 模型可能给出较高的语义相似度。

但两句话的事实含义恰好相反。

因此,Embedding Similarity 更适合衡量文本的语义接近程度,而不是严格的逻辑蕴含、事实一致或真假关系。

对于涉及:

  • 否定词
  • 时间条件
  • 数值限制
  • 权限与身份
  • 法律条款
  • 金融交易条件

的任务,不建议只靠向量相似度做最终决策。

5.3 为什么需要 Reranker?

Embeddings 模型通常采用双塔或 Bi-Encoder 结构。

它分别编码查询和文档:

Query ──> Encoder ──> Query Vector

Document ──> Encoder ──> Document Vector

优点是可以预计算文档向量,检索速度快。

缺点是,查询和文档之间没有在最终编码阶段进行充分的逐项交互。

Reranker 则可以直接联合处理查询与候选文档,对相关性进行更精细的判断。

因此,常见组合是:

Embeddings 模型
      │
      ▼
初步召回 Top-50
      │
      ▼
Reranker
      │
      ▼
重新排序
      │
      ▼
最终 Top-5

这里的 Top-50 和 Top-5 只是示例参数。

这种方式特别适合知识库检索和相似意图较多的分类系统。

5.4 向量数据库什么时候有必要?

假设使用 512 维、Float32 向量。

每个向量所需原始存储空间约为:

[
512\times4=2048\text{ bytes}
]

如果有 10 万条文档:

[
100000\times2048

204800000\text{ bytes}
]

约为 195 MiB。

这还不包括向量索引、文档正文和元数据。

对于几百条或几千条数据,直接使用 NumPy 计算点积就可以完成原型验证。

但当数据量扩大、并发请求增加时,可以考虑:

  • FAISS:本地向量索引和近似最近邻检索。
  • Milvus:面向更大规模向量检索的数据库。
  • PostgreSQL + pgvector:在关系型数据库中增加向量检索能力。

向量数据库主要解决高效存储、索引和近邻检索,并不会自动提高 Embeddings 模型自身的语义理解能力。

5.5 模型切换时是否需要重新生成向量?

通常需要。

因为不同 Embeddings 模型学习到的向量空间并不相同。

例如:

模型 A:
文本 → 512 维向量

模型 B:
文本 → 1024 维向量

二者不仅维度不同,向量空间的语义结构也不同。

即使两个模型输出维度一样,也不能直接把它们的向量混合比较。

因此,从一个 Embeddings 模型切换到另一个模型时,通常需要重新生成知识库或类别向量,并重建相关索引。


六、如何评估 Embeddings 模型?

模型效果应当根据具体任务分别评估,而不是只比较公开排行榜上的综合分数。

6.1 语义检索任务

建议使用:

指标 含义
Recall@K 正确文档是否出现在前 K 个检索结果中
MRR 第一个正确结果在排名中有多靠前
NDCG@K 综合考虑排序位置与相关性等级
P95 Latency 95% 请求可以在多少时间内完成

对于知识库问答系统,Recall@K 往往是非常重要的指标。

因为如果正确资料未被召回,后续再强的 Reranker 或 LLM 也无法通过这些结果找到它。

6.2 意图分类任务

建议使用:

指标 含义
Top-1 Accuracy 第一候选类别是否正确
Recall@K 正确意图是否包含在前 K 个候选中
Macro-F1 对各类意图平均计算的综合分类表现
Micro-F1 汇总各类别样本预测后的综合分类表现
自动路由覆盖率 有多少请求能够直接处理
自动路由准确率 自动处理请求中实际分类正确的比例

对于一个 Embeddings + 决策模型的两阶段架构,应该分别评估:

  1. Embeddings 候选召回阶段的 Recall@K。
  2. 下游分类器在候选集合上的 Precision、Recall 和 F1。
  3. 完整链路的端到端准确率、P95 延迟和成本。

只有这样,才能判断 Embeddings 是否真正为整体系统带来了收益。

6.3 特别关注“其他”类与拒识能力

在意图识别中,经常需要支持:

意图A
意图B
意图C
其他

但 Embeddings 最近邻分类往往会遇到一个问题:

无论用户输入什么,系统总能找到最相似的已知类别。

即使用户输入:

今天公司的空调为什么这么冷?

在一个只包含退款、物流、发票的电商意图分类器中,系统仍然会返回某个最高相似度类别。

但这不意味着它真的属于该类别。

因此,需要独立设计拒识机制,例如:

  • 最低相似度阈值。
  • 第一与第二候选的分数间隔。
  • 额外的域内/域外分类器。
  • 决策模型或 LLM 的最终复核。

拒识能力对于大型意图识别系统尤其重要。


七、总结:Embeddings 模型最适合解决什么问题?

综合两个案例,可以把 Embeddings 模型的主要用途归纳如下:

场景 Embeddings 的作用
知识库语义搜索 根据问题找到相关文档
RAG 为生成式 LLM 提供相关知识
智能客服意图识别 召回最可能的意图类别
相似文本检测 发现重复或近似的表达
文本聚类 将语义相近的文本组织在一起
内容推荐 根据文本语义寻找相关内容
大规模分类 生成可复用的文本特征或候选类别

本文的第一个案例展示了 Embeddings 最经典的应用:把文本转化为向量,通过相似度计算实现语义检索。

第二个案例展示了另一种重要用途:将类别描述与用户文本映射到同一向量空间,从而构建无需专门训练分类头的初步意图识别系统。

这两个场景看起来不同,但底层方法相同:

[
\text{文本}
\rightarrow
\text{向量}
\rightarrow
\text{相似度}
\rightarrow
\text{排序或候选召回}
]

进一步说,Embeddings 模型的真正价值并不在于输出了一组浮点数,而在于它使大量原本难以直接比较的自然语言内容,变成了可以进行数学计算和快速索引的数据。

最后,如果将 Embeddings 模型、决策模型和生成式 LLM 结合,可以形成一种分层的智能处理架构:

                    用户输入
                       │
                       ▼
                 Embeddings 模型
                       │
                       ▼
                语义检索 / 候选召回
                       │
                       ▼
                结构化决策模型
                       │
             ┌─────────┴──────────┐
             │                    │
             ▼                    ▼
         简单明确任务          复杂或不确定任务
             │                    │
             ▼                    ▼
          自动处理             生成式 LLM
                                  │
                                  ▼
                             进一步分析
                                  │
                                  ▼
                             输出最终结果

这并不是所有应用都必须采用的架构,但它提供了一个有价值的工程思路:

  • Embeddings 负责高效的语义表示与候选召回。
  • 决策模型负责在明确的候选空间内判断和分类。
  • 生成式 LLM 负责开放式理解、复杂推理及文本生成。

三个模型分别承担适合自己的工作,有机会在准确率、推理成本和端到端延迟之间取得更好的平衡。

Embeddings 模型不一定是能够直接完成业务决策的模型,却往往是构建高效语义检索、智能分类和复杂 AI 工作流的重要基础组件。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。