Utilizar o Milvus como um armazém de vectores LangChain

Este caderno mostra como utilizar a funcionalidade relacionada com o Milvus como um armazém de vectores LangChain.

Configuração

Terá de instalar langchain-milvus e outras dependências necessárias.

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

A última versão do pymilvus vem com uma base de dados vetorial local Milvus Lite, boa para prototipagem. Se tiver uma grande escala de dados, como mais de um milhão de documentos, recomendamos a configuração de um servidor Milvus de maior desempenho no docker ou kubernetes.

Inicialização

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

Compartimentar os dados com Milvus Collections

Você pode armazenar diferentes documentos não relacionados em diferentes coleções dentro da mesma instância Milvus para manter o contexto

Veja como pode criar uma nova coleção de armazenamento vetorial a partir de documentos:

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

E eis como pode recuperar essa coleção armazenada

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

Gerir o armazenamento vetorial

Depois de ter criado o seu repositório de vectores, podemos interagir com ele adicionando e eliminando diferentes itens.

Adicionar itens ao repositório de vectores

Podemos adicionar itens ao nosso repositório de vectores utilizando a função 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']

Eliminar itens do repositório de vectores

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

Consultar o repositório de vectores

Depois de o seu repositório de vectores ter sido criado e os documentos relevantes terem sido adicionados, é muito provável que pretenda consultá-lo durante a execução da sua cadeia ou agente.

Consultar diretamente

A realização de uma pesquisa de semelhanças simples com filtragem de metadados pode ser efectuada da seguinte forma:

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

Pesquisa de similaridade com pontuação

Também é possível pesquisar com pontuação:

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

Para obter uma lista completa de todas as opções de pesquisa disponíveis ao utilizar o repositório de vectores Milvus, pode visitar a referência da API.

Consulta por transformação em retriever

Também pode transformar o armazenamento de vectores num recuperador para facilitar a utilização nas suas cadeias.

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

Utilização para geração aumentada por recuperação

Para obter guias sobre como utilizar este armazenamento de vectores para geração aumentada por recuperação (RAG), consulte este guia RAG.

Recuperação por usuário

Ao criar uma aplicação de recuperação, é frequente ter de a criar tendo em conta vários utilizadores. Isto significa que pode estar a armazenar dados não apenas para um utilizador, mas para muitos utilizadores diferentes, e estes não devem poder ver os dados uns dos outros.

Milvus recomenda o uso de partition_key para implementar multi-tenancy, aqui está um exemplo.

A funcionalidade de Partition key não está agora disponível no Milvus Lite, se a quiser utilizar, tem de iniciar o servidor Milvus a 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
)

Para realizar uma pesquisa usando a chave de partição, você deve incluir um dos seguintes itens na expressão booleana da solicitação de pesquisa:

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

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

Substituir <partition_key> pelo nome do campo que é designado como a chave de partição.

O Milvus muda para uma partição com base na chave de partição especificada, filtra entidades de acordo com a chave de partição e pesquisa entre as entidades filtradas.

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

Referência da API

Para obter documentação detalhada, consulte a referência da API: https://reference.langchain.com/python/integrations/langchain_milvus/