Faiss
Faiss的简介¶
如果你正在构建一个 RAG 系统、智能问答平台、文本相似度比对、或者 AI 搜索系统,你几乎一定听过 FAISS 这个名字。
FAISS(Facebook AI Similarity Search) 是由 Meta(原 Facebook)开发的开源向量检索引擎,专为“海量向量的高效相似度搜索”而设计。它又不是数据库,而是一个超高性能的 C++/Python 向量索引库,可以让你在本地环境下进行数百万级别的向量匹配操作。如果你要的是嵌入项目的轻量向量库,首选 FAISS。
应用场景¶
- 语义检索:根据问句的语义找到最接近的文档片段
- RAG 系统:作为大模型上下文召回的向量库
- 文本聚类:找出相似内容或主题群组
- 图像 / 视频搜索:嵌入图像特征后进行相似内容比对
特点¶
| 特点 | 优势说明 |
|---|---|
| 性能极强 | 支持百万向量以内毫秒级响应(本地 CPU / GPU) |
| 部署轻量 | 不需要服务器,不需要 Docker,一句 pip 即可 |
| 本地私有化友好 | 所有数据都在你机器上,无外泄风险 |
| 模块组合灵活 | 提供 10 多种索引结构,适配不同精度 / 速度场景 |
如何衡量“相似”¶
向量检索的本质是:你给我一个向量,我从海量向量中找到它的“邻居”们。
常见的相似度度量方式有两种:
- 欧氏距离(L2 距离) 衡量两个向量在空间中的“直线距离”,距离越近表示越相似。
D(x, y) = √[(x1 - y1)^2 + (x2 - y2)^2 + ... + (xn - yn)^2]
FAISS 中使用索引类型:IndexFlatL2。
- 余弦相似度(Cosine Similarity)
衡量两个向量之间的夹角,夹角越小相似度越高,值越接近 1 表示越相似。
cos(θ) = (x · y) / (||x|| × ||y||)
其中:
- x · y 表示两个向量的点积
- ||x|| 是向量的 L2 范数(模长)
FAISS 中使用:IndexFlatIP + 向量归一化。
FAISS 在 RAG 系统中的角色¶
在现代 RAG(检索增强生成)系统中,FAISS 扮演着 “语义中间人” 的角色:帮大模型找出最有可能相关的上下文。
标准 RAG 工作流图:
【用户问题】
↓
【句子向量化】
↓
【FAISS 向量检索】
↓
【相关文段 TopK】
↓
【Prompt 拼接】
↓
【大模型生成回答】
为什么大模型必须搭配向量检索?
* 大模型不能 “凭空知道”你给的知识;
* 文档直接塞进 prompt 会超长、杂乱、失真;
* FAISS 帮你精准提取与问题最相关的语义片段,极大提升准确率。
Prompt 构建建议(适用于 LLM)
推荐使用 “资料块 + 问题” 结构拼接 prompt,提升上下文可读性:
你是一位专业的知识助手,请根据以下资料回答用户的问题。
[1] 公司是法人,有独立资产。
[2] 股东以其出资额为限承担责任。
问题:公司和股东的法律责任分别是什么?
Prompt 拼接函数示例:
def build_prompt(query: str, matched_chunks: list) -> str:
context_block = "\n".join([f"[{i+1}] {c}" for i, c in enumerate(matched_chunks)])
return f"""你是一位专业的法律助手,请根据以下资料回答用户的问题。
{context_block}
问题:{query}
"""
项目 |建议 ---|--- 上下文数量| 通常建议 Top 3~5 段,超过影响 token 上限 加编号 |[1]、[2]…便于 LLM 回答引用 指令句 |如果找不到答案,请说不知道,减少幻觉输出 合并片段 |同类文段可合并为一条,节省空间
简单流程¶
1、安装
以cpu版本为例
pip install faiss-cpu
创建一个简单的样本文本,内容如下(law.txt):
第七条:公司是企业法人,有独立的法人财产。
第八条:公司以其全部财产对公司债务承担责任。
董事会对公司的经营决策具有最终权力。
股东大会是公司的最高权力机构。
from sentence_transformers import SentenceTransformer
import numpy as np
# 加载文档内容(每行为一个 chunk)
with open("law.txt", "r", encoding="utf-8") as f:
docs = [line.strip() for line in f if line.strip()]
# 加载 embedding 模型(可替换为 bge/text2vec)
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
# 生成向量(默认维度 384)
embeddings = model.encode(docs, normalize_embeddings=True)
print(f"共生成 {len(embeddings)} 个向量,每个维度为 {embeddings.shape[1]}")
import faiss
# 创建 IndexFlatIP(使用 Cosine 相似度需先归一化)
dim = embeddings.shape[1]
index = faiss.IndexFlatIP(dim)
index.add(embeddings)
query = "公司法人要承担哪些责任?"
query_vec = model.encode([query], normalize_embeddings=True)
# 查询最相似的 top-k 向量
k = 2
D, I = index.search(np.array(query_vec), k)
# 输出检索结果
for rank, idx in enumerate(I[0]):
print(f"[Top {rank+1}] {docs[idx]}")
[Top 1] 公司以其全部财产对公司债务承担责任。
[Top 2] 公司是企业法人,有独立的法人财产。
结合大模型实例¶
1、定义工具
import os
from langchain_community.tools.tavily_search import TavilySearchResults
# 定义 AVILY_KEY 密钥
os.environ["TAVILY_API_KEY"] = "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"
# 查询 Tavily 搜索 API
search = TavilySearchResults(max_results=1)
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
import os
import dotenv
dotenv.load_dotenv()
# 1. 提供一个大模型
os.environ['OPENAI_API_KEY'] = os.getenv("aliyun_api_key")
os.environ['OPENAI_BASE_URL'] = os.getenv("aliyun_base_url")
embedding_model = OpenAIEmbeddings(model="qwen3-vl-embedding")
# 2.加载HTML内容为一个文档对象
loader = WebBaseLoader("https://zh.wikipedia.org/wiki/%E7%8C%AB")
docs = loader.load()
#print(docs)
# 3.分割文档
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200
)
documents = splitter.split_documents(docs)
# 4.向量化 得到向量数据库对象
vector = FAISS.from_documents(documents, embedding_model)
# 5.创建检索器
retriever = vector.as_retriever()
# 测试检索结果
# print(retriever.invoke("猫的特征")[0])
from langchain.tools.retriever import create_retriever_tool
# 创建一个工具来检索文档
retriever_tool = create_retriever_tool(
retriever=retriever,
name="wiki_search",
description="搜索维基百科",
)
# 构建工具集
tools = [search, retriever_tool]
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
# 获取大模型
model = ChatOpenAI(model="qwen3-max")
# 模型绑定工具
model_with_tools = model.bind_tools(tools)
# 根据输入自动调用工具
# messages = [HumanMessage(content="今天上海天气怎么样")]
# response = model_with_tools.invoke(messages)
# print(f"ContentString: {response.content}")
# print(f"ToolCalls: {response.tool_calls}")
from langchain import hub
prompt = hub.pull("hwchase17/openai-functions-agent")
# print(prompt.messages)
from langchain.agents import create_tool_calling_agent
from langchain.agents import AgentExecutor
# 创建Agent对象
agent = create_tool_calling_agent(model, tools, prompt)
# 创建AgentExecutor对象
agent_executor = AgentExecutor(agent=agent, tools=tools,verbose=True)
print(agent_executor.invoke({"input": "猫的特征"}))
7、添加记忆
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
store = {}
# 调取指定session_id对应的memory
def get_session_history(session_id: str) -> BaseChatMessageHistory:
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
agent_with_chat_history = RunnableWithMessageHistory(
runnable=agent_executor,
get_session_history=get_session_history,
input_messages_key="input",
history_messages_key="chat_history",
)
response = agent_with_chat_history.invoke(
{"input": "Hi,我的名字是Cyber"},
config={"configurable": {"session_id": "123"}},
)
print(response)
> Entering new AgentExecutor chain...
你好,Cyber!很高兴见到你。有什么我可以帮助你的吗?
> Finished chain.
{'input': 'Hi,我的名字是Cyber', 'chat_history': [], 'output': '你好,Cyber!很高兴见到你。有什么我可以帮助你的吗?'}
response = agent_with_chat_history.invoke(
{"input": "我叫什么名字?"},
config={"configurable": {"session_id": "123"}},
)
print(response)
Entering new AgentExecutor chain...
你叫Cyber。有什么特别的事情想和我分享吗?
> Finished chain.
{'input': '我叫什么名字?', 'chat_history': [HumanMessage(content='Hi,我的名字是Cyber', additional_kwargs={}, response_metadata={}), AIMessage(content='你好,Cyber!很高兴见到你。有什么我可以帮助你的吗?', additional_kwargs={}, response_metadata={})], 'output': '你叫Cyber。有什么特别的事情想和我分享吗?'}
原文链接:https://blog.csdn.net/sinat_28461591/article/details/147031798 SentenceTransformers 库介绍: https://zhuanlan.zhihu.com/p/457876366