Использование Milvus в качестве хранилища векторов LangChain
В этом блокноте показано, как использовать функциональность Milvus в качестве хранилища векторов LangChain.
Установите
Вам потребуется установить langchain-milvus и другие необходимые зависимости.
$ pip install -qU langchain-milvus milvus-lite langchain-openai
Последняя версия pymilvus поставляется с локальной векторной базой данных Milvus Lite, которая хорошо подходит для прототипирования. Если у вас большие объемы данных, например, более миллиона документов, мы рекомендуем установить более производительный сервер Milvus на docker или kubernetes.
Инициализация
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.
Вы можете хранить разные несвязанные документы в разных коллекциях в рамках одного экземпляра 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 = 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.')]
Использование для генерации с расширенным извлечением
Руководство по использованию этого векторного хранилища для генерации с расширением поиска (RAG) см. в этом руководстве по RAG.
Извлечение для каждого пользователя
При создании приложения для извлечения информации часто приходится учитывать интересы нескольких пользователей. Это означает, что вы можете хранить данные не только для одного пользователя, но и для многих других, и они не должны иметь возможности видеть данные друг друга.
Milvus рекомендует использовать partition_key для реализации многопользовательского доступа, вот пример.
Функция Partition key сейчас недоступна в Milvus Lite, если вы хотите использовать ее, вам нужно запустить сервер Milvus из docker или kubernetes.
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/.