Milvus 搭載の MemPalace

MemPalaceは、コーディングエージェントや長時間実行される開発ワークフロー向けのメモリレイヤーです。プロジェクトの知識を「ウィング」「ルーム」「ドロワー」に整理し、セッションをまたいで元のコンテンツを検索可能にします。

このチュートリアルでは、MemPalace CLI を使用して、公開されているMilvus ドキュメントの実際のサブセットを抽出し、Milvus に保存します。このコーパスには、アナライザー、トークナイザー、およびトークンフィルターに関するドキュメントが含まれています。これらの密接に関連したページは、検索の例を意味のあるものにするのに十分な「妨害要素」を提供します。

この例では Milvus Lite を使用するため、Docker や別途のデータベースサーバーを必要とせず、ローカルで実行できます。また、同じ MemPalace 設定を使用して、共有展開用の Milvus サーバーや Zilliz Cloud を指定することも可能です。

前提条件

PyPI から MemPalace と、そのオプションの Milvus 依存関係をインストールしてください。このコマンドでは意図的にバージョンを指定していないため、新規インストール時には利用可能な最新リリースがインストールされます。

uv tool install "mempalace[milvus]"

また、ドキュメントコーパスをダウンロードするにはGitが必要です。

このチュートリアルでは、MemPalaceのローカルMiniLM埋め込みモデルを使用するため、外部モデルのAPIキーは必要ありません。最初のマイニングまたは検索コマンドを実行すると、小さなONNX埋め込みモデルがダウンロードされる場合があります。

ワークスペースの設定

ドキュメント用とMemPalace用のディレクトリを分けてワークスペースを作成します:

mkdir -p mempalace-milvus-demo
cd mempalace-milvus-demo

export PALACE_DIR="$PWD/palace"
export DOCS_REPO="$PWD/milvus-docs"
export PROJECT_DIR="$PWD/milvus-analyzer-docs"
export MEMPALACE_EMBEDDING_MODEL="minilm"
export MEMPALACE_EMBEDDING_DEVICE="cpu"
export MEMPALACE_EMBEDDING_THREADS="2"

以下のMemPalaceコマンドには、--backend milvus を指定します。リモートのMilvus URIが設定されていないため、MemPalaceは$PALACE_DIR/milvus.db にローカルのMilvus Liteデータベースを作成します。

バックエンドで使用されるMilvusClient の引数については:

  • uri./milvus.db のようなローカルパスに設定するのが最も便利な方法です。これにより、Milvus Liteが自動的に使用され、データがローカルに保存されます。
  • より大規模な展開の場合は、Milvusサーバーを使用し、URIをそのエンドポイント(例:http://localhost:19530 )に設定できます。
  • Zilliz Cloud を使用する場合は、URI とトークンをクラスタのパブリックエンドポイントおよび API キーに設定してください。

Milvusドキュメントコーパスのダウンロード

Milvusのドキュメントリポジトリは、この例で必要とされるものよりもはるかに大規模です。Gitのスパースチェックアウトを使用して、v3.0.x ブランチからAnalyzerのドキュメントディレクトリのみをダウンロードしてください:

git clone \
  --depth 1 \
  --filter=blob:none \
  --sparse \
  --branch v3.0.x \
  https://github.com/milvus-io/milvus-docs.git \
  "$DOCS_REPO"

git -C "$DOCS_REPO" sparse-checkout set \
  site/en/userGuide/schema/analyzer

cp -R \
  "$DOCS_REPO/site/en/userGuide/schema/analyzer" \
  "$PROJECT_DIR"

本稿執筆時点で、このディレクトリには31ページのMarkdownファイルが含まれています。これには、Analyzerの一般的なガイドに加え、密接に関連する3つのページ群が含まれています:

milvus-analyzer-docs/
├── analyzer/       # Built-in language analyzers
├── filter/         # Token filters
├── tokenizer/      # Tokenizers
└── *.md            # Analyzer overviews and selection guides

ソースページの数を確認します:

find "$PROJECT_DIR" -type f -name "*.md" | wc -l

参照出力:

31

Milvusのドキュメントブランチが更新されるにつれて、正確なページ数は変動する可能性があります。

MemPalaceのルームを定義する

MemPalaceはmempalace init 中にルームを検出できますが、その初期化フローではプロジェクト全体にわたるヒューリスティックなエンティティ分類も実行され、承認された結果がエンティティレジストリに書き込まれます。このドキュメントコーパスを定義するにはその分類ステップは必要ないため、ここでは小規模なタクソノミーを直接提供します。 マイニング中、MemPalaceは依然として決定論的なヒューリスティックなエンティティメタデータを付加し、内部のホールウェイリンクを構築する場合がありますが、それらの関連付けは、どのルームがファイルを受け取るかを決定するものではなく、以下のルームスコープの検索を変更するものでもありません。

以下の内容で `$PROJECT_DIR/mempalace.yaml ` を作成してください:

wing: milvus_analyzer_docs
rooms:
  - name: analyzer
    description: Built-in language analyzers and analyzer selection guides
    keywords:
      - analyzer
  - name: filter
    description: Token filters used in analyzer pipelines
    keywords:
      - filter
  - name: tokenizer
    description: Tokenizers and language identification
    keywords:
      - tokenizer
  - name: general
    description: Analyzer documentation that does not fit another room
    keywords: []

「wing」はドキュメントコーパス全体を表します。「room」はトピック領域を表します。MemPalaceは、ファイルをルーティングする際、まずディレクトリ、次にファイル名、そしてコンテンツ内のルームキーワードの順に確認します。例えば、filter/ 配下のファイルは、filter ルームに直接振り分けられます。

その後、各ファイルは重複するテキストチャンクに分割されます。各チャンクは「引き出し」となり、その中にはMarkdownの原文に加え、wingroomsource_filechunk_index 、およびソースコードの行番号などのメタデータが含まれます。ルームと引き出しは、MemPalaceのMilvusコレクション内の論理的なメタデータとして扱われます。MemPalaceは、ルームごとに個別のMilvusコレクションを作成することはありません。

ドキュメントをMilvusに取り込む

Milvusバックエンドを使用してプロジェクトをマイニングする:

mempalace \
  --palace "$PALACE_DIR" \
  mine "$PROJECT_DIR" \
  --backend milvus

検証済みのドキュメントスナップショットからの出力を参照:

=======================================================
  Done.
  Files processed: 31
  Files skipped (already filed or other): 0
  Drawers filed: 473

  By room:
    filter               16 files
    analyzer              8 files
    tokenizer             7 files
=======================================================

MemPalaceはMarkdownを要約や書き換えを行わずに読み込み、ローカル埋め込みを計算し、引き出しをMilvusに保存します。テスト対象のドキュメントスナップショットでは、31個のファイルから473個の引き出しが生成されました。

生成されたルームとドロワーの数を確認します:

mempalace --palace "$PALACE_DIR" status --backend milvus

参照出力:

=======================================================
  MemPalace Status -- 473 drawers
=======================================================

  WING: milvus_analyzer_docs
    ROOM: analyzer               212 drawers
    ROOM: filter                 156 drawers
    ROOM: tokenizer              105 drawers

=======================================================

アップストリームのドキュメントが変更されると、ページが長くなるほどチャンクの数が増えるため、正確なドローワーの数は変動する可能性があります。

mempalace search を使用して、意味に基づいてドキュメントを検索します。以下のクエリでは、特定のファイル名やアナライザー機能名は指定していません:

mempalace \
  --palace "$PALACE_DIR" \
  search "How should I analyze documents that mix several languages?" \
  --backend milvus \
  --wing milvus_analyzer_docs \
  --results 3

参照出力(スコアは異なる場合があります):

Results for: "How should I analyze documents that mix several languages?"
Wing: milvus_analyzer_docs

[1] milvus_analyzer_docs / analyzer
    Source: multi-language-analyzers.md
    Match: cosine_sim=0.334 bm25=2.469
[2] milvus_analyzer_docs / analyzer
    Source: multi-language-analyzers.md
[3] milvus_analyzer_docs / analyzer
    Source: multi-language-analyzers.md

検証済みの実行では、コーパスには個々の言語アナライザー、トークナイザー、フィルターに関するページも含まれていたにもかかわらず、3つの結果すべてがmulti-language-analyzers.md から得られました。

ルーム内での検索

関連する概念がコーパス全体に散在している場合、ルームフィルターが役立ちます。次のクエリは、同義語を一致させる方法について、「filter 」ルームのみを検索します:

mempalace \
  --palace "$PALACE_DIR" \
  search "How can equivalent terms such as USA and United States match one another?" \
  --backend milvus \
  --wing milvus_analyzer_docs \
  --room filter \
  --results 3

参照出力(スコアは異なる場合があります):

Results for: "How can equivalent terms such as USA and United States match one another?"
Wing: milvus_analyzer_docs
Room: filter

[1] milvus_analyzer_docs / filter
    Source: synonym-filter.md
    Match: cosine_sim=0.765 bm25=2.573
[2] milvus_analyzer_docs / filter
    Source: stemmer-filter.md
[3] milvus_analyzer_docs / filter
    Source: stop-filter.md

上位の結果はsynonym-filter.md からのものになるはずです。ルームの制約はベクトル検索の前にドロワーのメタデータを通じて適用されるため、この検索からはトークナイザーおよび言語アナライザーのドロワーが除外されます。

完全一致の検索

MemPalace CLIは、ベクトル検索の候補をランク付けする際、意味的類似性とBM25シグナルを組み合わせています。したがって、正確な構成名や機能名を使用することで、別のCLI検索モードに切り替えることなく、ランキングを向上させることができます。

mempalace \
  --palace "$PALACE_DIR" \
  search "language_identifier tokenizer" \
  --backend milvus \
  --wing milvus_analyzer_docs \
  --room tokenizer \
  --results 3

参照出力(スコアは異なる場合があります):

Results for: "language_identifier tokenizer"
Wing: milvus_analyzer_docs
Room: tokenizer

[1] milvus_analyzer_docs / tokenizer
    Source: language-identifier.md
    Match: cosine_sim=0.420 bm25=0.969
[2] milvus_analyzer_docs / tokenizer
    Source: language-identifier.md
[3] milvus_analyzer_docs / tokenizer
    Source: lindera-tokenizer.md

結果は、language-identifier.md を優先するはずです。このドキュメントには、検出された言語に基づいてアナライザーを選択するために使用されるlanguage_identifier トークナイザーが記載されています。

Milvusコレクションの確認

MemPalaceはMilvusスキーマを自動的に管理します。何が保存されたかを確認するには、以下のスクリプトをinspect_milvus.py として保存してください。このスクリプトは、同じMilvus Liteデータベースを開き、コレクションを検査し、部屋ごとの引き出し数をカウントします:

import os
from collections import Counter

from pymilvus import MilvusClient


client = MilvusClient(uri=os.environ["MEMPALACE_MILVUS_LITE_PATH"])

for collection_name in sorted(client.list_collections()):
    stats = client.get_collection_stats(collection_name)
    schema = client.describe_collection(collection_name)
    fields = [field["name"] for field in schema["fields"]]
    print(f"{collection_name}: rows={stats['row_count']}, fields={fields}")

client.load_collection("mempalace_drawers")
rows = client.query(
    collection_name="mempalace_drawers",
    filter='metadata["wing"] == "milvus_analyzer_docs"',
    limit=2000,
    output_fields=["metadata"],
)
room_counts = Counter(row["metadata"]["room"] for row in rows)
print("Drawers by room:", dict(sorted(room_counts.items())))

CLIで使用されているのと同じオプションの依存関係セットを指定して、スクリプトを実行します:

export MEMPALACE_MILVUS_LITE_PATH="$PALACE_DIR/milvus.db"
uv run --with "mempalace[milvus]" inspect_milvus.py

出力例:

mempalace_closets: rows=74, fields=['id', 'document', 'metadata', 'vector', 'sparse']
mempalace_drawers: rows=473, fields=['id', 'document', 'metadata', 'vector', 'sparse']
Drawers by room: {'analyzer': 212, 'filter': 156, 'tokenizer': 105}

テスト対象のドキュメントスナップショットの場合、mempalace_drawers には473行、mempalace_closets には74件の内部ナビゲーションレコードが含まれていました。クローゼットと引き出しの数は一致する必要はありません。引き出しのメタデータによると、analyzer には212個、filter には156個、tokenizer には105個の引き出しが存在することが示されました。

この検査は新しいプロセスで実行され、CLIによって作成されたデータベースを再度開きます。これにより、コマンドをまたいでデータが保持されていることも確認できます。

オプション:MilvusサーバーまたはZilliz Cloudの使用

共有環境でのデプロイを行う場合は、同じ MemPalace CLI コマンドを実行する前に、Milvus 接続用の環境変数を設定してください。上記のローカル Milvus Lite データベースを使用する場合は、これらの変数を設定しないでください。

Milvusサーバーの場合:

export MEMPALACE_MILVUS_URI="http://localhost:19530"
export MEMPALACE_MILVUS_DB_NAME="default"
export MEMPALACE_MILVUS_NAMESPACE="team-memory"

Zilliz Cloudの場合:

export MEMPALACE_MILVUS_URI="https://your-cluster.api.region.zillizcloud.com"
export MEMPALACE_MILVUS_TOKEN="your-api-key"
export MEMPALACE_MILVUS_DB_NAME="default"
export MEMPALACE_MILVUS_NAMESPACE="team-memory"

このチュートリアルで紹介した一連のコマンドは、Milvus Lite を使用して検証されています。上記のサーバーおよびクラウドの設定はオプションのデプロイ構成であり、ローカルでの検証には必要ありませんでした。

まとめ

MemPalaceは、エージェントがプロジェクトの知識を体系的に保存するための仕組みを提供します。「ウィング」がコーパスを区分し、「ルーム」がトピックレベルの範囲を定義し、「ドロワー」が元のソーステキストを保持します。 この例では、密接に関連する 31 ページの Milvus ドキュメントが、手書きの記録が数件あるだけという状態ではなく、検索可能な何百もの「引き出し」として整理されています。Milvus は、その構造の背後で、ベクトル、スパースデータ、テキスト、およびメタデータの永続的な保存機能を提供します。