BluePeriod Docs
開発

長期記憶アーキテクチャとモデル拡張ガイド

セマンティック検索による長期記憶の仕組みと拡張手法

11. 長期記憶アーキテクチャとモデル拡張ガイド (Long-term Memory Architecture)

1. アーキテクチャ概要

BluePeriod の長期記憶(Long-term Memory)は、ユーザーとの過去の対話を蓄積し、セマンティック検索(ベクトル検索)を用いて関連性の高い情報を現在の会話コンテキストに注入するための仕組みです。

プライバシー保護とオフライン動作のため、サーバーサイドのベクトルデータベースを使用せず、すべてブラウザ内で完結する Local-First アーキテクチャを採用しています。

1.1. 技術スタック

  • 検索エンジン: Orama (全文検索およびベクトル検索)
  • 埋め込み(Embedding)推論: Transformers.js (WebGPU/WASM/CPU)
  • 永続化層: IndexedDB (Dexie.js を介して vectorIndex テーブルにシリアライズして保存)

1.2. データフロー

  1. 会話の分析 (Memory Judge): 直近のユーザーとの対話に、長期的に記憶すべき事実(ユーザーの好み、設定、決定事項など)が含まれているかをLLMが判定します。
  2. 事実の抽出と要約 (Memory Refiner): 記憶すべきと判定された場合、LLMがその内容を**AIキャラクター自身の視点による日記(またはメモ)**として短い文章に要約します。
  3. Embedding 生成: Transformers.js を使用し、ブラウザ内でこの要約テキストを多次元ベクトルに変換します。
  4. インデックス登録: Orama DB に要約テキスト、属性(role: 'memory', characterId, timestamp)、およびベクトルを登録します。以前使用されていた 'user' ロール(生のメッセージ)の保存は、一貫性と精度向上のため現在は行われません。
  5. 永続化: Orama インデックス全体をシリアライズし、IndexedDB の chat-memory-index キーに保存。

1.3. データ属性 (Role Definition)

長期記憶には以下の role が存在し、現在は 'memory' を中心に運用されています。

role意味誰の視点か現在のステータス
memoryAI自身が書き残した日記・事実AIキャラクター✅ 主力の記憶形式
userユーザーの生のメッセージユーザー⚠️ 非推奨(重複回避のため)
assistant(未使用)AI-

1.3. 検索モードの選択

Orama は以下の検索モードをサポートしていますが、長期記憶の検索には vector モードを使用します。

モード説明スコア範囲長期記憶への適性
vector純粋なベクトル検索(コサイン類似度)0.0 〜 1.0✅ 推奨
hybridフルテキスト検索 + ベクトル検索の融合0.0 〜 1.0(ただし重み付けにより圧縮)⚠️ スコア圧縮の問題あり
fulltextBM25 によるキーワード検索可変上限❌ 意味的検索には不向き

Vector モードを使用する理由:

長期記憶の目的は「意味的に近い過去の会話」を想起することです。フルテキスト検索(キーワード一致)はこのユースケースでは不要であり、hybrid モードを使用するとスコアが圧縮される問題があります。

技術メモ: Orama の hybrid モードはデフォルトで text: 0.5, vector: 0.5 の重み付けを使用します。フルテキスト検索がマッチしない場合、最終スコアは vector_score * 0.5 となり、最大で 0.5 が上限になります。これは similarityThreshold の意味を変えてしまうため、長期記憶には vector モードが適しています。

2. インデックス管理と整合性

2.1. 埋め込みモデルの依存性

ベクトル検索において、検索クエリと保存されたドキュメントは必ず同一の埋め込みモデルで計算される必要があります。モデルが異なるとベクトルの「意味的な距離」が正しく計算できません。 このため、インデックスデータには生成に使用した modelId を付与し、アプリ起動時やモデル切り替え時に不一致を検出し、必要に応じて「再ベクタライズ(Re-vectorization)」をユーザーに促します。

2.2. アイソレーション(分離)

記憶は characterId というメタデータを持っており、検索時にフィルターを適用することで、特定のキャラクターとの会話のみを想起するように設計されています。

2.3. モデルダウンロードの可視化 (Download Progress)

Embeddingモデルは数十MBから数百MBのサイズがあるため、ブラウザへのダウンロードには時間がかかる場合があります。Transformers.js の progress_callback を購読し、以下の仕組みでユーザーにフィードバックを提供します。

  • グローバル・コールバック: embedding.ts に登録されたコールバックを通じて、ダウンロードイベント(init, progress, done, error)を捕捉。
  • 状態集約: 複数ファイルのダウンロード状況を Map で管理し、合計サイズに対する合計取得量から全体の進捗率を算出。
  • UI表示: ModelDownloadStatus コンポーネントがこの状態を監視し、ダウンロード中のみ画面端にフローティング表示します。

3. 新しい埋め込みモデルを追加するための開発フロー

新しいモデルを追加する際は、以下のステップに従ってコードと定義を更新してください。

Step 1: next-app/src/lib/memory/models.ts への定義追加

EMBEDDING_MODELS 定数に新しいモデルの設定を追加します。

export const EMBEDDING_MODELS: Record<string, EmbeddingModelConfig> = {
  // ...既存のモデル
  'onnx-community/your-new-model-id': {
    id: 'onnx-community/your-new-model-id',
    name: '表示名 (例: Google: Gemma-300M Embedding)',
    dimension: 1024, // モデルの出力次元数
    description: 'モデルの特徴や推奨される用途の短い説明。',
    supportsMatryoshka: false, // Matryoshka slicing をサポートするか
    dtype: 'q8', // 量子化フラグ (q8, fp16, etc.)
  },
};

Step 2: 推論ロジックの確認 (embedding.ts)

generateEmbedding 関数は、supportsMatryoshkatrue の場合に指定された dimension までベクトルをスライス(Matryoshka Slicing)します。モデルが固有の正規化やスライスを必要とする場合は、ここを調整します。通常、Transformers.js が ONNX 形式を透過的に扱うため、設定の追加のみで動作します。

Step 3: 多言語対応 (i18n)

next-app/src/i18n/locales/*.json に新しいモデルに関連する翻訳テキストがあれば追加します。通常は models.ts 内の name プロパティが UI に直接表示されますが、補足説明などを局所化する場合は i18n キーを使用します。

Step 4: 動作検証

  1. データベース管理画面 (/database-management) へ移動。
  2. 「メンテナンス」タブで新しいモデルを選択。
  3. 重要: モデルを変更したら「再ベクタライズ」を実行し、既存の記憶が新しいモデルの空間に正しくマッピングされることを確認してください。

4. モデル選定のガイドライン

追加するモデルは、以下の基準を考慮してください。

  • マルチリンガル: 日本語と英語の両方で高い精度を持つこと。
  • 軽量性 (Edge-Ready): ブラウザでダウンロードおよび推論されるため、量子化後(q8等)のサイズが 50MB〜300MB 程度に収まることが望ましい。
  • Matryoshka 対応: 高次元の情報を保持しつつ、検索時には低次元(128, 256等)に絞ってメモリ効率を高められるモデルが好まれます。

関連

On this page