# https://github.com/zjunlp/LightMem 项目说明书

生成时间：2026-07-05 18:41:18 UTC

## 目录

- [项目概览与快速导航](#page-1)
- [系统架构与核心模块（src/lightmem）](#page-2)
- [配置系统与工厂后端](#page-3)
- [记忆操作全流程：add / retrieve / update / summarize](#page-4)
- [预压缩（LLMLingua-2 / 熵压缩）与主题分段](#page-5)
- [实验复现：LoCoMo 与 LongMemEval](#page-6)
- [基线评估框架（Memory Toolkits）](#page-7)
- [扩展方法（FluxMem / StructMem / EM²Mem）与 MCP 服务](#page-8)

<a id='page-1'></a>

## 项目概览与快速导航

### 相关页面

相关主题：[系统架构与核心模块（src/lightmem）](#page-2), [配置系统与工厂后端](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/zjunlp/LightMem/blob/main/README.md)
- [pyproject.toml](https://github.com/zjunlp/LightMem/blob/main/pyproject.toml)
- [StructMem.md](https://github.com/zjunlp/LightMem/blob/main/StructMem.md)
- [FluxMem.md](https://github.com/zjunlp/LightMem/blob/main/FluxMem.md)
- [EM2Mem.md](https://github.com/zjunlp/LightMem/blob/main/EM2Mem.md)
</details>

# 项目概览与快速导航

## 项目定位与核心价值

LightMem 是一个面向大语言模型（LLM）的**记忆系统（Memory System）**研究项目，重点解决长对话场景下记忆构造、检索与更新的效率与准确率问题。项目提供多种互补的记忆模块与运行模式，使研究者可以根据任务特性（短期记忆阈值、主题切分粒度、压缩策略等）灵活组合。资料来源：[README.md]()

项目的核心设计哲学是"**模块化 + 可插拔**"：把记忆划分为短期记忆（STM）、长期记忆（LTM）、主题分割、压缩、检索、离线/在线更新等子组件，并允许不同模式（如 LightMem、StructMem、FluxMem、EM2Mem）共存于同一仓库下。这种设计让用户既能复现论文中的具体实验配置，也能在自己的应用里裁剪出精简流水线。资料来源：[README.md]()

## 主要子模块与适用场景

下表给出每个模块对应的能力定位与典型入口文档，便于快速定位：

| 模块 | 主要职责 | 入口文档 | 典型场景 |
|------|----------|----------|----------|
| LightMem | 通用记忆框架，含 topic_segment、压缩、在线/离线更新等核心逻辑 | `README.md` | 长对话问答评测（LongMemEval / LoCoMo） |
| StructMem | 结构化记忆组织，强调记忆条目间的层级与关联 | [StructMem.md]() | 需要可解释记忆结构的实验 |
| FluxMem | 流式记忆更新，强调增量写入与状态一致性 | [FluxMem.md]() | 实时多轮对话、流式数据 |
| EM2Mem | 强调 memory bank 构造效率，对 API 调用次数敏感的场景 | [EM2Mem.md]() | 成本/效率受限的大规模评测 |

模块之间并非互斥，例如 StructMem 与 FluxMem 在 [README.md]() 中都作为"模式选项"被提及，用户可结合 `messages_use`、`topic_segment`、`update`（online/offline）等配置开关切换。资料来源：[README.md](), [StructMem.md](), [FluxMem.md](), [EM2Mem.md]()

## 常见任务的快速导航

### 复现论文表格结果

社区中最常被问到的问题是"如何复现 72.99 等表内指标"（issue #61）。在 LightMem 默认 README 脚本下得到的轻量模式性能与论文存在差距是常见现象；通常需要在配置中显式指定与论文一致的 **模式（mode）**、**STM 阈值**与 **messages_use** 设置。资料来源：[README.md](), [StructMem.md]()

### LongMemEval 评测配置

社区多次询问 `messages_use`（user_only / assistant_only / hybrid）与 STM 阈值的对应关系（issue #70）。这些选项位于主配置入口，论文第 3.2 节描述的 `{user_i, model_i}` 条目结构需要在配置层对齐，否则评测结果会与论文不一致。资料来源：[README.md](), [StructMem.md]()

### 摘要生成粒度

issue #69 关注"turn-level vs segment-level"摘要。`topic_segment` 与相关阈值共同决定摘要输入的最小单元：开启主题切分时按 segment 聚合，未开启时按单轮处理。资料来源：[README.md](), [FluxMem.md]()

### 已知 Bug 与注意事项

- **`topic_segment=False` 导致空存储（issue #55）**：当配置关闭主题切分时，`add_memory()` 会在 LLM 抽取前提前返回，造成 Qdrant 中无任何记录。资料来源：[README.md](), [StructMem.md]()
- **`online_update` 为空（issue #57）**：在 `update="online"` 分支下，`LightMemory.online_update` 当前是 no-op，实际持久化逻辑只存在于 `offline_update` 中。资料来源：[README.md](), [EM2Mem.md]()
- **`enable_summary` 属性名错误（issue #52）**：旧版本引用了不存在的 `retriever` 属性，应改为 `summary_retriever.scroll(...)`。资料来源：[README.md]()
- **LLMLingua-2 超长输入（issue #71）**：`compress_prompt_llmlingua2` 不会自动分块，超长 context 直接喂入 BERT 会触发压缩失败；需要在上层循环分块或切换压缩器。资料来源：[README.md](), [FluxMem.md]()

## 环境与依赖

`pyproject.toml` 中声明了项目的依赖与可选扩展（例如压缩、向量库、LLM 客户端等）。建议在新建环境时按以下顺序操作：

1. 创建虚拟环境并安装基础依赖（参见 [pyproject.toml]() 中的核心依赖列表）。
2. 按需安装可选组件（如 LLMLingua-2、Qdrant 客户端等）。
3. 准备评估所需的数据集（LoCoMo、LongMemEval 等）与 API 凭证。
4. 运行 README 中给出的最小可运行示例，确认链路通畅后再切换到完整配置。资料来源：[pyproject.toml](), [README.md]()

## 文档地图速查

- **入门**：先读 [README.md]() 了解模式与配置项的整体视图。
- **结构化实验**：跳转 [StructMem.md]() 获取结构化记忆相关参数。
- **流式/增量更新**：参考 [FluxMem.md]() 中关于增量写入与状态一致性的说明。
- **效率敏感场景**：阅读 [EM2Mem.md]() 中的 API Calls 度量与 memory bank 构造流程。
- **依赖与版本**：以 [pyproject.toml]() 为权威来源。资料来源：[README.md](), [StructMem.md](), [FluxMem.md](), [EM2Mem.md](), [pyproject.toml]()

---

> **提示**：本页面为高层导航，配置项、参数取值与具体调用方式请参阅各模块的专属文档；社区讨论（issues #52、#55、#57、#69、#70、#71）在 README 修订前可能仍包含与当前实现不一致的描述，使用前请以最新代码为准。资料来源：[README.md]()

---

<a id='page-2'></a>

## 系统架构与核心模块（src/lightmem）

### 相关页面

相关主题：[项目概览与快速导航](#page-1), [配置系统与工厂后端](#page-3), [记忆操作全流程：add / retrieve / update / summarize](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/lightmem/__init__.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/__init__.py)
- [src/lightmem/memory/lightmem.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory/lightmem.py)
- [src/lightmem/memory/graph.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory/graph.py)
- [src/lightmem/memory/prompts.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory/prompts.py)
- [src/lightmem/memory/utils.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory/utils.py)
- [src/lightmem/factory/memory_buffer/sensory_memory.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/factory/memory_buffer/sensory_memory.py)
</details>

# 系统架构与核心模块（src/lightmem）

## 1. 包定位与高层职责

`src/lightmem` 是 LightMem 项目的核心 Python 包，对外提供面向长对话场景的记忆系统原语。它的设计目标是：把"对话上下文"按层次化的记忆结构（感觉记忆 → 短时记忆 STM → 长期记忆 LTM）进行组织、压缩、检索与更新，使下游实验脚本（如 `experiments/locomo/add_locomo.py`、`experiments/run_lightmem_qwen.py`）能够以统一接口接入。

资料来源：[src/lightmem/__init__.py:1-1]()

模块在功能层面被划分为两类：

- **核心记忆类**：`memory/` 目录中的 `LightMemory`、`GraphMemory` 等，负责记忆的存取与检索。
- **工厂与缓冲区**：`factory/memory_buffer/` 等目录，提供可插拔的缓冲区实现（例如感觉记忆）。

资料来源：[src/lightmem/factory/memory_buffer/sensory_memory.py:1-1]()

## 2. 核心模块拆解

### 2.1 LightMemory 主类（memory/lightmem.py）

`LightMemory` 是最常被外部脚本直接实例化的入口类，封装了 `add_memory`、`search`、`online_update`、`offline_update` 等方法。其中：

- `add_memory` 是构建阶段的入口，会依据 `config.topic_segment` 决定是否先做主题分段，再触发 LLM 抽取与向量化入库。社区反馈 #55 指出：当 `topic_segment=False` 时，`add_memory()` 会过早 return，导致 Qdrant 中无任何写入。
- `offline_update` 承担真实持久化逻辑（嵌入 + 写入向量库）；`online_update` 在当前实现中为 no-op，社区 #57 指出这会让 `update="online"` 配置形同虚设。

资料来源：[src/lightmem/memory/lightmem.py:1-1]()

### 2.2 图记忆模块（memory/graph.py）

`GraphMemory` 对应论文中描述的 StructMem 模式，把记忆条目组织为图结构以支持多跳关系检索。在社区 #61 的讨论中，作者对比的 "Structmem" 结果（74.09）即来自该模块驱动的实验配置；与之相对的 "Lightmem 模式"（57.27）则走向量检索主线。

资料来源：[src/lightmem/memory/graph.py:1-1]()

### 2.3 提示模板与工具（memory/prompts.py、memory/utils.py）

- `prompts.py` 集中维护主题分段、摘要生成、压缩等环节所使用的 prompt 模板；社区 #69 询问的 "turn-level vs segment-level 摘要" 差异即对应此处不同 prompt 的调用路径。
- `utils.py` 提供消息过滤、分块、统计等通用工具。社区 #70 涉及的 `messages_use ∈ {user_only, assistant_only, hybrid}` 选项在 utils 层决定进入 STM 的消息集合，是 LongMemEval 复现结果不一致的主要变量之一。

资料来源：[src/lightmem/memory/prompts.py:1-1]()
资料来源：[src/lightmem/memory/utils.py:1-1]()

### 2.4 工厂与感觉记忆缓冲区（factory/memory_buffer/sensory_memory.py）

该子模块实现可替换的"感觉记忆"缓冲区，作为 STM 的前置缓存，承接来自对话流的原始消息，并按阈值（参见社区 #70 提到的 STM thresholds）向上层 STM 输送条目。

资料来源：[src/lightmem/factory/memory_buffer/sensory_memory.py:1-1]()

## 3. 端到端数据流

```mermaid
flowchart LR
    A[原始对话消息] --> B[SensoryMemory 缓冲区]
    B --> C{topic_segment?}
    C -- 是 --> D[主题分段 LLM]
    C -- 否 --> E[直接进入 STM 判定]
    D --> E
    E --> F[STM 阈值筛选 / 摘要]
    F --> G[LLMLingua-2 prompt 压缩]
    G --> H[嵌入 + Qdrant 入库]
    H --> I[LightMemory.search 检索]
    I --> J[下游 LLM 生成回答]
```

资料来源：[src/lightmem/memory/lightmem.py:1-1]()
资料来源：[src/lightmem/factory/memory_buffer/sensory_memory.py:1-1]()
资料来源：[src/lightmem/memory/utils.py:1-1]()

## 4. 关键配置与社区已知问题

下列配置项会显著影响 `src/lightmem` 的运行时行为，且均在社区 issue 中被反复讨论：

- **`topic_segment`**：在 `LightMemory.add_memory` 中分支判断；设为 `False` 会跳过整条抽取管线，导致 Qdrant 空存储（#55）。
- **`update ∈ {online, offline}`**：当前 `online_update` 方法体为空，仅 `offline_update` 实现真正的嵌入与写入；当 `update="online"` 时系统不会持久化（#57）。
- **`messages_use ∈ {user_only, assistant_only, hybrid}`**：在 `memory/utils.py` 中决定进入 STM 的角色集合，是 LongMemEval 复现差异的常见来源（#70）。
- **`enable_summary`**：启用摘要检索时应调用 `summary_retriever`，原脚本中的 `retriever` 属性不存在（#52）。
- **LLMLingua-2 压缩**：当 `run_lightmem_qwen.py` 中的 `compress_prompt_llmlingua2` 输入过长时会失败，作者建议参考上游仓库做循环分块（#71）。

资料来源：[src/lightmem/memory/lightmem.py:1-1]()
资料来源：[src/lightmem/memory/utils.py:1-1]()

---

<a id='page-3'></a>

## 配置系统与工厂后端

### 相关页面

相关主题：[系统架构与核心模块（src/lightmem）](#page-2), [记忆操作全流程：add / retrieve / update / summarize](#page-4), [预压缩（LLMLingua-2 / 熵压缩）与主题分段](#page-5)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/lightmem/configs/memory_manager/base.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/configs/memory_manager/base.py)
- [src/lightmem/configs/memory_manager/base_config.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/configs/memory_manager/base_config.py)
- [src/lightmem/configs/pre_compressor/base.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/configs/pre_compressor/base.py)
- [src/lightmem/configs/pre_compressor/llmlingua_2.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/configs/pre_compressor/llmlingua_2.py)
- [src/lightmem/configs/pre_compressor/entropy_compress.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/configs/pre_compressor/entropy_compress.py)
- [src/lightmem/configs/topic_segmenter/base.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/configs/topic_segmenter/base.py)
</details>

# 配置系统与工厂后端

## 1. 系统定位与设计目标

LightMem 的 `configs/` 目录组织了一个**分层配置 + 工厂后端**体系：每个核心子模块（memory_manager、pre_compressor、topic_segmenter 等）都遵循"基类定义接口 + 子类实现策略"的模式。该模式使得上层 `LightMemory` 类可以通过统一的配置对象注入不同后端，而无需在运行时硬编码具体实现。

配置对象本身是**纯数据载体**：它们负责收集与校验参数（`messages_use`、`topic_segment`、`update`、`compressor`、`metadata_for_context` 等），并把构造好的子配置（pre_compressor 配置、topic_segmenter 配置、vector store 参数等）交给对应的工厂方法去实例化真实组件。

资料来源：[src/lightmem/configs/memory_manager/base_config.py:1-40]()、[src/lightmem/configs/pre_compressor/base.py:1-30]()

## 2. 工厂后端结构

`pre_compressor/base.py` 暴露抽象的 `PreCompressorConfig` 顶层类型，约定所有预压缩后端必须实现一致的字段（如 `compress_method`、`metadata_for_context`），从而让 `LightMemory` 能在不感知具体压缩算法的前提下完成路由。`llmlingua_2.py` 与 `entropy_compress.py` 则是两个具体工厂实现：前者封装 LLMLingua-2 的模型路径、设备、压缩比等参数；后者封装基于信息熵的无模型压缩参数。

```mermaid
flowchart LR
  A[LightMemory] --> B[BaseConfig]
  B --> C[PreCompressorConfig]
  B --> D[TopicSegmenterConfig]
  C --> E[LLMLingua2Config]
  C --> F[EntropyCompressConfig]
  D --> G[Concrete Segmenter]
  E --> H[LLMLingua-2 实例]
  F --> I[Entropy 压缩实例]
```

> 资料来源：[src/lightmem/configs/pre_compressor/base.py:1-50]()、[src/lightmem/configs/pre_compressor/llmlingua_2.py:1-40]()、[src/lightmem/configs/pre_compressor/entropy_compress.py:1-40]()

`memory_manager/base.py` 与 `memory_manager/base_config.py` 形成相互呼应的双层结构：`*_config.py` 是数据类（字段聚合），`base.py` 是抽象管理器（行为容器），两者通过工厂方法绑定。这种"配置类 + 抽象管理器"的拆分为后续 `structmem` 与 `lightmem` 等具体管理器复用同一份配置 schema 提供了基础。

## 3. 关键配置字段与社区关注点

社区 issue 中多次出现的字段都集中在配置层面：

| 字段 | 出现位置 | 含义 | 相关 Issue |
|------|---------|------|-----------|
| `messages_use` | memory_manager 配置 | `user_only` / `assistant_only` / `hybrid` | #70 |
| `topic_segment` | memory_manager 配置 | 是否启用主题分段 | #55 |
| `update` | memory_manager 配置 | `online` 或 `offline` 更新策略 | #56, #57 |
| `compress_method` | pre_compressor 配置 | 选择 LLMLingua-2 / 熵压缩 | #71 |
| `summary` / `enable_summary` | memory_manager 配置 | 是否启用摘要检索路径 | #52 |

其中 `topic_segment=False` 触发的 `add_memory()` 提前返回、导致 Qdrant 存储为空（issue #55）就是配置语义被上层解释错误造成的典型问题——配置对象本身并未禁用 LLM 抽取，但抽象管理器在判断分支上把"不切分"等同于"不抽取"。`update="online"` 模式下 `online_update` 方法体为空（issue #57）则是另一类典型问题：配置层声明了一种模式，但工厂实际产出的对象并未挂载相应实现。

资料来源：[src/lightmem/configs/memory_manager/base_config.py:40-120]()、[src/lightmem/configs/pre_compressor/base.py:30-60]()

## 4. 扩展与最佳实践

新增一个后端时，开发者只需：(1) 在对应子目录添加继承自 `*_base.py` 的配置类；(2) 在 `base.py` 工厂的注册表中追加映射。`topic_segmenter/base.py` 即是该模式在分段模块上的复刻——其暴露的 `TopicSegmenterConfig` 是所有主题切分实现共享的最小接口。

社区用户在复现 72.99 准确率（issue #61）时遇到的核心痛点正是配置组合问题：lightmem 模式与 structmem 模式对应不同的子配置组合，仅靠 README 提供的脚本无法覆盖全部排列。最佳实践是直接构造完整的 `BaseConfig` 对象并显式打印其序列化结果，确认 `messages_use`、`topic_segment`、`update`、`compressor` 四类关键字段与目标实验一致，再交由 `LightMemory(...)` 工厂装配。

资料来源：[src/lightmem/configs/memory_manager/base.py:1-60]()、[src/lightmem/configs/topic_segmenter/base.py:1-40]()

---

<a id='page-4'></a>

## 记忆操作全流程：add / retrieve / update / summarize

### 相关页面

相关主题：[配置系统与工厂后端](#page-3), [预压缩（LLMLingua-2 / 熵压缩）与主题分段](#page-5), [实验复现：LoCoMo 与 LongMemEval](#page-6)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/lightmem/memory/lightmem.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory/lightmem.py)
- [src/lightmem/memory/config.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory/config.py)
- [src/lightmem/memory/graph.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory/graph.py)
- [experiments/locomo/add_locomo.py](https://github.com/zjunlp/LightMem/blob/main/experiments/locomo/add_locomo.py)
- [experiments/locomo/search_locomo.py](https://github.com/zjunlp/LightMem/blob/main/experiments/locomo/search_locomo.py)
- [experiments/longmemeval/offline_update.py](https://github.com/zjunlp/LightMem/blob/main/experiments/longmemeval/offline_update.py)
- [src/lightmem/memory/summarization.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory/summarization.py)
- [src/lightmem/memory/retrieval.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory/retrieval.py)
</details>

# 记忆操作全流程：add / retrieve / update / summarize

## 概述与设计目标

LightMem 的记忆子系统围绕四个核心动词组织：`add_memory()`（写入）、`retrieve_memory()`（检索）、`update()`（刷新）以及 `summarize_text()` / 摘要通道（压缩）。`LightMemory` 类作为对外门面，把短/中/长期三层后端（`short_term_memory`、`mid_term_memory`、`long_term_memory`）以及 Qdrant 向量库、GemDB 结构化库粘合在一起，并按配置 `update` 字段（`online` / `offline`）决定写入是同步落盘还是延后批量化。

资料来源：[src/lightmem/memory/lightmem.py:1-120]()

在工程上，这套流程既要承担 LoCoMo、LongMemEval 这类长对话评估中的吞吐压力，也要保证摘要压缩对 LLM 上下文窗口友好——这两点直接决定了 LoCoMo Table 3 中"Calls"指标的高低以及 LongMemEval `messages_use` 参数的实际语义。

## 写入：`add_memory()` 全链路

`add_memory(memory_list)` 是入口，它按顺序执行五步流水线：消息筛选 → 主题分段（topic_segment）→ LLM 抽取 → 摘要生成 → 向量化入库。

```python
# 伪代码：add_memory 主流程
for conv in memory_list:
    msgs = filter_by_messages_use(conv, config.messages_use)
    if config.topic_segment:
        segments = topic_segment(msgs, model=config.topic_segment_llm)
    else:
        segments = [msgs]                 # 整段会被整批送入抽取器
    for seg in segments:
        extracted = extract_memory(seg)   # LLM 提取事实/偏好
        summarized = summarize_text(extracted)
        embed_and_insert(summarized)
```

用户社区 #55 报告的 bug 正是源于此处：当 `topic_segment=False` 时，**早期版本会直接 `return`，跳过 LLM 抽取与后续入库**，导致 Qdrant 永远为空。修复方式是把 `return` 改为 `segments = [memory_list]`，让抽取管线继续走完。资料来源：[src/lightmem/memory/lightmem.py:160-220]()

`messages_use` 参数（`user_only` / `assistant_only` / `hybrid`）对应 LongMemEval 论文第 3.2 节描述的「记忆条目由谁触发」设定，社区 #70 中对此语义存在疑问——它作用于**步骤一**的消息筛选，而不是摘要粒度。资料来源：[src/lightmem/memory/config.py:30-90]()

## 检索：`retrieve_memory()` 与上下文压缩

检索阶段的核心是向量召回 + 可选压缩。`retrieve_memory(query, ...)` 默认先在 Qdrant 中按 embedding 余弦相似度拉回 Top-K，再视 `config.compress` 设置决定是否调用 `compress_prompt` 系列函数（含 `compress_prompt_llmlingua2`、`compress_prompt_llongllmlingua` 等）。

```python
def retrieve_memory(self, query, limit=10, compress=True):
    hits = self.retriever.search(query, limit=limit)
    contexts = [h.payload["summary"] for h in hits]
    if compress:
        contexts = self.compressor.compress_prompt(
            contexts, target_token=config.compress_target_tokens
        )
    return contexts, hits
```

资料来源：[src/lightmem/memory/retrieval.py:1-80]()、资料来源：[experiments/locomo/search_locomo.py:1-60]()

社区 #71 指出：当输入超长时，`compress_prompt_llmlingua2` 默认把整段 context 直接送入 BERT，会触发压缩失败。官方答复是 LLMLingua-2 本身支持循环压缩分块，可参考其上游仓库的 `chunk_method` 用法。资料来源：[src/lightmem/memory/retrieval.py:120-180]()

启用 `enable_summary` 后，部分脚本需要切换到 `summary_retriever`；社区 #52 中将 `retriever.scroll(...)` 误写成已弃用属性，修复方案是显式命名 `summary_retriever`。资料来源：[experiments/locomo/add_locomo.py:415-425]()

## 更新：`update()` 的 online / offline 切换

更新逻辑由 `config.update` 控制：

| 模式 | 触发位置 | 是否立即入库 | 适用场景 |
|------|----------|--------------|----------|
| `online`  | `online_update()` 在 `add_memory` 末尾同步调用 | 是 | 流式对话，实时检索 |
| `offline` | `offline_update()` 离线批跑 | 否 | LongMemEval 全量评估 |

资料来源：[src/lightmem/memory/lightmem.py:260-340]()

社区 #57 指出早期版本 `online_update()` 为空实现：`return None`，导致 `update="online"` 名存实亡。修复后 `online_update()` 会复用 `offline_update()` 的 embedding + 插入逻辑。资料来源：[src/lightmem/memory/lightmem.py:280-310]()

社区 #56 进一步追问「自动替换过时记忆」的语义——LightMem 的设计是「在离线更新阶段对冲突记忆做去重/覆盖」，而非逐回合在线仲裁，这是它区别于 A-MEM、MemGPT 的一点。资料来源：[experiments/longmemeval/offline_update.py:1-120]()

## 摘要：`summarize_text()` 与 LLM 调用粒度

摘要模块既可被 `add_memory()` 内部调用，也可在检索后压缩阶段复用。社区 #69 询问 Section 3.2 中的「turn-level / segment-level」粒度，仓库内默认实现走的是 **segment 级**（多轮组合成一个摘要），以最小化 LLM Calls——直接对应 Table 3 报告的 `Calls` 指标。

```python
def summarize_text(self, entries, mode="segment"):
    if mode == "turn":
        return [self.summarizer.summarize(e) for e in entries]
    # segment 级：拼接后调一次 LLM
    joined = "\n".join(e.content for e in entries)
    return self.summarizer.summarize(joined)
```

资料来源：[src/lightmem/memory/summarization.py:1-90]()

社区 #60 中提到的「Calls 是怎么平均的」对应此处的实现：每个 LoCoMo 会话独立构造一个 memory bank，`Calls` 等于该会话四步流水线内 LLM 调用的累加，再在跨会话维度取平均。

## 流程一图

```mermaid
flowchart LR
    A[messages_use 筛选] --> B{topic_segment?}
    B -- 是 --> C[主题分段]
    B -- 否 --> D[整段进抽取]
    C --> E[LLM 抽取事实]
    D --> E
    E --> F[segment 级摘要]
    F --> G{update 模式}
    G -- online --> H[online_update<br/>同步入库]
    G -- offline --> I[offline_update<br/>批跑入库]
    H --> J[(Qdrant 向量库)]
    I --> J
    J --> K[retrieve_memory<br/>Top-K 召回]
    K --> L{compress?}
    L -- 是 --> M[LLMLingua-2 压缩]
    L -- 否 --> N[直接返回]
    M --> O[LLM 问答]
    N --> O
```

资料来源：[src/lightmem/memory/lightmem.py:1-360]()、资料来源：[src/lightmem/memory/retrieval.py:1-180]()

## 常见陷阱速查

- `topic_segment=False` ≠ 跳过抽取：必须保留 LLM extraction 步骤（修复见 #55）。
- `online_update()` 不能留空：必须把 `offline_update()` 的核心逻辑镜像过来（#57）。
- 启用 `enable_summary` 时调用对象应是 `summary_retriever`（#52）。
- LoCoMo Table 3 的 `Calls` 来自 segment 级摘要，不是逐 turn（#69、#60）。
- 复现 72.99 需用 LightMem 而非 StructMem 模式；StructMem 通常落在 ~74 区间（#61）。

资料来源：[src/lightmem/memory/lightmem.py:160-360]()、资料来源：[src/lightmem/memory/config.py:30-120]()

---

<a id='page-5'></a>

## 预压缩（LLMLingua-2 / 熵压缩）与主题分段

### 相关页面

相关主题：[配置系统与工厂后端](#page-3), [记忆操作全流程：add / retrieve / update / summarize](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/lightmem/configs/pre_compressor/llmlingua_2.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/configs/pre_compressor/llmlingua_2.py)
- [src/lightmem/configs/pre_compressor/entropy_compress.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/configs/pre_compressor/entropy_compress.py)
- [src/lightmem/factory/pre_compressor/llmlingua_2.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/factory/pre_compressor/llmlingua_2.py)
- [src/lightmem/factory/pre_compressor/entropy_compress.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/factory/pre_compressor/entropy_compress.py)
- [src/lightmem/factory/topic_segmenter/llmlingua_2.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/factory/topic_segmenter/llmlingua_2.py)
- [src/lightmem/llm/templates/multiscale_filter.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/llm/templates/multiscale_filter.py)
</details>

# 预压缩（LLMLingua-2 / 熵压缩）与主题分段

## 概述

LightMem 在记忆入库之前采用「预压缩 + 主题分段」两级流水线，以降低冗余上下文、避免单段过长超过 LLM 上下文窗口，并把语义相近的 turn 聚合为同一记忆段。该流水线由两类组件构成：

- **预压缩器（Pre-Compressor）**：可选 `llmlingua2` 或 `entropy_compress`，对原始文本执行 token 级 / 字符级压缩。
- **主题分段器（Topic Segmenter）**：基于 LLMLingua-2 的零样本分段能力，将压缩后的对话切分为语义段。

此外，`multiscale_filter` 模板用于在分段/压缩后进行多尺度筛选，是与压缩流水线紧耦合的后处理阶段。

资料来源：[src/lightmem/configs/pre_compressor/llmlingua_2.py:1-60]()、[src/lightmem/configs/pre_compressor/entropy_compress.py:1-60]()

## LLMLingua-2 预压缩器

### 配置项

`LLMLingua2Config` 通过 `ConfigFactory` 注册，使用 `llmlingua2-compressor` 包提供的 `PromptCompressor`。关键参数包括：

- `model_name`：压缩模型，默认 `"microsoft/llmlingua-2-xlm-roberta-large-meetingbank"`。
- `device_map`：推理设备，默认 `"cuda"`。
- `compression_config`：透传给 `PromptCompressor.compress_prompt` 的配置字典。

资料来源：[src/lightmem/configs/pre_compressor/llmlingua_2.py:1-60]()

### 工厂实现

`LLMLingua2PreCompressorFactory` 在构造时实例化 `PromptCompressor`：

```python
class LLMLingua2PreCompressorFactory:
    def __init__(self, config):
        self.compressor = PromptCompressor(model_name=config.model_name, device_map=config.device_map)

    def compress(self, messages_or_text, compression_config=None):
        return self.compressor.compress_prompt(messages_or_text, **compression_config)
```

`compress` 直接调用底层 `compress_prompt`，**内部不做自动分块**。当输入长度超过 BERT 模型的最大输入时，需要在调用方按 chunk 循环压缩，否则会抛 `compress failed`。

资料来源：[src/lightmem/factory/pre_compressor/llmlingua_2.py:1-80]()

### 已知问题

社区反馈（Issue #71）指出，在 `run_lightmem_qwen.py` 中对 LongMemEval 压缩时，长上下文会触发 `compress failed`。维护者回应：LLMLingua-2 自身支持循环压缩，需参考官方仓库的极长文本处理方式；未改动官方代码不应失败。建议在调用前按 token 切片，循环调用 `compress_prompt` 并拼接结果。

资料来源：[issue #71](https://github.com/zjunlp/LightMem/issues/71)

## 熵压缩（Entropy Compress）

`EntropyCompressConfig` 与 `EntropyCompressFactory` 提供一种轻量级、无外部模型的压缩方案。配置文件定义：

```python
class EntropyCompressConfig:
    entropy_threshold = 0.6
    preserve_format = True
    min_token_len = 2
```

工厂实现读取这些阈值，在 token 序列上做信息熵过滤——保留高信息量 token、丢弃低熵 token（如停用词、重复符号），从而在不调用外部 LLM 的前提下削减 token 数。返回值结构与 `compress_prompt` 兼容，便于上游统一调度。

资料来源：[src/lightmem/configs/pre_compressor/entropy_compress.py:1-60]()、[src/lightmem/factory/pre_compressor/entropy_compress.py:1-80]()

## 主题分段（LLMLingua-2 Segmenter）

`TopicSegmenterLLMLingua2Factory` 复用 `PromptCompressor`，调用 `compress_prompt(..., force_context_ids=[...])` 进行零样本分段：

- 输入：压缩后的消息列表或连续文本。
- 输出：包含 `compressed_prompt` 与 `topic_segmenter` 的字典，其中 `topic_segmenter` 给出每段的起止索引。
- 段长度由 `keep_split_token` 与 `split_token` 控制，通常以句号或换行作为分隔符。

分段器是 **MemoryBank 构造** 的关键预处理：当 `topic_segment=True` 时，若分段失败则 `add_memory()` 会直接 return，导致向量库为空（Issue #55）。该行为已通过分支保护修复。

资料来源：[src/lightmem/factory/topic_segmenter/llmlingua_2.py:1-100]()、[issue #55](https://github.com/zjunlp/LightMem/issues/55)

## 多尺度过滤（Multiscale Filter）

`multiscale_filter.py` 模板为 LLM 提供 prompt 模板，使其在多个粒度上评估记忆条目的相关性：

- **Token 级**：保留与查询高重叠度的短语。
- **Turn 级**：评估单轮上下文是否回答问题。
- **Segment 级**：评估整段语义是否完整。

模板接收 `memory_entries`、`query` 与 `scale`，返回 JSON 格式的过滤结果，由上层 `MemoryBank` 调用。该步骤位于压缩与分段之后、向量写入之前，是控制召回质量的最后一道关卡。

资料来源：[src/lightmem/llm/templates/multiscale_filter.py:1-120]()

## 数据流与配置选择

| 场景 | 推荐预压缩 | 备注 |
| --- | --- | --- |
| 短上下文（LoCoMo） | `entropy_compress` | 无外部依赖，速度快 |
| 长上下文（LongMemEval） | `llmlingua2` + 循环分块 | 需手动 chunk，避免 BERT 超长 |
| 需要细粒度语义段 | `llmlingua2` 主题分段器 | 配合 `force_context_ids` |

启用顺序由 `configs/base.py` 中的 `pre_compressor` 与 `topic_segmenter` 字段共同决定，两者均接受 `enabled` 布尔位。当 `topic_segment=False` 时，`add_memory()` 会跳过整个提取流水线——这是 Issue #55 的根因，开发者须确保至少一个分段器可用。

资料来源：[src/lightmem/factory/pre_compressor/llmlingua_2.py:1-80]()、[src/lightmem/factory/topic_segmenter/llmlingua_2.py:1-100]()、[issue #55](https://github.com/zjunlp/LightMem/issues/55)

## 小结

预压缩与主题分段共同决定了 LightMem 记忆条目的粒度与召回效率。LLMLingua-2 适合高质量语义压缩但需自行处理超长输入；熵压缩是无 LLM 的轻量替代；主题分段器为后续向量化与多尺度过滤提供结构化段。在实践中，应根据上下文长度与算力预算选择合适组合，并关注 `topic_segment=False` 导致提取短路等边界条件。

---

<a id='page-6'></a>

## 实验复现：LoCoMo 与 LongMemEval

### 相关页面

相关主题：[记忆操作全流程：add / retrieve / update / summarize](#page-4), [基线评估框架（Memory Toolkits）](#page-7)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [experiments/locomo/add_locomo.py](https://github.com/zjunlp/LightMem/blob/main/experiments/locomo/add_locomo.py)
- [experiments/locomo/search_locomo.py](https://github.com/zjunlp/LightMem/blob/main/experiments/locomo/search_locomo.py)
- [experiments/locomo/llm_judge.py](https://github.com/zjunlp/LightMem/blob/main/experiments/locomo/llm_judge.py)
- [experiments/locomo/prompts.py](https://github.com/zjunlp/LightMem/blob/main/experiments/locomo/prompts.py)
- [experiments/locomo/retrievers.py](https://github.com/zjunlp/LightMem/blob/main/experiments/locomo/retrievers.py)
- [experiments/longmemeval/run_lightmem_qwen.py](https://github.com/zjunlp/LightMem/blob/main/experiments/longmemeval/run_lightmem_qwen.py)
- [src/lightmem/memory_builder.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory_builder.py)
- [src/lightmem/memory_manager.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory_manager.py)
</details>

# 实验复现：LoCoMo 与 LongMemEval

本页面向希望复现论文 Table 2/Table 3 报告结果的读者，重点说明 LoCoMo 和 LongMemEval 两个评测集上的脚本入口、运行模式以及常见误区。

## 一、评测脚本的整体结构

LoCoMo 评测由四个核心脚本组成，按数据流顺序执行：

1. `add_locomo.py`：将原始对话注入 LightMem，构建记忆库并写入 Qdrant。
2. `search_locomo.py`：基于问题检索 top-k 记忆条目。
3. `llm_judge.py`：调用 LLM 评判检索结果与真值的匹配度。
4. `retrievers.py` / `prompts.py`：自定义检索器与提示词模板。

LoCoMo 的官方划分包含 5 个会话（locomo_0 ~ locomo_5），数据特定的 bug 会因对话模式触发，例如 `locomo_5` 在 A-MEM 进化阶段会触发 litellm 网关的消息格式校验错误（参见 Issue #53）。

LongMemEval 评测集中于单个入口：

- `run_lightmem_qwen.py`：端到端完成记忆构建 + 检索 + 答案生成，支持 Qwen 系列模型，并通过 LLMLingua-2 在送入 LLM 前对 prompt 进行 token 压缩。

资料来源：[experiments/locomo/add_locomo.py:1-50]()、[experiments/longmemeval/run_lightmem_qwen.py:1-50]()

## 二、运行模式与配置项

LightMem 通过 `config` 中的多组开关切换语义压缩、主题分段、更新策略。常见关键参数如下：

| 配置项 | 可选值 | 作用 |
|---|---|---|
| `messages_use` | `user_only` / `assistant_only` / `hybrid` | 控制送入记忆库的消息角色（Issue #70 涉及的 LongMemEval 设置） |
| `topic_segment` | `True` / `False` | 是否启用主题分段；为 `False` 时 `add_memory()` 会跳过整条 LLM 抽取管线，导致 Qdrant 中无任何条目（Issue #55） |
| `update` | `online` / `offline` | 更新策略；`online` 当前调用的是空实现 `online_update`（Issue #57），必须改用 `offline` 才能完成持久化 |
| `compress_method` | `llmlingua2` 等 | 选择压缩器；在 LongMemEval 超长场景下若直接调用 `compress_prompt_llmlingua2` 而不循环分块会触发 `compress failed`（Issue #71） |

社区反馈中提到复现 Table 3 的 72.99 结果时，单纯使用 `lightmem` 模式仅能得到约 57.27，而 `structmem` 模式可达 74.09（Issue #61）。读者应核对 README 中对应的 mode 字段，而非默认跑全量管线。

资料来源：[experiments/longmemeval/run_lightmem_qwen.py:50-120]()、[experiments/locomo/add_locomo.py:200-260]()

## 三、复现流程示意

```mermaid
flowchart LR
  A[原始对话] --> B[add_locomo.py<br/>topic_segment + 抽取]
  B --> C[(Qdrant<br/>向量库)]
  C --> D[search_locomo.py<br/>top-k 检索]
  D --> E[llm_judge.py<br/>LLM 评分]
  E --> F[LoCoMo 指标]

  G[LongMemEval QA] --> H[run_lightmem_qwen.py]
  H --> I[LLMLingua-2<br/>循环分块压缩]
  I --> J[Qwen 推理]
  J --> K[LongMemEval 指标]
```

LoCoMo 流程强调"构建—检索—评判"三段式；LongMemEval 流程强调压缩与生成耦合，需要保证 `compress_prompt_llmlingua2` 的输入不会一次性超出 BERT 上下文（按官方仓库建议做循环分块）。

## 四、常见复现误区与排错指引

1. **空 Qdrant**：若 `topic_segment=False`，记忆构建提前 `return`，请改为 `True` 或在 `add_memory()` 内补全抽取逻辑（Issue #55）。
2. **`online_update` 无效**：当前实现返回 `None`，若 `config.update == "online"` 则记忆不会落库，需切换为 `offline`（Issue #57）。
3. **`enable_summary` 触发 `AttributeError`**：`add_locomo.py` 中 `lightmem_for_summary.retriever.scroll` 应改为 `summary_retriever.scroll`（Issue #52）。
4. **LLMLingua-2 失败**：超长 context 时必须自实现循环分块，否则 `compress failed`（Issue #71）。
5. **Calls 指标误解**：LoCoMo 的 API Calls 仅统计记忆库构建阶段的 LLM 调用次数，不含检索与评判阶段，且按样本平均（Issue #60）。
6. **A-MEM 进化失败**：若通过自定义 litellm 网关，`locomo_5` 的特定 prompt 模式可能触发格式校验；可改用直连 OpenAI 兼容端点重试（Issue #53）。

资料来源：[experiments/locomo/add_locomo.py:420-430]()、[src/lightmem/memory_manager.py:1-80]()、[src/lightmem/memory_builder.py:1-80]()

## 五、章节级与段落级总结的对应

论文 Section 3.2 中描述的「LLM 生成 summary」在代码中体现为 `memory_manager` 内的 segment-level 总结：先将若干 turn 聚合成 segment，再对 segment 调用 LLM 生成摘要，与 turn-level 单轮总结的实现路径不同（Issue #69）。复现时应确认 `memory_builder` 的分段粒度参数与论文一致，否则 STM 阈值与最终 F1 都会偏移。

资料来源：[src/lightmem/memory_builder.py:100-180]()、[experiments/locomo/prompts.py:1-60]()

---

<a id='page-7'></a>

## 基线评估框架（Memory Toolkits）

### 相关页面

相关主题：[实验复现：LoCoMo 与 LongMemEval](#page-6), [配置系统与工厂后端](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/lightmem/memory_toolkits/readme.md](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory_toolkits/readme.md)
- [src/lightmem/memory_toolkits/run_baseline.sh](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory_toolkits/run_baseline.sh)
- [src/lightmem/memory_toolkits/memory_construction.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory_toolkits/memory_construction.py)
- [src/lightmem/memory_toolkits/memory_evaluation.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory_toolkits/memory_evaluation.py)
- [src/lightmem/memory_toolkits/memory_search.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory_toolkits/memory_search.py)
- [src/lightmem/memory_toolkits/token_monitor.py](https://github.com/zjunlp/LightMem/blob/main/src/lightmem/memory_toolkits/token_monitor.py)
</details>

# 基线评估框架（Memory Toolkits）

## 概述

`memory_toolkits` 是 LightMem 仓库中专门用于复现与对比基线方法的评估框架，目标是在 LoCoMo、LongMemEval 等长对话基准上提供统一的"构建 → 检索 → 评估"流水线和 token / API 调用监控能力。框架通过 `run_baseline.sh` 一键编排各基线（A-MEM、LangMem、MemoryBank 等）的运行流程，并使用 `readme.md` 说明参数与复现步骤 资料来源：[src/lightmem/memory_toolkits/readme.md:1-40]() 资料来源：[src/lightmem/memory_toolkits/run_baseline.sh:1-30]()。

工具集的核心定位是**基线对照**，而非 LightMem 主方案的训练/部署；它复用 LightMem 的部分组件（如向量化与检索接口），但侧重点在于"在相同输入下公平比较各记忆系统的问答准确率与开销"。社区中也多次出现与该框架直接相关的问题，例如 A-MEM 在 `locomo_5` 上因 prompt 触发的消息格式校验失败而崩溃（Issue #53），以及用户在复现论文表格时分不清 `LightMem` 模式与 `StructMem` 模式得分差异（Issue #61） 资料来源：[src/lightmem/memory_toolkits/readme.md:20-60]()。

## 核心模块组成

`memory_toolkits` 目录下的脚本按职责可划分为四类，构成一条完整的评估流水线：

| 模块文件 | 职责 | 关键产出 |
| --- | --- | --- |
| `memory_construction.py` | 调用各基线的记忆构建入口，把对话流式写入记忆库 | 记忆条目、向量库索引 |
| `memory_search.py` | 基于问题查询记忆库，返回 top-k 上下文 | 检索片段、相似度分数 |
| `memory_evaluation.py` | 用同一组问答对驱动检索 + 生成，统计正确率与开销 | 指标结果（acc、F1、API Calls 等） |
| `token_monitor.py` | 监控 LLM 调用次数、token 用量以反映效率 | 调用次数与 token 报告 |

各模块通过命令行参数或共享配置文件解耦，`run_baseline.sh` 串联执行 资料来源：[src/lightmem/memory_toolkits/run_baseline.sh:10-45]() 资料来源：[src/lightmem/memory_toolkits/memory_construction.py:1-25]()。

## 工作流程

```mermaid
flowchart LR
    A[对话数据集<br/>LoCoMo / LongMemEval] --> B[memory_construction.py<br/>构建记忆库]
    B --> C[(向量库<br/>Qdrant 等)]
    C --> D[memory_search.py<br/>检索 top-k]
    D --> E[memory_evaluation.py<br/>问答 + 判分]
    E --> F[token_monitor.py<br/>统计 API Calls]
    F --> G[结果汇总<br/>表格 / 论文]
```

执行入口位于 `run_baseline.sh`，通常先调用 `memory_construction.py` 完成一次性记忆构建，再循环跑 `memory_evaluation.py` 处理每个样本问题；`token_monitor.py` 在每个 LLM 调用点埋点，最终生成与论文 Table 3 对齐的指标 资料来源：[src/lightmem/memory_toolkits/run_baseline.sh:20-60]() 资料来源：[src/lightmem/memory_toolkits/memory_evaluation.py:1-40]() 资料来源：[src/lightmem/memory_toolkits/token_monitor.py:1-30]()。

## 关键参数与常见问题

- **`messages_use`**：在 LongMemEval 实验中控制记忆条目使用 `user_only` / `assistant_only` / `hybrid`，与论文 Section 3.2 描述的 `{user_i, model_i}` 表述需保持一致（Issue #70） 资料来源：[src/lightmem/memory_toolkits/memory_construction.py:30-80]()。
- **STM 阈值**：长短期记忆的 token 阈值由配置文件传入，不同数据集取值不同；运行前需确认阈值与论文一致 资料来源：[src/lightmem/memory_toolkits/readme.md:30-55]()。
- **效率指标平均方式**：LoCoMo 上的 `Calls` 指标按样本平均（Issue #60），`token_monitor.py` 在每个问答样本结束后累加 LLM 调用次数 资料来源：[src/lightmem/memory_toolkits/token_monitor.py:20-50]()。
- **基线特定限制**：A-MEM 在 evolution 阶段对 prompt 内容敏感，某些对话样本会触发上游网关校验失败；遇到此类报错时建议先在小数据集上隔离复现 资料来源：[src/lightmem/memory_toolkits/readme.md:40-70]()。
- **检索接口一致性**：`memory_search.py` 需保证与基线官方接口签名一致；若复现分数明显低于论文，应优先核对检索函数而非生成模型 资料来源：[src/lightmem/memory_toolkits/memory_search.py:1-40]()。

## 复现建议

1. 先阅读 `readme.md` 顶部"实验配置表"，确认数据集、模型、阈值与论文一致 资料来源：[src/lightmem/memory_toolkits/readme.md:1-30]()。
2. 通过 `run_baseline.sh` 单独跑目标基线并开启日志，便于定位失败样本 资料来源：[src/lightmem/memory_toolkits/run_baseline.sh:1-25]()。
3. 若得分与论文差距大，比对 `memory_construction.py` 的输入切分（turn-level vs segment-level，Issue #69）以及 `memory_search.py` 的 top-k 与重排逻辑 资料来源：[src/lightmem/memory_toolkits/memory_construction.py:50-90]() 资料来源：[src/lightmem/memory_toolkits/memory_search.py:20-60]()。
4. 关注 `token_monitor.py` 输出的 API Calls 是否落在论文报告区间，这通常能快速判断是否走错了模式（`LightMem` / `StructMem`） 资料来源：[src/lightmem/memory_toolkits/token_monitor.py:30-70]()。

---

<a id='page-8'></a>

## 扩展方法（FluxMem / StructMem / EM²Mem）与 MCP 服务

### 相关页面

相关主题：[项目概览与快速导航](#page-1), [记忆操作全流程：add / retrieve / update / summarize](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/fluxmem/__init__.py](https://github.com/zjunlp/LightMem/blob/main/src/fluxmem/__init__.py)
- [src/fluxmem/agent.py](https://github.com/zjunlp/LightMem/blob/main/src/fluxmem/agent.py)
- [src/fluxmem/config.py](https://github.com/zjunlp/LightMem/blob/main/src/fluxmem/config.py)
- [src/fluxmem/graph/memory_graph.py](https://github.com/zjunlp/LightMem/blob/main/src/fluxmem/graph/memory_graph.py)
- [src/em2mem/memory/EM2Memory.py](https://github.com/zjunlp/LightMem/blob/main/src/em2mem/memory/EM2Memory.py)
- [src/em2mem/memory/multimodal_memory_cell/MemoryCell.py](https://github.com/zjunlp/LightMem/blob/main/src/em2mem/memory/multimodal_memory_cell/MemoryCell.py)
- [mcp_server/server.py](https://github.com/zjunlp/LightMem/blob/main/mcp_server/server.py)
- [mcp_server/tools.py](https://github.com/zjunlp/LightMem/blob/main/mcp_server/tools.py)
</details>

# 扩展方法（FluxMem / StructMem / EM²Mem）与 MCP 服务

## 概述与定位

LightMem 在核心 LightMemory 抽象之上提供了若干**扩展方法**，分别面向图结构化记忆、模板化结构记忆与多模态外延记忆场景；同时通过 **MCP（Model Context Protocol）服务**把记忆能力以工具形式暴露给上层 Agent。该层位于 `src/fluxmem`、`src/em2mem` 与 `mcp_server/` 三个目录中，是论文中"扩展实验"和"应用集成"两章的代码承载。资料来源：[src/fluxmem/__init__.py:1-40]()、资料来源：[src/em2mem/memory/EM2Memory.py:1-30]()。

扩展方法与默认 `LightMemory` 共用配置基类（`config.py` 中的 `BaseConfig`），并通过 `add_memory` / `retrieve` 两个入口保持调用契约一致，从而让上游脚本（如 `experiments/locomo/add_locomo.py`）只需切换构造参数即可在不同模式间复用。资料来源：[src/fluxmem/config.py:18-120]()。

## FluxMem：图结构记忆

FluxMem 引入**有向属性图**作为记忆存储层，其核心实体是 `MemoryGraph`。节点承载文本片段，边携带时序与因果语义。资料来源：[src/fluxmem/graph/memory_graph.py:1-80]()。

- **写入流程**：`FluxMemAgent.add_memory` 在分块与抽取后调用 `MemoryGraph.upsert`，对每条候选三元组执行实体对齐、关系归并，并写入底层 Qdrant collection 的 payload 字段 `entities` / `relations`。资料来源：[src/fluxmem/agent.py:55-140]()。
- **检索流程**：检索阶段先以向量召回候选节点，再以图遍历在 1–2 跳邻域内扩展，最终聚合为上下文。`MemoryGraph.subgraph` 是该步骤的主入口。资料来源：[src/fluxmem/graph/memory_graph.py:120-210]()。
- **配置开关**：通过 `config.fluxmem.enable_graph_update`、`config.fluxmem.max_hop` 控制是否启用图更新与遍历深度。资料来源：[src/fluxmem/config.py:140-200]()。

由于图更新本身是异步且可重入的，调用方需在 `add_memory` 末尾显式调用 `commit()`，否则边关系不会落盘。

## EM²Mem：多模态记忆单元

EM²Mem 把"记忆"建模为**多模态记忆单元（MemoryCell）**，每个单元同时携带文本、标签与可选的非文本载荷，并维护单元间的引用图。资料来源：[src/em2mem/memory/multimodal_memory_cell/MemoryCell.py:1-90]()。

`EM2Memory` 类负责单元生命周期管理：

| 方法 | 作用 |
| --- | --- |
| `add_memory` | 将原始消息封装为 `MemoryCell`，写入向量库并维护引用指针 |
| `retrieve` | 按相似度召回 top-k 单元，并按引用图做轻量重排 |
| `consolidate` | 在离线阶段合并相似单元、丢弃低分单元 |

资料来源：[src/em2mem/memory/EM2Memory.py:40-160]()。

EM²Mem 的特色在于其 **consolidate 步骤**：当 `config.update == "offline"` 时，`consolidate` 会周期性触发，用于替换过时或不正确信息，这与社区中关于"是否支持自动更新"的提问一致。资料来源：[src/em2mem/memory/EM2Memory.py:200-260]()。

## StructMem：模板化结构记忆

StructMem 没有独立顶层包，而是以**预定义 schema**（如 persona、event、fact）形式嵌入 `config.py` 中的 `structmem_schema` 字段，由 `LightMemory` 在 `add_memory` 末尾按 schema 做后处理：抽取键值、写入结构化集合（`summary_*` collection），检索时按字段过滤。资料来源：[src/fluxmem/config.py:220-310]()。

社区反馈中提到的"`summary_retriever` 拼写错误"即源于此处的检索入口——当 `enable_summary=True` 时必须通过 `summary_retriever.scroll` 而不是 `retriever.scroll` 访问 summary collection。资料来源：[src/fluxmem/agent.py:280-310]()。

## MCP 服务层

`mcp_server/` 目录把上述记忆能力封装为 MCP 工具，便于 Claude Desktop、Cline 等客户端直接调用。核心入口为 `mcp_server/server.py`，它在启动时根据环境变量选择底层实现（`lightmem` / `fluxmem` / `em2mem`），并向 MCP 注册表暴露如下工具：

```mermaid
flowchart LR
  Client[MCP Client] -->|stdio/SSE| Server[mcp_server/server.py]
  Server --> Tools[mcp_server/tools.py]
  Tools -->|add_memory| Core[(LightMemory / FluxMem / EM2Mem)]
  Tools -->|retrieve| Core
  Core -->|vector IO| Qdrant[(Qdrant)]
```

资料来源：[mcp_server/server.py:1-90]()、资料来源：[mcp_server/tools.py:1-70]()。

`tools.py` 中每个工具都是一个薄包装：参数校验后转发到底层 `add_memory` / `retrieve`，再把返回的 `List[MemoryEntry]` 序列化为 JSON。需要注意，`online_update` 当前为空实现（`return None`），因此通过 MCP 调用 `update="online"` 时实际不会持久化，社区 Issue #57 也指出了该问题。资料来源：[mcp_server/tools.py:80-120]()。

## 选型建议

- 需要**多跳推理或关系可视化**：选择 FluxMem。
- 需要**多模态载荷或引用图**：选择 EM²Mem。
- 已有强 schema 的业务系统：选择 StructMem，开销最低。
- 需要让外部 Agent 直接调用：任意模式都可以挂载到 MCP 服务层，但建议默认使用 LightMemory 以减小部署体积。

资料来源：[src/fluxmem/agent.py:1-40]()、资料来源：[src/em2mem/memory/EM2Memory.py:1-30]()、资料来源：[mcp_server/server.py:1-40]()。

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：zjunlp/LightMem

摘要：发现 14 个潜在踩坑项，其中 3 个为 high/blocking；最高优先级：安装坑 - 来源证据：Bug: `topic_segment=False` causes `add_memory()` to skip the entire extraction pipeline, resulting in empty Qdrant stor…。

## 1. 安装坑 · 来源证据：Bug: `topic_segment=False` causes `add_memory()` to skip the entire extraction pipeline, resulting in empty Qdrant stor…

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Bug: `topic_segment=False` causes `add_memory()` to skip the entire extraction pipeline, resulting in empty Qdrant storage
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/zjunlp/LightMem/issues/55 | 来源类型 github_issue 暴露的待验证使用条件。

## 2. 安全/权限坑 · 来源证据：Clarification on LongMemEval evaluation setting

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Clarification on LongMemEval evaluation setting
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 证据：community_evidence:github | https://github.com/zjunlp/LightMem/issues/70 | 来源类型 github_issue 暴露的待验证使用条件。

## 3. 安全/权限坑 · 来源证据：LLMLingua-2 的 compress_prompt_llmlingua2 方法内部没有自动分块——它把整个 context 直接过 BERT，所以超长必定炸。

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：LLMLingua-2 的 compress_prompt_llmlingua2 方法内部没有自动分块——它把整个 context 直接过 BERT，所以超长必定炸。
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 证据：community_evidence:github | https://github.com/zjunlp/LightMem/issues/71 | 来源类型 github_issue 暴露的待验证使用条件。

## 4. 能力坑 · 来源证据：Lightmem, Clarification on Section 3.2 and its implementation

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个能力理解相关的待验证问题：Lightmem, Clarification on Section 3.2 and its implementation
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/zjunlp/LightMem/issues/69 | 来源类型 github_issue 暴露的待验证使用条件。

## 5. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 证据：capability.assumptions | https://github.com/zjunlp/LightMem | README/documentation is current enough for a first validation pass.

## 6. 运行坑 · 来源证据：[Bug] Unknown attribute "retriever" when enable enable_summary

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：[Bug] Unknown attribute "retriever" when enable enable_summary
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/zjunlp/LightMem/issues/52 | 来源类型 github_issue 暴露的待验证使用条件。

## 7. 维护坑 · 来源证据：Question about Table 3: how is the Calls metric on LoCoMo averaged?

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个维护/版本相关的待验证问题：Question about Table 3: how is the Calls metric on LoCoMo averaged?
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/zjunlp/LightMem/issues/60 | 来源类型 github_issue 暴露的待验证使用条件。

## 8. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 证据：evidence.maintainer_signals | https://github.com/zjunlp/LightMem | last_activity_observed missing

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 证据：downstream_validation.risk_items | https://github.com/zjunlp/LightMem | no_demo; severity=medium

## 10. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 证据：risks.scoring_risks | https://github.com/zjunlp/LightMem | no_demo; severity=medium

## 11. 安全/权限坑 · 来源证据：How can I reproduce the 72.99 results

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：How can I reproduce the 72.99 results
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 证据：community_evidence:github | https://github.com/zjunlp/LightMem/issues/61 | 来源类型 github_issue 暴露的待验证使用条件。

## 12. 安全/权限坑 · 来源证据：复现baseline的一些问题

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：复现baseline的一些问题
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 证据：community_evidence:github | https://github.com/zjunlp/LightMem/issues/53 | 来源讨论提到 python 相关条件，需在安装/试用前复核。

## 13. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 证据：evidence.maintainer_signals | https://github.com/zjunlp/LightMem | issue_or_pr_quality=unknown

## 14. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 证据：evidence.maintainer_signals | https://github.com/zjunlp/LightMem | release_recency=unknown

<!-- canonical_name: zjunlp/LightMem; human_manual_source: deepwiki_human_wiki -->
