MilvusをLangChainベクターストアとして使う

このノートでは、LangChainベクターストアとして Milvusに関連する機能を使用する方法を説明します。

セットアップ

langchain-milvus 、その他必要な依存関係をインストールする必要があります。

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

最新版のpymilvusにはローカルベクタデータベース Milvus Lite が付属しており、プロトタイピングに適しています。100万ドキュメント以上のような大規模なデータをお持ちの場合は、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 = 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(retrieval-augmented generation)に使用する方法については、このRAGガイドを参照してください。

ユーザーごとの検索

検索アプリを構築する場合、複数のユーザーを想定して構築しなければならないことがよくあります。つまり、1人のユーザーだけでなく、多くの異なるユーザーのデータを保存する可能性があります。

milvusはマルチテナントを実装するためにpartition_keyを使うことを推奨しています。

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/。