agentmemory 评测体系完全指南:用 LongMemEval 与 coding-agent-life-v1 量化混合记忆检索栈
agentmemory 的评测框架(eval/)为混合记忆检索栈(BM25 + 向量嵌入 + consolidation 记忆整合 + 图检索)提供了一套可复现、可比较的量化基准:一条基于公开 LongMemEval 500 问检索基准的"公共对比轴",一条基于 15 个虚构 Claude Code 会话语料的"内部快速迭代轴"。读完本文,你将掌握如何安装沙箱、运行两类评测、解读 P@K / R@K / 命中率等指标、对照 grep 与 OpenAI 向量基线验证每一层检索的价值,并学会为自定义后端编写新的 Adapter。
评测框架的定位:为什么 agentmemory 需要一套基准
agentmemory 的记忆栈不是单一检索器,而是由多层级联组成:BM25 词法检索、嵌入向量检索、consolidation 记忆整合以及图检索(graph retrieval)共同服务于 smart-search 端点。正如 eval/README.md 所陈述的,这些层级带来的数值提升必须能被证明——将整个栈与 grep 字符串匹配、OpenAI 向量检索这两种基线对比,每个组件对最终召回率的贡献才可量化,而不是停留在"感觉更好"的层面。
因此仓库提供两套互为补充的评测族,且都强调可复现(reproducible):
- LongMemEval:公开的 500 问多会话聊天检索基准,负责对外部公开结果的横向对比;
- coding-agent-life-v1:仓库内置的虚构语料,覆盖单会话、多会话因果推理、用户偏好与时间线问题,用于在不花费外部 API 费用的情况下快速迭代。
两套评测共用同一套 Runner 与打分逻辑,差异仅在于数据来源(见 eval/runner/coding-life.ts 与 eval/runner/longmemeval.ts)。
三个 Adapter:基线、向量与完整记忆栈
评测通过统一接口比较不同检索后端,接口定义在 eval/runner/types.ts:
export interface Adapter<State = unknown> {
name: string;
init(sessions: Session[], config?: Record<string, unknown>): Promise<State>;
query(q: string, state: State, k: number): Promise<RankedDoc[]>;
teardown?(state: State): Promise<void>;
}
三个内置 Adapter 由 eval/runner/longmemeval.ts 与 eval/runner/coding-life.ts 中的 ADAPTERS 映射表注册:
| Adapter | 后端 | 所需 API Key | 说明 |
|---|---|---|---|
grep |
分词子串匹配 | 无 | 纯词法基线,零成本、零外部依赖 |
vector |
OpenAI text-embedding-3-small + 余弦相似度 |
OPENAI_API_KEY |
纯向量基线,用于衡量语义检索相对词法匹配的提升 |
agentmemory |
运行中的 agentmemory 服务,走 smart-search 端点 |
无(可选 AGENTMEMORY_SECRET) |
完整的混合记忆栈,实际评测名称是 agentmemory-hybrid |
grep:最简单的词法基线
grep.ts 的实现非常直白:将查询串小写化、过滤掉长度 ≤2 的 token,然后在每个会话正文中统计命中的词项数并据此排序。它的价值在于给出"只做词法匹配、零语义理解"时的下限,任何声称有价值的记忆层都应稳定超越它。
vector:OpenAI 嵌入 + 余弦相似度
vector.ts 使用 text-embedding-3-small(维度 1536),init 阶段按每批 50 条会话批量编码(每条内容截断至 8000 字符),查询阶段对问题单独编码后与全部会话向量计算余弦相似度排序。注意 init 会立即抛出 OPENAI_API_KEY required 错误,因此运行 vector Adapter 必须显式提供密钥。
agentmemory:走生产级 smart-search 端点
agentmemory.ts 是最接近真实使用路径的 Adapter:init 阶段逐条调用 POST /agentmemory/remember 将每个会话写入记忆存储(type: "eval-session",并以会话 ID 作为 concept),同时建立"记忆条目 ID → 会话 ID"的映射;query 阶段调用 POST /agentmemory/smart-search(limit 取 max(k*10, 50)),把返回的观测结果去重后映射回会话 ID。由于走的是生产端点,它实际锻炼的是 BM25 + 嵌入 + 重排的完整链路。
该 Adapter 默认连接 http://localhost:3111,可通过 AGENTMEMORY_BASE_URL 环境变量或 config.baseUrl 覆盖;可选 AGENTMEMORY_SECRET 以 Bearer 方式鉴权。
先沙箱后评测:隔离你的真实记忆库
运行 agentmemory Adapter 会向运行中的服务写入 15 个(或 LongMemEval 的数百个)评测会话——如果直接连你的真实 ~/.agentmemory,会同时造成两个方向的污染:评测结果被既有记忆干扰,真实记忆库被评测数据污染。因此官方文档明确要求:Always sandbox(始终沙箱化)。
仓库提供了 eval/scripts/sandbox.sh 一键完成隔离:
- 在 3411/3412 端口启动干净的 agentmemory + iii-engine;
- 状态存放在
/tmp/agentmemory-eval-sandbox/下(该脚本强制要求SANDBOX_ROOT非空且位于/tmp/下,否则拒绝执行); - 自动导出
AGENTMEMORY_BASE_URL指向沙箱; - 脚本退出(EXIT trap)时自动销毁。
source eval/scripts/sandbox.sh
npm run eval:coding-life -- --adapters grep,agentmemory
脚本要求 iii v0.11.2 位于 PATH 上(agentmemory 的固定版本),且要求仓库已构建(缺少 dist/index.mjs 时会提示先执行 npm run build)。如果你已安装其他版本,可将固定版本装入 ~/.local/bin 并确保该目录在 PATH 最前:
mkdir -p ~/.local/bin
curl -fsSL https://github.com/iii-hq/iii/releases/download/iii/v0.11.2/iii-aarch64-apple-darwin.tar.gz | tar -xz -C ~/.local/bin
export PATH="$HOME/.local/bin:$PATH" # 持久化可加入 ~/.zshrc 或 ~/.bashrc
从源码看,沙箱通过生成的 iii-config.yaml 配置了 iii-http(HTTP 端口 3411)、iii-state(基于文件的 KV 存储)、iii-queue、iii-pubsub、iii-cron、iii-stream(流端口 3412)与 iii-exec(启动 node dist/index.mjs)等 worker,并轮询 /agentmemory/livez 等待就绪,30 秒内未就绪则打印日志尾部并退出。
快速上手:两条评测路径
coding-agent-life-v1:内置语料,无需下载
# 仅跑 grep 基线,不需要沙箱
npm run eval:coding-life -- --adapters grep
# 叠加 agentmemory 与 vector(需要沙箱 + OpenAI Key)
source eval/scripts/sandbox.sh
OPENAI_API_KEY=sk-... npm run eval:coding-life -- --adapters grep,vector,agentmemory
该语料位于 eval/data/coding-agent-life-v1/,包含:
sessions.json:15 个虚构的 Claude Code 会话(约 6KB),主题是一个名为shipctl的 Rust CLI 项目;queries.json:15 条人工评分的问题,每条带goldSessionIds(正确答案所在会话 ID)。
从 queries.json 可以看到问题类型覆盖相当全面:single-session-bug(如 q-001 认证环境变量优先级修复)、single-session-infra、single-session-refactor、single-session-feature、single-session-test、single-session-perf、single-session-api、single-session-db、single-session-release、multi-session-causal(如 q-011 追查 staging 事故根因需横跨 sess-001 与 sess-014)、preference(如 q-013 用户的格式化偏好)、multi-session-review 与 temporal(如 q-015 2026 年 4 月 8 日发布了什么)。
Runner 支持三个额外参数(见 coding-life.ts 的 CLI 解析):--data(数据目录,默认 eval/data/coding-agent-life-v1)、--k(截断深度,默认 5)、--out(报告输出目录,默认 eval/reports/coding-life)。
LongMemEval _s:公开基准(278MB 下载)
mkdir -p ~/datasets/longmemeval
curl -Lo ~/datasets/longmemeval/longmemeval_s.json \
https://huggingface.co/datasets/xiaowu0162/longmemeval/resolve/main/longmemeval_s
source eval/scripts/sandbox.sh
# 每类分层抽样 10 条(快速迭代,OpenAI 花费约 $0.20)
OPENAI_API_KEY=sk-... LONGMEMEVAL_PATH=~/datasets/longmemeval/longmemeval_s.json \
npm run eval:longmemeval -- --stratify 10
# 完整 500 问 × 3 个 Adapter(OpenAI 花费约 $2)
OPENAI_API_KEY=sk-... LONGMEMEVAL_PATH=~/datasets/longmemeval/longmemeval_s.json \
npm run eval:longmemeval
load.ts 负责把 LongMemEval 原始 JSON 转换为内部 Question 结构:每个会话的 [{role, content}] 轮次被扁平化为 [role] content 文本,并校验 haystack_session_ids 与 haystack_sessions 长度一致;stratifySample 则按问题类型分桶后每类取前 N 条,保证快速迭代时覆盖所有题型。Runner 额外支持 --limit(截断问题总数)与 --stratify(每类抽样数),--data 缺省时直接读取 LONGMEMEVAL_PATH。
打分与指标解读:P@K、R@K、命中率与 p50 延迟
打分逻辑集中在 score.ts:
- P@K(Precision@K):取前 K 个检索结果,其中命中 gold 会话的比例(
hits / k),逐问平均; - R@K(Recall@K):前 K 个结果覆盖全部 gold 会话的比例(
hits / gold.size),逐问平均; - Hit(命中率):是否至少有一个 gold 会话进入前 K;
- topGoldRank:第一个 gold 会话在完整排序中的位次(1-based),用于观察 gold 是否被排到很后面;
- latencyMs:单次查询耗时,聚合时按 Adapter 计算 p50 延迟。
每条问题的逐行结果以 NDJSON 写入 scores.ndjson(字段含 questionId、questionType、adapter、k、precisionAtK、recallAtK、hit、topGoldRank、latencyMs),聚合结果写入 summary.json,包含按 Adapter 与按问题类型的 P/R/hit 汇总。
理解 P@K 的数学上限很重要:以 coding-agent-life-v1 为例,15 问中 12 问只有 1 个 gold 会话、3 问有 2 个,因此 P@5 的理论上限是 (12×1/5 + 3×2/5)/15 = 0.240。正如已发布的记分卡 docs/benchmarks/2026-05-20-coding-agent-life-v1.md 指出的,该语料刻意设计得小而 gold 稀疏,目的是快速迭代检索栈而非比拼 P@K 头条数字,核心信号是 Recall 与按题型拆分的 P@5;而 LongMemEval 提供的就是那个"公共对比轴"。
报告落盘位置:eval/reports/<bench>/(已被 gitignore),即 scores.ndjson + summary.json;正式发布的记分卡则放入 docs/benchmarks/YYYY-MM-DD-<bench>.md。
写入与复现:一份已发布的记分卡样本
仓库已发布基于上述框架产出的示例记分卡 docs/benchmarks/2026-05-20-coding-agent-life-v1.md,其运行环境为 agentmemory v0.9.26 + iii-engine v0.11.2,本地默认嵌入提供方,沙箱端口 3411/3412。结果摘要(K=5):
| Adapter | P@5 | R@5 | 命中率 | p50 延迟 |
|---|---|---|---|---|
| grep(分词子串) | 0.227 | 0.967 | 15/15 | 0 ms |
agentmemory-hybrid |
0.240 | 1.000 | 15/15 | 14 ms |
解读要点:agentmemory-hybrid 的 R@5 达到 1.000,P@5 = 0.240 恰好处于该数据集的数学上限(所有 gold 会话均进入 top-5);grep 基线的 R@5 = 0.967,在某道多 gold 问题上漏掉了 1 个会话。提升体现在召回而非聚合精度——这正是该评测体系想展示的效果:完整的混合记忆栈相对纯词法基线,主要价值在于更稳地把正确答案捞回 top-K。该记分卡也明确提示:此基准体量小(15 问)、gold 稀疏,不应拿来做头条 P@K 对比。
编写新 Adapter:三步接入自己的检索后端
任何自定义检索后端都能以 Adapter 形式接入评测,官方文档给出完整模板:
import type { Adapter } from "../types.js";
export const myAdapter: Adapter<MyState> = {
name: "my-adapter",
async init(sessions, config) { /* index */ return state; },
async query(q, state, k) { /* search */ return ranked; },
};
接入步骤:
- 在 eval/runner/adapters/ 下按
Adapter<State>接口实现,query返回按相关性降序的RankedDoc[]({ sessionId, score }); - 在 eval/runner/longmemeval.ts 与 eval/runner/coding-life.ts 的
ADAPTERS映射表中注册,即可通过--adapters指定; - 先在 coding-agent-life-v1 上冒烟验证正确性,再投入 OpenAI 花费跑 LongMemEval。
从源码看可复用的细节:vector 展示了带批处理与维度校验的 init 写法;agentmemory 展示了"写入索引 + 记录 ID 映射 + 查询去重映射回会话"的完整状态机模式;scoreQuestion 对空 gold 集返回 R@K = 0 的边界处理也可作为实现参考。另外仓库在 test/eval-adapters.test.ts 与 test/eval.test.ts 中对适配器与评测流程有对应测试,可作为行为契约参考。
评测体系仓库结构速览
eval/
├── README.md
├── runner/
│ ├── types.ts Adapter、Question、RankedDoc、ScoreRow 类型
│ ├── score.ts P@K、R@K 计算与聚合
│ ├── load.ts LongMemEval JSON → Question[]
│ ├── adapters/
│ │ ├── grep.ts 分词子串匹配基线
│ │ ├── vector.ts OpenAI 嵌入 + 余弦
│ │ └── agentmemory.ts POST /agentmemory/{remember,smart-search}
│ ├── longmemeval.ts 公开基准 Runner
│ └── coding-life.ts 内部基准 Runner
├── scripts/
│ └── sandbox.sh 沙箱化启动与销毁
└── data/
└── coding-agent-life-v1/
├── sessions.json 15 个虚构会话(约 6KB)
└── queries.json 15 条带 gold 会话 ID 的问题
两条 npm 脚本(见 package.json)对应两个 Runner:npm run eval:coding-life 与 npm run eval:longmemeval,均通过 tsx 直接执行 TypeScript。
总结:如何用这套框架量化你的记忆层
agentmemory 评测体系的设计哲学是"每层价值可证明":grep 给出词法下限,vector 给出纯语义基线,agentmemory 给出完整生产链路,三者在同一批问题上、以同一套 P@K / R@K / hit / 延迟指标横向对比。内部语料小到几秒跑完、免费可复现,适合开发期快速迭代;LongMemEval 体量大、题型全,适合发布前产出可与公开结果对照的记分卡。任何想接入的检索后端,遵循 Adapter 接口三步即可纳入这套评测体系。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.21 K635- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python70
jforgamejforgame是一个一站式游戏服务器开发框架。包含游戏服务器开发所需要的各种组件,比如网关,socket服务端与客户端,自定义高效消息编解码,游戏热更新,游戏通用工具等等。包含游戏服,跨服,匹配服,后台管理系统等实现,同时提供大量业务案例以供学习。亦可用于其他socket应用,例如及时聊天等。Java201
fizz-gateway-nodeAn Aggregation API Gateway in Java . FizzGate 是一个基于 Java开发的微服务聚合网关,是拥有自主知识产权的应用网关国产化替代方案,能够实现热服务编排聚合、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理、回调管理等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界面,能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。Java90
certd开源SSL证书管理工具;全自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔;https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署JavaScript120
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python300