Skip to main content
Glama

AWHM Lite

CI

适用于 LLM 智能体的外部长期记忆。无需云端、无需 API 密钥,完全本地运行。

AWHM Lite 通过只追加日志、基于正则的模式匹配、具有矛盾感知的记忆图、符号化整合(零 LLM 调用),以及词法与语义特征融合的检索,赋予任何 LLM 跨会话的持久记忆。

状态: 研究原型。构建于 2026 年 2 月,发布于 2026 年 8 月;v0.2.0 加强了稳定性,v0.3.0 新增了钩子、第二阶段、实体解析、时间旅行、SQLite 存储和真实语料评估。共 145 项测试,CI 覆盖 Python 3.11 至 3.13。

项目文档

  • docs/awhm-whitepaper.md:完整 AWHM 架构论文(本项目是其子集)

  • docs/awhm-whitepaper-vs-lite.md:Lite 保留了哪些功能,又有哪些取舍

  • docs/Future Plans.md:计划中的下一步(静默的逐轮中间件)

Related MCP server: claude-memory-mcp

构建方式

其架构与背后的理念出自我本人。代码完全由 AI 编码智能体(主要是 Claude Code)在我的指导下编写:我负责设计、任务范围、审阅输出与整体把控。白皮书也以同样的方式完成。

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——你把它接入到自己使用的任何逻辑中即可:

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 集成(钩子,推荐)

通过钩子,记忆可以在每一轮都生效,而无需模型主动调用工具。每个钩子都是独立的短生命周期进程;会话缓冲区会从磁盘日志中恢复,在各钩子之间无缝衔接。

事件

命令

作用

UserPromptSubmit

awhm hook prompt

记录提示词,检索最相关的记忆(BM25 + 缓冲区;添加 --semantic 也可使用向量嵌入),并作为隐藏上下文返回

Stop

awhm hook stop

记录助手的回复

SessionEnd

awhm hook session-end

将会话整合到记忆图谱中(可通过 --stage2 或设置 AWHM_STAGE2=1,同时通过 claude -p 运行第二阶段的处理)

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 将自动使用这些工具,并能在跨会话中查询/存储记忆。

工作原理

原始日志

每条消息都会追加到一个 JSONL 文件中(每个会话一个文件)。日志只追加,绝不修改,除非是为了隐私进行硬删除。这是不可否认的事实来源。

会话缓冲区

基于正则的模式匹配器会对每条用户消息实时运行,捕捉:

  • 纠正:“实际上,X 其实是 Y”、“不,是 X”

  • 偏好:“我更喜欢 X”、“始终用 X”、“永远不要做 X”

  • 事实:“接口地址是 X”、“我的名字是 X”

  • 结果:“成功了”、“失败了”

只要零 LLM 调用,就能捕捉约 60%–70% 的显式信号。检索时会先检查会话缓冲区,以获得即时的会话内连续。在默认检索中,稍后语句若相同槽位或消息实时纠正的形式取代了之前的缓冲区条目,条目将被隐藏,因此更正会胜出。缓冲区通过 per-session 将技术到日志实现持久化(30 秒刷新间隔,在没有变化时跳过)。

记忆图

这是具有三种节点类型(情节、语义、程序)和三种边类型(时间、抽象、关联)的平面有向图。

目前每个节点都携带矛盾生命周期元数据:

  • canonical_key(槽位式身份,例如 fact:my preferred language)

  • status(active、superseded、retracted)

  • supersedes(被该节点替换的旧节点 ID)

  • valid_from / valid_to

  • confidence

存储为 JSON,加载进内存。

向后兼容:旧版图文件(没有生命周期字段)会在加载时在内存中自动迁移。

强度评分

每个节点都有一个综合强度评分:

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

近因性使用幂律衰减:s_rec = (1 + 0.1 * hours)^(-0.3)——大约是 24 小时为 0.71,7 天为 0.40,30 天为 0.27。频率是按第 90 百分位数归一化的访问计数。

整合(第一阶段)

在会话结束时运行,零 LLM 调用:

  1. NER 基于 spaCy:识别人物、组织、地点、产品。数字和时间类标签(CARDINAL、MONEY、DATE 等)会被过滤掉;它们会产生噪声节点。可通过 ner_labels 配置。

  2. 时间解析 via dateparser:将“yesterday”、“March 5”等解析为 ISO 时间戳

  3. 基于规则的提取:将同名正则模式与紧跟新消息的内容匹配

  4. 实体链接:将实体与现有节点进行匹配(义乌映射表 + 持久层实体类型一致性检查 + 字符串相似度门控)

  5. 去重:批次内相同的语句会被合并;与现有节点接近重复的语句(余弦相似度 > 0.92)会强化该节点,而不是新建节点

  6. 提交:分配 canonical keys,superseded 被取代的记忆,添加点和边,并刷新强度评分

矛盾:Canonical Keys

Canonical key 表示语句所填充的槽位。若两个 active 的记忆具有相同 key,它们彼此矛盾,因此较新的会取代旧的(status=superseded、valid_to 设置、新节点上添加 supersedes 链接)。

语句

Key

“My preferred language is Python”

fact:my preferred language

“I live in Cape Town”

fact:i live in

“I prefer dark mode”

preference:dark

“Never use tabs for indentation”

policy:use:tabs

“I use Python for scripting”

none(附加)

规则很保守,因为没有 LLM 来判断意图:

  • 相同 key:始终取代(槽位被新值重新声明)。

  • 偏好/政策族:在 correction_window_messages(默认 3)内出现显式纠正(如“实际上,我更喜欢 Rust”)时,会取代同族的先前陈述。没有纠正标记时,偏好是可附加的:“我 prefer tabs”和“I prefer dark mode”两者都保持 active。

  • 事实加族:只有完全相同的 key 才会取代,因此对 API 端点的纠正绝不会覆盖你的名字。

  • 未识别的内容不会获得 key,也永远不会被取代。

实体

命名实体无论写到哪种形式,都会归到同一个节点。表面形式会被规范化(大小写、所有格、企业后缀、域名:“Acme Holdings Ltd”和“acme.com”都变成“acme”),然后通过精确别名、明确的 token 包含(例如“Acme”出现在“Acme Holdings”内)以及同类型嵌入相似度来匹配。每个解析出的提及都会作为别名记录在节点上,相关语句也会建立到这些实体的关联边,因此从“Acme”可以检索所有已知相关信息。

第二阶段(可选 LLM 细化,无需 API 密钥)

第一阶段有硬上限:它能捕捉“I prefer Rust”,却会漏掉“let's go with Rust then”。第二阶段在第一阶段后运行,离线见于 LLM,并让 LLM 提出规则未发现的记忆。LLM 只提出候选:代码会验证每个候选(schema、引用的消息编号必须存在、置信度下限)、丢弃任何已捕获的内容,再通过同一种槽位和取代规则进行提交。检索过程中会保持零 LLM 调用。

默认客户端会调用 Claude Code CLI(claude -p 并生成结构化输出),因此使用你已有的登录配置,不会在任何地方存储 API 密钥。它会标注该次调用,使内部不会触发 hook。

即:

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的用户,可选启用 Anthropic SDK 客户端(stage2_client="anthropic",额外依赖 [anthropic])。

检索

零 LLM 调用,基于特征的融合:

  1. 缓冲区检查*:先从会话缓冲区中检索(立即命中,始终排在图谱结果之前)

  2. 锚点识别:BM25 术语匹配 + 嵌入余弦相似度(取并)。BM25 索引在进程内构建(Lucene 风格 IDF,因此即使很小的语料也能获得合理评分),并在节点未变化时缓存。

  3. 历史过滤:默认情况下,只有 status=active 的图谱节点才可被选择。

  4. 特征评分:语义相似度 + 词法分数 + 强度 + 置信度 – 矛盾惩罚;仅对候选节点重新计算强度分数。

  5. 返回 top-k(默认10)。

  6. 邻居扩展:锚点的一跳邻居(关联实体、连续事件)以衰减后的边权进入候选集,并通过 association 特征参与评分。只有当前有效的锚点才会被扩展。

  7. 冷启动回退:在前约 10 个会话,同时也会对原始日志运行 BM25。这些命中结果会被缩放至 [0, raw_log_score_scale] 范围内,因此不会超过真正的图谱匹配。

时间复盘

事实带有效期窗口。使用 “from”/“since” 的日期设置 valid_from,使用 “until” 的日期设置 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 可返回每个结果的排序到特征轨迹。

评估

内置基准是一个合成冒烟测试(三个纠正中心的分布查询,加上一个删除灾难)。真实结果来自真实语的回测:

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。这就是正则表达式上限的直观体现;Stage 2 的存在是为了突破它。完整表格、注意事项和复现方法见 docs/benchmarks.md。

配置

All parameters can be configured via 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

Top-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

以该边权重乘数拉入锚点的单跳图邻居

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 . 运行 linter;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

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.
    26 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