Skip to main content
Glama

AWHM Lite

CI

LLMエージェントのための外部長期記憶です。クラウド不要、APIキー不要、完全ローカルで動作します。

AWHM Liteは、追記専用ロギング、正規表現ベースのパターンマッチング、矛盾を考慮したメモリグラフ、シンボリック統合(LLM呼び出しゼロ)、語彙的+意味的特徴の融合による検索を通じて、あらゆるLLMにセッションを超えた永続的なメモリを提供します。

ステータス: 研究プロトタイプ。2026年2月に構築し、2026年8月に公開。v0.2.0で堅牢性を高め、v0.3.0でフック、Stage 2、エンティティ解決、タイムトラベル、SQLiteストレージ、実コーパスによる評価を追加しました。テストは145件で、Python 3.11〜3.13でCIを実行しています。

プロジェクトドキュメント

  • docs/awhm-whitepaper.md:Liteがサブセットであることを示す、AWHMの完全なアーキテクチャ論文

  • docs/awhm-whitepaper-vs-lite.md: Liteが保持するものと除外するもの

  • docs/Future Plans.md:計画中の次のステップ(ターンごとに自動で動作する、静かで副作用を生まないミドルウェア)

Related MCP server: claude-memory-mcp

このプロジェクトがどう作られたか

アーキテクチャとその背後にあるアイデアは私自身のものです。コードは、すべてAIコーディングエージェント(主にClaude Code)によって、私の指示の下で書かれました。私は設計を決め、タスクを範囲を絞り、成果物をレビューし、プロジェクトを指示(steer)しました。ホワイトペーパーも同様の方法で作成されています。

INTERACTION TIME                        OFFLINE (SESSION END)
────────────────────                    ─────────────────────
┌──────────────────┐   real-time log    ┌──────────────────────┐
│  PRIMARY AGENT   │──────────────────► │  STAGE 1 CONSOLIDATION│
│  (user-facing)   │   (middleware,     │  (symbolic only,      │
└──────┬───────────┘    no LLM)         │   zero LLM calls)     │
       │                                └──────────┬───────────┘
       │ queries                                   │ writes
       ▼                                           ▼
┌──────────────┐    ┌──────────┐    ┌──────────────────────┐
│  RETRIEVAL   │◄───│ SESSION  │    │    FLAT MEMORY GRAPH  │
│  ENGINE      │    │ BUFFER   │    │                      │
│              │◄───┤(checked  │    │  nodes: episodic,    │
│ BM25 +       │    │ first)   │    │  semantic, procedural│
│ embedding    │    └──────────┘    │                      │
│ similarity   │◄───────────────────│  edges: typed        │
│              │                    │  strength: rec + freq│
└──────────────┘                    └──────────────────────┘
       ▲
       │ fallback (first ~10 sessions)
┌──────┴───────┐
│   RAW LOGS   │
│ (append-only)│
└──────────────┘

インストール

# Core (numpy, spaCy, dateparser) plus the sentence-transformers embedding model
pip install -e ".[embeddings]"

# spaCy NER model (used in consolidation; without it, entity extraction is skipped)
python -m spacy download en_core_web_sm

# Claude Code MCP integration
pip install -e ".[mcp]"

# Optional: Anthropic SDK client for Stage 2 (the default Stage 2 client is
# the Claude Code CLI and needs nothing extra)
pip install -e ".[anthropic]"

sentence-transformersはPyTorchを引き込みため、オプショナルです。これを使わない場合は、use_mock_embeddings=True(決定的なハッシュベースのベクトル。テストやCLIの試用に十分)を指定してセッションを起動します。実際のモデル(all-MiniLM-L6-v2、22 MB)は、初回使用時にダウンロードされます。

クイックスタート

Python API

from awhm import AWHMSession
from awhm.types import Role

# Start a session (also usable as a context manager: `with AWHMSession.start_session() as session:`)
session = AWHMSession.start_session()

# Log messages
session.log_message(Role.USER, "My name is Alice")
session.log_message(Role.ASSISTANT, "Hello Alice!")
session.log_message(Role.USER, "I prefer Python over JavaScript")
session.log_message(Role.USER, "The API endpoint is https://api.example.com/v2")

# Query memory (works immediately via session buffer)
results = session.query("What language does the user prefer?")
for r in results:
    print(f"[{r.source}] {r.content}")

# Consolidate into long-term memory graph
session.consolidate_current()

# End session (flushes WAL, saves graph)
session.end_session()

LLMとの統合

AWHMはミドルウェアとして置かれます。これはLLMに対して直接呼び出しを行わず、あなたが使っている何らかのLLMに配線して使います:

from awhm import AWHMSession
from awhm.types import Role

session = AWHMSession.start_session()

def handle_message(user_text):
    session.log_message(Role.USER, user_text)

    # Retrieve relevant memories
    memories = session.query(user_text, k=5)
    memory_context = "\n".join(f"- {m.content}" for m in memories)

    # Inject into system prompt
    system = f"Memories from past conversations:\n{memory_context}"
    response = your_llm_call(system_prompt=system, user_message=user_text)

    session.log_message(Role.ASSISTANT, response)
    return response

# At end of conversation:
session.consolidate_current()
session.end_session()

CLI

awhm status                        # Show system stats
awhm query "Python preferences"    # Search memory
awhm query "API endpoint" --include-history --trace
awhm consolidate                   # Run Stage 1 on pending sessions
awhm snapshot create               # Backup current graph
awhm snapshot list                 # List snapshots
awhm snapshot restore --path FILE  # Restore from snapshot
awhm delete NODE_ID                # Hard-delete a node (privacy)
awhm eval --json                   # Run built-in benchmark report

Claude Codeの統合(フック、推奨)

フックを使うと、モデルがツールを呼び出さなくても毎ターンでメモリが機能します。各フックは独立した短寿命プロセスです。セッションバッファはそれらの間、書き込みを伴うログ(write-ahead log)から再開されます。

イベント

コマンド

処理内容

UserPromptSubmit

awhm hook prompt

プロンプトを記録し、上位メモリ(BM25+バッファ;--semanticを追加するとエンブリークダーも使用)を取得して、隠しコンテキストとして返す

Stop

awhm hook stop

アシスタントの応答を記録する

SessionEnd

awhm hook session-end

セッションをグラフに統合する(--stage2を追加するかAWHM_STAGE2=1を設定すると、claude -pを通じてStage 2も実行しする)

awhm hook settings          # prints the block to merge into ~/.claude/settings.json

フックがセッションをブロックすることはありません。どのような失敗でもstderrに書き込まれ、プロセスは終了コード0でです。AWHM_DATA_DIRを設定すると、メモリの保存先を変更できます。

Claude Codeの統合(MCP)

AWHM LiteはMCPサーバーとして配布されるので、Claude Codeがそれをツールとして使えます。

セットアップ

# Install with MCP support
cd awhm-lite
pip install -e ".[mcp]"

# Register with Claude Code
claude mcp add --transport stdio awhm-lite -- awhm-mcp

または手動で .claude/settings.json に追加します:

{
  "mcpServers": {
    "awhm-lite": {
      "type": "stdio",
      "command": "awhm-mcp",
      "env": {
        "AWHM_DATA_DIR": "~/.awhm"
      }
    }
  }
}

利用可能なMCPツール

ツール

説明

memory_query

自然言語クエリでメモリを検索する(include_history、with_traceはオプション)

memory_log

メッセージを生の会話ログに記録する

memory_consolidate

保留中のセッションからメモリを抽出してグラフに統合する

memory_status

ノード数、エッジ数、セッション数を表示する

memory_snapshot_create

バックアップスナップショットを作成する

memory_delete_node

ノードをハード削除し、一致するスナップショットデータを消去する

接続すると、Claude Codeは自動的にこれらのツールを使えるようになり、会話を越えてメモリをクエリ/保存できます。

どのように動作するか

生のログ

すべてのメッセージは、セッションごとに1つのJSONLファイルに追記されます。追記のみで、プライバシー上のハード削除以外では変更されません。これがグラウンドトルース(基準データ)です。

セッションバッファ

正規表現ベースのパターンマッチャーがすべてのユーザーメッセージにリアルタイムで動作し、以下を捕捉ます:

  • 修正: 「Actually, X is Y」「no, it's X」

  • 好み: 「I prefer X」「always use X」「never do X」

  • 事実: 「the endpoint is X」「my name is X」

  • 結果: 「that worked」「that failed」

LLM呼び出しゼロで、明示的なシグナルの約60〜70%をわしに行います。検討時はまずバッファがチェックされ、即座に`セッション内の連続性が得られます。デフォルトの検索では、後で出た別のステートメントに収束されるバッファエントリ(同一スロット、明示的な修正)を非表示にして、修正が優先されるようにします。セッションごとのwrite-aheadログに永続化され(30秒の書き出し間隔、変更がなければスキップします)。

メモリグラフ

3種類のノード型(エピソード的、意味的、手続き的)と3種類のエッジ型(時間的、抽象化、連合)を持つフラットな有向グラフ。

各ノードには現在、矛盾のライフサイクルメタデータが添付されている:

  • canonical_key(スロットス yleの識別子、例:fact:my preferred language)

  • status(active、superseded、retracted)

  • supersedes(このノードによって置き換えられた古いノードID)

  • valid_from / valid_to

  • confidence

JSONとして保存され、メモリにロードされます。

後方互換性:古いグラフファイル(ライフサイクルフィールドがないもの)は、ロード時にメモリ内で自動的にマイグレーションされます。

強度スコアリング

各ノードには合成された強度スコアがあります。

recency(打卡)はべき乗減衰:

strength = base。

S(v) = 0.4 * recency + 0.6 * frequency

新しさにはpower-law減衰を使用:s_new = (1 + 0.1 * hours)^(-0.3)。およそ24時間後は0.71、7日後は0.40、30日後は0.27です。頻度はアクセス回数を90パーセンタイルで正規化したものです。

統合(Stage 1)

セッション終了時に実行され、LLM呼び出しゼロ。

  1. NER:spaCyによって人、組織、場所、製品を抽出。数値や時間らしきラベル(CARDINAL、MONEY、DATE、...)は除外されます(そうしないとノイズノートになるため)。ner_labelsで設定可能。

  2. 時間表現解析:dateparserを用いて「yesterday」「March 5」を問題となくISOタイムスタンプに解決します。

  3. ルールベース抽出:セッションバッファと同型の正規表現パターンを、新しいメッセージに使用します。

  4. エンティティリンキング:既存ノードへエンティティを照合します(コサイン行列の積を一度行い、その後エンティティ型に見合うと文字列類似度ガードで検証)。

  5. 重複排除:バッチ内の同一表現をまとめます。既存ノードに近い文(コサイン > 0.92)は新しいノードを作らず、その既存ノードを強化します。

  6. コミット:canonicalキーを割り当て、矛盾したメモリを継承し、ノードとエッジを追加し、強度スコアを更新します。

矛盾: Canonicalキー

canonicalキーは、ステートメントが「埋める」スロットの名前を付けます。同じキーを持つアクティブなメモリが2つあると互いに矛盾するため、新しい方のメモリが古い方を置き換えます(status=superseded、valid_toを設定、新しいノードにはsupersedesリンク)。

ステートメント

キー

「私の好言語はPythonです」

fact:my preferred language

「私はケープタウンに住んでいます」

fact:i live in

「ダークモードが好みです」

preference:dark

「インデントにタブは使わない」

policy:use:tabs

「スクリプトにはPythonを使う」

none(加算的)

ルールは意図的に保守的です。というのは、意図を判断する LLM がいないからです。

  • 同一キー:常に置き換えます(スロットが同じで新しい値が提示される)。

  • 好み/ポリシーのファミリ:同じセッション内の correction_window_messages(デフォルト3)以内に来る明示的な修正(「Actually, I prefer Rust」)が、前の同ファミリのステートメントを置き換えます。修正マーカーがない場合は、好みは加算されます:「I prefer tabs」と「I prefer dark mode」両方がアクティブのままです。

  • 事実ファミリー:キーノードが完全一致した場合のみ置き換えます。したがってAPIエンドポイントに関する修正があなたの名前を破壊することはありません。

  • 検索されていないものにはキーがなく、置き換えも発生しません。

エンティティ

名前付きエンティティは、どんな表現でも1つのノードに解決されます。表面の形は正規化されます(大文字小文字、所有格、法人サフィックス、ドメイン:「Acme Holdings Ltd」と「acme.com」の両方が「acme」になる)。次に、完全一致のエイリアス、あいまいさのないトークン包含(「Acme Holdings」内の「Acme」)、最後に同じエンティティ型の埋め込み類似度で照合されます。解決された各メンションはエイリアスとしてノードに記録され、ステートメントは言及するエンティティへassociationエッジを持つので、検索は「Acme」からそのエンティティについて知られているすべてのことを辿ることができます。

Stage 2(任意のLLM再仕上げ、APIキー不要)

Stage 1には限界があります。「I prefer Rust」はわかりますが、「let's go withRust then」は見つけられません。Stage 2はStage 1の後にオフラインで実行され、ルールが見つけられなかったメモリをLLMに提案させます。LLMは提案するだけで、コードはすべての提案を検証し(スキーマ、引用されたメッセージ番号が存在し、確信度の下限を満たす)、既に捕捉されているものは捨て、同じスロットと置き換えルールに従ってコミットします。検索はゼロLLM呼び出のままです。

デフォルトのクライアントはClaude Code CLI(構造化出力付きの claude -p)に フォールアウトするため、既存のログインを利用し、APIキーはどこにも保存しません。また、メモリフックが内部で発火しないようにマークします。

awhm consolidate --stage2                    # Claude Code CLI, default model
awhm consolidate --stage2 --stage2-model sonnet
from awhm import AWHMSession, AWHMConfig

config = AWHMConfig(stage2_enabled=True, stage2_model="sonnet")
with AWHMSession.start_session(config) as session:   # builds ClaudeCodeClient
    ...
    session.consolidate_current()

complete_json(system, user, schema) -> str メソッドを持ついかなるオブジェクトもクライアントとして動作します(llm_client=...)。API課金を好む人向けにAnthropicSDKクライアントも同梱されています(stage2_client="anthropic"、追加の[anthropic]参照)。

検索

LLM呼び出しゼロ。特徴ベースの融合です。

  1. バッファチェック:セッションバッファを最初に検索します(インスタントヒット、常にグラフの結果を上位にランク付け)

  2. アンカー識別:BM25の用語オーバーラップと再類似度コサイン(union)。BM25インデックスはプロセス内に構築され(Lucene風のIDFで、小さなコーパスでも適切な点数になる)、ノードが変わらない限りキャッシュ。

  3. 履歴フィルタ:デフォルトでは、status=activeのグラフノードだけが対象です。

  4. 特徴スコアリング:意味的類似度+語彙的なスコア+強度+確からしさ、それから対立ペディじゃティを減します。強度はランキング対象の候補だけ再計算します。

  5. トップkを返す(デフォルト10件)

  6. Ne村拡張:アンカーの1ホップ隣接(リンクされたエンティティ、順次なエピソード)を候補セットに加え、エッジの減衰に応じて(sequence) association feature で評価します。 有効なアンカーのみ拡張できます。

  7. コールドスタートフォールバック:最初の約10セッションでは、生のログに対してBM25も動かします。そのヒットは[0, raw_log_score_scale] にスケーリングされるので、実際のグラフの一致順位を下回ります。

タイムトラベル

事実は有効ウィンドウを持ちます。「from」/「since」で導入された日付は valid_from を、「until」は valid_to を設定します。そして置き換えが古いノードの valid_to ウィンドウを閉めます。の時刻に、 query(..., as_of="2026-03-01") により、そのとき(置き換わったノードも含めて)真実だったものを取得できます:

awhm query "API endpoint"                       # what is true now
awhm query "API endpoint" --as-of 2026-02-01    # what was true then

include_history=True にすると、置き換え済み/破棄済みのメモリも表示します。

ランキングの特徴トレースを返すには with_trace=True を使います。

評価

組み込みのベンチマークは、合成のスモークテストです(修正に重心があるクエリ3つに削除の監査を加えたもの)。実際の指標はコーパスをリプレイして得られます:

awhm eval                                            # built-in synthetic benchmark
awhm eval --corpus my_sessions.json                  # native format, see below
awhm eval --corpus longmemeval_s.json --longmemeval --limit 50

両者とも Recall@k、nDCG@k、矛盾エラー率、p50/p95 レイテンシ、カテゴリ別再現率を報告します。ネイティブコーパス形式は {"sessions": [{"id", "messages": [{"role", "content"}]}], "questions": [{"id", "question", "expected": [...], "forbidden": [...], "as_of", "category"}]} です。
LongMemEval のインスタンスは、ベンチマークプロトコルに従って統合され、個別に質問されます。一致判定は回答の部分文字列によって行われ、これは意図的に下限を設定したものです。言い換えによる一致はカウントされません。

測定値(Stage 1 のみ、oracle 分割、500 問): Recall@5 0.196。単一セッションのユーザーファクトでは 0.40 から、好みでは 0.00 まで低下し、クエリあたり 4 ms です。これは regex の上限を可視化したものです。Stage 2 はこの上限を引き上げるために存在します。
完全な表、注意点、再現手順は docs/benchmarks.md にあります。

設定

すべてのパラメータは AWHMConfig で構成できます。

パラメータ

デフォルト

説明

alpha

0.3

減衰率(べき乗則の指数)

beta

0.1

減衰スケーリング定数

w_rec

0.4

強度スコアにおける近接性の重み

w_freq

0.6

強度スコアにおける頻度の重み

retrieval_profile

"balanced"

検索重み付けプロファイル

w_semantic

0.55

セマンティック類似度の重み

w_lexical

0.20

BM25 語彙の重み

w_strength

0.15

ノード強度の重み

w_confidence

0.10

統合信頼度の重み

contradiction_penalty

0.35

非アクティブな記憶へのペナルティ

include_history_by_default

False

デフォルトで置き換え・撤回された記憶を含める

trace_retrieval

False

デフォルトでランキングトレースを出力する

k

10

上位 k 件の検索数

entity_link_threshold

0.85

エンティティリンキングのコサイン閾値

dedup_threshold

0.92

重複排除のコサイン閾値

bm25_anchor_ratio

0.5

スコアが ratio × 最高 BM25 スコア以上のときに語彙アンカーになる

embed_threshold

0.3

アンカーセットに含める最小コサイン類似度

raw_log_score_scale

0.5

コールドスタート時で一致の生ログスコアの上限

neighbor_expansion / neighbor_decay

True / 0.6

アンカーの 1 ホップグラフ隣接を、このエッジ重み倍率で取り込む

w_association

0.10

ブレンドにおける隣接証拠の重み

storage_backend

"json"

"json"(単一ファイル)または "sqlite"(増分保存)

stage2_enabled

False

Stage 1 後のオフライン LLM による追加処理

stage2_client / stage2_model

"claude-code" / None

claude-code(CLI、キー不要)または anthropic。モデルエイリアス。None はクライアントデフォルト

stage2_max_messages / stage2_min_confidence

60 / 0.5

LLM 呼び出しごとのメッセージ数。この信頼度を下回る提案は破棄

correction_window_messages

3

明示的な修正が好み/ポリシーを無効化するために必要な近さ(メッセージ数)

ner_labels

PERSON, ORG, GPE, ...

ノードになる spaCy エンティティラベル

buffer_flush_interval

30s

WAL 永続化の間隔

ann_index_type

"none"

予約済み ANN インデックスモード

delete_snapshots_on_hard_delete

True

ハード削除時に対応するスナップショット記憶を削除する

from awhm.config import AWHMConfig

config = AWHMConfig(
    data_dir="~/.my-project-memory",
    k=20,
    w_rec=0.5,
    w_freq=0.5,
)

データディレクトリ

~/.awhm/
├── logs/                          # Raw JSONL logs (one per session)
│   ├── {session_id}.jsonl
│   └── ...
├── graph/
│   ├── memory_graph.json          # The memory graph (storage_backend="json")
│   └── memory_graph.sqlite        # ... or one row per node (storage_backend="sqlite")
├── snapshots/
│   └── snapshot_{timestamp}.json  # Manual backups
├── wal/
│   └── {session_id}.wal           # Per-session write-ahead logs
└── meta/
    ├── consolidated_sessions.json # Tracks which sessions have been processed
    ├── deletion_tombstones.jsonl  # Deletion tombstones
    └── deletion_ledger.jsonl      # Deletion audit ledger

テスト

pip install -e ".[dev]"
pytest tests/ -v

すべてのテストは MockEmbeddingService を使用します(プロセス間で決定的、モデルのダウンロードは不要)。ruff check . で lint を実行します。CI は Python 3.11、3.12、3.13 で両方を実行します。

依存パッケージ

パッケージ

サイズ

説明

numpy

~29 MB

ベクトル演算

spacy + en_core_web_sm

~35 MB

NER

dateparser

~2 MB

日付解析

sentence-transformers (optional, [embeddings])

~3 MB (+PyTorch ~350 MB)

埋め込みモデル

mcp (optional, [mcp])

~1 MB

Claude Code 統合

BM25 はパッケージ内で実装されており(約60行)、ランキングのための依存関係はありません。

埋め込みモデル(all-MiniLM-L6-v2、22 MB)は初回使用時に ~/.cache/huggingface にダウンロードされます。

プロジェクト構造

src/awhm/
├── __init__.py            # AWHMSession facade (top-level API)
├── config.py              # All parameters + path helpers
├── types.py               # Enums: Role, NodeType, NodeStatus, EdgeType, BufferEntryType
├── mcp_server.py          # MCP server for Claude Code
├── hooks.py               # Claude Code hook commands (prompt / stop / session-end)
├── timeutil.py            # Timestamp parsing, validity windows
├── eval/                  # Built-in benchmark + real-corpus replay (LongMemEval loader)
├── raw_log/               # Append-only JSONL logging
├── session_buffer/        # Regex pattern matching + WAL
├── graph/                 # Memory graph, strength scoring, JSON/SQLite stores
├── consolidation/         # NER, temporal, extraction, entities, dedup, Stage 2, pipeline
├── retrieval/             # Embedding, BM25, ranking, retrieval engine
├── snapshots/             # Snapshot create/restore/list
├── deletion/              # Hard-delete cascade
└── cli/                   # argparse CLI

Maintenance

ActivityStale
ResponsivenessNo recent community issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    A persistent memory MCP server for Claude Code that enables long-term recall across sessions via hybrid search, code intelligence, and tools for reading/writing memory.
    20 npm
    5
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A MCP server that gives Claude Code and other AI assistants long-term memory by automatically extracting technical knowledge from conversations and retrieving relevant experiences in future sessions.
    10 npm
    MIT