深入理解10个主流Embedding模型,从安装到使用的完整流程
Embedding模型将文本转换为向量(数字数组),让计算机能"理解"文本语义相似度
文本输入
"什么是RAG系统?"
模型处理
通过Transformer网络编码
向量输出
[0.23, -0.14, 0.67, ... ] (1024维)
智源AI研究院 - 中文Embedding王者
向量维度
1024
最大长度
512
模型大小
1.3GB
准确率
95%
# ========== 步骤1:安装 ==========
pip install sentence-transformers
# 如果遇到网络问题,使用清华镜像
pip install sentence-transformers -i https://pypi.tuna.tsinghua.edu.cn/simple
# ========== 步骤2:导入与初始化 ==========
from sentence_transformers import SentenceTransformer
import numpy as np
# 加载模型(首次会自动下载1.3GB)
model = SentenceTransformer('BAAI/bge-large-zh-v1.5')
print("✅ 模型加载成功!")
# ========== 步骤3:基础使用 ==========
# 单个文本编码
text = "RAG是检索增强生成系统"
embedding = model.encode(text)
print(f"文本:{text}")
print(f"向量维度:{embedding.shape}") # (1024,)
print(f"向量前5维:{embedding[:5]}")
# ========== 步骤4:批量编码(效率更高) ==========
texts = [
"什么是RAG系统?",
"向量数据库有哪些?",
"Embedding模型如何选择?"
]
embeddings = model.encode(texts, batch_size=32)
print(f"批量编码:{len(texts)}个文本 -> {embeddings.shape}")
# ========== 步骤5:计算相似度 ==========
def cosine_similarity(vec1, vec2):
"""计算余弦相似度"""
return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
# 计算两个文本的相似度
text1 = "RAG检索系统"
text2 = "检索增强生成"
text3 = "今天天气真好"
emb1 = model.encode(text1)
emb2 = model.encode(text2)
emb3 = model.encode(text3)
sim_12 = cosine_similarity(emb1, emb2)
sim_13 = cosine_similarity(emb1, emb3)
print(f"\n相似度对比:")
print(f"'{text1}' vs '{text2}': {sim_12:.3f}") # 高相似度:0.856
print(f"'{text1}' vs '{text3}': {sim_13:.3f}") # 低相似度:0.123
# ========== 步骤6:RAG检索示例 ==========
# 知识库文档
knowledge_base = [
"RAG是检索增强生成系统,结合信息检索和LLM",
"向量数据库用于存储文档向量",
"Embedding模型将文本转为向量",
"Python是一门编程语言"
]
# 查询
query = "什么是RAG?"
# 编码
query_emb = model.encode(query)
doc_embs = model.encode(knowledge_base)
# 计算相似度
similarities = [cosine_similarity(query_emb, doc_emb) for doc_emb in doc_embs]
# 排序获取top-3
top_indices = np.argsort(similarities)[::-1][:3]
print(f"\n🔍 查询:{query}")
print("📄 检索结果(相似度排序):")
for i, idx in enumerate(top_indices, 1):
print(f"{i}. {knowledge_base[idx]} (相似度: {similarities[idx]:.3f})")
# ========== 步骤7:性能优化 ==========
# GPU加速(如果有GPU)
# model = SentenceTransformer('BAAI/bge-large-zh-v1.5', device='cuda')
# 规范化向量(提升检索速度)
embeddings_normalized = model.encode(texts, normalize_embeddings=True)
print(f"\n✨ 向量已规范化(模为1)")
OpenAI - 英文和多语言最佳选择
# ========== 步骤1:安装 ==========
pip install openai
# ========== 步骤2:配置API密钥 ==========
import openai
import os
os.environ["OPENAI_API_KEY"] = "sk-your-api-key-here"
openai.api_key = os.getenv("OPENAI_API_KEY")
# ========== 步骤3:基础使用 ==========
def get_embedding(text, model="text-embedding-3-large"):
"""获取文本向量"""
response = openai.Embedding.create(
model=model,
input=text
)
return response['data'][0]['embedding']
# 单个文本
embedding = get_embedding("What is RAG system?")
print(f"维度:{len(embedding)}") # 3072
# ========== 步骤4:批量处理 ==========
texts = [
"Retrieval Augmented Generation",
"Vector database for semantic search",
"Embedding models comparison"
]
# 批量调用(更高效,降低成本)
response = openai.Embedding.create(
model="text-embedding-3-large",
input=texts
)
embeddings = [item['embedding'] for item in response['data']]
print(f"批量编码:{len(embeddings)}个文本")
# ========== 步骤5:降维使用(可选) ==========
# text-embedding-3支持指定维度(节省存储和成本)
response_small = openai.Embedding.create(
model="text-embedding-3-large",
input="RAG system guide",
dimensions=1024 # 从3072降到1024
)
embedding_1024 = response_small['data'][0]['embedding']
print(f"降维后:{len(embedding_1024)}维") # 1024
# ========== 步骤6:成本计算 ==========
total_tokens = sum(len(text.split()) for text in texts) * 1.3 # 粗略估算
cost = (total_tokens / 1_000_000) * 0.13
print(f"\n💰 成本:约${cost:.6f}")
🏆 核心优势
💰 成本分析
📊 性能数据
Moka - 中文轻量级高性能模型
向量维度
768
最大长度
512
模型大小
400MB
准确率
92%
# ========== 步骤1:安装 ==========
pip install sentence-transformers
# ========== 步骤2:加载模型 ==========
from sentence_transformers import SentenceTransformer
# 加载m3e-base模型
model = SentenceTransformer('moka-ai/m3e-base')
print("✅ m3e-base模型加载成功!")
# ========== 步骤3:基础编码 ==========
# 单个文本
text = "m3e是轻量级中文embedding模型"
embedding = model.encode(text)
print(f"向量维度: {embedding.shape}") # (768,)
# 批量编码
texts = [
"向量检索系统",
"语义搜索引擎",
"文档相似度计算"
]
embeddings = model.encode(texts)
print(f"批量编码: {embeddings.shape}") # (3, 768)
# ========== 步骤4:中文语义搜索实战 ==========
import numpy as np
# 知识库
knowledge = [
"Python是一种高级编程语言",
"机器学习需要大量数据",
"深度学习是AI的子领域",
"今天天气很好"
]
# 查询
query = "什么是人工智能的分支?"
# 编码
query_vec = model.encode(query)
doc_vecs = model.encode(knowledge)
# 计算相似度
def cosine_sim(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
scores = [cosine_sim(query_vec, doc) for doc in doc_vecs]
top_idx = np.argmax(scores)
print(f"\n🔍 查询: {query}")
print(f"📄 最匹配: {knowledge[top_idx]}")
print(f"💯 相似度: {scores[top_idx]:.3f}")
# ========== 步骤5:性能对比测试 ==========
import time
test_texts = ["测试文本"] * 100
# 测试编码速度
start = time.time()
embeddings = model.encode(test_texts, batch_size=32, show_progress_bar=False)
elapsed = time.time() - start
print(f"\n⚡ 编码100条文本耗时: {elapsed:.2f}秒")
print(f"📊 平均每条: {elapsed/100*1000:.1f}ms")
智源AI - 多语言、多粒度、多功能三合一
向量维度
1024
最大长度
8192
支持语言
100+
准确率
96%
# ========== 步骤1:安装 ==========
pip install FlagEmbedding
# ========== 步骤2:加载模型 ==========
from FlagEmbedding import BGEM3FlagModel
# 加载bge-m3模型
model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True) # FP16加速
print("✅ bge-m3模型加载成功!")
# ========== 步骤3:三种编码模式 ==========
# 模式1: 密集向量(Dense)- 最常用
texts = ["人工智能发展", "AI technology progress", "IA développement"]
dense_embeddings = model.encode(
texts,
return_dense=True, # 密集向量
return_sparse=False,
return_colbert_vecs=False
)['dense_vecs']
print(f"密集向量维度: {dense_embeddings.shape}") # (3, 1024)
# 模式2: 稀疏向量(Sparse)- 关键词匹配
sparse_embeddings = model.encode(
texts,
return_dense=False,
return_sparse=True, # 稀疏向量(类似BM25)
return_colbert_vecs=False
)['lexical_weights']
print(f"稀疏向量: {len(sparse_embeddings)}个文本")
# 模式3: ColBERT多向量 - 精细检索
colbert_embeddings = model.encode(
texts,
return_dense=False,
return_sparse=False,
return_colbert_vecs=True # 多向量表示
)['colbert_vecs']
print(f"ColBERT向量: {len(colbert_embeddings)}个文本")
# ========== 步骤4:跨语言语义搜索 ==========
import numpy as np
# 多语言知识库
docs = [
"机器学习是人工智能的核心",
"Machine learning is core to AI",
"L'apprentissage automatique est au cœur de l'IA",
"今天天气很好"
]
# 中文查询
query = "什么是AI的核心技术?"
# 编码
query_vec = model.encode(query, return_dense=True, return_sparse=False,
return_colbert_vecs=False)['dense_vecs'][0]
doc_vecs = model.encode(docs, return_dense=True, return_sparse=False,
return_colbert_vecs=False)['dense_vecs']
# 计算相似度
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
scores = [cosine_similarity(query_vec, doc) for doc in doc_vecs]
ranked = sorted(enumerate(scores), key=lambda x: x[1], reverse=True)
print(f"\n🔍 查询: {query}")
print("📄 跨语言检索结果:")
for idx, score in ranked[:3]:
print(f" {idx+1}. {docs[idx][:50]} (相似度: {score:.3f})")
# ========== 步骤5:长文本处理 ==========
# bge-m3支持8192 tokens,适合长文档
long_text = "这是一篇很长的文档..." * 500 # 模拟长文本
long_embedding = model.encode(
[long_text],
max_length=8192, # 支持超长文本
return_dense=True,
return_sparse=False,
return_colbert_vecs=False
)['dense_vecs']
print(f"\n📄 长文本编码: {long_embedding.shape}")
# ========== 步骤6:混合检索(Dense + Sparse) ==========
query = "深度学习算法"
docs = ["深度学习是神经网络", "机器学习包括监督学习", "自然语言处理应用"]
# 同时获取密集和稀疏向量
query_result = model.encode(query, return_dense=True, return_sparse=True,
return_colbert_vecs=False)
doc_results = model.encode(docs, return_dense=True, return_sparse=True,
return_colbert_vecs=False)
# 密集向量相似度
dense_scores = [cosine_similarity(query_result['dense_vecs'][0], doc)
for doc in doc_results['dense_vecs']]
print(f"\n🎯 混合检索结果:")
print(f"密集向量top1: {docs[np.argmax(dense_scores)]}")
print(f"分数: {max(dense_scores):.3f}")
1️⃣ Multi-Lingual 多语言
支持100+语言,中英日韩等主流语言效果优异,真正的跨语言语义理解
2️⃣ Multi-Granularity 多粒度
支持短文本到长文本(8192 tokens),自动处理不同粒度的语义
3️⃣ Multi-Functionality 多功能
Dense密集检索 + Sparse关键词 + ColBERT精细匹配,三合一
shibing624 - 简单易用的中文向量化工具
# ========== 安装 ==========
pip install text2vec
# ========== 使用(超简单!)==========
from text2vec import SentenceModel
# 加载模型
model = SentenceModel('shibing624/text2vec-base-chinese')
# 编码
texts = ["如何学习自然语言处理", "机器学习入门教程"]
embeddings = model.encode(texts)
print(f"向量维度: {embeddings.shape}") # (2, 768)
# 计算相似度(内置方法)
similarity = model.similarity(texts[0], texts[1])
print(f"相似度: {similarity:.3f}")
阿里达摩院 - 通用文本嵌入模型
# ========== 安装与使用 ==========
from sentence_transformers import SentenceTransformer
# 加载GTE模型
model = SentenceTransformer('thenlper/gte-large-zh')
# 编码
texts = ["检索增强生成系统", "RAG应用实践"]
embeddings = model.encode(texts)
print(f"GTE向量: {embeddings.shape}") # (2, 1024)
# GTE特色:支持query-doc区分
# 查询时添加前缀
query = "Represent this sentence for searching relevant passages: RAG系统"
docs = ["passage: 检索增强生成系统介绍", "passage: 向量数据库应用"]
query_emb = model.encode(query)
doc_embs = model.encode(docs)
# 计算相似度
import numpy as np
scores = np.dot(query_emb, doc_embs.T)
print(f"检索分数: {scores}")
Sentence-BERT - 超轻量英文模型
向量维度
384
模型大小
90MB
推理速度
5ms
准确率
88%
# ========== 安装与使用 ==========
from sentence_transformers import SentenceTransformer
# 加载超轻量模型
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
# 编码英文文本
texts = [
"Machine learning for beginners",
"Deep learning tutorial",
"Natural language processing"
]
embeddings = model.encode(texts)
print(f"向量维度: {embeddings.shape}") # (3, 384)
print(f"模型大小: ~90MB")
# ========== 移动端部署示例 ==========
# 导出ONNX格式(用于移动端)
import torch
dummy_input = torch.randn(1, 128) # 假设输入
torch.onnx.export(
model,
dummy_input,
"minilm_mobile.onnx",
opset_version=11
)
print("✅ 已导出移动端模型!")
# ========== 性能测试 ==========
import time
# 测试1000条编码速度
test_texts = ["test sentence"] * 1000
start = time.time()
embeddings = model.encode(test_texts, batch_size=64, show_progress_bar=False)
elapsed = time.time() - start
print(f"\n⚡ 1000条编码耗时: {elapsed:.2f}秒")
print(f"📊 平均每条: {elapsed/1000*1000:.1f}ms")
print(f"🚀 吞吐量: {1000/elapsed:.0f} docs/sec")
微软 - 多语言文本嵌入模型
# ========== 安装与使用 ==========
from sentence_transformers import SentenceTransformer
# 加载E5模型
model = SentenceTransformer('intfloat/e5-large-v2')
# E5特殊用法:需要添加前缀
query = "query: What is machine learning?"
docs = [
"passage: Machine learning is a subset of AI",
"passage: Deep learning uses neural networks"
]
# 编码
query_emb = model.encode(query)
doc_embs = model.encode(docs)
# 计算相似度
import numpy as np
scores = np.dot(query_emb, doc_embs.T)
print(f"相似度分数: {scores}")
# ========== 多语言示例 ==========
multilingual_texts = [
"query: 什么是人工智能?",
"passage: Artificial intelligence is...",
"passage: 人工智能是计算机科学的分支"
]
embeddings = model.encode(multilingual_texts)
print(f"多语言编码: {embeddings.shape}")
OpenAI - 图文多模态模型
向量维度
512
模态
图+文
图像尺寸
224x224
准确率
94%
# ========== 安装 ==========
pip install torch torchvision transformers pillow
# ========== 图文检索示例 ==========
from transformers import CLIPProcessor, CLIPModel
from PIL import Image
import torch
# 加载模型
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
# 准备图像和文本
image = Image.open("cat.jpg")
texts = ["a photo of a cat", "a photo of a dog", "a landscape"]
# 编码
inputs = processor(text=texts, images=image, return_tensors="pt", padding=True)
outputs = model(**inputs)
# 获取相似度
logits_per_image = outputs.logits_per_image # 图像-文本相似度
probs = logits_per_image.softmax(dim=1) # 概率
print("图像与文本的匹配概率:")
for text, prob in zip(texts, probs[0]):
print(f" {text}: {prob:.3f}")
# ========== 以图搜图 ==========
image1 = Image.open("cat1.jpg")
image2 = Image.open("cat2.jpg")
image3 = Image.open("dog.jpg")
images = [image1, image2, image3]
# 编码图像
inputs = processor(images=images, return_tensors="pt", padding=True)
image_features = model.get_image_features(**inputs)
# 计算相似度
similarity = torch.nn.functional.cosine_similarity(
image_features[0].unsqueeze(0),
image_features[1:]
)
print(f"\n以图搜图相似度:")
print(f"cat1 vs cat2: {similarity[0]:.3f}")
print(f"cat1 vs dog: {similarity[1]:.3f}")
# ========== 获取向量用于存储 ==========
# 文本向量
text_inputs = processor(text=["machine learning"], return_tensors="pt", padding=True)
text_features = model.get_text_features(**text_inputs)
print(f"\n文本向量维度: {text_features.shape}") # (1, 512)
# 图像向量
image_inputs = processor(images=image, return_tensors="pt")
image_features = model.get_image_features(**image_inputs)
print(f"图像向量维度: {image_features.shape}") # (1, 512)
Cohere - 企业级商业API
# ========== 安装 ==========
pip install cohere
# ========== 使用 ==========
import cohere
# 初始化客户端
co = cohere.Client("your-api-key")
# 编码文本
texts = ["Retrieval augmented generation", "Vector database"]
response = co.embed(
texts=texts,
model='embed-multilingual-v3.0',
input_type='search_document' # 或 'search_query'
)
embeddings = response.embeddings
print(f"向量维度: {len(embeddings[0])}") # 1024
# ========== 检索场景 ==========
# 1. 编码文档(用于存储)
docs = ["Document 1 content", "Document 2 content"]
doc_response = co.embed(
texts=docs,
model='embed-multilingual-v3.0',
input_type='search_document',
truncate='END'
)
# 2. 编码查询
query = "Find relevant information"
query_response = co.embed(
texts=[query],
model='embed-multilingual-v3.0',
input_type='search_query' # 查询类型
)
# ========== 成本计算 ==========
# embed-multilingual-v3.0: $0.10/1M tokens
total_tokens = sum(len(text.split()) for text in texts) * 1.3
cost = (total_tokens / 1_000_000) * 0.10
print(f"\n💰 成本: ${cost:.6f}")
| 模型 | 维度 | 语言 | 最大长度 | 模型大小 | 准确率 | 成本 | 最佳场景 |
|---|---|---|---|---|---|---|---|
| bge-large-zh-v1.5 | 1024 |
中文 | 512 | 1.3GB | 95% | 免费 | 中文知识库 |
| text-embedding-3 | 3072 |
多语言 | 8191 | API | 98% | $0.13/1M | 英文/国际 |
| m3e-base | 768 |
中文 | 512 | 400MB | 92% | 免费 | 轻量应用 |
| bge-m3 | 1024 |
100+ | 8192 | 2.2GB | 96% | 免费 | 跨语言长文本 |
| text2vec-base | 768 |
中文 | 512 | 400MB | 90% | 免费 | 入门学习 |
| GTE-large-zh | 1024 |
中英 | 512 | 1.3GB | 94% | 免费 | 通用文本 |
| all-MiniLM-L6-v2 | 384 |
英文 | 256 | 90MB | 88% | 免费 | 边缘计算 |
| E5-large-v2 | 1024 |
多语言 | 512 | 1.3GB | 95% | 免费 | 多语言检索 |
| CLIP (ViT-B/32) | 512 |
图+文 | 77 | 350MB | 94% | 免费 | 多模态搜索 |
| Cohere Embed v3 | 1024 |
多语言 | 512 | API | 96% | $0.10/1M | 企业应用 |
🇨🇳
中文项目
bge-large-zh-v1.5
🌏
英文/国际
text-embedding-3
📱
轻量/边缘
all-MiniLM-L6-v2
📚
长文档
bge-m3
✅ 优先考虑因素:
⚠️ 常见误区:
从零开始构建生产级Embedding应用
使用bge-large-zh + 向量数据库
# ========== 步骤1: 安装依赖 ==========
pip install sentence-transformers chromadb pypdf
# ========== 步骤2: 导入库 ==========
from sentence_transformers import SentenceTransformer
import chromadb
from pathlib import Path
import pypdf
# ========== 步骤3: 初始化 ==========
# 加载Embedding模型
model = SentenceTransformer('BAAI/bge-large-zh-v1.5')
# 初始化向量数据库
client = chromadb.PersistentClient(path="./chroma_db")
collection = client.get_or_create_collection(
name="knowledge_base",
metadata={"description": "企业知识库"}
)
print("✅ 系统初始化完成")
# ========== 步骤4: 文档处理 ==========
def load_documents(folder_path):
"""加载文档并分块"""
docs = []
folder = Path(folder_path)
# 处理PDF文件
for pdf_file in folder.glob("*.pdf"):
with open(pdf_file, 'rb') as f:
pdf_reader = pypdf.PdfReader(f)
text = ""
for page in pdf_reader.pages:
text += page.extract_text()
# 简单分块(每500字符)
chunks = [text[i:i+500] for i in range(0, len(text), 500)]
for idx, chunk in enumerate(chunks):
docs.append({
'id': f"{pdf_file.stem}_{idx}",
'text': chunk,
'source': pdf_file.name,
'chunk_id': idx
})
return docs
# 加载文档
documents = load_documents("./knowledge_docs")
print(f"📄 加载了 {len(documents)} 个文档块")
# ========== 步骤5: 向量化并存储 ==========
def index_documents(documents):
"""批量向量化并存储"""
batch_size = 32
for i in range(0, len(documents), batch_size):
batch = documents[i:i+batch_size]
# 提取文本
texts = [doc['text'] for doc in batch]
ids = [doc['id'] for doc in batch]
metadatas = [{k: v for k, v in doc.items() if k != 'text'}
for doc in batch]
# 生成向量
embeddings = model.encode(texts, show_progress_bar=True)
# 存入数据库
collection.add(
embeddings=embeddings.tolist(),
documents=texts,
ids=ids,
metadatas=metadatas
)
print(f"✅ 已处理 {min(i+batch_size, len(documents))}/{len(documents)}")
# 执行索引
index_documents(documents)
# ========== 步骤6: 检索函数 ==========
def search_knowledge(query, top_k=5):
"""语义检索"""
# 查询向量化
query_embedding = model.encode(query)
# 检索
results = collection.query(
query_embeddings=[query_embedding.tolist()],
n_results=top_k
)
# 格式化结果
formatted_results = []
for i in range(len(results['ids'][0])):
formatted_results.append({
'id': results['ids'][0][i],
'text': results['documents'][0][i],
'distance': results['distances'][0][i],
'metadata': results['metadatas'][0][i]
})
return formatted_results
# ========== 步骤7: 测试检索 ==========
query = "如何提高团队协作效率?"
results = search_knowledge(query, top_k=3)
print(f"\n🔍 查询: {query}")
print("\n📄 检索结果:")
for i, result in enumerate(results, 1):
print(f"\n{i}. 来源: {result['metadata']['source']}")
print(f" 相似度: {1-result['distance']:.3f}")
print(f" 内容: {result['text'][:100]}...")
# ========== 步骤8: 增量更新 ==========
def add_new_document(text, doc_id, metadata=None):
"""添加新文档"""
embedding = model.encode(text)
collection.add(
embeddings=[embedding.tolist()],
documents=[text],
ids=[doc_id],
metadatas=[metadata or {}]
)
print(f"✅ 已添加文档: {doc_id}")
# 示例:添加新文档
add_new_document(
text="敏捷开发提倡迭代式增量开发...",
doc_id="agile_dev_001",
metadata={"category": "开发方法论", "date": "2025-01-15"}
)
# ========== 步骤9: 持久化 ==========
# ChromaDB自动持久化,无需额外操作
print("\n✅ 知识库构建完成!")
print(f"📊 统计: 共 {collection.count()} 个文档块")
支持模糊搜索、同义词、相关概念
# ========== 完整语义搜索引擎 ==========
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
import json
from typing import List, Dict
class SemanticSearchEngine:
def __init__(self, model_name='BAAI/bge-large-zh-v1.5'):
"""初始化搜索引擎"""
self.model = SentenceTransformer(model_name)
self.index = None
self.documents = []
self.dimension = 1024
def build_index(self, documents: List[Dict]):
"""构建FAISS索引"""
print("🔨 开始构建索引...")
# 提取文本
texts = [doc['text'] for doc in documents]
self.documents = documents
# 向量化
embeddings = self.model.encode(
texts,
batch_size=64,
show_progress_bar=True,
normalize_embeddings=True # L2规范化
)
# 创建FAISS索引(使用HNSW)
self.index = faiss.IndexHNSWFlat(self.dimension, 32)
self.index.hnsw.efConstruction = 40
self.index.hnsw.efSearch = 16
# 添加向量
self.index.add(embeddings.astype('float32'))
print(f"✅ 索引构建完成!共 {len(documents)} 条记录")
def search(self, query: str, top_k: int = 10, filters: Dict = None):
"""语义搜索"""
# 查询向量化
query_vec = self.model.encode(
query,
normalize_embeddings=True
).astype('float32').reshape(1, -1)
# 检索
distances, indices = self.index.search(query_vec, top_k * 2)
# 格式化结果
results = []
for dist, idx in zip(distances[0], indices[0]):
if idx == -1: # 无效索引
continue
doc = self.documents[idx].copy()
doc['score'] = float(1 / (1 + dist)) # 转换为相似度分数
# 应用过滤器
if filters:
if not self._apply_filters(doc, filters):
continue
results.append(doc)
if len(results) >= top_k:
break
return results
def _apply_filters(self, doc: Dict, filters: Dict) -> bool:
"""应用过滤条件"""
for key, value in filters.items():
if key not in doc or doc[key] != value:
return False
return True
def save_index(self, filepath: str):
"""保存索引"""
faiss.write_index(self.index, f"{filepath}.index")
with open(f"{filepath}.docs", 'w', encoding='utf-8') as f:
json.dump(self.documents, f, ensure_ascii=False, indent=2)
print(f"✅ 索引已保存到 {filepath}")
def load_index(self, filepath: str):
"""加载索引"""
self.index = faiss.read_index(f"{filepath}.index")
with open(f"{filepath}.docs", 'r', encoding='utf-8') as f:
self.documents = json.load(f)
print(f"✅ 索引已加载,共 {len(self.documents)} 条记录")
# ========== 使用示例 ==========
# 准备数据
documents = [
{
"id": 1,
"text": "机器学习是人工智能的核心技术",
"category": "AI",
"date": "2025-01-01"
},
{
"id": 2,
"text": "深度学习使用神经网络进行训练",
"category": "AI",
"date": "2025-01-02"
},
{
"id": 3,
"text": "Python是数据科学最流行的编程语言",
"category": "编程",
"date": "2025-01-03"
},
# ... 更多文档
]
# 初始化搜索引擎
engine = SemanticSearchEngine()
# 构建索引
engine.build_index(documents)
# 保存索引(可选)
engine.save_index("./search_index")
# ========== 搜索测试 ==========
# 1. 基础搜索
results = engine.search("人工智能技术", top_k=5)
print("\n🔍 搜索: 人工智能技术")
for result in results:
print(f" [{result['score']:.3f}] {result['text']}")
# 2. 带过滤器的搜索
results = engine.search(
"编程语言",
top_k=5,
filters={"category": "编程"}
)
print("\n🔍 搜索: 编程语言 (仅限编程类)")
for result in results:
print(f" [{result['score']:.3f}] {result['text']}")
# 3. 模糊搜索(同义词)
queries = ["AI技术", "人工智能", "机器智能"]
for query in queries:
results = engine.search(query, top_k=3)
print(f"\n🔍 搜索: {query}")
print(f" 最佳匹配: {results[0]['text']}")
print("\n✅ 搜索引擎测试完成!")
基于语义相似度的智能去重
# ========== 文本去重系统 ==========
from sentence_transformers import SentenceTransformer
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
from tqdm import tqdm
class TextDeduplicator:
def __init__(self, threshold=0.90):
"""
threshold: 相似度阈值,超过此值认为是重复
"""
self.model = SentenceTransformer('BAAI/bge-large-zh-v1.5')
self.threshold = threshold
def deduplicate(self, texts: list) -> dict:
"""去重并返回结果"""
print(f"📊 开始处理 {len(texts)} 条文本...")
# 1. 向量化
embeddings = self.model.encode(
texts,
batch_size=64,
show_progress_bar=True,
normalize_embeddings=True
)
# 2. 计算相似度矩阵
print("🔍 计算相似度...")
similarity_matrix = cosine_similarity(embeddings)
# 3. 去重逻辑
unique_indices = []
duplicate_groups = []
processed = set()
for i in tqdm(range(len(texts))):
if i in processed:
continue
# 找到与当前文本相似的所有文本
similar_indices = np.where(
similarity_matrix[i] > self.threshold
)[0]
if len(similar_indices) > 1:
# 有重复
duplicate_groups.append({
'master': i,
'duplicates': [j for j in similar_indices if j != i],
'texts': [texts[j] for j in similar_indices],
'similarities': [similarity_matrix[i][j]
for j in similar_indices]
})
processed.update(similar_indices)
else:
# 唯一文本
unique_indices.append(i)
processed.add(i)
# 4. 返回结果
return {
'unique_texts': [texts[i] for i in unique_indices],
'unique_count': len(unique_indices),
'original_count': len(texts),
'duplicate_groups': duplicate_groups,
'dedup_rate': 1 - len(unique_indices) / len(texts)
}
# ========== 使用示例 ==========
texts = [
"机器学习是人工智能的核心技术",
"机器学习是AI的核心", # 重复
"深度学习使用神经网络",
"Python是最流行的编程语言",
"Python是最受欢迎的编程语言", # 重复
"自然语言处理技术发展迅速",
]
# 初始化去重器
deduplicator = TextDeduplicator(threshold=0.85)
# 执行去重
result = deduplicator.deduplicate(texts)
# 打印结果
print(f"\n📊 去重统计:")
print(f" 原始文本数: {result['original_count']}")
print(f" 去重后数量: {result['unique_count']}")
print(f" 去重率: {result['dedup_rate']*100:.1f}%")
print(f"\n🔄 发现 {len(result['duplicate_groups'])} 组重复:")
for i, group in enumerate(result['duplicate_groups'], 1):
print(f"\n 组{i} (主文本索引: {group['master']}):")
print(f" 主: {texts[group['master']]}")
for dup_idx, sim in zip(group['duplicates'], group['similarities'][1:]):
print(f" └─ [{sim:.3f}] {texts[dup_idx]}")
A: 不可以。不同模型的向量空间完全不同,无法直接比较。如果更换模型,需要重新对所有文档进行向量化。
💡 建议:选定模型后保持稳定,避免频繁更换。
A: 在真实数据上测试。准备100-200个查询-文档对,计算准确率、召回率、MRR等指标。
💡 推荐工具:MTEB评测框架、自建测试集。
A: 不一定。高维度增加存储和计算成本,但不一定提升效果。要看模型训练质量。
💡 实践:768-1024维是性价比最优的选择。
A: 1) 选择支持长文本的模型(bge-m3) 2) 智能分块 3) 滑动窗口 4) 层次化编码。
💡 推荐:按段落分块,保留上下文重叠。
A: 取决于规模。小规模(<1万文档)CPU够用;大规模或实时要求高用GPU,提速10-50倍。
💡 方案:离线索引用GPU,在线查询用CPU。
A: 小规模(<1万)可用NumPy/FAISS;大规模(>10万)建议用专业向量数据库(Milvus/Qdrant)。
💡 选择:根据规模、性能、预算综合考虑。