Skip to main content
Open In Colab在 GitHub 上打开

Milvus

Milvus 是一个数据库,用于存储、索引和管理由深度神经网络和其他机器学习 (ML) 模型生成的海量嵌入向量。

此笔记本介绍如何使用与 Milvus 向量数据库相关的功能。

设置

您需要安装langchain-milvuspip install -qU langchain-milvus以使用此集成。

pip install -qU langchain_milvus
Note: you may need to restart the kernel to use updated packages.

凭据

使用Milvus向量存储。

初始化

pip install -qU langchain-openai
import getpass
import os

if not os.environ.get("OPENAI_API_KEY"):
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter API key for OpenAI: ")

from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(model="text-embedding-3-large")

Milvus Lite 系列

最简单的原型方法是使用 Milvus Lite,其中所有内容都存储在本地矢量数据库文件中。只能使用 Flat 索引。

from langchain_milvus import Milvus

URI = "./milvus_example.db"

vector_store = Milvus(
embedding_function=embeddings,
connection_args={"uri": URI},
index_params={"index_type": "FLAT", "metric_type": "L2"},
)
API 参考:Milvus

Milvus 服务器

如果你有大量的数据(例如,超过 100 万个 vector),我们建议在 DockerKubernetes 上设置一个性能更高的 Milvus 服务器。

Milvus 服务器支持多种索引。利用这些不同的索引可以显著增强检索功能并加快检索过程,并根据您的特定要求进行定制。

例如,考虑 Milvus Standalone 的情况。要启动 Docker 容器,您可以运行以下命令:

!curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh -o standalone_embed.sh

!bash standalone_embed.sh start
Password:

这里我们创建一个 Milvus 数据库:

from pymilvus import Collection, MilvusException, connections, db, utility

conn = connections.connect(host="127.0.0.1", port=19530)

# Check if the database exists
db_name = "milvus_demo"
try:
existing_databases = db.list_database()
if db_name in existing_databases:
print(f"Database '{db_name}' already exists.")

# Use the database context
db.using_database(db_name)

# Drop all collections in the database
collections = utility.list_collections()
for collection_name in collections:
collection = Collection(name=collection_name)
collection.drop()
print(f"Collection '{collection_name}' has been dropped.")

db.drop_database(db_name)
print(f"Database '{db_name}' has been deleted.")
else:
print(f"Database '{db_name}' does not exist.")
database = db.create_database(db_name)
print(f"Database '{db_name}' created successfully.")
except MilvusException as e:
print(f"An error occurred: {e}")
Database 'milvus_demo' does not exist.
Database 'milvus_demo' created successfully.

请注意下面 URI 中的更改。初始化实例后,导航到 http://127.0.0.1:9091/webui 以查看本地 Web UI。

以下是如何使用 Milvus 数据库服务创建 vector store 实例的示例:

from langchain_milvus import BM25BuiltInFunction, Milvus

URI = "http://localhost:19530"

vectorstore = Milvus(
embedding_function=embeddings,
connection_args={"uri": URI, "token": "root:Milvus", "db_name": "milvus_demo"},
index_params={"index_type": "FLAT", "metric_type": "L2"},
consistency_level="Strong",
drop_old=False, # set to True if seeking to drop the collection with that name if it exists
)

如果你想使用 Milvus 的完全托管云服务 Zilliz Cloud,请调整 uri 和 token,它们对应于 Zilliz Cloud 中的 Public EndpointApi key

使用 Milvus Collections 划分数据

你可以将不相关的文档存储在同一个 Milvus 实例内的不同集合中。

以下是创建新产品系列的方法:

from langchain_core.documents import Document

vector_store_saved = Milvus.from_documents(
[Document(page_content="foo!")],
embeddings,
collection_name="langchain_example",
connection_args={"uri": URI},
)
API 参考:文档

以下是检索该存储集合的方法:

vector_store_loaded = Milvus(
embeddings,
connection_args={"uri": URI},
collection_name="langchain_example",
)

管理矢量存储

创建 vector store 后,我们可以通过添加和删除不同的项目来与之交互。

将项目添加到向量存储

我们可以使用add_documents功能。

from uuid import uuid4

from langchain_core.documents import Document

document_1 = Document(
page_content="I had chocolate chip pancakes and scrambled eggs for breakfast this morning.",
metadata={"source": "tweet"},
)

document_2 = Document(
page_content="The weather forecast for tomorrow is cloudy and overcast, with a high of 62 degrees.",
metadata={"source": "news"},
)

document_3 = Document(
page_content="Building an exciting new project with LangChain - come check it out!",
metadata={"source": "tweet"},
)

document_4 = Document(
page_content="Robbers broke into the city bank and stole $1 million in cash.",
metadata={"source": "news"},
)

document_5 = Document(
page_content="Wow! That was an amazing movie. I can't wait to see it again.",
metadata={"source": "tweet"},
)

document_6 = Document(
page_content="Is the new iPhone worth the price? Read this review to find out.",
metadata={"source": "website"},
)

document_7 = Document(
page_content="The top 10 soccer players in the world right now.",
metadata={"source": "website"},
)

document_8 = Document(
page_content="LangGraph is the best framework for building stateful, agentic applications!",
metadata={"source": "tweet"},
)

document_9 = Document(
page_content="The stock market is down 500 points today due to fears of a recession.",
metadata={"source": "news"},
)

document_10 = Document(
page_content="I have a bad feeling I am going to get deleted :(",
metadata={"source": "tweet"},
)

documents = [
document_1,
document_2,
document_3,
document_4,
document_5,
document_6,
document_7,
document_8,
document_9,
document_10,
]
uuids = [str(uuid4()) for _ in range(len(documents))]

vector_store.add_documents(documents=documents, ids=uuids)
API 参考:文档

从 vector store 中删除项目

vector_store.delete(ids=[uuids[-1]])
(insert count: 0, delete count: 1, upsert count: 0, timestamp: 0, success count: 0, err count: 0, cost: 0)

查询向量存储

创建矢量存储并添加相关文档后,您很可能希望在链或代理运行期间对其进行查询。

直接查询

可以按如下方式执行对元数据进行筛选的简单相似性搜索:

results = vector_store.similarity_search(
"LangChain provides abstractions to make working with LLMs easy",
k=2,
expr='source == "tweet"',
)
for res in results:
print(f"* {res.page_content} [{res.metadata}]")
* Building an exciting new project with LangChain - come check it out! [{'pk': '9905001c-a4a3-455e-ab94-72d0ed11b476', 'source': 'tweet'}]
* LangGraph is the best framework for building stateful, agentic applications! [{'pk': '1206d237-ee3a-484f-baf2-b5ac38eeb314', 'source': 'tweet'}]

带分数的相似性搜索

您还可以使用 score 进行搜索:

results = vector_store.similarity_search_with_score(
"Will it be hot tomorrow?", k=1, expr='source == "news"'
)
for res, score in results:
print(f"* [SIM={score:3f}] {res.page_content} [{res.metadata}]")
* [SIM=21192.628906] bar [{'pk': '2', 'source': 'https://example.com'}]

有关使用Milvusvector store 中,您可以访问 API 参考

通过转换为 retriever 进行查询

您还可以将 vector store 转换为检索器,以便在您的链中更轻松地使用。

retriever = vector_store.as_retriever(search_type="mmr", search_kwargs={"k": 1})
retriever.invoke("Stealing from the bank is a crime", filter={"source": "news"})
[Document(metadata={'pk': 'eacc7256-d7fa-4036-b1f7-83d7a4bee0c5', 'source': 'news'}, page_content='Robbers broke into the city bank and stole $1 million in cash.')]

最常见的混合搜索方案是密集 + 稀疏混合搜索,其中使用语义向量相似性和精确关键字匹配来检索候选项。这些方法的结果被合并、重新排序并传递给 LLM 以生成最终答案。这种方法平衡了精度和语义理解,使其对各种查询场景非常有效。

Milvus 2.5 开始,通过 Sparse-BM25 方法原生支持全文搜索,将 BM25 算法表示为稀疏向量。Milvus 接受原始文本作为输入,并自动将其转换为存储在指定字段中的稀疏向量,无需手动生成稀疏嵌入。

对于全文搜索,Milvus VectorStore 接受builtin_function参数。通过此参数,您可以传入BM25BuiltInFunction.这与语义搜索不同,语义搜索通常将密集的嵌入传递给VectorStore,

下面是一个在 Milvus 中混合搜索的简单示例,其中 OpenAI 密集嵌入用于语义搜索,BM25 用于全文搜索:

from langchain_milvus import BM25BuiltInFunction, Milvus
from langchain_openai import OpenAIEmbeddings

vectorstore = Milvus.from_documents(
documents=documents,
embedding=OpenAIEmbeddings(),
builtin_function=BM25BuiltInFunction(),
# `dense` is for OpenAI embeddings, `sparse` is the output field of BM25 function
vector_field=["dense", "sparse"],
connection_args={
"uri": URI,
},
consistency_level="Strong",
drop_old=True,
)
  • 当您使用BM25BuiltInFunction,请注意,全文搜索在 Milvus Standalone 和 Milvus Distributed 中可用,但在 Milvus Lite 中不可用,尽管它正在未来的包含路线图上。它也将很快在 Zilliz Cloud(完全托管的 Milvus)中提供。请联系 support@zilliz.com 了解更多信息。

在上面的代码中,我们定义了一个BM25BuiltInFunction并将其传递给Milvus对象。BM25BuiltInFunctionFunction在 Milvus 中。我们可以将其与OpenAIEmbeddings初始化一个密集 + 稀疏混合搜索 Milvus 向量存储实例。

BM25BuiltInFunction不需要客户端通过 corpus 或 training,都在 Milvus 服务器端自动处理,用户不需要关心任何词汇和语料。此外,用户还可以自定义分析器,在 BM25 中实现自定义文本处理。

对候选项进行重新排序

在第一阶段检索之后,我们需要对候选者进行重新排序以获得更好的结果。您可以参考 重新排名 了解更多信息。

以下是加权重新排名的示例:

query = "What are the novels Lila has written and what are their contents?"

vectorstore.similarity_search(
query, k=1, ranker_type="weighted", ranker_params={"weights": [0.6, 0.4]}
)

关于全文检索和混合检索的更多信息,请参考 LangChain 和 Milvus 进行全文检索LangChain 和 Milvus 混合检索

用于检索增强生成

有关如何使用此向量存储进行检索增强生成 (RAG) 的指南,请参阅以下部分:

每用户检索

在构建检索应用程序时,您通常必须在考虑多个用户的情况下构建它。这意味着您可能不仅为一个用户存储数据,而且为许多不同的用户存储数据,并且他们应该无法看到彼此的数据。

Milvus 建议使用 partition_key 来实现多租户。下面是一个示例:

Partition key 功能在 Milvus Lite 中没有,如果你想使用它,你需要启动 Milvus 服务器,如上所述。

from langchain_core.documents import Document

docs = [
Document(page_content="i worked at kensho", metadata={"namespace": "harrison"}),
Document(page_content="i worked at facebook", metadata={"namespace": "ankush"}),
]
vectorstore = Milvus.from_documents(
docs,
embeddings,
connection_args={"uri": URI},
drop_old=True,
partition_key_field="namespace", # Use the "namespace" field as the partition key
)
API 参考:文档

要使用分区键执行搜索,您应该在搜索请求的布尔表达式中包含以下任一内容:

search_kwargs={"expr": '<partition_key> == "xxxx"'}

search_kwargs={"expr": '<partition_key> == in ["xxx", "xxx"]'}

执行 replace<partition_key>替换为指定为分区键的字段的名称。

Milvus 根据指定的分区键对分区进行修改,根据分区键对实体进行筛选,并在被筛选的实体中进行搜索。

# This will only get documents for Ankush
vectorstore.as_retriever(search_kwargs={"expr": 'namespace == "ankush"'}).invoke(
"where did i work?"
)
[Document(page_content='i worked at facebook', metadata={'namespace': 'ankush'})]
# This will only get documents for Harrison
vectorstore.as_retriever(search_kwargs={"expr": 'namespace == "harrison"'}).invoke(
"where did i work?"
)
[Document(page_content='i worked at kensho', metadata={'namespace': 'harrison'})]

API 参考

有关所有 __ModuleName__VectorStore 功能和配置的详细文档,请参阅 API 参考:https://python.langchain.com/api_reference/milvus/vectorstores/langchain_milvus.vectorstores.milvus.Milvus.html