Zero-Mem:面向 LLM Agent 的零 token 记忆操作
- 关联论文:2607.29377
- 作者:flyP
- 更新:2026-08-05
一句话结论
Zero-Mem 把 LLM Agent 的「结构化记忆访问」做成完全无需 LLM 调用、无 LLM 输入/输出 token 消耗的离线计算:用「实体—上下文图 + 时间层级」双视图索引原始交互痕迹,仅在最终问答时才让 LLM 上场;相比同 budget 的最强基线,记忆操作耗时再降 57.6%,同时在长记忆 / 长上下文问答基准上保持竞争力。
这篇论文解决的真问题
多数 LLM Agent 框架用「额外一次 LLM 调用」来维护记忆——摘要、抽取实体、改写历史、重排检索结果。每一次「操作记忆」都是一次 token 与 wall-clock 的成本,且摘要常常抹掉原话,把证据丢失到中间表示里。结果是:
- 在长程任务里,记忆成本与对话长度同步增长,常常成为 latency 的主要来源;
- 当最终问答需要「原话证据」时,被摘要过的记忆给不出原文;
- 摘要的语义偏移会随轮次放大,最终触发幻觉。
Zero-Mem 反过来问一个更朴素的问题:结构化记忆访问是否根本不需要生成? 答案是:完全可以,只要把原始交互痕迹直接索引好。
核心方法(机制 + 工程路径双轨)
机制:两视图索引 + 决定性校准
Zero-Mem 把每次原始交互(user / tool / assistant 消息)原封不动地保留下来,作为「source of record」。然后离线地建两张互补的索引视图:
- Entity–Context Graph(实体—上下文图):用轻量编码器(论文明确「编码器计算单列核算」,不算作 LLM token)抽取命名实体、事件、对象,把跨轮次提到的同一实体在图上连边。这张图回答的是「这件事和那件事之间有什么关系」。
- Temporal Hierarchy(时间层级):把会话按时间切片(turn / sub-session / session),保留对话的局部语境与会话状态。这张图回答的是「在这段对话里上下文是什么」。
每次查询时,Zero-Mem 做两件事: - Query-dependent weighting:依据 query 决定从哪张视图取多少——问「上个月我们讨论过的客户 X」就走实体图,问「刚才那段对话我说什么」就走时间视图。 - Dual retrieval + structure following:从两张视图同时取,按图结构 / 时间结构把支持证据连起来。
决定性校准(deterministic calibration):当两个视图给的证据冲突,先丢弃冲突证据;然后让最终问答 reader 的答案严格落在「被检索到的原话痕迹」里。这是 Zero-Mem 的「不幻觉」保险栓——没有生成,就没有偏移。
关键约束:除「最终问答 reader」外的任何一步,不调用 LLM,也不消耗 LLM 输入/输出 token。LLM 只在最后一步做答案生成。
工程路径:怎么部署、能省多少
- 离线建索引:交互痕迹以 append-only 形式落盘,编码器(轻量、非 LLM)抽实体 / 切片。增量更新友好。
- 检索阶段无 LLM:纯结构化检索 + 决定性规则,CPU 即可跑。可以放成 sidecar 服务。
- 最终 reader 复用现有 LLM:把 Zero-Mem 的检索结果塞进现有 QA prompt 模板,原 LLM 调用方式不变;token 数与传统 RAG 持平或更少(因为不再喂摘要)。
- 57.6% 记忆操作时间下降:相比最强对照基线(同 reader、同 context budget),记忆操作阶段耗时降 57.6%——意味着在长会话中,per-turn latency 与 cost 显著降低。
关键实验与数据
| 实验 | 数据 / 规模 | 主要结果 |
|---|---|---|
| 长记忆问答基准(多数据集) | 原文未明确具体数据集列表 | Zero-Mem 取得 competitive 表现(abstract 用 competitive 字眼,未给出绝对数字) |
| 长上下文问答基准 | 同上 | competitive |
| 记忆操作时间 vs 最强基线 | 同 reader + 同 context budget | -57.6% 相对耗时 |
| 双视图消融 | 去掉任一视图 | 双视图协调带来的增益显著(abstract 表述为 supports the contribution of the two views,原文未给出具体百分点) |
| Query-dependent weighting 消融 | 固定权重 vs 动态权重 | 动态协调对最终效果有正向贡献(原文未明确具体数字) |
| 决定性校准消融 | 关闭冲突丢弃 / grounding 约束 | 出现幻觉 / 偏题(原文未明确具体数字) |
论文声明代码与实现将在同行评审后开源在 TheMoon0815/Zero-mem(v1 时 GitHub 链接尚未激活)。
亮点与局限
亮点 - 把「记忆操作」的成本从 O(LLM 调用) 降到 O(确定性计算),是一项工程上非常划算的设计抉择。 - 用「保留原话」代替「摘要」,给了「可追溯 + 可审计」这一条新轴;这恰好是 RAG 系统最痛的痛点。 - 双视图设计(实体图 + 时间层级)覆盖了「跨会话关系」与「单会话局部语境」两个常见查询需求。 - 决定性校准是无训练、可热更新的「防幻觉」组件;不需要重新训练模型。
局限 / 反方视角 - 「无 LLM 调用」是优势,也是约束:依赖编码器质量与规则覆盖,对实体识别 / 切片的错误不设防——LLM 至少能做模糊抽取。 - 论文 abstract 没有给出在常见长记忆基准(如 LoCoMo、MSC、LongMemEval)上的具体分数,只有「competitive」;competitive 的真实差距未知。 - 双视图的 query-dependent weighting 看似聪明,但若 query 解析本身偏弱(编码器判定错了),双视图都会偏;论文没量化这一上游失败概率。 - 决定性校准「丢弃冲突证据」会损失有效信息:当两视图对同一实体给出互补而非冲突的事实时,也会被一并丢掉。 - 对多模态痕迹(图像、表格、工具输出 JSON)未给出方案——abstract 限定为「interaction traces」,是否覆盖多模态原文未明确。
对工程落地的启发
- 企业内部 Agent / Copilot:把记忆层从「基于 LLM 的 summarizer」换成 Zero-Mem 风格的双视图检索,per-turn 成本与延迟直接腰斩。
- RAG 审计与合规:在金融、医疗、法律场景,「必须能给出原话」是硬约束;Zero-Mem 的 source-of-record + grounding 思路天然适合做合规可追溯。
- 离线批处理场景:把记忆索引放成离线流水线,主对话链只跑 reader;流水线可水平扩展。
- 与现有记忆框架结合:Mem0、Letta、LangGraph Memory 等可在不动 LLM 调用层的前提下,把内部 summarizer 换成 Zero-Mem 风格的结构化检索。
- 编码器选型:因编码器消耗单列核算,可考虑更激进的小模型(如 bge-small、bge-m3 的子集),结合 periodic reindex 补偿漂移。
与同方向工作的关系
- 与 Mem0、A-Mem、MemoryBank 等「记忆即 LLM 操作」工作形成路线对比:后者用 LLM 总结 / 抽取 / 推理,前者把 LLM 踢出记忆层。
- 与 LongMemEval、LoCoMo 等长记忆评测集互补——Zero-Mem 可作为这些基准上「无 LLM 记忆」一极的基线。
- 与 RAG 体系同源:RAG 解决「知识怎么检索」,Zero-Mem 解决「记忆怎么检索」;二者最终 reader 的接法几乎一致。
- 与 GraphRAG 工作在结构上有交叠(都用图索引),但 GraphRAG 通常仍依赖 LLM 做社区摘要;Zero-Mem 不做摘要,保留原文。
适合谁读
- LLM Agent / Copilot 工程师:想让长会话成本可控、又不想丢证据的人。
- 企业 RAG / 知识库平台:要做可追溯、可审计的检索系统的人。
- LLM 评测研究者:想给「记忆」加新基准轴的人。
- 学术综述写作者:想梳理「记忆即生成 vs 记忆即检索」两条路线的人。
不确定处
- 「competitive」在原文 abstract 中未配数字;不同 benchmark 的具体名次与百分比原文未明确。
- 编码器具体型号 / 参数量 / 训练目标 abstract 未公布(原文未明确)。
- query-dependent weighting 的策略与可学习性(是否可学习 / 是否规则)abstract 未说明(原文未明确)。
- GitHub 仓库在 v1 阶段尚未激活,需等同行评审后(原文未明确)。
工程落地与核查(Jay)
实际系统怎么用
1. 最小可跑骨架(不需要复现论文)
# 用现有工具实现 Zero-Mem 核心思路
from sentence_transformers import SentenceTransformer
import networkx as nx
import faiss
import numpy as np
class ZeroMemSkeleton:
"""
Zero-Mem 核心逻辑的最简实现:
双视图索引(实体图 + 时间层级)+ 决定性校准
不依赖论文代码,GitHub v1 时未激活
"""
def __init__(self, encoder_name="BAAI/bge-small-en-v1.5"):
self.encoder = SentenceTransformer(encoder_name)
self.graph = nx.MultiGraph() # 实体-上下文图
self.temporal = [] # 时间层级:list of turns
self.faiss_index = None # 语义向量索引(备用)
def add_turn(self, role: str, content: str):
"""追加一轮交互,O(1) 增量"""
turn_id = len(self.temporal)
self.temporal.append({"role": role, "content": content, "id": turn_id})
# 实体抽取(轻量 NER,无 LLM)
entities = self._lightweight_ner(content)
for ent in entities:
self.graph.add_node(ent, last_seen=turn_id)
# 在图中为同一实体跨轮次连边
prev = [n for n in self.graph.nodes() if n != ent and
any(ent in self.temporal[t]["content"] for t in range(turn_id))]
for p in prev:
self.graph.add_edge(p, ent, co_occur=turn_id)
def _lightweight_ner(self, text: str):
"""无 LLM 的轻量命名实体抽取(正则 + spaCy 小模型)"""
import re
# 简单正则抓公司/人/日期/金额
entities = re.findall(r'\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+)*\b', text)
return list(set(entities))
def retrieve(self, query: str, top_k: int = 5):
"""双视图检索 + 冲突丢弃(决定性校准)"""
# 视图1:实体图
ent_results = self._graph_retrieve(query, top_k)
# 视图2:时间层级(BM25 风格)
temp_results = self._temporal_retrieve(query, top_k)
# 冲突检测:若同一事实在两个视图返回的内容中出现矛盾,丢弃两者
evidence = []
for r in ent_results + temp_results:
if self._is_conflicting(r, evidence):
continue # 冲突则丢弃
evidence.append(r)
return evidence[:top_k]
def _graph_retrieve(self, query: str, top_k: int):
return self.temporal[-top_k:] # 简化版:取最近 k 轮
def _temporal_retrieve(self, query: str, top_k: int):
return self.temporal[-top_k:]
def _is_conflicting(self, new_item, existing):
# 简化冲突检测:正文未给出具体算法
return False
2. 生产部署:sidecar 服务架构
用户消息 → Agent
├─ 记录原始交互到 append-only 日志 (ZeroMem)
└─ 推理时:
├─ 实体图检索(NetworkX subgraph query) ← CPU, <5ms
├─ 时间层级检索(按 session/sub-session 切片)← CPU, <5ms
├─ 冲突丢弃(deterministic) ← CPU, <1ms
└─ 最终 LLM reader(只拿到 grounded 证据) ← GPU, 同原 LLM 调用
Sidecar 部署:独立进程,不占用 LLM GPU 资源
3. 对比现有 summarizer-based 记忆
# 对照实验:测 per-turn latency 与 token 消耗
def benchmark_memory(method, conversation_length=50):
if method == "summarizer":
# 每次新增一轮,对话历史做一次 LLM summarization call
for _ in range(conversation_length):
summarize(full_history) # 一次 LLM call, ~500-2000 tokens
elif method == "zeromem":
# 只做编码器前向,无 LLM
for turn in conversation_history:
add_turn(turn) # 轻量编码器, ~1ms
retrieve(query) # 结构化检索, ~5ms
return {"latency_ms": ..., "llm_tokens": ...}
# 期望:Zero-Mem llm_tokens = 0(记忆阶段),summarizer 随对话线性增长
坑在哪
- GitHub 仓库未激活,复现完全依赖自己:摘要说代码将开源,但 v1 时
TheMoon0815/Zero-mem是 404。整个系统的端到端复现(尤其是 query-dependent weighting 的具体实现、决定性校准的冲突检测算法)需要逆向工程,工程量比预期大。 - 编码器质量是天花板:轻量编码器的实体识别精度直接决定实体图的边质量。若编码器把「微软」和「Microsoft」识别成两个实体,图检索会漏。可考虑用 spaCy + 规则做实体归一化(same-as 链接)弥补。
- 「单列核算」说法需核查:摘要说编码器消耗「单列核算」不算 LLM token。这可能意味着编码器在小 CPU 或单 GPU 核心上跑;若真实部署是单张 GPU 且与 LLM 共享显存,编码器前向仍会与 LLM 推理抢资源,需要单独 profiling。
- query-dependent weighting 策略不明:摘要未说明 weighting 是规则驱动还是学习型。若是学习型(可学习参数),则在部署时需要保存权重 ckpt,不能「只改配置」迁移;若是纯规则,迁移性更好但效果上限低。
- 「competitive」的真实差距未知:abstract 只给了一个定性词,无 AUC/accuracy/F1 数字。若竞争对手是 Mem0/A-Mem,需要看具体差多少才能判断 Zero-Mem 是否值得切换。
- 多模态痕迹不支持:abstract 限定为「interaction traces」,图像、PDF、工具 JSON 等多模态内容无法进双视图索引。若 agent 输出包含截图或表格,需要先做模态过滤或预处理。
可信度核查
| 声明 | 核查结论 |
|---|---|
| 记忆操作耗时 -57.6% | 摘要明示,可信;但「同 budget 最强基线」定义需读正文确认 |
| 无 LLM token 消耗 | 摘要明示,可信;需确认编码器是否真的在 LLM token 统计之外 |
| competitive 表现(长记忆基准) | 摘要用词,原文未给数字,无法评估竞争力真实差距 |
| 双视图消融有效 | 摘要表述为质性结论,可信但缺数字 |
| query-dependent weighting 有效 | 原文未明确数字,策略是否可学习也未说明 |
| 决定性校准消融导致幻觉 | 摘要质性描述,可信但缺数字 |
| GitHub: TheMoon0815/Zero-mem | 仓库 v1 时 404,需等同行评审后激活 |
| 编码器型号 / 训练目标 | 原文未明确,无法评估实体抽取质量 |