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 的成本,且摘要常常抹掉原话,把证据丢失到中间表示里。结果是:

  1. 在长程任务里,记忆成本与对话长度同步增长,常常成为 latency 的主要来源;
  2. 当最终问答需要「原话证据」时,被摘要过的记忆给不出原文;
  3. 摘要的语义偏移会随轮次放大,最终触发幻觉。

Zero-Mem 反过来问一个更朴素的问题:结构化记忆访问是否根本不需要生成? 答案是:完全可以,只要把原始交互痕迹直接索引好。

核心方法(机制 + 工程路径双轨)

机制:两视图索引 + 决定性校准

Zero-Mem 把每次原始交互(user / tool / assistant 消息)原封不动地保留下来,作为「source of record」。然后离线地建两张互补的索引视图:

  1. Entity–Context Graph(实体—上下文图):用轻量编码器(论文明确「编码器计算单列核算」,不算作 LLM token)抽取命名实体、事件、对象,把跨轮次提到的同一实体在图上连边。这张图回答的是「这件事和那件事之间有什么关系」。
  2. 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」,是否覆盖多模态原文未明确。

对工程落地的启发

  1. 企业内部 Agent / Copilot:把记忆层从「基于 LLM 的 summarizer」换成 Zero-Mem 风格的双视图检索,per-turn 成本与延迟直接腰斩。
  2. RAG 审计与合规:在金融、医疗、法律场景,「必须能给出原话」是硬约束;Zero-Mem 的 source-of-record + grounding 思路天然适合做合规可追溯。
  3. 离线批处理场景:把记忆索引放成离线流水线,主对话链只跑 reader;流水线可水平扩展。
  4. 与现有记忆框架结合:Mem0、Letta、LangGraph Memory 等可在不动 LLM 调用层的前提下,把内部 summarizer 换成 Zero-Mem 风格的结构化检索。
  5. 编码器选型:因编码器消耗单列核算,可考虑更激进的小模型(如 bge-small、bge-m3 的子集),结合 periodic reindex 补偿漂移。

与同方向工作的关系

  • Mem0A-MemMemoryBank 等「记忆即 LLM 操作」工作形成路线对比:后者用 LLM 总结 / 抽取 / 推理,前者把 LLM 踢出记忆层。
  • LongMemEvalLoCoMo 等长记忆评测集互补——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,需等同行评审后激活
编码器型号 / 训练目标 原文未明确,无法评估实体抽取质量