多エージェント協調におけるコンテキスト管理のための記憶システム設計

1. プロジェクト概要:共有記憶としての「議会型メモリ」

マルチエージェントシステムの開発において、各エージェントが過去の対話や中間結果を共有し、一貫性のある意思決定を行うためには、効果的なコンテキスト管理が不可欠です。オープンソースプロジェクト council-memory は、この課題に特化した記憶管理モジュールとして注目されています。「議会(council)」という名称が示す通り、複数のエージェントが情報を共同で参照・更新できる中央記憶庫を提供します。

このモジュールは、council-ai などのエージェントフレームワークと連携し、エージェントが生成した情報(プラン、調査結果、ユーザーのフィードバックなど)を構造化された形式で保存・検索可能にします。これにより、開発者は記憶の永続化、検索、有効期限管理といった低レベルの実装から解放され、エージェントのビジネスロジックに集中できます。

2. 設計思想とアーキテクチャ

2.1 エージェントに独立した記憶モジュールが必要な理由

単純なタスクではコンテキストを関数引数で受け渡せますが、複数エージェントが長期にわたって協働するシナリオでは、そのような方法はスケーラビリティに欠けます。council-memory は以下の原則に基づいて設計されています:

  • 永続化と共有:メモリはプロセス間・セッション間で共有され、サービス再起動後も状態を維持できる必要があります。
  • 構造化と検索可能性:記憶は単なるテキストではなく、メタデータ(例:agent_id, task_type)や埋め込みベクトルとともに保存され、意味的または条件ベースで検索可能です。
  • ライフサイクル管理:不要な記憶は自動的に削除・アーカイブされ、検索精度とパフォーマンスを維持します。

2.2 コアコンポーネント

council-memory は以下のモジュールで構成されています:

  1. MemoryEntry:記憶の基本単位。内容(content)、メタデータ(metadata)、埋め込みベクトル(embedding)、重要度スコア(importance_score)などを含みます。
  2. Storage Backend:記憶を物理的に保存するレイヤー。選択肢には以下があります:
    • InMemoryStorage:開発用の揮発性ストレージ
    • FileStorage:JSONL形式でローカルファイルに保存
    • SQLStorage:SQLite/PostgreSQLによるリレーショナル保存
    • VectorDBStorage:Chroma、Weaviate、Pineconeなどのベクトルデータベース。意味的検索を実現
  3. Retriever:記憶を検索する戦略をカプセル化:
    • RecentRetriever:最新のN件を取得
    • ConditionalRetriever:メタデータでフィルタリング(例:type="draft" AND agent_id="writer"
    • SemanticRetriever:ベクトル類似度に基づく検索
    • HybridRetriever:複数戦略を組み合わせたハイブリッド検索
  4. MemoryManager:開発者が直接操作する高レベルAPI。記憶の追加・検索を統一インターフェースで提供します。

3. 実装例:コンテンツ作成チームへの統合

3.1 環境設定

from council.memory import MemoryManager, MemoryEntry
from council.memory.storage import ChromaVectorStorage
from council.memory.retrievers import SemanticRetriever, RecentRetriever, SequentialRetriever
from council.memory.embedders import SentenceTransformerEmbedder

# 埋め込みモデルの初期化
embedder = SentenceTransformerEmbedder("all-MiniLM-L6-v2")

# ベクトルストレージの設定
storage = ChromaVectorStorage(
    collection_name="team_memory",
    embedder=embedder,
    persist_directory="./db"
)

# 検索戦略の組み合わせ
semantic_retriever = SemanticRetriever(storage, top_k=3)
recent_retriever = RecentRetriever(storage, top_k=2)
retriever = SequentialRetriever([semantic_retriever, recent_retriever])

# メモリマネージャの作成
mem_mgr = MemoryManager(storage=storage, retriever=retriever)

3.2 エージェント内での記憶操作

プランナー(Planner)エージェントが過去の計画を参照して新規計画を生成し、それを記憶に保存する例:

class PlanGenerationSkill:
    def __init__(self, memory_mgr):
        self.mem = memory_mgr

    async def run(self, user_request: str, session_id: str):
        # 関連する過去の計画を検索
        past_plans = await self.mem.search_memory(
            query=user_request,
            filters={"memory_type": "plan_outline"},
            limit=2
        )

        context = ""
        if past_plans:
            context = f"参考計画:\n{past_plans[0].content}\n\n"

        # LLMで新計画を生成(簡略化)
        new_plan = f"{context}計画:\n1. 基礎概念の調査\n2. 最新進展の収集\n3. 草稿作成\n4. 校正"

        # 記憶に保存
        entry = MemoryEntry(
            content=new_plan,
            metadata={
                "agent_id": "planner",
                "session_id": session_id,
                "memory_type": "plan_outline",
                "domain": "quantum_computing"
            }
        )
        await self.mem.add_memory(entry)
        return new_plan

3.3 セッション横断的な記憶関連付け

長期プロジェクトを跨いで記憶を参照するには、安定した識別子(例:project_id)をメタデータに含めることが重要です:

# 記憶保存時
entry = MemoryEntry(
    content=findings,
    metadata={
        "agent_id": "researcher",
        "project_id": "proj_qc_2024",  # 固定IDで関連付け
        "memory_type": "research_note"
    }
)

# 後日の問い合わせ時に検索
results = await mem_mgr.search_memory(
    query="量子計算の調査進捗",
    filters={"project_id": "proj_qc_2024"}
)

4. 高度な機能と最適化

4.1 記憶の圧縮と重要度管理

  • 要約:LLMを使って冗長な記憶を短い要約に変換し、検索効率を向上
  • 重要度スコア:アクセス頻度やエージェント評価に基づき動的にスコアを更新。低スコア記憶を定期的に削除
  • 統合:関連する複数の記憶を一つの高レベル記憶にマージ

4.2 検索戦略のカスタマイズ

エージェントごとに異なる検索ロジックを適用できます:

# ライター向けの検索器
writer_retriever = SequentialRetriever([
    ConditionalRetriever(storage, {"memory_type": "fact"}, top_k=3),
    SemanticRetriever(storage, top_k=5),
    RecentRetriever(storage, top_k=1)
])

また、クエリの前処理(指代語解決、同義語展開)により、ベクトル検索の精度を向上させることも可能です。

4.3 監視とデバッグ

運用中は以下のメトリクスを監視すべきです:

  • 記憶の追加速度(ストレージ容量の予測)
  • 検索のヒット率とレイテンシ
  • 記憶利用によるタスク成功率の変化(A/Bテスト)

デバッグ時は、検索結果とその類似度スコアをログ出力し、フィルタ条件や埋め込み品質を見直します。

5. 注意点とベストプラクティス

  • 記憶の汚染を防ぐ:エージェントは成功した結果や検証済み情報のみを記憶に書き込むべきです。中間状態や失敗ログは除外。
  • メタデータスキーマの標準化:全チームで共通のフィールド名(例:memory_type)と値(例:["plan", "fact", "feedback"])を定義。
  • ハイブリッド検索の採用:ベクトル検索だけに依存せず、まずメタデータで絞り込み、その後に意味検索を実行。
  • 記憶の一貫性管理:古い記憶を上書きするのではなく、新しいバージョンを追加し、古いものを status: "deprecated" でマーク。
  • 大規模時のパフォーマンス対策:ユーザー単位で記憶をシャーディング、またはホット/コールドデータを分けて保存。

記憶システムの設計は、エージェントの協働プロセスをいかに抽象化するかにかかっています。シンプルな最近記憶検索から始め、観察と反復を通じて徐々に高度な機能を追加していくのが現実的です。

タグ: council-memory multi-agent-systems vector-database semantic-search context-management

7月21日 02:23 投稿