Utiliser Milvus comme magasin de vecteurs LangChain

Ce carnet montre comment utiliser les fonctionnalités liées à Milvus en tant que magasin de vecteurs LangChain.

Installation

Vous devrez installer langchain-milvus et les autres dépendances nécessaires.

$ pip install -qU langchain-milvus milvus-lite langchain-openai

La dernière version de pymilvus est livrée avec une base de données vectorielles locale Milvus Lite, bonne pour le prototypage. Si vous avez des données à grande échelle, comme plus d'un million de documents, nous vous recommandons d'installer un serveur Milvus plus performant sur docker ou kubernetes.

Initialisation

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},
)

Compartimenter les données avec Milvus Collections

Vous pouvez stocker différents documents non liés dans différentes collections au sein de la même instance Milvus afin de maintenir le contexte

Voici comment créer une nouvelle collection de stockage vectoriel à partir de documents :

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},
)

Et voici comment récupérer cette collection stockée

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

Gérer le magasin de vecteurs

Une fois que vous avez créé votre magasin de vecteurs, vous pouvez interagir avec lui en ajoutant et en supprimant différents éléments.

Ajouter des éléments à la base de données vectorielles

Nous pouvons ajouter des éléments à notre magasin de vecteurs en utilisant la fonction 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']

Supprimer des éléments de la base de données vectorielles

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

Interroger la base de données vectorielles

Une fois que votre magasin de vecteurs a été créé et que les documents pertinents ont été ajoutés, vous souhaiterez probablement l'interroger au cours de l'exécution de votre chaîne ou de votre agent.

Interroger directement

Une simple recherche de similarité avec filtrage des métadonnées peut être effectuée comme suit :

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'}]

Recherche de similarité avec score

Vous pouvez également effectuer une recherche avec 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=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'}]

Pour une liste complète de toutes les options de recherche disponibles lors de l'utilisation du magasin de vecteurs Milvus, vous pouvez consulter la référence API.

Recherche en transformant le magasin de vecteurs en récupérateur

Vous pouvez également transformer le magasin de vecteurs en un récupérateur pour une utilisation plus facile dans vos chaînes.

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.')]

Utilisation pour la génération améliorée par récupération

Pour savoir comment utiliser ce magasin de vecteurs pour la génération augmentée par récupération (RAG), voir le guide RAG.

Récupération par utilisateur

Lorsque vous créez une application de recherche, vous devez souvent la concevoir en pensant à plusieurs utilisateurs. Cela signifie que vous pouvez stocker des données non pas pour un seul utilisateur, mais pour plusieurs utilisateurs différents, et qu'ils ne doivent pas être en mesure de voir les données de chacun d'entre eux.

Milvus recommande d'utiliser partition_key pour mettre en œuvre la multi-location, dont voici un exemple.

La fonction de clé de partition n'est pas disponible dans Milvus Lite, si vous souhaitez l'utiliser, vous devez démarrer le serveur Milvus à partir de docker ou 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
)

Pour effectuer une recherche à l'aide de la clé de partition, vous devez inclure l'un des éléments suivants dans l'expression booléenne de la requête de recherche :

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

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

Remplacez <partition_key> par le nom du champ désigné comme clé de partition.

Milvus passe à une partition basée sur la clé de partition spécifiée, filtre les entités en fonction de la clé de partition et effectue une recherche parmi les entités filtrées.

# 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')]

Référence API

Pour une documentation détaillée, consultez la référence API : https://reference.langchain.com/python/integrations/langchain_milvus/