调研对象:HaluMem(Hallucination in Memory Benchmark),arXiv:2511.03506(v3, 2026-01)。 材料来源:论文正文、本仓库
eval/全部评测代码、README 排行榜,以及 arXiv/GitHub/HuggingFace/OpenReview/第三方综述(见附录)。 贯穿全文的例子:数据集真实用户 Martin Mark——他把宠物偏好从拉布拉多改成了金毛,这条"改养金毛"线贯穿数据构造、三大任务与指标手算。
摘要
HaluMem 将记忆系统拆成抽取、更新和问答三个操作,为每一步提供标准答案并单独评分。与只看最终答对率的评测相比,它可以区分捏造、记错、冲突和漏记发生在哪个阶段,也能观察上游错误怎样影响后续更新与回答。
论文实验中 MemOS 的综合结果最好;抽取与更新的耗时明显高于检索,长上下文和复杂任务也会让各系统的表现下降。不过,HaluMem 与 MemOS 来自同一组织且作者高度重叠,评测又依赖大模型裁判,并要求被测系统开放三个内部接口。因此它更适合作为操作级诊断方法,而不宜单独作为系统优劣的最终排名。
结果解读和复现时需要注意三点:
-
更新指标的读法:多数系统的改错率 H 接近 0,但这不代表更新可靠。许多失败表现为没有输出更新,因此需要把 H 与正确率 C、漏改率 O 一起阅读。
-
论文与实现的差异:若干关键口径只体现在代码中,例如召回只认可完全正确的记忆,更新指标的实际分母也小于论文文字所暗示的范围。复现时必须以代码核对。
-
合成数据的有效信息量:数据全部由 LLM 生成,实际样本存在对话循环填充(详见 §7),因此对话轮数和 token 长度可能高估真实的信息密度。
它适合 Mem0、MemOS 一类抽取改写型系统,前提是能提供抽取、更新和问答三个接口。黑盒或高度自主的 Agent 无法完整接入;如果重点是 Recall@k 等检索诊断,或者场景不是英文通用对话,还需要补充其他基准或自建数据。
1. 为什么需要它:现有评测差在哪
现在的 AI 助手大多号称"有记忆":从多轮对话里抽取用户信息,存下来,之后需要时再取用(代表系统有 Mem0、MemOS、Zep、Memobase、Supermemory)。问题是,它们在存、改、取的过程中会出错,论文把这些错误统称为记忆幻觉,表现为四种:捏造(fabrication)、记错(error)、冲突(conflict)、漏记(omission)。
麻烦在于怎么发现这些错误。现有评测的做法是把整个记忆系统当黑盒:喂一堆对话,最后问几个问题,看答对率。论文用一个式子点破它的局限——端到端准确率只是"预测答案等于正确答案"的比例,一旦答错,这个数字没法告诉你错在抽取、更新还是问答。病因被埋没在最终分数里。
HaluMem 换了个思路:与其只验最终成品,不如给流水线上的每个工位单独质检。
表 1 端到端与操作级评测:后者可以定位错误来源并量化误差传递
| 端到端(LoCoMo / LongMemEval) | 操作级(HaluMem) | |
|---|---|---|
| 怎么测 | 喂对话,问问题,看答对率 | 给每一步单独标好标准答案,分别打分 |
| 答错时 | 不知道错在哪 | 能定位是抽取、更新还是问答出错 |
| 额外能拿到 | —— | 分清"漏"和"编"、量化误差如何往下游放大 |
拆开操作后,评测可以定位错误来源,并量化误差怎样向下游传递。这是 HaluMem 相比端到端评测新增的信息。

图 1 把记忆系统拆成三个操作、逐步质检,并观察错误如何往下游传导。
论文把评测设计成"边聊边测":按时间顺序把 session 依次喂进去,遇到带标准答案的 session 就立刻评。(代码实现其实是"先整轮跑完存盘、再统一打分"两趟,效果一样,只是不是字面上的实时——见 §4。)
2. 一个完整的例子:数据怎么造、长什么样
要判断"记忆有没有出错",前提是先有一份标准答案:哪些该记、哪些是干扰、每道题的正确答案是什么。真实对话没有这种标注,所以 HaluMem 干脆自己造——给一个虚构的人编一套可追溯的人生,再演成对话。把这个构造过程看懂了,数据里那些字段就都有了着落。下面跟着数据集里的真实用户 Martin Mark 走一遍。
2.1 六步,编出一个用户
第一步,给 Martin 一个人设:公共卫生专业、性格 ENTP、喜欢狗,尤其是拉布拉多。
第二步,为他搭一条人生骨架,其中有一条规则——偏好会随时间改变。
第三步,顺着这条规则生成一个具体事件:2026 年 1 月 6 日,他去朋友家玩,接触到一只金毛,决定改喜欢金毛。
第四步,从这个事件里提炼出一条记忆点:Martin 的宠物偏好从拉布拉多变成了金毛。因为这是一次改变,它被标记为"需要更新",并把旧版本(原来喜欢拉布拉多)一并记下。留着旧版不是要系统保存它,而是将来好判断系统有没有真的改过来——这把"旧版标尺"在测更新时要用到。
第五步,把这件事展开成一段多轮对话。为了模拟真实场景里 AI 常犯的毛病,构造时故意让对话中的 assistant 顺嘴多说几句用户没确认的引申,比如"你是不是想探索各种不同物种""愿意尝试非常规的宠物"。这些叫诱饵:听着合理,但 Martin 从没这么说,好的记忆系统不该把它们当成他的真实偏好记下来。
第六步,基于这段对话出几道题,比如"Martin 现在喜欢什么狗?"(答案:金毛),并给每道题标注:回答它需要用到前面哪几条记忆——这几条叫 evidence,是裁判判分时的解题依据。
走完这六步,就得到了一份带完整标准答案的对话数据:一段对话、一批该记的记忆点(含诱饵)、几道带答案和依据的题。

图 2 六步构造,用 Martin"改养金毛"这条线走完全程。
正因为构造者从头就知道每条记忆的真值、每个诱饵、每道题的答案,事后才能精确指出系统错在哪一步。这是 HaluMem"能测幻觉"的根本前提。(论文另有人工质检:8 名标注员抽查了半数以上的数据,正确率 95.70%、相关性 9.58、一致性 9.45。)
2.2 造出来的数据长什么样
有了上面的来龙去脉,再看数据结构就不费劲了。一份数据不是几个分开的文件,而是一个用户对象,底下挂着多个 session;每个 session 里,对话、记忆点、问题三样是并排放的,问题的 evidence 反过来指向本 session 的记忆点。

图 3 数据的嵌套结构:一个用户对象挂多个 session,每个 session 并排放对话、记忆点、问题三样;问题的 evidence 反指回本 session 的记忆点。
落到字段,下面是 Martin"改养金毛"session 的骨架,长文本用 … 省略:
{
"uuid": "2f1f897e-…",
"user_name": "Martin Mark",
"persona_info": "Name: Martin Mark; Major: Public Health; MBTI: ENTP; …",
"sessions": [
{
"session_id": "S5",
"dialogue_turn_num": 26,
"dialogue": [ // 喂给系统的原始输入
{ "role": "user", "content": "I interacted with a friend's Golden Retriever…" },
{ "role": "assistant", "content": "Golden Retrievers are known for their calm demeanor…" }
// …共 26 轮…
],
"memory_points": [ // 该记的记忆点,= 抽取/更新的靶子
{
"index": 1,
"memory_content": "Martin has changed his pet preference from Labradors to Golden Retrievers.",
"memory_type": "Persona Memory", // 记忆分三类:Persona / Event / Relationship
"memory_source": "secondary", // 非 interference 即"该记"
"is_update": "True", // 这是一条"更新"
"original_memories": ["Martin … likes Dogs, especially Labradors"], // 旧版标尺
"importance": 0.75
},
{
"index": 10,
"memory_content": "Martin is interested in exploring different pet species…",
"memory_source": "interference", // 诱饵!用户没这么说,好系统不该记
"reference_memory_index": 9 // 它由第 9 条真话引申、夸大而来
}
// …其余记忆点略…
],
"questions": [ // 考题,= 问答任务的题目
{
"question": "What new activity might Martin try after April 2026?",
"answer": "Other extreme sports.",
"evidence": [ { "memory_content": "Martin developed an appreciation for extreme sports…" } ],
"question_type": "Generalization & Application" // 六类问题之一
}
]
}
]
}
2.3 三个容易看错的地方
一是 index 只是记忆点在本 session 内的序号(1、2、3……),不代表重要性,也不代表优先级,而且跨 session 会从头再数。上面那个 reference_memory_index: 9 就是靠它在 session 内指认"第 9 条记忆点"。
二是记忆点和对话轮次没有对应关系。上例有 26 轮对话,却只有十来条记忆点——记忆点是从整段对话提炼出来的事实,字段里根本没有"这条对应第几轮"的锚。这一点和 LoCoMo/LongMemEval 正好相反:它们把每条证据死死绑在"第几轮对话"上,而 HaluMem 走的是语义比对的路子,既不需要、也没有轮次锚。原因很直接——记忆是系统嚼碎、改写后吐出的新句子,没有原文页码可对,只能比意思。
三是 evidence 不是新东西,它就是 memory_points 的一个子集。出题人从"本 session 该记的全部记忆点"里,挑出"回答这道题要用到的那一两条",作为裁判的标准解题依据。全部记忆点是这段对话的所有知识点,evidence 是这道题考的那个知识点。
2.4 两个规模版本
数据在 HuggingFace 的 IAAR-Shanghai/HaluMem,本仓库内只有构造中间产物。它有两个版本:
表 2 两个规模版本。记忆点与问题数完全相同,Long 只是塞进大量不计分的干扰 session 把上下文撑到 1M
| 版本 | 用户 | 对话轮 | 平均 session/用户 | 上下文 | 记忆点 | 问题 |
|---|---|---|---|---|---|---|
| HaluMem-Medium | 20 | 30,073 | 70 | ~160k tok | 14,948 | 3,467 |
| HaluMem-Long | 20 | 53,516 | 120 | ~1M tok | 14,948 | 3,467 |
两版的记忆点数和问题数完全一样,因为 Long 只是在 Medium 的基础上插入大量"纯干扰 session"(科普问答、数学题、无关闲聊),把上下文撑到 1M 来专门考抗干扰。这些干扰 session 只制造噪声,不计分。
3. 三大任务:分别在测什么、怎么打分
一段对话被系统处理完之后,我们想验证三件事:该记的它记全了吗?该改的它改对了吗?拿问题去问,它答得对吗?这就是抽取、更新、问答三个任务。
这里要先破除一个最常见的误解:只有问答任务才真的"问问题"。抽取和更新根本不问问题,它们是直接去翻系统的记忆库、和标准答案对。三个任务各用各的数据、各有各的判法,下面逐个说,说完在 §3.4 汇成一张对照表。
3.1 抽取:记全了吗,记的都是真的吗
抽取任务只关心一件事:这段对话处理完,系统到底记下了哪些东西。它从两个相反的方向各查一遍。
一个方向是查漏:拿着标准答案里每一条"该记"的记忆,去系统记下的东西里找,看有没有覆盖。完全记对给 2 分,记了个大概给 1 分,没记或记错给 0 分。这个方向得到的是召回——衡量系统健不健忘。
另一个方向是查编:反过来,拿系统实际记下的每一条,回到原对话和标准答案里核对,看它有没有依据。全都属实给 2 分,半真半假给 1 分,纯属编造给 0 分。这个方向得到的是准确——衡量系统爱不爱瞎编。
一句话记住方向:查漏站在标准答案上问系统"你覆盖我了吗",查编站在系统记忆上问它"你有依据吗"。两者互补,一个抓漏、一个抓编。
用金毛这条数据演示一遍。gold 里有一条记忆点:「Martin 把宠物偏好从拉布拉多改成了金毛(重要度 0.75)」。系统处理完对话后,假设记下了这几条:
-
「Martin changed his preference from Labradors to Golden Retrievers due to their gentle nature.」→ 查漏:完全覆盖,2 分;查编:有对话依据,2 分。
-
「Martin likes dogs.」→ 查漏:只提到"喜欢狗",没捕捉到"从拉布拉多改成金毛"这个关键变化,1 分(部分覆盖)。
-
「Martin is a healthcare professional.」→ 查编:对话里没有依据,0 分(纯编造)。
查漏和查编的裁判视角完全不同:查漏每次只看"某一条 gold 有没有被覆盖",查编每次只看"某一条系统记忆有没有依据"——同一条系统记忆在两个方向里扮演的角色不一样。
除此之外还有第三把尺,专门测诱饵,叫抗诱饵率(FMR)。前面说过,诱饵是构造时故意塞进 assistant 话里的引申,比如 Martin 明明只说改喜欢金毛,assistant 却顺嘴说他"想探索不同物种"。系统收到的是没有任何标签的普通对话,它并不知道哪句是诱饵。测的时候反过来查:系统有没有把这些诱饵也当成真事记进去?没记到算抗住,记到了算被骗,抗住的比例就是 FMR。
3.2 更新:旧的改成新的了吗
更新任务也不问问题,它直接去看系统的记忆库有没有完成"旧版到新版"的迁移。还是金毛这条:新版是"偏好从拉布拉多变成金毛",旧版是"喜欢拉布拉多"。正确的系统,记忆库里应该体现出新版,而不是还停在旧版。
具体做法是,拿新版记忆当查询词去系统里检索,把检索到的相关记忆交给裁判,裁判对照新版和旧版给出四种判定:
-
记忆里体现了新版(金毛)——改对了(Correct)。
-
还停在旧版(拉布拉多),或者缺了关键新信息——忘改了(Omission)。
-
生成了一个相关但错误的新版本(比如说成牧羊犬)——改错了(Hallucination)。
-
其他说不清的失败——归入兜底类(Other)。
裁判拿到的是三样东西:系统在处理完对话后、用新版 query 检索到的相关记忆,加上标准新版和旧版。对照逻辑很直接:
表 3 更新任务的三种判定(以金毛为例)
| 系统记忆里有什么 | 判定 |
|---|---|
| 「Martin now prefers Golden Retrievers over Labradors.」 | Correct(体现了新版) |
| 「Martin loves Labradors for their loyalty and friendliness.」 | Omission(还停在旧版) |
| 「Martin recently switched his preference to Border Collies.」 | Hallucination(改了,但改错了方向) |
这里藏着 §0 说的坑一的一半。评测时有个门槛:只有系统"还能检索到相关记忆"的那些更新,才会真正进入更新打分;如果系统压根检索不到,这条更新不算进更新的分母,而是被算成上游的"漏记"。所以当你看到某个系统"更新改错率极低、漏改率极高"时,别以为它更新做得好——很可能是它在这一步干脆没输出,失败被记成了沉默的漏改。
3.3 问答:六类题,同一套判法
问答任务才是真正拿问题去问系统的。流程对所有题目都一样:系统拿到问题,检索记忆,交给统一的 GPT-4o 生成回答,再由同一个裁判对照标准答案和 evidence,判成答对、答不出、答错三类。
裁判每次拿到四样东西:问题、标准答案、关键记忆点(evidence)、系统的回答。还是用金毛的那道泛化题演示:
-
问题:「What new physical activity might Martin try after April 2026?」
-
标准答案:「Other extreme sports.」
-
关键记忆点:「Martin has developed a newfound appreciation for extreme sports.」
-
系统回答 A:「Martin might try other extreme sports, such as rock climbing.」→ 语义等价,答对(Correct)。
-
系统回答 B:「Martin enjoys hiking and outdoor activities.」→ 与关键记忆点不符(不是泛指户外,而是极限运动),答错(Hallucination)。
-
系统回答 C:「I don't have information about Martin's physical activities.」→ 明明有记忆却说不知道,答不出(Omission)。
题目本身分六类,但请注意,这六类靠的是出题方式不同,而不是用了不同的数据标签或不同的裁判:
表 4 六类问答题:区别只在出题方式,判分和裁判同一套
| 类型 | 在考什么 | 例子 |
|---|---|---|
| 基础事实回忆 | 单条事实 | "Martin 住哪?" |
| 动态更新 | 答最新的值 | "Martin 现在喜欢什么狗?"→金毛 |
| 多跳推理 | 串联好几条记忆 | 把职业、健康、计划拼起来 |
| 泛化应用 | 举一反三 | 由"喜欢极限运动"推"可能尝试别的极限运动" |
| 记忆冲突 | 在矛盾信息里选对的 | 新旧信息打架时选正确结论 |
| 记忆边界 | 该不知道就说不知道 | 历史没提过,系统不能编 |
有两个地方最容易搞混,值得单独点出来。其一,"动态更新题"不等于"更新任务":前者是问答里的一种题,考的是答得对不对;后者是独立的操作,考的是记忆库改没改。名字像,考的东西完全是两码事。其二,六类题之间没有权重,每道题一样重;所谓"分题型准确率",只是把同一批答对/答错/答不出的判定,换成"按六类分别去数"而已,指标还是那三个,变的只是这次数哪些题。
(补充一个实现细节:这个"按六类分组"的统计,主评测脚本 evaluation.py 其实没有现成产出——它只算总的答对/答错/答不出,脚本里唯一的分组是按三类记忆类型统计抽取和更新的准确率。README 里那张六类分题型的表来自论文的额外统计,别以为跑一遍脚本就能得到。)
3.4 三个任务对照
表 5 三任务终极对照:各用各的数据、各有各的判法,只有问答真的"问问题"
| 任务 | 用哪部分数据 | 问问题吗 | 系统产物 | 裁判怎么判 |
|---|---|---|---|---|
| 抽取 | memory_points | 不问 | 系统抽出的记忆 | 查漏(召回)+ 查编(准确)+ 抗诱饵 |
| 更新 | 标了"需更新"的记忆点(新版+旧版) | 不问 | 用新版检索到的系统记忆 | 改对 / 忘改 / 改错 / 其他 |
| 问答 | questions(答案+evidence+题型) | 问 | 检索后生成的回答 | 答对 / 答不出 / 答错,再按六类分组 |
4. 评测怎么跑起来
整个评测分两趟。第一趟连着被测系统,把数据喂进去、把它的产出记下来,形成一份"答卷";第二趟连着 GPT-4o 裁判,拿答卷逐条打分。之所以分两趟,是因为连被测系统很慢,先一次性跑完存盘,之后打分可以反复来。

图 4 两趟 pipeline:先连被测系统产出答卷(慢,跑一次存盘),再连 GPT-4o 裁判打分(可反复)。①②③ 是被测系统必须提供的三个接口。
图里第一趟的 ①②③ 对应被测系统必须提供的三个接口:喂入对话(系统据此自动抽取、更新)、取回某段对话抽出的记忆(供抽取打分)、按查询检索相关记忆(更新用新版检索、问答用问题检索)。
这三个接口是硬门槛,缺一个就有整块指标算不出来。Zep 因为拿不到"抽出的记忆",抽取全套指标只能记为空;Memobase 也缺这个接口,实测靠直连数据库绕过。换句话说,一个完全黑盒、只肯回答问题的系统,在 HaluMem 里只能测问答——这是"操作级"的代价:想看得越细,就越要求系统掀开内部。
5. 指标与一遍手算
所有指标本质都是"数个数再做除法"。用 Martin 的一个简化账本走一遍就清楚了:该记 5 条(姓名、住址、金毛、生日、专业,重要度分别 1.0 / 0.75 / 0.5 / 0.5 / 0.75),另有 2 条诱饵;系统记了 6 张卡片(姓名对、住址对、金毛对、生日只记了年份、编了个"医生"、还上当记了 1 条诱饵)。
表 6 六个抽取指标的手算账本(下文给出后两行的算术展开,可逐项验证)
| 指标 | 怎么数 | 结果 | 高了说明 |
|---|---|---|---|
| 召回 | 完全记对 3 条 ÷ 该记 5 条 | 60% | 不健忘(只认完全记对) |
| 加权召回 | Σ(0.5 × 分数 × 重要度) ÷ Σ重要度 | 71.4% | 重要的没漏 |
| 准确 | Σ(0.5 × 分数) ÷ 卡片总数 | 66.7% | 不瞎编 |
| 目标精确 | 只看命中标准答案的那几张 | 100% | 该记的记得准 |
| 抗诱饵 | 躲过 1 条 ÷ 诱饵 2 条 | 50% | 不被诱饵带偏 |
| F1 | 召回与准确的调和平均 | 75% | 又全又准 |
后两行的算术展开,一眼就能验:
加权召回的分子 = 0.5×2×1.0(姓名)+ 0.5×2×0.75(住址)+ 0.5×2×0.5(金毛)+ 0.5×1×0.5(生日只记了年,得1分)+ 0.5×0×0.75(专业没记到)= 1.0 + 0.75 + 0.5 + 0.25 + 0 = 2.5;分母 = 1.0+0.75+0.5+0.5+0.75 = 3.5;2.5÷3.5 ≈ 71.4%。
准确的分子 = 0.5×2(姓名)+ 0.5×2(住址)+ 0.5×2(金毛)+ 0.5×1(生日只记年)+ 0.5×0(编造"医生")+ 0.5×1(诱饵是 assistant 说过的话,有对话依据但非用户原意,得1分)= 1+1+1+0.5+0+0.5 = 4;卡片总数 = 6;4÷6 ≈ 66.7%。
更新和问答的指标更简单,就是"分几个筐,各筐数量 ÷ 总数"。比如更新里改对 2、改错 1、忘改 2,就是改对 40% / 改错 20% / 忘改 40%;问答里答对 3、答错 1、答不出 1,就是 60% / 20% / 20%。
这里要提醒 §0 说的坑二,两个口径都写在代码里、论文没细说:
其一,召回的分子只认"完全记对"(2 分),记了个大概(1 分)不算数;而加权召回会把 1 分也按重要度折算进去。所以通常加权召回会不低于召回,但并非永远如此——当"完全记对的恰好是那些不重要的、漏掉的恰好是最重要的"时,两者会反过来(因为一个按条数算、一个按重要度算,分母不一样)。
其二,更新的分母不是全部"该更新"的记忆,而只是那些"系统还检索得到相关记忆"的更新;完全检索不到的,会被算去"漏记"。论文写的分母是全体,代码实际用的更小。这也是坑一里那个现象的来源。
(还有一个措辞上的小提醒:抗诱饵率论文里只定义了一种,代码里则叫 interference_accuracy,另有一个"只除以裁判成功判定的诱饵数"的变体;看排行榜时以论文口径为准。)
6. 结果与关键发现
排行榜有两版。表里的 R 是抽取召回、F1 是抽取 F1、FMR 是抗诱饵率,更新和问答的 C/H/O 分别是改对(答对)/ 改错(答错)/ 忘改(答不出)。箭头朝上表示越高越好、朝下越低越好,加粗是该列最优。
先看常规规模(HaluMem-Medium),按抽取召回排:
表 7 HaluMem-Medium 排行榜(约 160k 上下文)
| 系统 | 抽取R↑ | 抽取F1↑ | FMR↑ | 更 C↑ | 更 H↓ | 更 O↓ | 答 C↑ | 答 H↓ | 答 O↓ |
|---|---|---|---|---|---|---|---|---|---|
| MemOS | 74.1 | 79.7 | 44.9 | 62.1 | 0.42 | 37.5 | 67.2 | 15.2 | 17.6 |
| Mem0-Graph | 43.3 | 57.9 | 55.7 | 24.5 | 0.26 | 75.2 | 54.7 | 19.3 | 26.1 |
| Mem0 | 42.9 | 57.3 | 56.8 | 25.5 | 0.45 | 74.0 | 53.0 | 19.2 | 27.8 |
| Supermemory | 41.5 | 56.9 | 51.8 | 16.4 | 1.15 | 82.5 | 54.1 | 22.2 | 23.7 |
| Memobase | 14.6 | 25.1 | 80.8 | 5.2 | 0.55 | 94.3 | 35.3 | 30.0 | 34.7 |
| Zep | – | – | – | 47.3 | 0.42 | 52.3 | 55.5 | 21.9 | 22.6 |
再看长上下文(HaluMem-Long,约 1M):
表 8 HaluMem-Long 排行榜(约 1M 上下文)——注意 Mem0 系从 Medium 到这里的断崖
| 系统 | 抽取R↑ | 抽取F1↑ | FMR↑ | 更 C↑ | 更 H↓ | 更 O↓ | 答 C↑ | 答 H↓ | 答 O↓ |
|---|---|---|---|---|---|---|---|---|---|
| MemOS | 81.9 | 82.1 | 28.9 | 65.3 | 0.29 | 34.5 | 64.4 | 16.6 | 19.0 |
| Supermemory | 53.0 | 65.5 | 36.9 | 17.0 | 0.58 | 82.4 | 53.8 | 22.2 | 24.0 |
| Memobase | 6.2 | 11.6 | 85.4 | 4.1 | 0.36 | 95.4 | 33.6 | 29.5 | 37.0 |
| Mem0 | 3.2 | 6.2 | 87.7 | 1.45 | 0.03 | 98.5 | 28.1 | 17.3 | 54.6 |
| Mem0-Graph | 2.2 | 4.4 | 88.4 | 1.47 | 0.04 | 98.4 | 32.4 | 21.8 | 45.7 |
| Zep | – | – | – | 37.4 | 0.48 | 62.1 | 50.2 | 22.5 | 27.3 |
几个值得记住的读法:
MemOS 综合最强,但"领先"要看是哪一列。它在召回、抽取 F1、更新改对、问答答对这些主指标上两版都第一。可它在抗诱饵率和更新改错率这两列却不是第一——排在它前面的是 Memobase、Mem0 这类记得极少的保守系统。原因不难想:记得少,自然不容易把诱饵也记进去(所以 FMR 高)、也不会主动去改写记忆(所以改错率低)。这两项上的"领先"其实是漏记的副产品,不代表系统更好。
这就引出坑一:更新的改错率几乎全系统接近 0,看着漂亮,实则说明更新失败几乎都变成了沉默的漏改——因为系统在更新这步可以不吭声,而要"改错"得主动写出一条错记忆,反而少见。最极端的是 Mem0 的 Long 版:改对 1.45%、改错 0.03%、忘改 98.51%,改错率全场最低,却是最不干活的系统。所以改错率必须连着改对、忘改一起看。相比之下,问答的答错率就高(15%~30%),因为答题被逼着开口、更容易编。跨任务直接比"错误率"是没意义的。
再看两版之间的落差,就能直观看到误差怎么传递。上下文从 160k 拉到 1M 之后,弱系统上游一崩,下游跟着塌:

图 5 误差传递(以 Mem0 从 Medium 到 Long 为例):上游抽取的漏,一路放大到更新和问答。这正是操作级分层的价值——能指出病根在最上游。
最后两条:复杂任务确实更难,多跳、动态更新、泛化的准确率都明显低于基础事实回忆;而"写记忆"是真正的瓶颈——抽取加更新的耗时远高于检索(Mem0 光是加对话就花了 2768 分钟,检索只用 42 分钟),这提示真实部署里,写入成本可能比检索成本更值得优化。
7. 优缺点,以及和 LoCoMo / LongMemEval 的差别
先说它好在哪:
-
方法论上是真进步:第一个操作级的记忆幻觉基准,能定位病根、能量化误差传递。
-
把"漏"和"编"清楚分开,抽取还用了双向打分,覆盖了两类互补的错误。
-
数据是"上帝视角"造出来的,真值、诱饵、证据全都预先可控。
-
覆盖面广:三类记忆、六类问题、最长 1M 上下文,外加抗诱饵。
-
有人工质检背书,代码和数据都开源。
再说要留神的地方:
-
中立性。HaluMem 由 MemTensor 构建,和榜首 MemOS 同组织、作者高度重叠。数据公开可核、并非造假,但横向排名要谨慎看待。
-
重度依赖 LLM 裁判。成本高、有波动(人工核对裁判正确率 95.7%,不是 100%),判定口径由 prompt 决定。
-
接口门槛高。黑盒或 agentic 系统很难完整评测,缺接口就整块指标记空。
-
没有细粒度检索指标。它不单独评检索,所以没有 recall@k / ndcg,检索好坏只能隐含在最终结果里。
-
数据同源风险。数据全由 LLM 生成,与真实对话分布有差异;"用 LLM 造的数据评 LLM 系统"存在同源偏差。
-
语言单一。以英文为主,跨语言和垂直领域没有验证。
-
口径藏在代码里。前面反复提到的召回只认完全记对、更新分母偏小、改错率易误读,都属于此;另外复现时还有一个 version 硬编码的坑(见附录)。
-
数据质量瑕疵。核对金毛那条 session 的原始对话文件时发现,标称 26 轮,其中后 14 轮是前面 6 轮的完全逐字复制(一模一样的六轮循环了三遍),真正独有的内容只有约一半。这说明生成对话时存在循环填充,所以"对话轮数、token 长度"这类规模数字会高估真实信息量——用长上下文相关的结论时要打个折。这一条论文没有提到,是本报告在原始数据里独立核实出来的。
最后,把它放到同类里比一比,最能看清它的取舍:
表 9 三种记忆评测范式对比:对"记忆是什么"的假设决定了打分方式
| LoCoMo | LongMemEval | HaluMem | |
|---|---|---|---|
| 评测粒度 | 端到端 | 端到端 | 操作级 |
| 把"记忆"当成 | 原始对话片段 | 原始对话片段 | 抽取改写后的新句子 |
| 怎么对齐打分 | 证据 ID + 词面匹配 | 证据 ID(recall@k 等)+ LLM 裁判 | 纯 LLM 语义比对,不靠 ID |
| 检索诊断 | 有(仅 RAG 模式) | 有(强,独立一条线) | 无 |
| 测更新 | 否 | 是 | 是(直接对记忆库打分) |
| 测抽取失真 | 否 | 否 | 是(召回+准确+抗诱饵) |
| 最大上下文 | ~16K(发布版实测) | ~115K(S)/ ~1.5M(M) | ~1M |
差别的根子在于对"记忆"的假设不同。LoCoMo 和 LongMemEval 认为记忆就是原文片段,天然带 ID,于是能用又便宜又精确的 recall@k;HaluMem 认为现代系统的记忆是被嚼碎、改写过的新句子,没有原文页码可对,只能比意思,因此全程用语义比对、也就放弃了 ID。两种做法没有高下,是被各自的"记忆形态"逼出来的——评"存原文 / RAG 型"的系统用 ID 那派,评"抽取改写型"的现代记忆系统用语义这派。
8. 结论与适用场景
如果你的系统是"抽取改写型"(Mem0 / MemOS 这类)、能提供三个接口,而你又关心"幻觉到底出在哪一步、怎么往下游传",那么 HaluMem 很合适,它还能顺带给你多类型记忆、长上下文、抗干扰的综合压力测试。反过来,如果系统是黑盒或自主 agent、你需要 recall@k 这种细粒度检索诊断、或者场景是非英文或垂直领域,那它要么用不了、要么得改造。
一句话总结:HaluMem 把记忆评测从"黑盒看答对率"推进到了"白盒看每一步的幻觉",方法论上是实打实的进步,"分清漏与编 + 三任务分层 + 误差传递"这套框架尤其值得借鉴。但用它的时候要清醒——它是一把诊断尺子,不是中立裁判:依赖 LLM 打分、接口门槛高、没有检索指标、数据有生成瑕疵,而且出自榜首系统的同一批作者。把它当成"该怎么测记忆幻觉"的优秀范本,比当成"谁最强"的权威排名,要稳妥得多。
9. 附录
9.1 术语速查
| 术语 | 一句话 |
|---|---|
| 漏 / Omission | 该有的没有(没记、没改、答不出),表现为"空白 / 不知道" |
| 编 / Hallucination | 冒出了假的(捏造、改错、答矛盾),表现为"言之凿凿但错" |
| 记忆点 memory point | 一条该被记住的事实,带类型、重要度、是否更新、旧版溯源 |
| 诱饵 interference | 对话里 AI 顺嘴引申、用户没确认的错误信息,好系统不该记 |
| FMR | 抗诱饵率 = 躲过的诱饵 ÷ 诱饵总数 |
| 查漏 / 查编 | 抽取的双向打分:查漏站标准答案找覆盖(召回),查编站系统记忆核依据(准确) |
| 三接口 | 喂入对话 / 取回抽出的记忆 / 按查询检索——被测系统必须提供 |
| gold | 数据自带的标准答案,与系统实际产出对照打分 |
9.2 复现要点与已知坑
-
从 HuggingFace
IAAR-Shanghai/HaluMem下载数据放进data/(仓库内只有构造中间产物)。 -
配置
eval/.env(OpenAI 裁判 + 各系统 key)。 -
分两步:先
python eval_memzero.py跑答卷,再python evaluation.py --frame memzero --version <xxx>打分。 -
version 硬编码坑:
eval_memzero.py#L331末尾硬编码了version="long",而evaluation.py默认--version default,两处必须手动对齐,否则打分脚本读不到结果目录。
9.3 代码索引
| 看什么 | 位置 |
|---|---|
| 指标聚合总入口 | evaluation.py |
| 抽取查漏 / 查编两个循环 | 查漏 #L58 · 查编 #L87 |
| 召回只认完全记对 | #L229 |
| 更新分母门槛 | #L59 |
| 按三类记忆分组 | #L364 |
| 四个裁判 prompt | 召回 #L4 · 准确 #L68 · 更新 #L161 · 问答 #L218 |
| 三接口示例 | 喂入 #L75 · 检索 #L97 · 取抽取结果 #L204 |
9.4 参考资料
-
论文:arXiv:2511.03506 · PDF · OpenReview
-
代码 / 数据:github.com/MemTensor/HaluMem · HuggingFace IAAR-Shanghai/HaluMem
-
中立性佐证:MemTensor 组织 · MemOS 论文 arXiv:2505.22101(作者与 HaluMem 高度重叠)
-
第三方综述:themoonlight.io 评论
-
写作标准参考:Mernst《How to write a technical paper》 · survey 写作方法论 arXiv:2509.25828
调研时间 2026-07。基于论文、开源代码与公开资料,未运行 pipeline;代码行号、指标数字、论文数据、§7 数据瑕疵均经一手核对,指标手算已离线复现。§6–8 的判断与 §7 数据瑕疵含作者独立核对,供参考。