在之前我们学习了如何让大模型"说话"(LLMs)和"聊天"(Chat Models)。但在构建
RAG(检索增强生成)系统时,还有一个至关重要的环节:让模型"理解"文本的语义 。
计算机无法直接理解"苹果"和"水果"之间的关系,但它能理解向量(Vector) 。通过将文本转换为高维空间中的向量,我们可以计算它们之间的相似度。这个过程叫做Embedding(嵌入)。 本文将带你掌握如何在 LangChain 中使用阿里云 DashScope 的 Embedding 模型,将文字转化为机器可计算的数字向量。
📊 LangChain API 全景回顾
在开始之前,我们先梳理一下目前掌握的 LangChain 核心组件。不同的任务对应不同的类和方法:
| 组件类型 | 作用 | 阿里云 (DashScope) 导入路径 | 核心方法 |
|---|---|---|---|
| LLMs (大语言模型) | 文本生成、补全 | langchain_community.llms.tongyi import Tongyi |
invoke() (批量)stream() (流式) |
| Chat Models (聊天模型) | 多轮对话、角色扮演 | langchain_community.chat_models.tongyi import ChatTongyi |
invoke() (批量)stream() (流式) |
| Embeddings (文本嵌入) | 文本转向量 (本课重点) | langchain_community.embeddings import DashScopeEmbeddings |
embed_query() (单次)embed_documents() (批量) |
💡 关键区别:
- LLMs 和 Chat Models 输出的是文本。
- Embeddings 模型输出的是浮点数列表(向量)。
- Embeddings 不需要 也不支持
stream流式输出,因为向量计算是一次性完成的。
🛠️ 实战:调用阿里云 Embedding 模型
我们将使用阿里云通义千问提供的 text-embedding-v1 模型(默认),将中文句子转换为 1536 维的向量。
1. 环境准备
确保你已经安装了必要的库,并配置了阿里云的 API Key。
bash
pip install langchain-community dashscope
设置环境变量(或在代码中指定):
python
import os
os.environ["DASHSCOPE_API_KEY"] = "sk-..." # 替换为你的真实 Key
2. 代码实现
python
from langchain_community.embeddings import DashScopeEmbeddings
# 1. 创建模型对象
# 如果不传 model 参数,默认使用 text-embedding-v1 (1536 维)
# 也可以指定其他模型,如 model="text-embedding-v2"
model = DashScopeEmbeddings()
print("🚀 开始向量化测试...\n")
# ---------------------------------------------------------
# 场景 A: 单次查询转换 (embed_query)
# 适用于:用户输入一个问题,需要将其转为向量去数据库搜索
# ---------------------------------------------------------
query_text = "我喜欢你"
print(f"📝 原文:{query_text}")
# embed_query 返回一个 list[float]
query_vector = model.embed_query(query_text)
print(f"🔢 向量维度:{len(query_vector)}")
print(f"🔢 向量前 5 位:{query_vector[:5]}... (省略后续)")
print("-" * 30)
# ---------------------------------------------------------
# 场景 B: 批量文档转换 (embed_documents)
# 适用于:初始化知识库时,将大量文档切片转为向量存入数据库
# ---------------------------------------------------------
docs = [
"我喜欢你",
"我很喜欢你",
"晚上吃啥"
]
print(f"📚 批量处理 {len(docs)} 个文档...")
doc_vectors = model.embed_documents(docs)
print(f"✅ 成功生成 {len(doc_vectors)} 个向量")
for i, vec in enumerate(doc_vectors):
print(f"文档 {i+1} ('{docs[i]}') -> 向量维度: {len(vec)}")
3. 代码深度解析
A. 初始化模型
python
model = DashScopeEmbeddings()
这里不需要像 LLM 那样传入 model_name="qwen-max",因为 Embedding 模型的版本较少。默认就是 text-embedding-v1,它针对中文语境进行了优化,输出维度为 1536。
B. embed_query vs embed_documents
这是 Embedding 类最重要的两个方法,用途截然不同:
-
embed_query(text: str) -> List[float]- 输入:单个字符串。
- 输出:单个向量列表。
- 场景 :检索阶段。当用户提问"如何做红烧肉?"时,你用这个方法把问题变成向量,然后去向量数据库里找最相似的文档。
-
embed_documents(texts: List[str]) -> List[List[float]]- 输入:字符串列表。
- 输出:向量列表的列表(二维数组)。
- 场景 :入库阶段 。当你有一万个文档切片需要存入向量数据库时,必须用这个方法批量处理。
- 优势 :批量调用比循环调用
embed_query一万次要快得多,且能节省 API 请求次数。
C. 为什么没有 invoke 和 stream?
- 无
stream:向量计算是数学运算,结果是瞬间确定的(或者需要等待几毫秒到几百毫秒),不存在"逐字生成"的过程,所以不需要流式输出。 - 无
invoke:虽然底层逻辑类似,但 LangChain 专门为 Embedding 定义了embed_*接口,以明确区分"生成文本"和"生成向量"这两种完全不同的任务。
🔍 向量的意义:语义相似度
运行上面的代码后,你会发现:
- "我喜欢你" 和 "我很喜欢你" 生成的向量虽然数值不同,但在高维空间中距离非常近。
- "晚上吃啥" 生成的向量与前两者距离较远。
这就是 RAG 的核心原理:
- 把知识库里的所有句子都变成向量存起来。
- 用户提问时,把问题也变成向量。
- 计算问题向量 和知识库向量的距离(通常是余弦相似度)。
- 找出距离最近的几个句子,作为上下文喂给大模型。
🚀 总结
本节我们补齐了 RAG 拼图中最关键的一块------Embedding。
- API 定位 :掌握了
DashScopeEmbeddings类的导入和使用。 - 核心方法 :
embed_query:用于处理用户单次提问。embed_documents:用于批量处理知识库文档。
- 理解差异:明白了 Embedding 模型输出的是数值向量,而非文本,因此不需要流式输出。