很多项目把“轻量”写在 README 里,但这个词经常只代表安装命令短、核心代码少,或者演示时能在一台小机器上启动。
对一个需要 24 小时在线的个人助理来说,这些都不够。真正的问题是:它空闲时占多少资源?连续调用工具后会不会涨内存?断网、重启、模型限额和审批暂停之后还能不能回来?
因此我给“极简 Agent”定义了一套实用测试基准。它不评模型知识,也不追求实验室里的漂亮分数,只回答一个工程问题:
这个 Agent 能不能在低资源 VPS 上,长期、稳定、安全地替一个人处理真实任务?
极简不是一个内存数字
一个个人 Agent 至少包含四层:
消息入口 → Agent Runtime → 外部模型 → 工具与状态
只统计 Agent 主进程的 RSS,会漏掉浏览器、Node bridge、MCP 子进程、后台 worker 和模型代理。只统计空闲内存,也会漏掉长上下文、文件解析和工具输出带来的峰值。
所以“轻量”应该同时满足:
- 常驻资源低;
- 任务峰值有上限;
- 空闲后能够回落;
- 不产生孤儿进程;
- 重启后能恢复必要状态;
- 失败不会演变成无限重试;
- 高风险动作不会绕过审批。
测试环境必须先固定
不同机器、Python/Node 版本和模型端点会显著影响结果。每次测试至少记录:
host:
cpu: 2 vCPU
memory: 1 GiB
swap: 1 GiB
os: Ubuntu 24.04
runtime:
version: git commit / release tag
language: Python 3.12 / Node 26 / Go 1.x
model:
endpoint: remote OpenAI-compatible
model: fixed model id
context_window: fixed
features:
channel: Lark WebSocket
memory: SQLite or files
mcp_servers: [luck-ops]
browser: disabled
不要一边测 Agent A 的最小配置,一边给 Agent B 打开浏览器、语音和十个插件。功能集合必须一致,模型也必须一致。
本地大模型要单独测试。模型推理本身可能需要数 GB 到数十 GB 内存,不能和“远程模型 + 轻量 Gateway”放在同一张表里。
资源指标:主进程 RSS 只是辅助值
Linux 上最容易看到的是:
ps -o pid,rss,%mem,etimes,args -p "$PID"
RSS 适合快速观察单进程,但真正的主指标应该是 systemd/cgroup 口径,因为它会把子进程算进服务:
systemctl show my-agent.service \
-p MainPID \
-p MemoryCurrent \
-p MemoryPeak \
-p TasksCurrent \
-p CPUUsageNSec
测试报告至少保留这些值:
| 指标 | 含义 | 为什么重要 |
|---|---|---|
| Cold start | 从启动到健康检查成功 | 判断升级和故障恢复速度 |
| Idle memory | 启动稳定 15 分钟后的中位数 | 判断长期常驻成本 |
| Peak memory | 完成固定任务集时的 cgroup 峰值 | 防止小 VPS 被 OOM |
| Recovery memory | 任务完成 10 分钟后的内存 | 发现缓存或对象不能释放 |
| Tasks/FD | 线程、进程和文件描述符数量 | 发现连接与子进程泄漏 |
| CPU idle/P95 | 空闲与任务阶段 CPU | 发现忙轮询和异常重试 |
| Disk growth | 日志、会话、缓存的日增量 | 防止运行几周后磁盘写满 |
一个可操作的个人门槛
下面不是行业标准,而是我给“1GB VPS + 远程模型 + 单用户”的项目预算:
| 项目 | 合格线 | 理想值 |
|---|---|---|
| 空闲 cgroup 内存 | ≤ 150 MiB | ≤ 100 MiB |
| 固定任务集峰值 | ≤ 350 MiB | ≤ 250 MiB |
| 常驻服务进程 | ≤ 2 | 1 |
| 冷启动健康 | ≤ 5 秒 | ≤ 2 秒 |
| 72 小时内存漂移 | ≤ 10% | 接近 0 |
| 非模型安装体积 | ≤ 500 MiB | ≤ 200 MiB |
如果同一台机器还跑 PostgreSQL、Docker、Mem0 或反向代理,就应该继续下调 Agent 的内存预算,而不是把剩余内存全部吃掉。
九组实用工作负载
B0:冷启动
清空临时缓存但保留真实配置,启动服务,记录健康检查成功、Lark 上线和 MCP 可用的时间。
验收点:
- 没有迁移死锁;
- 没有等待模型才能健康;
- MCP 不可用时主服务仍能启动;
- 重启不会重复发送旧消息。
B1:空闲 15 分钟
不发送请求,每 10 秒采集一次内存、CPU、线程和 FD,使用中位数而不是某一个瞬时值。
重点检查是否存在忙轮询、WebSocket 重连风暴或定时器持续创建对象。
B2:20 轮普通对话
固定 20 条短对话,包含问答、翻译、摘要和偏好追问。记录首 token 延迟、总延迟、上下文大小和任务后内存。
这个测试验证的是会话连续性,而不是模型智力。相同输入应该能映射到同一个用户和会话,重启后也不能串到其他群聊。
B3:MCP 只读工具
执行目标列表、服务状态、资源查看和有限日志查询。要求:
- 工具参数严格符合 schema;
- 超时有上限;
- 长输出分页或截断;
- 密钥、内部 ID 和完整命令被脱敏;
- MCP 服务失败不会拖死 Agent。
B4:高风险操作审批
请求重启一个固定服务,但先不要批准。检查任务是否进入 approval_required,然后分别测试批准、拒绝、过期、重复点击和参数篡改。
最关键的断言是:
批准时看到的操作快照
==
最终实际执行的操作快照
审批不能只绑定一句自然语言,也不能把可复用验证码交给模型自由携带。
B5:大结果与附件
输入一篇长文、一个 PDF 或一段多页日志,观察内存峰值、响应截断、临时文件清理和上下文压缩。
这一组很容易暴露“空闲很轻,处理一个文件就 OOM”的伪轻量方案。
B6:重启恢复
分别在普通对话后、工具执行中、等待审批时和定时任务前重启服务。
期望结果:
- 已完成任务不重复执行;
- 未完成任务有明确状态;
- 等待审批不会被默认为批准;
- 定时任务不会漏跑或重复跑;
- 回复仍回到原来的 Lark chat。
B7:渠道故障
临时阻断 Lark 或模型端点,观察指数退避、日志数量和恢复时间。核心健康检查、只读运维和审批状态查询不应该依赖 LLM 可用。
B8:72 小时浸泡
每小时执行固定的小任务集,连续运行 72 小时。记录:
- 每小时 MemoryCurrent;
- 进程、线程和 FD;
- WebSocket 重连次数;
- 未清理临时文件;
- 失败任务和重复通知;
- 日志增长速度。
“运行三天没崩”还不够。如果内存、线程或 FD 呈稳定上升趋势,它只是还没到出故障的时间。
能力指标:轻但不能没用
一个只会聊天、不保存状态、不调工具的进程当然很轻,但它不是个人助理。资源测试之外,还需要最小能力矩阵:
| 能力 | 最小验收 |
|---|---|
| Lark | 私聊、群聊隔离、重复消息去重、断线恢复 |
| 会话 | 连续追问正确,重启后保留必要上下文 |
| 记忆 | 显式保存、查询、删除;失败不阻塞聊天 |
| 定时任务 | 创建、触发、重启恢复、结果回推 |
| MCP | 工具发现、超时、失败降级、输出脱敏 |
| 审批 | 批准、拒绝、过期、一次性、参数绑定 |
| 可观测性 | 健康、日志、任务状态和版本可查询 |
| 升级 | 备份、升级、验收、可回滚 |
最终报告应同时给出“资源分”和“实用分”。任何一边单独达标都不算通过。
一次真实测量带来的提醒
我在 2026-08-25 对当前 luck-agent 做过一次现场测量:主服务 RSS 大约为 210 MiB,systemd 的 MemoryCurrent 大约为 190 MiB,Python 虚拟环境约 214 MiB。
更有价值的发现不是这些数字,而是三条早期验证命令已经持续运行接近五天,合计占用约 385 MiB RSS。它们不是正式服务,却因为 Runtime 生命周期没有完全关闭而留在系统里。
这正是为什么基准必须包含进程数、运行时长和 72 小时浸泡:
一次启动时看起来只有 200 MiB,不代表一周后仍然只有 200 MiB。
最终判定
我会把“极简 Agent”定义为:
在固定资源预算内
完成固定个人助理任务集
经历重启、断网、审批和长时间运行后
仍然不丢状态、不越权、不持续膨胀
代码少只是实现方式,资源低只是约束,真正的目标是低维护成本下的长期可用。
下一篇将用这套基准评估 Hermes Agent、OpenClaw、nanobot 以及几种开发框架:轻量个人助理 Agent 选型评估。