
OpenHuman Agent 规模基准测试指南进程外驱动真实openhuman-core的泄漏判定与容量分析【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhumanscripts/bench/是 OpenHuman 仓库中的 Agent 规模agent-scale基准测试工具集它以并发方式驱动一个正常构建的openhuman-core服务器进程通过 JSON-RPC over HTTP/rpc发起真实 Agent 轮次turnLLM 由本地 mock 端点替代采样器从进程外部读取其 CPU 与内存最终由分析器给出**泄漏判定leak verdict**与吞吐/延迟/CPU 漂移结论。读完本文你将掌握该工具的运行方式、全部命令行参数、其不改核心代码即可测量的设计原理、verdict 的准确解读方法以及如何利用内存开关做对照实验分离数据增长与进程泄漏两类成本。一、定位它测的是你要发布的东西会不会涨OpenHuman 仓库里同时存在两套资源测量工具二者回答的是不同问题scripts/bench/README.md 用一张表精确划清了边界维度scripts/profile/scripts/bench/本文Core 运行方式作为库嵌入在 bench 二进制中正常构建的openhuman-core serve进程驱动途径直接Agent调用JSON-RPC over HTTP/rpcLLM 由谁 mock原生ChatModel覆写核心拨号的 HTTP 端点需要什么--features rss-bench无——使用正式发布的特性集测量什么领域与 harness 成本的隔离测量操作系统向正式二进制收取的真实成本最适用于把成本归属到某个子系统泄漏排查、容量规划、尾延迟scripts/profile/看不到传输层、serde、连接处理与调度器——因为在该层级它们根本不运行scripts/bench/把这些全部包含进来但成本归属更粗。用profile/找出什么在花钱用bench/判断你要发布的东西是否在增长。也正因如此它不需要任何 cargo test features也不需要改动核心代码。二、环境前提Linux、Node 20、磁盘文件系统、release 二进制运行前提在 run-agent-scale.sh 中都有硬性校验任何一项不满足都会直接报错退出Linux采样器读取/proc见 sampler.mjs 中的parseStatus/parseSmapsRollup/parseStatCpu。Node 20runner、driver、mock、sampler、analyze 均为.mjs脚本。产物必须放在磁盘文件系统而非 tmpfsrunner 会把 core 的工作区放到--out-dir下并用findmnt -no FSTYPE检查tmpfs/ramfs 直接拒绝启动。这不是洁癖——tmpfs 页面本身就是内存core 的磁盘写入会被记到机器 RAM 头上而基准测试正在试图把 RAM 归因给 core且长时间运行会写满挂载点随后出现 Failed to write auth profile lock owner 与 SQLite I/O 错误看起来像泄漏引发的崩溃实际上是磁盘满了对应 run-agent-scale.sh 中的完整注释。几个 GB 空闲空间5 分钟、并发 8 的跑法会留下约 5 GB 的内存块memory chunks与嵌入embeddings。release 核心二进制构建命令product-features.sh 产出正式发布的特性集cargo build --release --bin openhuman-core \ --no-default-features --features $(bash scripts/ci/product-features.sh)release 至关重要debug 二进制的分配行为与 CPU 成本与产品不符从中得出的泄漏结论没有参考价值。三、快速开始运行、产物与退出码scripts/bench/run-agent-scale.sh # 默认8 并发、300 轮次 scripts/bench/run-agent-scale.sh --concurrency 32 --turns 2000 scripts/bench/run-agent-scale.sh --duration-ms 900000 --tool-depth 3 # 15 分钟浸泡测试退出状态即判定泄漏或漂移检查失败时非零退出。产物落在target/bench/时间戳/文件内容report.json判定及其背后的数字samples.jsonl原始资源采样序列driver.json吞吐、延迟百分位、错误桶turns.jsonl每轮延迟与结果mock-stats.jsonmock 实际服务的统计core.logcore 的 stderr完整参数表runner 的全部选项--help输出与此一致见 run-agent-scale.sh 的用法头--concurrency N 并行在途轮次数默认 8 --turns N 测量窗口内总轮次数默认 300 --duration-ms N 按墙钟时长运行而非按轮次计数 --warmup-turns N 先运行并丢弃的轮次数默认 10 --tool-depth N mock 每轮驱动的工具调用次数默认 1 --latency-ms N mock 推理延迟默认 40 --jitter-ms N 围绕该延迟的抖动默认 20 --reply-chars N 助手回复大小默认 240 --fail-rate F 完成响应中返回 500 的比例默认 0 --thread-mode M fresh | per-worker | shared默认 fresh --interval-ms N 资源采样间隔默认 250 --tree 同时采样子进程 --keep-workspace 退出时不删除临时工作区 --workspace DIR 复用已有工作区隐含 --keep-workspace --memory-off 禁用内存读写recall learning --memory-writes-off 仅禁用内存写入保留 recall 读取与 --memory-off 互斥 --out-dir DIR 产物目录默认 target/bench/stamp注意两个内存开关互斥--memory-off已包含--memory-writes-off所做的写入抑制两者组合会生成重复的[memory]与[learning]表项核心会直接拒绝该配置见 run-agent-scale.sh。内存对照实验三件套--memory-off禁用 recall、autosave、learning hooks、embeddings 与 memory tree。与默认运行对比可把内存成本与无关的进程存活效应分离开。--memory-writes-off禁用 autosave 与 learning 写入但保留 recall。配合指向已填充数据的--workspace DIR可区分读成本与写成本。--workspace DIR复用调用方拥有的数据并保留。对同一个已填充语料连续跑两轮可区分数据规模效应与进程存活时间效应。--workspace的实验设计很关键run-agent-scale.sh先跑一轮累积状态再把全新 core 进程指向结果。若每轮延迟从上一轮结束处继续攀升成本是已累积数据存储上的 O(N) 路径的函数若重新从低位起步成本才是进程存活时间进程内泄漏的函数。两者的修复手段完全不同而该 harness 中没有其他东西能分离它们。四、核心设计不改核心代码的两个承重事实整个层级由两个事实支撑任何一个改变都会打破该层详见 README 的 How it works without touching the coreBACKEND_URL重定向全部推理流量。核心从这一个值同时推导出推理基址与后端基址因此把BACKEND_URL指向 mock 就一次捕获了 chat completions、embeddings 与 Langfuse 遥测。这有源码依据src/api/config.rs中effective_backend_api_url/effective_inference_url两族 URL 的分辨顺序均为用户显式配置 →BACKEND_URL/VITE_BACKEND_URL运行时环境变量 → 编译期烘焙见 src/api/config.rs 的解析顺序注释。runner 用env -i清空环境再注入BACKEND_URLhttp://127.0.0.1:$MOCK_PORT防止开发者自己的OPENHUMAN_*或BACKEND_URL静默地把运行重定向到真实账号或后端run-agent-scale.sh。形如a.b.local的会话令牌跳过后端校验。存储这样一个令牌即可持久化 profile而不会触发远程 JWT 会引发的GET /auth/me往返因此基准测试无需登录、mock 也无需 auth 路由。driver 在负载开始前用openhuman.auth_store_session方法写入bench.session.localdriver.mjs核心侧的判定依据是is_local_session_token——本地离线会话仅凭 JWT 签名段为字面量local识别跳过后端校验且永不过期见 credentials/README.md 的说明。三个手工复现必踩坑的细节runner 额外处理了三处细节手工复刻这套环境时任一遗漏都会静默毁掉运行审批门必须关闭OPENHUMAN_APPROVAL_GATE0。它默认开启会把交互式聊天轮次挂起等待人工决策10 分钟 TTL 后裁决为 Deny不关的话每次基准轮次都会阻塞在一个没人回答的提示上测到的是被挂起轮次的队列而非 Agent 吞吐run-agent-scale.sh。每日成本上限必须调高。核心会把 mock 上报的 token 用量按 $10/天的托管推理预算计价持续运行几百轮就会耗尽之后每轮瞬间失败。runner 选择调高上限而非禁用检查[cost] enabled false这样预算检查本身的开销仍留在测量内。注入的配置如下写入workspace/config.toml与workspace/workspace/config.toml两个候选位置因为解析器两种布局都接受[cost] enabled true daily_limit_usd 1000000.0 monthly_limit_usd 1000000.0嵌入维度必须匹配mock 默认--embed-dims1024runner 从不覆盖它只有手工启动的 mock 才会偏离。维度不匹配只是警告chunks 会被无向量存储整个运行期间内存写入路径处于降级状态mock-llm.mjs 明确提醒 1536——text-embedding-3-small的常见宽度——在这里是错误的默认值存储期望 1024。另外mock 绝不能监听 11434、8000、8080、1234 或 8888——核心将这些端口归类为本地 AI 端点并绕行。这有双重依据src/api/config.rs 定义了const LOCAL_AI_PORTS: [u16] [11434, 8000, 8080, 1234, 8888];而 mock-llm.mjs 中LOCAL_AI_PORTS集合与之一致并在启动时硬性拒绝。五、五件套的运行机制逐层拆解整个链路由五个 Node/bash 组件协作完成runner 负责编排1. mock LLMmock-llm.mjs——无状态、确定性、可注入故障它替代api.tinyhumans.ai让正常构建的 core 无需网络、无需特殊 features 即可跑真实轮次。核心通过BACKEND_URL到达它因此一个基址捕获一次轮次的所有后端调用POST /openai/v1/chat/completions——轮次本身非流式POST /openai/v1/embeddings——内存 recall/写入触发时POST /telemetry/langfuse/ingestion——每轮之后除非禁用两个对基准测试至关重要的性质mock-llm.mjs 中的设计说明回复由请求推导而非存储状态——轮次深度通过统计请求体里role: tool消息数得出没有会话表N 个并发轮次不会互相串线mock 持有的唯一可变状态是几个整数计数器这也让 mock 游离在测量之外——若 mock 保留请求日志它自己也会增长作为独立进程不会出现在 core 的数字里但会改变机器内存压力、污染运行因此代码注释明确禁止在此添加请求保留。工具循环由TOOL_PREFERENCE [memory_search, glob]驱动两者只读且廉价深工具循环锻炼的是 harness 而非文件系统mock-llm.mjs。回复文本从一个 24 词词汇表确定性采样生成——若所有回复是同一字符串整个语料会塌缩成一个文档吞吐没问题但任何哪个记忆被检索的实验都失去意义mock-llm.mjs。嵌入是由文本哈希推导的确定性单位向量embeddingFor保证同文本同向量、不同文本不同向量的结构性真实足以对比检索策略且无共享状态。注入的失败--fail-rate与延迟--latency-ms/--jitter-ms都由请求内容哈希的确定性函数驱动同一请求的重试会获得新的一次抽取。mock 还预置了 4 个辅助路由GET /teams/me/usage、composio connections/toolkits、GET /orchestration/v1/sessions这些是核心轮询的后台路由404 会走错误上报路径、浪费 CPU 与分配用空而形状正确的载荷应答让进程保持在正常路径上mock-llm.mjs。2. driverdriver.mjs——按并发打负载并记录每轮向运行中的 core 按固定并发发射openhuman.agent_chat轮次JSON-RPC 2.0 over HTTP/rpc记录每轮延迟与结果。三个要点线程模式决定测的是哪种规模driver.mjsfresh每轮开新线程模拟大量短独立会话是唯一能抓住每会话分配后永不回收状态的模式per-worker每个 worker 全程持有一条线程模拟长对话shared所有 worker 共享一条线程面向争用。预热轮次不计入测量启动会触发热点初始化模型客户端、存储、工具注册表把预热轮计入稳态会显示首次接触初始化导致的增长而非泄漏。driver 在预热后清零所有统计再开始测量driver.mjs。明文 HTTP 仅限回环地址CWE-319--core-url若非 localhost/127.0.0.1/::1直接用http:会抛错重定向每跳重新校验并仅在原 origin 上附加 bearer token防止把令牌交给Location头指向的第三方driver.mjs。3. samplersampler.mjs——从 /proc 进程外采样以固定间隔从/proc/pid/读取并输出 JSONL 序列rssKib、vmHwmKib内核所见峰值 RSS、pssKib/privateKib来自smaps_rollup、cpuUserMs/cpuSystemMs累计 CPU按_SC_CLK_TCK100 换算、threads、openFds--tree时额外给出treeRssKib与子进程数。两个实现细节值得注意/proc/pid/stat中 comm 字段本身可含空格与括号因此按最后一个)定位字段而非整体 splitsampler.mjs--tree需扫描整个/proc构建父进程表才能找到孙进程这是它默认关闭的原因。每个样本同时带tMs相对本序列与epochMs墙钟后者用于与 driver 的轮次日志对齐。采样器在 driver 启动前就开始、停止后继续采 3 秒头部由分析器按--warmup-frac丢弃尾部用于观察负载停止后是否释放内存、是否还在烧 CPU——后者本身就是一个发现。4. analyzeranalyze.mjs——判定生成器消费采样序列与 driver 摘要、轮次日志产出每类资源的判定。它被刻意做成独立进程录好的运行可用不同阈值重新分析不必重付负载代价。判定逻辑要点对应 analyze.mjs 中的analyzeMemory/analyzeCounter/analyzeCpu/analyzeThroughput窗口裁剪采样序列含负载前空闲头与负载后空闲尾若把空闲尾纳入分析增长在结尾停止与CPU 速率下降会平凡成立每次运行都谎报健康。因此必须先按 driver 的measureStartedAtMs/wallMs裁剪到负载窗口analyze.mjs。OLS 线性拟合斜率换算为 KiB/轮单独拟合最后 1/3 窗口判定增长是否停止——增长后趋平与从未增长在早期/晚期均值对比下不可区分把饱和缓存误判为泄漏会训练人们无视该检查analyze.mjs。关键阈值均可通过参数调整--rss-kib-per-turn 8每轮增长预算默认宽松待基线确立后再收紧、--warmup-frac 0.25、--max-thread-growth 8、--max-fd-growth 32、CPU 漂移 25% 判定线analyze.mjs。样本不足 40 个或窗口不足 30 秒时标记underpowered弱证据警告但不判失败——吞吐/延迟数据仍有价值。5. runnerrun-agent-scale.sh——编排、健康检查与交叉校验runner 依次启动 mockcurl/health轮询就绪、coreenv -i干净环境注入BACKEND_URL、OPENHUMAN_APPROVAL_GATE0等见 run-agent-scale.sh、sampler、driver并在结束后做交叉校验对比 driver 认为跑了的轮次数与 mock 实际服务的 completions 数。存在一条容易忽略的坑轮次可以返回 200 而其背后的推理调用已静默降级——RPC 成功、Agent 以错误字符串应答运行看起来全绿实则什么都没测到。交叉校验还会检查失败率超过 5% 判定本次测的是错误路径而非 Agent 工作、mock 收到未预期的路由unknownRoutes等任一失败即拒绝出具判定run-agent-scale.sh。六、如何解读 verdict三态内存判定与confounded内存判定有三种结果中间那个才是关键README 的 Reading a verdictpass——无增长趋势或增长在每轮预算内。plateau——总体超预算增长但在窗口最后 1/3 停止攀升。这是缓存填充到工作集的形状值得跑更久确认平台期成立。fail——超预算增长且到结束时仍在增长。这正是分析器分别拟合序列尾部、而非比较早期均值与晚期均值的原因。线程与文件描述符用更严格的标准二者在稳态负载下没有合法理由无限攀升因此是直截了当的阈值判定而非趋势检验且独立于内存判fail。实践中它们是最少歧义的泄漏信号。内存判定可能是confounded。fresh线程模式阻止了对话历史累积但并不能阻止 Agent 每轮持久化内存块与嵌入——5 分钟运行写出数 GB。对真实增长的数据建的索引不是泄漏。因此当 RSS 判 fail 同时伴随大量工作区增长时报告标记confounded并说明无法排除什么而不是断言一个它无法与正确行为区分的泄漏。分离方法带--memory-off重跑或跑到磁盘增长趋平而 RSS 继续攀升。confounded阈值在工作区增长 ≥100 MiB 时触发analyze.mjs。吞吐保持 / 存活liveness分析器检查轮次是否持续完成——仅凭资源指标一个死进程与一个健康空闲进程无法区分内存平、无 CPU、线程稳定。该报告早期版本就曾在核心跑完 2/3 就停止应答的运行上给出自信的 PASS。完全停机额外标记livenessBroken并使其他所有判定作废单纯降级不标记因为进程仍在工作、其资源数字仍然真实对应 analyze.test.mjs 中 a core that stops serving fails 等回归用例。CPU 漂移比较窗口首尾每单位墙钟消耗的 CPU。恒定负载下该值上升意味着每轮越来越贵——内存泄漏的 CPU 类比典型是每轮被重扫的无界结构。判定线为漂移 25%analyze.mjs。线程模式决定你能得出什么结论--thread-mode fresh # 默认每轮新线程 --thread-mode per-worker # 每个 worker 一条长对话 --thread-mode shared # 所有 worker 一条线程只有fresh支持泄漏判定。另外两种模式下对话历史按设计累积RSS 增长是预期的泄漏与正确行为不可区分——分析器报告增长率并明确拒绝判定。它们用于争用与尾延迟分析不用于泄漏排查。七、调校 mock工具深度、延迟与失败注入--tool-depth N 每轮最终答复前的工具调用次数锻炼 Agent 循环而非单次补全 --latency-ms N 平均推理延迟真实值让多轮保持在途彻底改变并发画像 --jitter-ms N 围绕该延迟的抖动 --reply-chars N 回复大小——改变 serde 与分配压力 --fail-rate F 补全中返回 500 的比例锻炼重试--tool-depth 0只测 RPC 与推理路径任何大于 0 的值都会让 Agent 的工具循环受到考验——而每轮状态正是在那里累积的所以泄漏排查至少应该用 1。八、真实基线一次运行能告诉我们什么README 记录了一次 5 分钟、并发 8、tool-depth 1 的单机运行指示性数据非目标值尚未跨主机复现度量值轮次数~8,5000 失败吞吐~29 轮/秒均值延迟p50 260 msp99 570 msCPU~6.9 核均值~245 ms/轮RSS1.48 → 2.33 GiB线程 / FD稳定工作区写入~5 GB两次跨重复复现的发现值得追查而非当作 harness 噪声RSS 以 ~115 KiB/轮增长且结束时仍在增长被 5 GB 工作区增长混淆需内存禁用对比来裁决以及恒定负载下吞吐跌到起始值的 ~37%——后者无法用工作区增长直观解释。仓库中的 FINDINGS.md 展示了这套工具的实际产出形态它先框定不是内存泄漏、不是缺索引再用对照实验证明成本在内存 recall 读路径--memory-off后每轮 CPU 从 253 ms 降到 28 ms、吞吐保持率从 33% 回到 102%并用同一已填充工作区、全新进程立即继承全部成本的实验排除进程存活效应。随后的优化锁外解码嵌入、只读连接池经 A/B 测量无效果后被回退——这正体现了本工具以测量为准的定位微优化扫描周边已被测量两次并被证明无用。最终实施的 recall diet移除load_context()、autosave 移出global命名空间、citations 并行化在 4 分钟运行中把吞吐从 32.5/s 提到 69.1/s、每轮 CPU 从 223 ms 降到 82 ms并用--memory-writes-off进一步隔离出残余漂移全在写入路径。这些结论都建立在本文所述参数与判定的基础上。九、测试让泄漏数学的错误响亮失败分析器的失败模式是沉默数学错了会在泄漏运行上报 pass没人注意到——这比根本没有检查更糟。因此 analyze.test.mjs 用正确判定由构造已知的合成序列驱动分析器稳定泄漏、平台期、平线、线程与 FD 增长、CPU 漂移、负载后空闲尾不应掩盖泄漏、核心中途停机应判定存活断裂、工作区大增长应标记 confounded 等共 20 余个用例使泄漏数学的回归响亮失败。运行方式node --test scripts/bench/analyze.test.mjs十、小结何时用这套工具scripts/bench/是 OpenHuman 面向发布物的资源验证层不改核心代码、使用正式特性集、把openhuman-core当作黑盒从外部驱动与采样回答这个会发布的二进制在恒定 Agent 负载下是否会持续增长。它与scripts/profile/的分工进程外 vs 进程内、整体成本 vs 子系统归属构成了完整的资源测量矩阵。排查泄漏时请牢记只有fresh线程模式可出泄漏判定RSS 判 fail 前先看工作区增长是否造成confounded恒定负载下吞吐下滑与 CPU 漂移同样是需要追踪的增长信号。【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhuman创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考