使用 Milvus 作為 LangChain 向量儲存庫
本筆記展示如何使用Milvus作為LangChain 向量儲存庫的相關功能。
安裝
您需要安裝langchain-milvus 及其他必要的相依性。
$ pip install -qU langchain-milvus milvus-lite langchain-openai
最新版本的 pymilvus 隨附一個本機向量資料庫 Milvus Lite,很適合做為原型。如果您有大規模的資料,例如超過一百萬份的文件,我們建議您在docker 或 kubernetes 上架設效能更高的 Milvus 伺服器。
初始化
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
from langchain_milvus import Milvus
# The easiest way is to use Milvus Lite where everything is stored in a local file.
# If you have a Milvus server you can use the server URI such as "http://localhost:19530".
URI = "./milvus_example.db"
vector_store = Milvus(
embedding_function=embeddings,
connection_args={"uri": URI},
)
使用 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},
)
以下是如何擷取儲存的集合
vector_store_loaded = Milvus(
embeddings,
connection_args={"uri": URI},
collection_name="langchain_example",
)
管理向量儲存
一旦你創建了你的向量商店,我們可以通過添加和刪除不同的項目與它互動。
新增項目至向量儲存
我們可以使用add_documents 功能將項目新增至向量儲存空間。
from uuid import uuid4
from langchain_core.documents import Document
document_1 = Document(
page_content="I had chocalate 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)
['31915e2d-55fd-4bfb-ae08-d441252b8e08',
'dbf6560a-1487-4a6e-8797-245d57874f5b',
'e991a253-5f37-46ae-850a-82a660e33013',
'2818c051-5a1a-44cb-9deb-aaaac709f616',
'91c7ef07-26d1-4319-b48c-9261df9ce8d7',
'fb258085-6400-4cd7-aa92-fc5e32ca243e',
'ffea9a9f-460d-4d8d-ba07-c45e9cfa1e33',
'eb149e29-239a-4e2c-9f99-751cb7207abf',
'119d4a42-fd6b-433d-842b-1e0be5df81e5',
'5b099eb0-98fe-40a3-b13a-300c10250960']
從向量庫中刪除項目
vector_store.delete(ids=[uuids[-1]])
True
查詢向量儲存
一旦您的向量儲存庫建立完成,並加入相關文件後,您很可能希望在連鎖或代理程式執行期間查詢它。
直接查詢
相似性搜尋
執行簡單的類似性搜尋並過濾元資料的方法如下:
results = vector_store.similarity_search(
"LangChain provides abstractions to make working with LLMs easy",
k=2,
expr='source == "tweet"',
# param=... # Search params for the index type
)
for res in results:
print(f"* {res.page_content} [{res.metadata}]")
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1761298048.354308 7886403 fork_posix.cc:71] Other threads are currently calling into gRPC, skipping fork() handlers
* Building an exciting new project with LangChain - come check it out! [{'source': 'tweet', 'pk': 'e991a253-5f37-46ae-850a-82a660e33013'}]
* LangGraph is the best framework for building stateful, agentic applications! [{'source': 'tweet', 'pk': 'eb149e29-239a-4e2c-9f99-751cb7207abf'}]
使用分數進行相似性搜尋
您也可以使用分數進行搜尋:
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=0.893776] The weather forecast for tomorrow is cloudy and overcast, with a high of 62 degrees. [{'source': 'news', 'pk': 'dbf6560a-1487-4a6e-8797-245d57874f5b'}]
如需使用Milvus 向量商店時可用的所有搜尋選項的完整清單,您可以造訪API 參考資料。
透過轉換成retriever進行查詢
您也可以將向量儲存轉換成retriever,以便在您的鏈中更容易使用。
retriever = vector_store.as_retriever(search_type="mmr", search_kwargs={"k": 1})
retriever.invoke("Stealing from the bank is a crime", expr='source == "news"')
I0000 00:00:1761298049.275354 7886403 fork_posix.cc:71] Other threads are currently calling into gRPC, skipping fork() handlers
[Document(metadata={'source': 'news', 'pk': '2818c051-5a1a-44cb-9deb-aaaac709f616'}, page_content='Robbers broke into the city bank and stole $1 million in cash.')]
擷取增強世代的使用方式
有關如何使用此向量儲存器進行retrieval-augmented generation (RAG),請參閱此RAG 指南。
按使用者擷取
在建立擷取應用程式時,您通常必須以多位使用者為考量。這表示您可能不只為一個使用者儲存資料,而是為許多不同的使用者儲存資料,而且他們應該無法看到彼此的資料。
Milvus 建議使用partition_key來實現多重租用,這裡是一個範例。
現在 Milvus Lite 沒有分區鑰匙的功能,如果你想使用它,你需要從docker 或 kubernetes 啟動 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,
collection_name="partitioned_collection", # Use a different collection name
connection_args={"uri": URI},
# drop_old=True,
partition_key_field="namespace", # Use the "namespace" field as the partition key
)
若要使用分割區金鑰進行搜尋,您應該在搜尋請求的布林表達式中包含下列任一項:
search_kwargs={"expr": '<partition_key> == "xxxx"'}
search_kwargs={"expr": '<partition_key> == in ["xxx", "xxx"]'}
請以指定為分割區金鑰的欄位名稱取代<partition_key> 。
Milvus 會根據指定的分割區金鑰變更為分割區,根據分割區金鑰過濾實體,並在過濾的實體中進行搜尋。
# This will only get documents for Ankush
vectorstore.as_retriever(search_kwargs={"expr": 'namespace == "ankush"'}).invoke(
"where did i work?"
)
[Document(metadata={'namespace': 'ankush', 'pk': 460829372217788296}, page_content='i worked at facebook')]
# This will only get documents for Harrison
vectorstore.as_retriever(search_kwargs={"expr": 'namespace == "harrison"'}).invoke(
"where did i work?"
)
[Document(metadata={'namespace': 'harrison', 'pk': 460829372217788295}, page_content='i worked at kensho')]
API 參考
如需詳細說明文件,請前往 API 參考: https://reference.langchain.com/python/integrations/langchain_milvus/