ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

agentmemory 负载测试指南:用 load-100k 工具测量 p99 延迟与吞吐

agentmemory 负载测试指南:用 load-100k 工具测量 p99 延迟与吞吐 agentmemory 负载测试指南用 load-100k 工具测量 p99 延迟与吞吐【免费下载链接】agentmemory#1 Persistent memory for AI coding agents based on real-world benchmarks项目地址: https://gitcode.com/GitHub_Trending/age/agentmemory导读agentmemory 仓库的benchmark/目录存放了两类关键数字一类是检索/质量评估LongMemEval、内部数据集、真实嵌入、规模扩展另一类是负载形态测试——由零依赖的load-100k.ts压测工具驱动直接对运行中的 agentmemory daemon 发起真实 HTTP 请求产出 p50 / p90 / p99 延迟、吞吐与错误数。本文将完整讲解这套负载测试工具的设计、测量指标、默认测试矩阵、运行方式与全部环境变量并结合源码深入剖析其百分位计算、并发调度、可复现内容生成等底层实现帮助你复现结果、自定义压测矩阵并理解为什么 p99 才是容量规划时最该盯住的那个数字。benchmark 目录的两类数字根据 benchmark/README.md 的定位这个目录里住着两种性质完全不同的数字质量 / 检索类——对应脚本longmemeval-bench.ts、quality-eval.ts、real-embeddings-eval.ts、scale-eval.ts衡量召回率Recall、精确率Precision与 token 节省量分别记录在 benchmark/LONGMEMEVAL.md、benchmark/QUALITY.md、benchmark/REAL-EMBEDDINGS.md、benchmark/SCALE.md 四份文档中。负载形态类——对应load-100k.ts针对一个正在运行的 daemon 测出 p50 / p90 / p99 延迟与吞吐。当有人问在 100 并发、10 万条记忆的规模下 p99 是多少时你要找的就是这个文件。质量类回答检索得准不准负载类回答扛得住扛不住两者互补共同构成 agentmemory 的性能画像。load-100k.ts手写、零依赖的负载压测工具benchmark/load-100k.ts 是一个刻意保持轻量的负载测试 harness不依赖任何压测框架只用 Node 原生能力node:child_process、node:fs、node:path、node:perf_hooks对本地 agentmemory daemon 在http://localhost:3111发起真实 HTTP 请求用performance.now()记录每次请求的延迟并在每次运行结束时写出一份 JSON 报告。文件头注释benchmark/load-100k.ts说明其规格来源于 GitHub issue #346默认情况下假设 daemon 已经启动设置AGENTMEMORY_BENCH_AUTOSTART1时则自行通过node dist/cli.js start拉起一个。包脚本入口定义在 package.jsonnpm run bench:load实际执行node --import tsx benchmark/load-100k.ts因此需要 Node 20见 package.json 的 engines 声明。它测量什么每个矩阵单元的六类指标对于测试矩阵(N, concurrency, endpoint)中的每一个单元cellharness 会记录指标含义p50_ms/p90_ms/p99_ms最近秩nearest-rank百分位延迟单位毫秒min_ms/max_ms该单元的最小、最大请求延迟ops/errors实际完成的请求数 / 失败请求数throughput_per_sec该单元的墙钟时间吞吐ops / 秒源码层面summarize()函数benchmark/load-100k.ts将升序排序后的延迟数组交给pXX()计算百分位吞吐则用ops / (wallMs / 1000)得出。每个单元默认发出BENCH_OPS200次请求——样本量足够让 p99 稳定又不会让 10 万条记忆的种子运行拖到几十分钟。nearest-rank 百分位实现百分位计算没有引入统计库而是手写在 benchmark/lib/percentiles.ts 中export function pXX(sorted: number[], p: number): number { const n sorted.length; if (n 0) return NaN; const clamped Math.max(0, Math.min(100, p)); if (clamped 0) return sorted[0]!; if (clamped 100) return sorted[n - 1]!; // Nearest-rank: rank ceil(p/100 * n), index rank - 1. const rank Math.ceil((clamped / 100) * n); const idx Math.min(n - 1, Math.max(0, rank - 1)); return sorted[idx]!; }这段实现有三个值得注意的设计点零依赖、零分配排序责任交给调用方benchmark/load-100k.ts 中sorted latencies.slice().sort(...)以避免把 O(n log n) 的排序成本藏进看似廉价的查找里p 值超界时自动 clamp 到 [0, 100]。空数组返回NaN语义清晰。并发调度固定 in-flight 上限的 worker 池driveLoad()benchmark/load-100k.ts是并发控制的核心它维护一个自增计数器issued启动concurrency个 worker每个 worker 循环取号、发请求、记录耗时取不到号i total即退出。这样任何时刻在途请求数都被严格限制在C与报告注释中concurrent in-flight C的口径一致。请求失败不会中断整个单元而是计入errors后继续最终用Promise.allSettled收尾。默认测试矩阵N × C × 三个端点默认矩阵见 benchmark/load-100k.tsN ∈ {1000, 10000, 100000}——单元运行前预置进 daemon 的记忆条数C ∈ {1, 10, 100}——单元运行期间的在途并发请求数被测端点POST /agentmemory/remember写入POST /agentmemory/smart-search检索GET /agentmemory/memories?latesttrue列出最新记忆这三个端点分别对应 MCP 工具层的关键调用mem::remember、mem::smart-search在 src/mcp/server.ts、src/mcp/server.ts 中通过sdk.trigger触达latest列表则与 src/mcp/server.ts 中的agentmemory://memories/latest资源同源。也就是说压测覆盖的是 Agent 日常使用中最核心的记忆写入—检索—翻阅三条路径。种子阶段seedMemoriesbenchmark/load-100k.ts以 32 并发向/agentmemory/remember写入type: observation的合成记忆并实时 drain 响应体以释放 socket。N 值会先升序排序让每个 N 在前一个 N 的种子上增量补齐delta N - seededSoFar既节省时间又保证大 N 场景覆盖了完整的历史写入过程。为什么 p99 才是那个该被盯住的数字原文档的论断值得原样引用p50 只告诉你中位请求感觉很快p90 只告诉你大多数请求感觉很快而p99 告诉你尾部用户在最需要它的那一刻请求是否仍然快。容量规划就发生在这一层——无论是给 daemon 扩机器、横向扩容还是设定 SLO都应该以 p99 为规划基准。p50 会骗你它会把整体尚可但存在明显长尾的系统误判为健康。在负载测试语境下长尾往往来自 GC 停顿、索引重建、磁盘抖动或锁竞争等偶发因素。只看 p50这些都被平均掉了p99 则把这些真实世界里会咬人的时刻显式暴露出来。运行它两步走与全部环境变量原文档给出的标准流程# 1. 启动 daemonnpx、Docker 等方式皆可 npx agentmemory/agentmemory # 2. 在仓库根目录另开一个 shell npm run bench:loadharness 启动后会先等待GET /agentmemory/livez就绪30 秒超时见 benchmark/load-100k.ts然后按 N 升序执行全部单元最后在 stdout 打印一张紧凑结果表并写入 JSON 报告。覆盖测试矩阵BENCH_N1000 BENCH_C1,10 BENCH_OPS100 npm run bench:load让 harness 自己拉起 daemon先执行npm run build生成dist/再AGENTMEMORY_BENCH_AUTOSTART1 npm run bench:load自动启动逻辑benchmark/load-100k.ts会按序探测dist/cli.mjs、dist/cli.js用当前 Node 解释器spawn出cli start子进程并 drain 其 stdout/stderr结束后先发SIGTERM2 秒未退出再补SIGKILL见 benchmark/load-100k.ts。全部环境变量速查表环境变量作用默认值AGENTMEMORY_URLdaemon 的基础 URLhttp://localhost:3111BENCH_N逗号分隔的 N 规模列表1000,10000,100000BENCH_C逗号分隔的并发级别列表1,10,100BENCH_OPS每个单元测量期间的请求数200BENCH_SEEDmulberry32内容 RNG 的种子12648430即0xC0FFEEBENCH_OUT_DIRJSON 报告的落盘目录benchmark/resultsAGENTMEMORY_BENCH_AUTOSTART设为1时由 harness 拉起 daemon关闭假设 daemon 已在运行解析逻辑集中在loadConfig()benchmark/load-100k.ts其中parseIntList会过滤掉非正数非法输入回退到默认值AGENTMEMORY_URL会去除尾部斜杠——细节虽小但保证了配置的健壮性。结果落在哪里带 schema 版本号的 JSON报告写入benchmark/results/load-100k-short-git-sha.json目录由 harnessmkdir -p创建。git sha 通过git rev-parse --short HEAD尽力获取非 git 检出环境下退化为nogit-时间戳见 benchmark/load-100k.ts。报告顶层RunReportbenchmark/load-100k.ts包含{ schema_version: 1, generated_at: 2026-05-13T19:49:26.116Z, git_sha: 96c0ed0, base_url: http://localhost:3111, seed: 12648430, matrix: { N: [1000], C: [10] }, ops_per_cell: 200, cells: [ /* 每个矩阵单元一个 CellResult */ ], notes: Single-process load harness. Latency in milliseconds. Throughput is wall-clock ops/sec for the cell (concurrent in-flight C). }schema_version: 1字段是刻意的兼容性设计——未来格式变更时消费方可以据此优雅地拒绝旧文件而不是静默解析出错。仓库内已提交的示例报告 benchmark/results/load-100k-96c0ed0.jsonN1000、C10展示了实际产出POST /agentmemory/remember单元 p50577ms、p99675ms、吞吐 17.38 ops/sPOST /agentmemory/smart-search单元 p99224ms、吞吐 61.26 ops/sGET /agentmemory/memories?latesttrue单元 p99542ms、吞吐 24.84 ops/s三组均 0 错误。注意这是仓库内记录的一次具体运行样本不同机器、不同构建的绝对数值会有差异其价值在于报告结构与复现方法。内容生成是可种子化的mulberry32 的意义合成记忆内容并非随意拼凑而是由一个mulberry32(BENCH_SEED)伪随机数生成器驱动的确定性过程function mulberry32(seed: number): () number { let s seed 0; return () { s (s 0x6d2b79f5) 0; let t s; t Math.imul(t ^ (t 15), t | 1); t ^ t Math.imul(t ^ (t 7), t | 61); return ((t ^ (t 14)) 0) / 4294967296; }; }实现见 benchmark/load-100k.ts。内容模板来自三组小型词汇表NOUNS28 个、VERBS18 个、CONCEPTS15 个组合出形如seed-42 the cache flushes throughput under latency pressure (k1337)的句子buildContentbenchmark/load-100k.ts。原文档的观点非常明确这套内容的目的不是真实本来就不存在唯一的真实内容而是可复现性——同样的 seed 加上同样的构建就能得到逐字节一致的种子语料。这样当延迟出现差异时差异只能来自 daemon 本身而不是 JSON payload 的随机抖动。每个单元还会用派生种子如cfg.seed ^ (N * 0x9e3779b1) ^ C生成探针内容避免单元间内容重叠干扰测量。发布流程数字进 CHANGELOGJSON 当收据原文档描述了与版本发布绑定的流程发布时向CHANGELOG.md追加一个## Performance段落引用该发布 git sha 对应的benchmark/results/下的 JSON。p99 是头条数字JSON 是原始凭据——任何声称的延迟改进都能回溯到具体报告文件。这与 package.json 中bench:load脚本形成的闭环一致改代码 → 构建 → 跑bench:load→ 提交 JSON → 发布时把 p99 写进 CHANGELOG。从 CHANGELOG.md 可看到负载 harness 本身是 v0.9.13 中随 PR #346/#363 落地的能力说明这套压测体系是版本演进的一部分而非一次性脚本。配套质量评估的另一类数字要完整理解 benchmark 目录还应知道与负载测试并列的质量评估体系它们的运行与解读方式分别记录在四份文档中benchmark/LONGMEMEVAL.md——基于 ICLR 2025 学术基准 LongMemEval-S500 题、每题约 48 个会话、约 115K token的纯检索评估指标为recall_anyK嵌入模型为本地all-MiniLM-L6-v2384 维、无需 API key全程无 LLM 参与。复现命令为npx tsx benchmark/longmemeval-bench.ts bm25与npx tsx benchmark/longmemeval-bench.ts hybrid数据需先按文档说明下载到 benchmark/data。值得强调这是检索召回率不是端到端问答准确率文档明确声明不将其称为LongMemEval 官方分数。benchmark/QUALITY.md——240 条合成观察、30 个会话、20 条带标注查询的内部评测对比内置记忆CLAUDE.md/grep、BM25、双流BM25向量、三流BM25向量图五套系统的 Recall/Precision/NDCG/MRR 与 token 开销。benchmark/REAL-EMBEDDINGS.md——真实本地嵌入Xenova/all-MiniLM-L6-v2相对纯关键词检索的增益测量结论是语义类查询收益最大如database performance optimization从 BM25 的 0% 提升到向量增强后的 40% 召回10。benchmark/SCALE.md——5 种语料规模240 → 50,000 条观察下的索引构建时间、BM25/混合检索延迟、堆占用、存储成本BM25 索引 384 维向量索引以及跨会话检索能力的 12 条查询验证。它们共同回答了负载测试回答不了的问题检索质量在规模增长时如何退化。负载测试告诉你 p99 是多少质量评估告诉你检索结果值不值得信任。小结把压测纳入你的开发闭环load-100k.ts的全部价值可以归结为三点零依赖可复现seeded 内容 schema 化报告 git sha 命名、口径明确nearest-rank 百分位 固定 in-flight 并发、面向决策p99 作为容量规划基准JSON 作为发布凭据。想要复现或扩展这套测量只需四步启动 daemon →npm run bench:load→ 读取benchmark/results/下的 JSON → 需要更细粒度时用BENCH_N/BENCH_C/BENCH_OPS/BENCH_SEED定制矩阵并提交报告。对于任何我的记忆服务在真实负载下表现如何的问题这套 harness 就是现成的、可审计的答案来源。【免费下载链接】agentmemory#1 Persistent memory for AI coding agents based on real-world benchmarks项目地址: https://gitcode.com/GitHub_Trending/age/agentmemory创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表