调研对象:VehicleMemBench(An Executable Benchmark for Multi-User Long-Term Memory in In-Vehicle Agents),arXiv:2603.23840,2026-03。
材料来源:论文 PDF、当前仓库的全部
benchmark/、environment/、evaluation/与示例脚本;另参照同目录的 HaluMem、LoCoMo、LongMemEval 调研以做横向定位。
贯穿全文的真实样例:
qa_1.json的第 0 题。Gary 想恢复自己常用的“平静氛围”,但车里还有喜欢白色仪表盘的 Patricia、喜欢蓝色的 Justin;正确动作是把仪表盘设为绿色。
摘要
VehicleMemBench 把“长期记忆是否有用”落到可执行结果上。系统不只要回答 Gary 喜欢什么颜色,还要从多人长期历史中找回他的偏好,选择正确的车机 API,并把虚拟车辆调整到标准状态。这个设计比纯问答更接近工具型 Agent 的实际链路,但主分数同时受记忆、检索、LLM 推理和工具执行影响,不能只凭最终 ESM 判断故障发生在哪一环。
每个场景包含一辆由三名固定使用者共享的虚拟车、一份长期历史和十道新请求。Agent 可以检索记忆、发现车机工具,并调用 carcontrol_instrumentPanel_set_color 等 API。评测器把模型动作作用到一份虚拟车状态,把标准动作作用到另一份,再比较两者。仓库覆盖 23 个可控模块和 111 个 API。
论文中,无记忆设置下表现最好的 Gemini-3-Pro-Preview 得到 19.43 ESM;提供 Gold Memory 后达到 90.60 ESM。同一模型使用递归摘要时为 64.80 ESM,比 Gold Memory 低 25.8 点。这组结果表明,当前请求不足以让模型直接猜中答案,正确记忆和正确工具执行也是两项可以分开的能力。
阅读和复现时需要把握三个边界:
-
它测的是记忆带来的任务效用,不是记忆库的纯质量。代码会记录检索调用和工具序列,但主聚合指标不计算检索结果相对标准记忆的 Recall@k、Precision@k,也不测写入是否完整。
-
接入是 adapter 开发,不是填一个 URL。当前 CLI 只接受 Mem0、MemOS、LightMem、Memobase、Supermemory 五个硬编码名字。自己的系统需新增 Python adapter,至少实现历史写入、按用户检索、结果文本化等约定。
-
当前实现是离线全历史写入。每份
history_N.txt会完整灌入记忆系统后,再评该场景的十题;代码没有按题目发生时间截断可见历史。因此它测“完成一段长期历史后的检索”,不是严格防未来信息的在线会话回放。
它适合检查“记忆系统 + 工具型 Agent”能否完成会改变外部状态的任务,也适合验证接入不同记忆后端后的端到端收益。若目标是单独比较检索 Recall@k / NDCG、定位写入或更新阶段的丢失,仍需搭配 LongMemEval、HaluMem 或自建过程指标;它也不能替代真实车载环境中的安全和物理行为验证。
1. 评测对象与核心流程
先不要把 VehicleMemBench 想成“一个问答数据集”。它更像一场给 Agent 的驾驶舱操作考试:试卷先给它一段很长的多人聊天记录,最后只给一句模糊的车机请求;它必须自己查记忆、自己找到正确的车机函数、自己执行操作。裁判不看它说得是否漂亮,只看虚拟车有没有被调到标准状态。
它的核心目标可以写成:
它测的不是「模型能否说出偏好」,
而是「接上记忆后,Agent 能否把虚拟车调成偏好要求的状态」。
1.1 先看全局:四块拼成一个 benchmark
下面这张图把全文最重要的对象放在一起。读后续章节时,只要沿着“数据从哪来 → 哪种评测用它 → Agent 对车做什么 → 怎么判分”这条线走,就不会把数据集、模拟器和记忆系统混成同一件事。

图 0 VehicleMemBench 的全局结构:数据集提供历史和标准动作;模型评测或外部 memory adapter 驱动 Agent;最终统一在 VehicleWorld 的状态上判分。
这张图有一个容易忽略的要点:被测的 memory system 并不直接操作车辆。它只负责把历史写进去、在 Agent 请求时返回相关记忆;真正决定动作的是 LLM Agent,真正被比较的是两份虚拟车的最终状态。
1.2 先在 30 秒内跑完一题
以下图中的每一步都发生在一次真实评测中。Gary 的颜色偏好只是一个例子;换成座椅、空调、导航或车窗,链条不变。

图 1 一题的最短链条:历史不是直接送进评分器,而是要先经记忆、推理与工具调用,最后才落到可比较的车辆状态。
这张图也解释了“为什么需要工具”。如果题目只问“Gary 喜欢什么颜色”,答案是文本;但真正的车机助手需要让仪表盘变绿,所以必须调用能改变状态的函数。仓库里的 VehicleWorld 是一辆在内存中的虚拟车,不是实体汽车,也不是连接车厂云端的真实 API。
1.3 它为什么不是普通记忆问答
传统长期记忆 benchmark 的终点通常是“问一个问题,看答案是否正确”。这能测模型是否找回事实,却绕开了 Agent 落地时更麻烦的后半程:谁的偏好应当优先、该调用什么工具、参数填什么、以及是否误动了别的设备。
车载场景把问题放大得很自然。一辆共享汽车有多个长期使用者;“把灯调回舒服的状态”不是一个确定指令,而是需要识别当前人、历史偏好、时间、天气、地点与乘客关系。即使模型回了一句“已为你调整”,也不能说明车真的被调对。
VehicleMemBench 的核心选择是:给 Agent 一个可执行的虚拟车,而不是只给标准文本答案。车由 Python 对象 VehicleWorld 表示,包含 HUD、座椅、空调、导航、灯光、车窗等模块;每个车机 API 都会改变对象中的字段状态。最终裁判只问一件事:
模型实际执行后的车辆状态 == 标准动作执行后的车辆状态 ?
这带来两项真优势。
-
不用 LLM 裁判。“绿色还是白色”“驾驶位头枕是否为 44”都落在程序状态里,可重复比较。
-
惩罚多余操作。只把仪表盘调绿是正确;若同时无故改了空调,即使关键颜色正确,完整状态也不一致,Exact State Match 仍失败。
代价也清楚:最终状态是一个端到端信号。失败可能来自没写入偏好、没检索到、检索到了但没理解、找错工具、参数填错、或多调用了无关 API。状态比较能准确发现“车没调好”,但不能自动诊断“记忆在哪一步坏了”。后文 §5 和 §7 会把这个边界拆开。
2. 一个完整例子:Gary 的绿色仪表盘
全文只用 qa_1.json 的第一题说明机制,避免在不同例子之间来回切换。它属于 preference_conflict(偏好冲突):
{
"gold_memory": [
"Justin 喜欢蓝色仪表盘。",
"Gary 说绿色仪表盘让他想起森林,喜欢绿色。",
"Patricia 夜晚觉得绿色太暗,改成白色。"
],
"query": "Gary 坐在驾驶位,Patricia 是乘客;"
"Gary 说:让我们恢复我平常那种平静氛围。",
"new_answer": [
"carcontrol_instrumentPanel_set_color(color=\"green\")"
]
}
这里至少有四件事不能混:
| 信息 | 它的作用 | 谁能看见 |
|---|---|---|
完整 history_1.txt | 真正的长期对话,含大量无关聊天 | 写入阶段给记忆系统 |
gold_memory | 本题相关事实的人工整理片段 | 仅 Gold Memory 模式直接给 Agent;也可供离线审计 |
query | 当前要执行的新请求 | 被测 Agent |
new_answer | 标准动作序列 | 评测器,不给 Agent |
为什么答案是绿色。当前驾驶者是 Gary;“平常”“平静氛围”指向他自己的绿色偏好。Patricia 的白色偏好有“夜晚看不清”这个条件,且她现在只是乘客;Justin 的蓝色偏好也不属于当前人。正确动作不是复述“Gary 喜欢绿色”,而是实际调用设色 API。
这类题最难的地方不是记住三种颜色,而是把“历史事实”筛成“当前情境下该生效的事实”。可以把 Gary 题的判断过程看成下面三次过滤;它描述的是这道题的推理,不是代码里写死的一条“驾驶者永远优先”的通用规则。

图 2 多人偏好如何落到一个动作:不是取“最新一次设置”,而是同时过滤人物、条件和指代,再得到本题应生效的偏好。
2.1 两份“车”不是两辆实体车
每题运行时,评测程序在内存中新建两个相同的 VehicleWorld() 对象:
初始状态:仪表盘颜色 = white
参考副本 vw_ref:执行标准动作 set_color(green)
→ 参考最终状态:颜色 = green
模型副本 vw_pred:执行模型实际选择的动作
→ 模型最终状态:由模型决定
若模型调用 set_color("white"),模型副本没有完成应有的变更;若调用 set_color("green") 后又改了空调,模型副本多出不应有的变更;两种都不能 Exact Match。只有最终完整状态与参考副本相同才算通过。
这就是“可执行”的准确含义:不是连真车,也不是调用某个云端车机服务,而是执行仓库内自己定义的 Python 方法。InstrumentPanel 的默认颜色为 white,carcontrol_instrumentPanel_set_color 会校验并写入其 color 属性。
3. 数据长什么样:50 份长期多人历史,挂 500 道可执行题
一条 benchmark 样本不是“一问一答”。正确的心智模型是“50 套共享车辆档案,每套有一本长历史和十道操作题”:
benchmark/
├── history/history_1.txt ─┐
├── qa_data/qa_1.json ─┘ 同一组三名用户;10 个新请求
├── history/history_2.txt ─┐
├── qa_data/qa_2.json ─┘ 下一组独立用户;10 个新请求
└── ...
本地数据统计与论文 Table 3 相互印证:50 个用户组、每组三人,合计 150 个 persona、500 条可执行查询。论文还报告每组由 30 条事件链交织而成,平均 81.78 个事件、2,690 行 / 92,819 GPT-4o tokens 的历史。
表 1 本地发布数据的离线统计——历史很长,题目本身很短
| 对象 | 数量 / 范围 | 说明 |
|---|---|---|
history_N.txt | 50 份 | 每份对应一个三人用户组 |
qa_N.json | 50 份 | 每份恰有 10 个可执行请求 |
| 总请求 | 500 | 每题含 query、reasoning type、标准动作 |
| 历史字符数 | 28.4 万 ~ 44.3 万;中位数 33.0 万 | 全量约 1,684 万字符 |
| 历史覆盖天数 | 38 ~ 77;中位数 46.5 | 由每行时间戳离线统计 |
| 历史行数 | 2,382 ~ 3,469;中位数 2,642 | 对话与事件穿插 |
| 每题 Gold Memory 长度 | 104 ~ 621 字符;中位数 306 | 仅相关证据摘要,不是完整历史 |
| 参考动作数 | 432 题 1 个、64 题 2 个、4 题 3 个 | 多动作题会同时改变多个字段 |
3.1 五种“记忆为什么会难”的类型
表 2 五类推理任务分布——偏好冲突最多,条件约束是论文中最难的一类
| 类型 | 数量 | 占比 | 它在考什么 | Gary 题对应什么 |
|---|---|---|---|---|
| Preference Conflict | 149 | 29.8% | 多人偏好冲突时识别当前应优先谁 | Gary / Patricia / Justin 对仪表盘颜色不同 |
| Conditional Constraint | 102 | 20.4% | 同一偏好只在时间、天气、地点、活动等条件下成立 | “工业区开内循环”“夜间白色面板” |
| Coreference Resolution | 97 | 19.4% | “他的最爱”“上次那个设置”究竟指谁、指哪条历史 | “把灯设成他喜欢的颜色” |
| State Shift | 90 | 18.0% | 偏好或状态后来改变,应使用新值而非旧值 | 治疗建议后按摩强度从 2 改为 3 |
| Error Correction | 62 | 12.4% | 用户纠正过一次,应记住纠正后的值 | 通风 3 太强,舒适值应为 2 |
五类任务均有自然语言表面形式,但其标准答案都是可解析的工具调用字符串。论文的目标模块分布以导航 96 题、座椅 85 题、灯光和空调各 64 题为主,其余模块合计 108 题;这避免 benchmark 只在单一设备上成立。
3.2 数据如何构造
数据不是从真实车机日志采集的,而是 persona 与事件链驱动的合成数据。图 0 已给出它在全局流程中的位置;它的内部顺序可压缩为五步:三人 persona → 车载与非车载偏好事件链 → 按时间交织 → 生成并人工核查长对话 → 生成、人工复核且在模拟器中验证 query 与标准动作。
特别重要的是第二步:每组不仅有 10 条可执行的车载偏好链,还有 20 条不直接控制车辆的背景链。历史中会有工作、旅行、家人、爱好等看似真实却无关的聊天。被测系统若把所有信息都压进记忆,不一定更好——它可能在检索时把噪声一并递给 Agent。
4. 评测怎样运行:写入记忆、检索、调车、对状态
VehicleMemBench 有两条相关但不同的评测路径。第一条是“模型在不同内置记忆构造下表现如何”;第二条才是“把一个外部记忆系统接进来后表现如何”。
先区分两条路径,再看各自细节。两者都用同一批 QA、同一个 VehicleWorld 和同一套状态指标;差别只在 Agent 在做题前如何获得历史信息。

图 3 两套评测方法的关系:A 测同一模型在不同“记忆供给方式”下的表现;B 测“外部 memory + 固定 Agent”这套组合的端到端效用。
4.1 模型评测:四种记忆条件
| 模式 | Agent 在做题时拿到什么 | 主要隔离什么 |
|---|---|---|
none | 只有当前 query,没有历史 | 无记忆下的下限 |
gold | 本题的 gold_memory | 给定正确记忆后的工具与推理上限 |
summary | 对整份历史按天递归更新的摘要 | 压缩记忆能否保住关键偏好 |
key_value | LLM 逐日写入的键值库;做题时可 memory_search / memory_list | 结构化记忆与按键检索 |
README 把 none 叫作 “Raw History”,但源代码实际对该模式传入空历史;它是无记忆基线,并非把完整原始历史塞给模型。这是文档和实现的一个小口径差异。
摘要模式会按日期分组,提示 LLM 只保留车载偏好、条件、冲突和纠错;代码希望摘要少于 2,000 词,并把超过 8,192 字符的单次记忆截断。KV 模式也明确要求丢弃与车辆无关的生活信息,再通过 memory_add/remove/search 维护偏好键值。
4.2 外部记忆系统评测:真正的接入路径
外部系统评测分两个阶段。第一阶段先把一份完整历史灌入某个记忆后端;第二阶段让 LLM Agent 在每个新请求中自主决定是否搜索、搜索什么、再调用车机工具。图 3 的 B 路径说明了两阶段的边界:add 发生在做题之前,test 才发生检索和车辆操作。
Agent 一开始并不会得到全部 111 个工具,而是先看到 list_module_tools(module_name)。它要先决定“这是仪表盘问题”,加载 instrumentPanel 模块的函数 schema,再能调用具体 API。这个设计既能测工具发现,也避免把全量 schema 直接塞入 prompt。
外部记忆模式额外提供 search_memory(query, top_k);代码要求“请求依赖历史偏好时先查记忆”,但 LLM 是否遵循仍是被测行为。每次搜索、工具发现、车辆调用都写入逐题结果。
4.3 标准动作如何变成目标状态
new_answer 不是直接拿来和模型输出字符串比,而是先被解析成 {name, args},在参考车对象中执行。例如 Gary 题的标准字符串会让参考车的 instrumentPanel.color 从 white 改为 green。
模型的实际函数调用作用在另一份车对象上。最后,评测器递归展开初始状态、参考最终状态、模型最终状态的所有标量字段,找出应变字段、已变字段、错误值与意外变更。顺序不同但最终状态相同可以通过状态指标;相反,工具名看似合理但末状态不对也会失败。
5. 指标与一遍手算:状态是主判据,过程只被记录
论文定义的主指标围绕状态变化。设初始状态为 v_init,标准动作执行后为 v_ref,模型执行后为 v_pred:
Δref = 相比 v_init,标准答案应该改变的字段集合
Δpred = 相比 v_init,模型实际改变的字段集合
状态指标的对象不是“模型回复的文本”,而是四份可比较的状态:一份初始车、标准动作后的参考车、模型动作前后的模型车。为了便于理解,当前实现把两条路径都从同样的初始状态展开:

图 4 状态评分究竟在比什么:它比较两条动作路径造成的字段变化,而不是直接比较两段自然语言或两个工具字符串。
表 3 官方状态指标——同一答案可从“是否完成”“改对字段”“填对值”“是否乱动”四个角度看
| 指标 | 代码中的含义 | 高分说明 |
|---|---|---|
| Exact State Match(ESM) | 没有差异、没有意外变更、没有应变未变 | 整辆虚拟车完全对 |
| 字段 Recall / Precision / F1 | 字段是否应该变、是否实际变 | 找到正确的控制目标,且不乱动 |
| 值级 Change Accuracy / F1 | 应变字段中,最终值是否等于参考值 | 绿色、44、inside 等参数也对 |
| 负向 Accuracy / F1 | 本应不变的字段是否维持不变 | 没有把无关设备调坏 |
| 平均调用数 / 输出 token | 每题交互量与模型输出量 | 执行成本低 |
代码还对模型工具序列计算了精确的 Tool-call F1:工具名和全部参数序列化后必须匹配才算 TP。不过它保存在每题 all_results.json 的 tool_score 中,当前 metric.json 并没有聚合输出 Tool-call F1;需要自行汇总。
5.1 用 Gary 题手算
初始时,仪表盘颜色为 white。标准答案只改一个字段:
Δref = { instrumentPanel.color : white → green }
下表分别演示四种模型行为。这里先只关注颜色与额外空调字段,其他状态均保持初始值。
表 4 Gary 题的手算账本——“改了正确字段”并不等于“最终正确”
| 模型实际操作 | Δpred 的关键内容 | 字段 TP / FP | 值正确数 | ESM | 解释 |
|---|---|---|---|---|---|
| 不调用工具 | 空集 | 0 / 0 | 0 | ❌ | 应改颜色却没改,属于应变未变 |
set_color("black") | 只改颜色,但值错 | 1 / 0 | 0 | ❌ | 字段 Recall=1,但值级 F1=0 |
set_color("green") + 无故改空调 | 颜色正确,外加空调 | 1 / 1 | 1 | ❌ | 字段 Precision=1/2,存在意外变更 |
set_color("green") | 只改颜色且值对 | 1 / 0 | 1 | ✅ | 状态与参考车一致 |
第三行可把 F1 真正算一遍。模型改了两个字段,其中仪表盘颜色是应变字段、空调不是:
字段 Precision = TP / (TP + FP) = 1 / 2
字段 Recall = TP / |Δref| = 1 / 1
字段 F1 = 2 × 1/2 × 1 / (1/2 + 1) = 2/3
值级 Precision = 正确值数 / (TP + FP) = 1 / 2
值级 Recall = 正确值数 / |Δref| = 1 / 1
值级 F1 = 2/3
ESM 仍为 0,因为它不是“平均正确率”,而是“完整状态是否全对”的严格门槛。这恰好是本 benchmark 相对纯 QA 的强项:它能区分“核心偏好找对了但做了多余操作”和“真正完成了任务”。
5.2 过程指标的缺口
外部记忆评测的逐题结果会保存:
-
memory_tool_calls:调用了什么检索 query; -
num_memory_calls:检索次数; -
pred_call_outputs:每次工具返回; -
tool_score:标准动作与模型动作的精确匹配; -
state_score:状态级 TP / FP / 差异。
但聚合器只平均 ESM、字段/值指标、总调用数与输出 token;它不把检索文本同 gold_memory 做语义或事实对齐。因此,以下问题官方不会直接回答:
-
记忆系统是否写入了 Gary 喜欢绿色这条事实?
-
Agent 搜索 “Gary preference” 时,前
k条是否包含这条事实? -
检索到了绿色,但 Agent 是否因为 prompt、工具 schema 或推理失误没有使用?
-
记忆系统是漏掉了事实,还是取回了很多无关事实导致决策受干扰?
把这件事画出来会更直观:同样一个 ESM=0,可能代表完全不同的工程问题。

图 5 端到端状态分数的归因盲区:不同根因会汇聚成同一个失败结果,因此需要读取逐题日志并补检索审计。
论文讨论的 MemoryScore = ESM_auto / ESM_gold 和 MemToken 能在概念上缓解这个问题:前者用 Gold 上界归一化,后者衡量检索内容量。但当前仓库的 metric.json 实现没有计算 memory_score 或 mem_token,只输出 avg_output_token。使用者不能把论文图表中的字段误认为“一跑仓库就会得到”。
6. 论文结果与关键发现
论文报告了 12 个模型的内置记忆构造实验,以及两种 backbone 上若干外部记忆系统的接入实验。以下数字均来自论文 Table 1、2、6;并非本文本地复跑的结果。
6.1 Gold Memory 把“工具能力”与“记忆能力”分开
表 5 三种记忆条件下的代表性 ESM——Gold 是上界,不是可部署方案
| 模型 | Recursive Summary | Key-Value Store | Gold Memory | Gold → Summary 落差 |
|---|---|---|---|---|
| Gemini-3-Pro-Preview | 64.80 | 57.37 | 90.60 | 25.80 |
| Qwen3-Max | 60.60 | 46.60 | 83.60 | 23.00 |
| GPT-5 | 61.20 | 52.40 | 81.60 | 20.40 |
| Doubao-Seed-1.6 | 59.00 | 26.60 | 85.40 | 26.40 |
| GLM-4.7-Flash | 24.20 | 19.60 | 55.40 | 31.20 |
读法有两层:
Gold 高,不表示记忆系统强。 Gold Memory 是把正确相关事实直接塞给 Agent,因此更接近“模型在已知偏好时会不会选工具、填参数”。Gemini 的 90.60 证明该模型在这个虚拟车环境里有很强的执行上限;GLM-4.7-Flash 的 55.40 则提示即使记忆正确,工具调用能力仍可能成为瓶颈。
Summary / KV 到 Gold 的缺口,才是端到端记忆损失。 Gemini 从 90.60 到 64.80,Qwen3-Max 从 83.60 到 60.60。论文据此认为,历史压缩与取用比单纯工具执行更常成为误差来源。需要谨慎的是:这个差值仍包含 Agent 接收、理解、利用记忆时的失败,不能直接等同于“记忆库自身的 Recall 损失”。
无记忆实验进一步支持任务确实依赖历史:论文中所有模型 ESM 都低于 20,Gemini-3-Pro-Preview 为 19.43。模型无法只从“恢复我常用的氛围”猜到 Gary 的绿色偏好。
6.2 通用记忆系统不一定胜过朴素的领域基线
表 6 外部记忆系统结果(ESM / Mem Token)——读法重点是“端到端效用与上下文成本”
| Backbone | 系统 | ESM | Mem Token |
|---|---|---|---|
| Gemini-3-Pro-Preview | Gold Memory | 90.60 | 93.29 |
| Gemini-3-Pro-Preview | Recursive Summary | 64.80 | 303.25 |
| Gemini-3-Pro-Preview | Key-Value Store | 57.37 | 29.25 |
| Gemini-3-Pro-Preview | LightMem | 60.72 | 170.19 |
| Gemini-3-Pro-Preview | Mem0 | 52.10 | 171.16 |
| Gemini-3-Pro-Preview | MemOS | 56.11 | 444.91 |
| Gemini-3-Pro-Preview | Supermemory | 65.79 | 960.79 |
| Gemini-3-Pro-Preview | Memobase | 29.40 | 993.49 |
| Qwen3-Max | Recursive Summary | 60.60 | 215.22 |
| Qwen3-Max | Key-Value Store | 46.60 | 26.03 |
| Qwen3-Max | Supermemory | 58.20 | 972.19 |
论文的主要发现是:简单、任务定制的递归摘要和 KV baseline 具有很强竞争力;若干通用 memory system 并未稳定超过它们。原因并不一定是某个后端“没有记忆”,也可能是通用系统保留了许多与车机决策无关的信息,检索阶段把噪声递给 Agent。这个解释与数据构造中 20 条背景链的设计是对应的。
条件约束最难。 在 Qwen3-Max + Recursive Summary 下,Preference Conflict 为 67.79,而 Conditional Constraint 仅 51.96;KV 下则是 61.07 与 38.24。多人冲突可以靠识别当前驾驶者解决;“工业区”“夜间”“雨天”“读蓝图”等条件需要把场景和偏好绑定,后端表示与检索更容易丢失这种关联。
不能只看 ESM。 论文还观察到自主记忆条件下字段级 F1 与值级 F1 的差距扩大:系统可能知道“应该调仪表盘”,但忘了“具体应为 green、white 还是 10”。对车机工具来说,后半步才决定真实状态是否正确。
7. 五项适用边界与复现注意事项
7.1 真盲区:没有独立的记忆写入与检索正确率
这是最重要的限制。VehicleMemBench 通过状态结果间接评价记忆系统;它记录调用过程,却没有用题目 gold_memory 自动计算检索覆盖,也没有检查 memory store 内部是否存有正确事实。
这使它特别适合回答“接上后任务有没有成功”,不适合单独回答“哪个检索器 Recall 更高”。若两个系统都拿 60 ESM,原因可能完全不同:
系统 A:写入完整、检索命中,但 Agent 常把参数填错。
系统 B:Agent 工具很稳,但检索常漏掉条件偏好。
官方成绩单无法自动区分 A 和 B。实践中应在 §8 所述的端到端跑分之外,再做 retrieval-level 审计。
7.2 时序边界:代码是“先完整写入,再统一答题”
run_add 会遍历 history_N.txt 的所有时间桶并写入后端;test 阶段再读取同一 qa_N.json 的十题。查询数据结构不带“只允许读取到哪天”的 cutoff,评测器也没有在搜索时附带或过滤该时间界限。
这并不必然说明发布数据存在未来泄漏——题目设计者可能已确保查询发生在所有相关事件之后——但代码本身没有执行这个保证。若把框架用于自己的在线产品数据,应自行加上 query_timestamp,并让 add / search 严格遵守历史上界。
7.3 接入门槛:是代码 adapter,不是通用插件协议
支持列表写死在 evaluation/memorysystems/init.py,CLI 的 --memory_system 也用同一列表做 choices。传一个未注册服务名会在命令行参数阶段被拒绝。
这有好处:每个 adapter 能处理其后端特有的鉴权、用户隔离、时间戳与结果格式。代价是新系统需要改仓库代码,不能只填 MEMORY_URL。此外,不同后端并不完全等价:有些按小时写入,有些需要单线程或复用本地模型;示例脚本甚至对 LightMem、Supermemory、Memobase 使用了不同文件范围,横向复现时应统一范围。
7.4 论文口径与仓库输出并非完全一致
论文定义并展示了 MemToken、MemoryScore,而当前评测聚合只写 ESM、状态指标、avg_pred_calls、avg_output_token。Tool-call F1 与检索次数保留在逐题 JSON,未在汇总报告中显示。
这不是说论文数字错误,而是说仓库公开的脚本尚未把所有论文分析字段复现为一键输出。做横向实验时,建议保存论文同口径的原始日志并自己补聚合,不要把 avg_output_token 当成 MemToken。
7.5 快速脚本目前不能按 README 的“从根目录运行”直接复现
README 写“从 repository root 运行”,并给出 bash scripts/model_test.sh。但该脚本内部执行的是 python model_evaluation.py,而该文件实际位于 evaluation/model_evaluation.py,根目录没有同名文件。示例脚本的相对路径也像是默认在 evaluation/ 下执行。
scripts/memorysystem_test.sh 虽然正确算出评测脚本绝对路径,但使用了 py 命令;本文撰写环境中该命令不存在。更关键的是,该脚本要求一次性配置所有外部后端的密钥,即使你只想跑其中一个也会被前置检查挡住。
建议做法:不要把示例脚本当作最小可跑入口;直接从仓库根目录运行 python evaluation/memorysystem_evaluation.py add ... 与 python evaluation/memorysystem_evaluation.py test ...,先用一个后端、一个场景、十道题验证 adapter。具体命令见 §11.2。
8. 怎样接入自己的记忆系统
这一节给的是工程接入路径,而不是假装“填配置就能用”。假设你的系统叫 your_memory,它至少要能做到:
写入:add(messages, user_id, timestamp)
检索:search(query, user_id, top_k)
你可以内部使用向量库、图数据库、抽取式 memory、RAG、规则引擎或远端 API;VehicleMemBench 不限制内部实现。它真正要求的是把系统包装成既有 adapter 的形状。
从框架视角看,adapter 有两条完全不同的 I/O 链路:离线写入时接收时间桶对话;在线做题时把后端搜索结果翻译成 Agent 能阅读的文本。只实现其中一条都无法完成完整评测。

图 6 自定义 memory adapter 的边界:上半段负责把历史写进你的系统;下半段负责把检索结果转换为 LLM 可用的上下文。
8.1 最小 adapter 契约
以 evaluation/memorysystems/mem0.py 为模板,新建 evaluation/memorysystems/your_memory.py。五个现有后端都实现了下表函数;没有显式抽象基类,但这是事实上的接口。
表 7 自定义 adapter 的契约——真正需要接通的是“写入”和“检索”两条线
| 函数 | 阶段 | 你要负责什么 |
|---|---|---|
validate_add_args(args) | 写入前 | 检查地址、密钥、模型等必要参数 |
validate_test_args(args) | 评测前 | 检查检索阶段所需配置 |
run_add(args) | 写入 | 读取每份 history_N.txt,逐时间桶调用你的写入 API |
init_test_state(...) | 评测初始化 | 可选:加载共享模型、连接池、索引 |
build_test_client(...) | 每场景 | 返回带 search(query, user_id, top_k) 的客户端 |
format_search_results(raw) | 每次搜索 | 把后端响应转成 (text, count),交给 LLM 阅读 |
is_test_sequential() | 并发控制 | 后端若不线程安全,返回 True |
close_test_state(...) | 清理 | 关闭客户端、释放本地模型等 |
还需在 evaluation/memorysystems/init.py 中 import 并注册:
from . import your_memory
SYSTEM_MODULES = {
# 既有后端 ...
"your_memory": your_memory,
}
评测框架会为第 N 个场景设置 user_id = "your_memory_N"。adapter 必须把它真正传给后端的写入和搜索,不能把 50 个场景混入同一个共享用户空间,否则结果会跨样本泄漏。
8.2 建议的最小验证顺序
先把模型、题目范围、并发全部固定,只替换 memory system;否则得分变化无法归因。
-
基线:跑
none,确认任务不是模型凭 query 猜出来的。 -
执行上界:跑
gold,确认所选 LLM 能理解车辆工具;Gold 很低时不要先优化记忆。 -
你的系统:只跑
history_1.txt/qa_1.json的十题,手看 Gary 题是否检索到绿色偏好。 -
扩大范围:统一跑 50 个场景,保存每题日志。
-
补过程审计:把检索文本与
gold_memory对齐,额外计算事实覆盖、噪声率、检索延迟与写入成本。
第 5 步不是锦上添花,而是回答“为什么 ESM 掉了”的必要条件。一个实用的四格诊断表如下:
| Gold | 你的系统 | 解释 | 优先改什么 |
|---|---|---|---|
| 低 | 低 | LLM 或工具使用能力不足 | 工具 schema、Agent prompt、模型 |
| 高 | 低,且检索漏证据 | memory 写入/检索有问题 | 索引、query rewrite、时间/用户过滤 |
| 高 | 低,且检索命中证据 | Agent 没利用记忆 | 检索结果格式、上下文编排、规划 |
| 高 | 接近 Gold | 端到端记忆效用好 | 再测成本、鲁棒性与线上时序 |
8.3 从根目录运行的最小命令
以下是面向自定义 adapter 的最小结构;密钥以环境变量或 CI secret 注入,勿写进脚本或提交。
# 1. 先只写入场景 1 的历史
python evaluation/memorysystem_evaluation.py add \
--memory_system your_memory \
--history_dir benchmark/history \
--file_range 1 \
--memory_url "$YOUR_MEMORY_URL" \
--memory_key "$YOUR_MEMORY_KEY"
# 2. 用同一场景的 10 个 query 做端到端评测
python evaluation/memorysystem_evaluation.py test \
--memory_system your_memory \
--benchmark_dir benchmark/qa_data \
--file_range 1 \
--api_base "$LLM_API_BASE" \
--api_key "$LLM_API_KEY" \
--model "$LLM_MODEL" \
--memory_url "$YOUR_MEMORY_URL" \
--memory_key "$YOUR_MEMORY_KEY" \
--max_workers 1
输出目录中应至少检查四个文件:
-
results_1.json:该场景逐题结果; -
all_results.json:可审计的memory_tool_calls、工具序列、状态差异; -
metric.json:聚合 ESM 与字段/值指标; -
config.json:模型、范围、并发等复现实验配置。
9. 怎么选:和 HaluMem、LongMemEval、LoCoMo 的根本差别
这四个基准看似都在测“长期记忆”,但它们对“记忆应该怎样被验证”的假设不同。选择的第一问不应是“哪个分高”,而应是“你要定位哪一层”。
表 8 四种范式的对照——VehicleMemBench 的独特性是“可执行状态”,缺口是“检索与写入诊断”
| 基准 | 主要终点 | 是否直接诊断记忆过程 | 是否可执行环境状态 | 检索指标 | 适合什么系统 |
|---|---|---|---|---|---|
| VehicleMemBench | 虚拟车辆最终状态 | ❌,仅间接 | ✅ | ❌,需自己补 | 记忆 + 工具型 Agent |
| HaluMem | 抽取、更新、问答各步的幻觉 | ✅ | ❌ | ❌,以操作级语义判定为主 | 抽取改写型 memory,想定位漏与编 |
| LongMemEval | 检索证据 + 最终回答 | ✅,检索/阅读两条线 | ❌ | ✅,依赖 session ID | 原文存储 / RAG 型 memory |
| LoCoMo | 长期对话问答、事件总结、生成 | 部分,按任务结果 | ❌ | 仅特定 RAG 设定 | 超长对话理解、多模态、时间与因果 |
VehicleMemBench 与 HaluMem 是互补,不是替代。 HaluMem 把记忆系统的抽取、更新、问答拆开,适合问“偏好改写为什么错”;VehicleMemBench 不看 memory card 本身,而是问“错误有没有让车辆操作失败”。前者白盒诊断强,后者环境后果更真实。
VehicleMemBench 与 LongMemEval 的差异在于可归因性。 LongMemEval 为每题标记证据 session ID,因此能分别算检索是否找回证据、读到证据后是否答对。VehicleMemBench 的 gold_memory 是自由文本相关片段,没有发布为面向检索的细粒度证据 ID 与自动对齐器;因此它天然更容易做“最终操作对不对”,不容易做“第 k 条是否找到了正确证据”。
VehicleMemBench 与 LoCoMo 的差异在于任务后果。 LoCoMo 适合测能否理解很长、跨月、含多模态的对话;VehicleMemBench 则把任务限制到可执行车载偏好,换来状态级客观判分与工具使用压力。若你的 Agent 不操作外部系统,VehicleMemBench 的最大特色就发挥不出来。
10. 结论与适用场景
VehicleMemBench 给长期记忆评测补上了一块常被忽略的拼图:记忆不只是为了答出一句正确的话,而是为了让 Agent 把外部世界改成正确状态。 多用户、条件变化、纠错和车机 API 使这种“从记忆到行动”的链条具体可测;状态比较又避免了 LLM 裁判的主观性。
但它的成绩单应被准确解读:ESM 低不等于你的 memory system 一定差,ESM 高也不等于它的写入、检索、更新都正确。它衡量的是“你的 memory system 与指定 Agent、指定 prompt、指定工具环境组合起来,完成这 500 道车载任务的效用”。
因此最稳妥的使用方式是:
-
用 VehicleMemBench 测端到端任务成功、动作正确性与误操作;
-
用 LongMemEval 或自建证据标注测检索覆盖与排序;
-
用 HaluMem 或自建更新审计测抽取、冲突、更新中的幻觉;
-
在线上数据上补齐严格时序、延迟、成本、安全与真实用户行为。
因此,VehicleMemBench 适合作为“记忆系统是否能帮助工具型 Agent 完成任务”的集成测试;若要形成完整的记忆质量诊断,还需要补充过程级指标。
11. 附录:术语、最小流程、代码索引与来源
11.1 术语速查
| 术语 | 一句话解释 |
|---|---|
| Agent | 收到 query 后会选择调用记忆或车辆函数的 LLM 程序 |
| 工具 / tool | 以 function calling 暴露的函数;既包含 search_memory,也包含 carcontrol_* |
| 模拟器 | 仓库内的 VehicleWorld Python 对象,不是真车或真实车厂 API |
参考车 vw_ref | 执行标准动作、用于生成正确最终状态的虚拟副本 |
模型车 vw_pred | 执行模型实际动作、用于生成预测最终状态的虚拟副本 |
| Gold Memory | 该题相关历史的标准摘要;只用于提供理想记忆上界 |
| ESM | 预测最终状态与参考最终状态完全相同才为 1 |
| adapter | 把一个具体 memory backend 包装成 benchmark 所需写入/检索接口的代码 |
| 条件约束 | 偏好只在某环境、时间、活动或关系成立,例如“工业区开内循环” |
11.2 最小可跑流程
-
安装
requirements.txt,配置一个 LLM 的 OpenAI-compatible API; -
先跑内置
none/gold,确认模型与工具调用链工作; -
以
mem0.py为模板写 adapter,先只跑场景 1; -
检查
all_results.json中 Gary 题的检索和工具日志; -
固定 LLM 与参数后扩大到 50 场景;
-
在官方状态指标外,追加检索覆盖、噪声、延迟与存储成本统计。
11.3 代码索引
| 看什么 | 位置 |
|---|---|
| 23 个模块的初始状态组装 | environment/vehicleworld.py:5 |
| 模块列表与 API 状态包装器 | environment/utils.py:12、environment/utils.py:57 |
| 动态生成车机函数 schema | evaluation/model_evaluation.py:154 |
| 按日期构造递归摘要 | evaluation/model_evaluation.py:410、evaluation/model_evaluation.py:595 |
| 按日写入 KV memory | evaluation/model_evaluation.py:635、evaluation/model_evaluation.py:781 |
| 模型任务执行循环与两份虚拟车 | evaluation/model_evaluation.py:848 |
| 参考动作执行与状态比较入口 | evaluation/model_evaluation.py:1052 |
| 字段和值级指标计算 | evaluation/eval_utils.py:181 |
| 工具序列 F1 | evaluation/eval_utils.py:111 |
| 外部 memory 的搜索 / 车辆调用循环 | evaluation/memorysystem_evaluation.py:118 |
| 外部 memory 写入、测试与输出 | evaluation/memorysystem_evaluation.py:603、evaluation/memorysystem_evaluation.py:631 |
| 当前硬编码支持的后端列表 | evaluation/memorysystems/init.py:4 |
| 可模仿的 adapter 模板 | evaluation/memorysystems/mem0.py |
11.4 参考资料
-
论文:VehicleMemBench: An Executable Benchmark for Multi-User Long-Term Memory in In-Vehicle Agents · PDF
-
代码 / 数据:GitHub isyuhaochen/VehicleMemBench · Hugging Face dataset
-
对照调研:HaluMem_调研报告.md · LoCoMo_深度调研.md · LongMemEval_深度调研.md
调研时间:2026-07-12。本文依据论文、当前本地代码与发布数据完成;未运行需要模型/记忆后端密钥的完整 pipeline。本文中“当前仓库未聚合某指标”“示例脚本路径不可直接按 README 使用”“无按 query cutoff”的结论均为对本地代码和命令的独立核对;行号对应撰写时的本地版本,后续提交可能变化。