跳到主要內容
Open In ColabOpen on GitHub

Qdrant

Qdrant (發音:quadrant) 是一個向量相似度搜尋引擎。它提供生產就緒的服務,具有方便的 API,可用於儲存、搜尋和管理向量,並支援額外的酬載和擴展篩選。這使其適用於各種神經網路或語義基礎的匹配、分面搜尋和其他應用程式。

本文檔示範如何將 Qdrant 與 LangChain 結合使用,以進行密集(即基於嵌入)、稀疏(即文字搜尋)和混合檢索。QdrantVectorStore 類別透過 Qdrant 新的 Query API 支援多種檢索模式。它需要您執行 Qdrant v1.10.0 或更高版本。

設定

有多種執行 Qdrant 的模式,根據選擇的模式,會有一些細微的差異。選項包括

  • 本機模式,無需伺服器
  • Docker 部署
  • Qdrant Cloud

請參閱此處的安裝說明:here

pip install -qU langchain-qdrant

憑證

執行此筆記本中的程式碼不需要憑證。

如果您想要獲得一流的模型呼叫自動追蹤,您也可以透過取消註解下方內容來設定您的 LangSmith API 金鑰

# os.environ["LANGSMITH_API_KEY"] = getpass.getpass("Enter your LangSmith API key: ")
# os.environ["LANGSMITH_TRACING"] = "true"

初始化

本機模式

Python 用戶端提供在本機模式下執行程式碼的選項,而無需執行 Qdrant 伺服器。這非常適合測試、偵錯或僅儲存少量向量。嵌入可以完全保留在記憶體中或持續儲存在磁碟上。

記憶體內

對於某些測試場景和快速實驗,您可能更喜歡僅將所有數據保留在記憶體中,以便在用戶端被銷毀時將其刪除 - 通常在您的腳本/筆記本末尾。

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")
from langchain_qdrant import QdrantVectorStore
from qdrant_client import QdrantClient
from qdrant_client.http.models import Distance, VectorParams

client = QdrantClient(":memory:")

client.create_collection(
collection_name="demo_collection",
vectors_config=VectorParams(size=3072, distance=Distance.COSINE),
)

vector_store = QdrantVectorStore(
client=client,
collection_name="demo_collection",
embedding=embeddings,
)

磁碟儲存

本機模式(不使用 Qdrant 伺服器)也可以將您的向量儲存在磁碟上,以便它們在執行之間持續存在。

client = QdrantClient(path="/tmp/langchain_qdrant")

client.create_collection(
collection_name="demo_collection",
vectors_config=VectorParams(size=3072, distance=Distance.COSINE),
)

vector_store = QdrantVectorStore(
client=client,
collection_name="demo_collection",
embedding=embeddings,
)

內部部署伺服器部署

無論您選擇使用 Docker 容器在本機啟動 Qdrant,還是選擇使用 官方 Helm chart 進行 Kubernetes 部署,您連接到此執行個體的方式都將相同。您需要提供指向該服務的 URL。

url = "<---qdrant url here --->"
docs = [] # put docs here
qdrant = QdrantVectorStore.from_documents(
docs,
embeddings,
url=url,
prefer_grpc=True,
collection_name="my_documents",
)

Qdrant Cloud

如果您不希望忙於管理基礎架構,您可以選擇在 Qdrant Cloud 上設定完全託管的 Qdrant 叢集。包含一個永久免費的 1GB 叢集,供您試用。使用託管版本的 Qdrant 的主要區別在於,您需要提供 API 金鑰以保護您的部署免於公開存取。該值也可以在 QDRANT_API_KEY 環境變數中設定。

url = "<---qdrant cloud cluster url here --->"
api_key = "<---api key here--->"
qdrant = QdrantVectorStore.from_documents(
docs,
embeddings,
url=url,
prefer_grpc=True,
api_key=api_key,
collection_name="my_documents",
)

使用現有集合

若要取得 langchain_qdrant.Qdrant 的執行個體,而不載入任何新文件或文字,您可以使用 Qdrant.from_existing_collection() 方法。

qdrant = QdrantVectorStore.from_existing_collection(
embedding=embeddings,
collection_name="my_documents",
url="http://localhost:6333",
)

管理向量儲存庫

建立向量儲存庫後,我們可以透過新增和刪除不同的項目與其互動。

將項目新增至向量儲存庫

我們可以使用 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 Fahrenheit.",
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))]
API 參考:Document
vector_store.add_documents(documents=documents, ids=uuids)

從向量儲存庫刪除項目

vector_store.delete(ids=[uuids[-1]])
True

查詢向量儲存庫

建立向量儲存庫並新增相關文件後,您很可能希望在執行鏈或代理程式期間查詢它。

直接查詢

使用 Qdrant 向量儲存庫的最簡單情境是執行相似度搜尋。在幕後,我們的查詢將被編碼為向量嵌入,並用於在 Qdrant 集合中尋找相似的文件。

results = vector_store.similarity_search(
"LangChain provides abstractions to make working with LLMs easy", k=2
)
for res in results:
print(f"* {res.page_content} [{res.metadata}]")
* Building an exciting new project with LangChain - come check it out! [{'source': 'tweet', '_id': 'd3202666-6f2b-4186-ac43-e35389de8166', '_collection_name': 'demo_collection'}]
* LangGraph is the best framework for building stateful, agentic applications! [{'source': 'tweet', '_id': '91ed6c56-fe53-49e2-8199-c3bb3c33c3eb', '_collection_name': 'demo_collection'}]

QdrantVectorStore 支援 3 種相似度搜尋模式。可以使用 retrieval_mode 參數進行配置。

  • 密集向量搜尋 (預設)
  • 稀疏向量搜尋
  • 混合搜尋

密集向量搜尋涉及透過基於向量的嵌入來計算相似度。若要僅使用密集向量進行搜尋

  • retrieval_mode 參數應設定為 RetrievalMode.DENSE。這是預設行為。
  • 應為 embedding 參數提供 密集嵌入 值。
from langchain_qdrant import QdrantVectorStore, RetrievalMode
from qdrant_client import QdrantClient
from qdrant_client.http.models import Distance, VectorParams

# Create a Qdrant client for local storage
client = QdrantClient(path="/tmp/langchain_qdrant")

# Create a collection with dense vectors
client.create_collection(
collection_name="my_documents",
vectors_config=VectorParams(size=3072, distance=Distance.COSINE),
)

qdrant = QdrantVectorStore(
client=client,
collection_name="my_documents",
embedding=embeddings,
retrieval_mode=RetrievalMode.DENSE,
)

qdrant.add_documents(documents=documents, ids=uuids)

query = "How much money did the robbers steal?"
found_docs = qdrant.similarity_search(query)
found_docs

若要僅使用稀疏向量進行搜尋

  • retrieval_mode 參數應設定為 RetrievalMode.SPARSE
  • 使用任何稀疏嵌入提供者的 SparseEmbeddings 介面的實作必須作為值提供給 sparse_embedding 參數。

langchain-qdrant 套件提供基於 FastEmbed 的現成實作。

若要使用它,請安裝 FastEmbed 套件。

%pip install -qU fastembed
from langchain_qdrant import FastEmbedSparse, QdrantVectorStore, RetrievalMode
from qdrant_client import QdrantClient, models
from qdrant_client.http.models import Distance, SparseVectorParams, VectorParams

sparse_embeddings = FastEmbedSparse(model_name="Qdrant/bm25")

# Create a Qdrant client for local storage
client = QdrantClient(path="/tmp/langchain_qdrant")

# Create a collection with sparse vectors
client.create_collection(
collection_name="my_documents",
vectors_config={"dense": VectorParams(size=3072, distance=Distance.COSINE)},
sparse_vectors_config={
"sparse": SparseVectorParams(index=models.SparseIndexParams(on_disk=False))
},
)

qdrant = QdrantVectorStore(
client=client,
collection_name="my_documents",
sparse_embedding=sparse_embeddings,
retrieval_mode=RetrievalMode.SPARSE,
sparse_vector_name="sparse",
)

qdrant.add_documents(documents=documents, ids=uuids)

query = "How much money did the robbers steal?"
found_docs = qdrant.similarity_search(query)
found_docs

若要使用密集向量和稀疏向量以及分數融合執行混合搜尋,

  • retrieval_mode 參數應設定為 RetrievalMode.HYBRID
  • 應為 embedding 參數提供 密集嵌入 值。
  • 使用任何稀疏嵌入提供者的 SparseEmbeddings 介面的實作必須作為值提供給 sparse_embedding 參數。

請注意,如果您已使用 HYBRID 模式新增文件,則可以在搜尋時切換到任何檢索模式,因為密集向量和稀疏向量都可在集合中使用。

from langchain_qdrant import FastEmbedSparse, QdrantVectorStore, RetrievalMode
from qdrant_client import QdrantClient, models
from qdrant_client.http.models import Distance, SparseVectorParams, VectorParams

sparse_embeddings = FastEmbedSparse(model_name="Qdrant/bm25")

# Create a Qdrant client for local storage
client = QdrantClient(path="/tmp/langchain_qdrant")

# Create a collection with both dense and sparse vectors
client.create_collection(
collection_name="my_documents",
vectors_config={"dense": VectorParams(size=3072, distance=Distance.COSINE)},
sparse_vectors_config={
"sparse": SparseVectorParams(index=models.SparseIndexParams(on_disk=False))
},
)

qdrant = QdrantVectorStore(
client=client,
collection_name="my_documents",
embedding=embeddings,
sparse_embedding=sparse_embeddings,
retrieval_mode=RetrievalMode.HYBRID,
vector_name="dense",
sparse_vector_name="sparse",
)

qdrant.add_documents(documents=documents, ids=uuids)

query = "How much money did the robbers steal?"
found_docs = qdrant.similarity_search(query)
found_docs

如果您想要執行相似度搜尋並接收相應的分數,您可以執行

results = vector_store.similarity_search_with_score(
query="Will it be hot tomorrow", k=1
)
for doc, score in results:
print(f"* [SIM={score:3f}] {doc.page_content} [{doc.metadata}]")
* [SIM=0.531834] The weather forecast for tomorrow is cloudy and overcast, with a high of 62 degrees. [{'source': 'news', '_id': '9e6ba50c-794f-4b88-94e5-411f15052a02', '_collection_name': 'demo_collection'}]

如需 QdrantVectorStore 可用的所有搜尋函數的完整列表,請閱讀 API 參考

Metadata 過濾

Qdrant 具有 廣泛的過濾系統,具有豐富的類型支援。也可以在 Langchain 中使用篩選器,方法是將額外的參數傳遞給 similarity_search_with_scoresimilarity_search 方法。

from qdrant_client import models

results = vector_store.similarity_search(
query="Who are the best soccer players in the world?",
k=1,
filter=models.Filter(
should=[
models.FieldCondition(
key="page_content",
match=models.MatchValue(
value="The top 10 soccer players in the world right now."
),
),
]
),
)
for doc in results:
print(f"* {doc.page_content} [{doc.metadata}]")
* The top 10 soccer players in the world right now. [{'source': 'website', '_id': 'b0964ab5-5a14-47b4-a983-37fa5c5bd154', '_collection_name': 'demo_collection'}]

轉換為檢索器進行查詢

您也可以將向量儲存庫轉換為檢索器,以便在您的鏈中更輕鬆地使用。

retriever = vector_store.as_retriever(search_type="mmr", search_kwargs={"k": 1})
retriever.invoke("Stealing from the bank is a crime")
[Document(metadata={'source': 'news', '_id': '50d8d6ee-69bf-4173-a6a2-b254e9928965', '_collection_name': 'demo_collection'}, page_content='Robbers broke into the city bank and stole $1 million in cash.')]

用於檢索增強生成

如需關於如何將此向量儲存庫用於檢索增強生成 (RAG) 的指南,請參閱以下章節

自訂 Qdrant

您可以選擇在 LangChain 應用程式中使用現有的 Qdrant 集合。在這種情況下,您可能需要定義如何將 Qdrant 點對應到 LangChain Document

具名向量

Qdrant 透過具名向量支援每個點多個向量。如果您使用外部建立的集合,或想要使用不同命名的向量,您可以透過提供其名稱來進行配置。

from langchain_qdrant import RetrievalMode

QdrantVectorStore.from_documents(
docs,
embedding=embeddings,
sparse_embedding=sparse_embeddings,
location=":memory:",
collection_name="my_documents_2",
retrieval_mode=RetrievalMode.HYBRID,
vector_name="custom_vector",
sparse_vector_name="custom_sparse_vector",
)

Metadata

Qdrant 儲存您的向量嵌入 (vector embeddings) 以及選用的 JSON 類型的酬載 (payload)。酬載是選用的,但由於 LangChain 假設嵌入是從文件中產生的,我們會保留上下文資料,以便您也可以提取原始文本。

預設情況下,您的文件將會儲存在以下酬載結構中

{
"page_content": "Lorem ipsum dolor sit amet",
"metadata": {
"foo": "bar"
}
}

然而,您可以決定為頁面內容和metadata使用不同的鍵 (keys)。如果您已經有一個想要重複使用的集合 (collection),這會很有用。

QdrantVectorStore.from_documents(
docs,
embeddings,
location=":memory:",
collection_name="my_documents_2",
content_payload_key="my_page_content_key",
metadata_payload_key="my_meta",
)

API 參考

如需所有 QdrantVectorStore 功能和設定的詳細文件,請前往 API 參考:https://langchain-python.dev.org.tw/api_reference/qdrant/qdrant/langchain_qdrant.qdrant.QdrantVectorStore.html


此頁面是否對您有幫助?