昨天的 RAG 入门用的是关键词匹配,有个问题:用户搜"猫咪"找不到"猫",因为字不一样。
今天用 Embedding API 实现真正的语义搜索——让"猫咪"能找到"猫",让"小狗"能找到"狗"。
一、Embedding 是什么?
简单理解:把文字变成一串数字,意思相近的数字也相近。
"猫" → [0.23, 0.45, 0.12, -0.08, 0.33, ...]
"猫咪" → [0.24, 0.44, 0.13, -0.07, 0.32, ...] (和"猫"的数字很像!)
"小狗" → [0.25, 0.43, 0.14, -0.09, 0.31, ...] (和"狗"的数字很像!)
"汽车" → [0.01, 0.02, 0.88, 0.55, 0.12, ...] (和"猫""狗"差别很大)
用处:用户问"猫咪怎么养",能找到关于"猫"的文档,即使文档里没有"猫咪"这个词。
二、Embedding API 怎么用?
调用 Embedding API
import requests
# Embedding API(阿里云/智谱等都有提供)
EMBEDDING_URL = "https://dashscope.aliyuncs.com/api/v1/services/embeddings/text-embedding/text-embedding"
HEADERS = {
"Authorization": "Bearer your-api-key",
"Content-Type": "application/json"
}
def get_embedding(text):
"""把文字转成向量"""
data = {
"model": "text-embedding-v2",
"input": {"texts": [text]}
}
response = requests.post(EMBEDDING_URL, headers=HEADERS, json=data)
result = response.json()
# 返回向量(一串数字)
return result["output"]["embeddings"][0]["embedding"]
# 测试
vec_cat = get_embedding("猫")
vec_kitty = get_embedding("猫咪")
print(f"猫的向量长度:{len(vec_cat)}")
print(f"猫咪的向量长度:{len(vec_kitty)}")
计算向量相似度
def cosine_similarity(vec1, vec2):
"""计算两个向量的相似度(余弦相似度)"""
import numpy as np
# 转成 numpy 数组
a = np.array(vec1)
b = np.array(vec2)
# 计算余弦相似度
similarity = np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
return similarity
# 测试
sim_cat_kitty = cosine_similarity(vec_cat, vec_kitty)
sim_cat_car = cosine_similarity(vec_cat, get_embedding("汽车"))
print(f"猫 vs 猫咪 相似度:{sim_cat_kitty:.3f}") # 0.95(很像)
print(f"猫 vs 汽车 相似度:{sim_cat_car:.3f}") # 0.12(不像)
三、实战:用 Embedding 实现 RAG
第一步:把文档转成向量
# 学习记录文档
documents = [
{"id": 1, "content": "2026-04-15 学习了 cat,意思是猫"},
{"id": 2, "content": "2026-04-16 学习了 dog,意思是狗"},
{"id": 3, "content": "2026-04-17 学习了 bird,意思是鸟"},
]
# 给每个文档生成向量
def build_vector_index(documents):
"""把所有文档转成向量,存起来"""
for doc in documents:
doc["embedding"] = get_embedding(doc["content"])
return documents
# 构建向量索引
indexed_docs = build_vector_index(documents)
print(f"已为 {len(indexed_docs)} 条文档生成向量")
第二步:用向量相似度检索
def retrieve_by_embedding(query, documents, top_k=3):
"""用向量相似度检索相关文档"""
# 把用户问题转成向量
query_embedding = get_embedding(query)
# 计算每个文档的相似度
results = []
for doc in documents:
similarity = cosine_similarity(query_embedding, doc["embedding"])
results.append({
"content": doc["content"],
"score": similarity
})
# 按相似度排序,取前 top_k 个
results.sort(key=lambda x: x["score"], reverse=True)
return results[:top_k]
# 测试语义搜索
query = "我学了什么猫咪相关的单词"
docs = retrieve_by_embedding(query, indexed_docs)
for doc in docs:
print(f"相似度 {doc['score']:.3f}: {doc['content']}")
运行效果:
用户问:"我学了什么猫咪相关的单词"
关键词匹配:找不到(文档里没有"猫咪")
向量匹配:
相似度 0.87: "2026-04-15 学习了 cat,意思是猫"
相似度 0.42: "2026-04-16 学习了 dog,意思是狗"
相似度 0.31: "2026-04-17 学习了 bird,意思是鸟"
成功!用户说"猫咪",找到了关于"猫"的记录。
四、关键词匹配 vs 向量匹配对比
| 关键词匹配(Day 2) | 向量匹配(Day 3) | |
|---|---|---|
| 搜"猫咪" | ❌ 找不到"猫" | ✅ 能找到"猫" |
| 搜"小狗" | ❌ 找不到"狗" | ✅ 能找到"狗" |
| 搜"宠物" | ❌ 找不到"猫/狗" | ✅ 能找到"猫/狗" |
| 实现难度 | 简单 | 需要 Embedding API |
| 速度 | 快 | 需要计算向量 |
| 准确度 | 字面匹配 | 语义匹配 |
五、完整代码流程
def rag_with_embedding(query, documents):
"""用 Embedding 实现完整 RAG 流程"""
# 1. 检索:用向量相似度找相关文档
print("【第一步:向量检索】")
docs = retrieve_by_embedding(query, documents)
print(f"找到 {len(docs)} 条相关文档")
for doc in docs:
print(f" 相似度 {doc['score']:.3f}: {doc['content'][:50]}...")
# 2. 增强:把检索结果加到问题里
print("\n【第二步:增强 Prompt】")
context = "\n".join([doc["content"] for doc in docs])
augmented_prompt = f"""
根据以下学习记录回答:
{context}
问题:{query}
"""
print(f"增强后的 prompt(前100字):{augmented_prompt[:100]}...")
# 3. 生成:调用 AI 回答
print("\n【第三步:生成回答】")
answer = call_ai(augmented_prompt)
print(f"AI 回答:{answer}")
return answer
# 测试
rag_with_embedding("我学了什么宠物相关的单词?", indexed_docs)
六、代码结构
week3/02_rag/
├── app.py # Day 2:关键词匹配版
├── app_embedding.py # Day 3:向量匹配版(新增)
└── documents/
└── learning_records.json # 学习记录数据
七、今日总结
今天干了啥:
- ✅ 理解 Embedding API 怎么用(把文字转成向量)
- ✅ 实现向量相似度计算(余弦相似度)
- ✅ 用 Embedding 替换关键词匹配,实现真正的语义搜索
- ✅ 测试效果:用户说"猫咪"能找到"猫"
对比效果:
| 用户问题 | Day 2 关键词匹配 | Day 3 向量匹配 |
|---|---|---|
| "猫咪相关单词" | ❌ 找不到 | ✅ 找到 cat |
| "小狗相关单词" | ❌ 找不到 | ✅ 找到 dog |
| "宠物相关单词" | ❌ 找不到 | ✅ 找到 cat/dog |
写于 2026-04-19,RAG 实战——用 Embedding 实现语义搜索