编码代理 VPS 需要多少内存?
单个常驻编码代理从 4 GB RAM 和 2 vCPU 起步,但语言服务器与 Docker 构建才是内存占满、任务卡死的主要原因。
编码代理 VPS 需要多少 RAM?
对于在代码仓库中持续运行的单个编码代理,请从 4 GB RAM 和 2 vCPU 开始。只要会话中加入语言服务器或 Docker 构建,就应立即提升到 8 GB RAM 和 4 vCPU。对于大多数代码仓库,这通常在第一天就会发生。代理进程本身占用很少,真正占满 VPS 的是代理代为驱动的工具链。
The data behind this chart
[
{
"plan": "Minimum viable",
"ram_gb": 4,
"vcpu": 2,
"disk_gb": 50
},
{
"plan": "Comfortable",
"ram_gb": 8,
"vcpu": 4,
"disk_gb": 100
},
{
"plan": "Team, 4 sessions",
"ram_gb": 16,
"vcpu": 8,
"disk_gb": 200
}
]上表中的每一行都假设模型运行在其他位置,而 VPS 通过网络调用模型 API。这个假设决定了整个配置问题,因此应先确认这一点。
您运行的是代理,还是模型?
调用云端模型的编码代理,本质上是一个附带 shell 的网络客户端。它会将文件和计划发送到 API,等待响应,然后在本地编辑文件并运行命令。等待期间,它几乎不占用 CPU。它自身占用的内存通常只有几百 MB,因此中等配置的 CPU 服务器就足够了。
自行运行模型则是另一种产品,需要不同的硬件。只要服务器在运行,模型权重就会一直保留在内存中。一个量化为 4 bit 的 70 亿参数模型,仅权重就大约需要 5 GB 内存,还不包括会随上下文长度增长的 key/value cache。仅使用 CPU 时,共享 vCPU 每秒只能生成几个 token,而一个代理任务可能生成数千个 token。因此,通过 API 不到 1 分钟即可完成的工作,在本地运行可能需要近 1 小时。如果您需要的是这种方式,应按 VRAM(GPU 的显存)规划,并阅读GPU VPS 实际能提供什么,而不是本页面。
以下内容均假设使用云端模型。
实际占用内存的是什么
The data behind this chart
[
{
"label": "Agent CLI process, idle",
"typical_mb": 250,
"peak_mb": 600
},
{
"label": "TypeScript language server",
"typical_mb": 700,
"peak_mb": 2000
},
{
"label": "rust-analyzer, large workspace",
"typical_mb": 1200,
"peak_mb": 4000
},
{
"label": "Headless Chrome, one tab",
"typical_mb": 350,
"peak_mb": 900
},
{
"label": "Node test run, 4 workers",
"typical_mb": 1600,
"peak_mb": 3000
},
{
"label": "Docker image build",
"typical_mb": 800,
"peak_mb": 2500
}
]这些是中型项目的典型公开数据。应将其视为大致范围,而不是对您的代码的保证。
图表包含 6 行,其中 agent 的成本最低。它空闲时约占用 250 MB,因为它只保留会话内容和一个小型文件缓存,没有其他内容。TypeScript language server 在建立索引时约占用 2000 MB,因为它会为从您的 tsconfig.json 可访问的每个文件构建类型图,并将该图保留在内存中,以便快速响应下一次请求。对于大型工作区,rust-analyzer 通常也会超过 4000 MB,原因相同,而且会覆盖工作区中的每个 crate。
Headless Chrome 运行浏览器和一个标签页时约占用 350 MB,每增加一个标签页,就会增加一个操作系统进程。使用四个 worker 运行 Node 测试时,会启动四个 Node 进程,因此峰值接近 3000 MB。Docker 镜像构建的峰值接近 2500 MB,因为构建过程会在容器内运行项目自己的编译器,同时 daemon 还会写入镜像层。
在购买前,先在您自己的代码仓库中测量这些数据
sudo apt update && sudo apt install -y time
/usr/bin/time -v -o /tmp/build.rusage npm run build
grep "Maximum resident set size" /tmp/build.rusage返回结果为 Maximum resident set size (kbytes): 1842160。将其除以 1024 即可换算为 MB。GNU time 报告的是它等待的单个进程的最大值,因此会派生四个 worker 的构建过程会显示较低的数值。对于这类情况,请在第二个 shell 中使用 free -h 或 systemd-cgtop -m 监控整台主机。
请读取 free -h 的 available 列,而不是 free 列。Linux 会将所有空闲页面用于磁盘缓存,因此在运行完全正常的主机上,free 可能很小,无法提供有用信息。available 才是新进程实际可以获得的内存。
三种可用的配置
最低可用配置:4 GB RAM、2 vCPU、50 GB 磁盘。 运行一个代理会话、一个代码仓库和一个语言服务器,并接受较长的构建等待时间。此配置可以运行,但大型测试运行与语言服务器索引同时进行时,第一次就可能触发 out-of-memory killer。添加 swap,并限制构建工作进程数。
舒适配置:8 GB RAM、4 vCPU、100 GB 磁盘。 运行一个代理、Docker 和用于测试的无头浏览器,并为一次构建峰值预留余量。大多数单人开发者应购买此配置。将 vCPU 数量加倍通常也会使构建等待时间大致减半,而这种收益远比内存余量更常见。
团队配置:16 GB RAM、8 vCPU、200 GB 磁盘。 同时运行 4 个会话,每个会话都有自己的代码检出目录和工具链。应按峰值容量规划,因为 4 个空闲代理几乎不产生额外成本,而 4 个测试运行在同一时刻执行时,成本会达到上方峰值列的 4 倍。
截至 2026 年 8 月,从第一行配置升级到最后一行配置,在按年计费的 VPS 方案中,月费大致会增加到 4 倍:最低配置每月为个位数美元,最高配置为几十美元。规划前请查看当前价格列表,因为这些数字会变化。服务器通常不是成本最高的部分。对于每天使用代理的人,模型 API 费用很快就会超过服务器费用,因此在缩小服务器配置前,请先限制代理可使用的费用。至于构建本身,在 VPS 上运行编码代理的操作指南介绍了账户设置,以及断开连接后保持会话运行的方法。
磁盘空间耗尽前,RAM 可能还很充足
The data behind this chart
[
{
"label": "Ubuntu 24.04 base and toolchain",
"typical_gb": 6
},
{
"label": "One JS monorepo checkout",
"typical_gb": 3
},
{
"label": "node_modules across 3 branches",
"typical_gb": 4
},
{
"label": "Docker images and build cache",
"typical_gb": 20
},
{
"label": "Agent logs and journal, 90 days",
"typical_gb": 2
}
]将这些项目相加后,50 GB 磁盘在你写下一行代码前就几乎已满。占用空间最大的是 Docker,约为 20 GB,因为 BuildKit 会保留每次构建的所有中间层,直到你明确清理它们。
docker system df
docker builder prune --filter until=168hdocker system df 会按类别显示可回收空间,因此应在清理前后分别运行。until=168h 过滤器会删除超过一周的构建缓存,并保留本周的缓存;这些缓存仍能节省构建时间。docker image prune -a 会进一步删除所有没有被容器使用的镜像,因此下一次构建需要重新拉取镜像。
Node 项目会以更隐蔽的方式失败。npm install 会创建数十万个小文件,因此文件系统可能先耗尽 inode,而 df -h 仍显示有数 GB 可用空间。此时写入会因 No space left on device 失败,即使磁盘看起来只使用了一半。
df -h /
df -i /如果 IUse% 显示为 100,请删除不再使用的分支对应的 node_modules 目录,或切换到 pnpm。后者只存储每个软件包版本的一份副本,并通过硬链接将其链接到每个项目中。
日志是一个容易被忽略的占用来源。持续运行的代理会写入会话记录,而 systemd journal 默认会逐渐占用一部分磁盘空间。
sudo journalctl --disk-usage
sudo journalctl --vacuum-size=200M
du -xh --max-depth=1 / 2>/dev/null | sort -h | tail在 /etc/systemd/journald.conf 中设置 SystemMaxUse=200M,然后运行 sudo systemctl restart systemd-journald,使该上限永久生效。临时执行一次 vacuum 只能释放当天的空间。
Swap 的作用与掩盖的问题
建议添加 Swap,因为它可以将小幅内存超额转换为缓慢运行,而不是让进程终止。将 Swap 大小设为 RAM 的一半,最多约 4 GB。对于构建服务器,没有太大必要继续增加。
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
swapon --showswapon --show 现在应显示大小符合要求的 /swapfile。如果没有 /etc/fstab 行,下一次重启后 Swap 就会消失,服务器会悄然恢复原来的行为。如果 fallocate 返回 Operation not supported,请使用 sudo dd if=/dev/zero of=/swapfile bs=1M count=4096 创建文件,然后从 chmod 继续。
echo 'vm.swappiness = 10' | sudo tee /etc/sysctl.d/99-swappiness.conf
sudo sysctl --system较低的 swappiness 值会告诉内核:在将程序内存移出到磁盘之前,先回收磁盘缓存。这样可以保持语言服务器的响应速度。
现在说明 Swap 所掩盖的问题。当任务确实需要超过服务器现有容量的内存时,内核会将时间花在 RAM 与磁盘之间移动页面,而不是运行构建任务。系统不会崩溃,但所有操作都会变得极其缓慢;CPU 处于空闲状态时,负载平均值却不断升高。
vmstat 1 10si 和 so 列中的数值持续为非零,表示系统正在持续进行交换。因此应减少并发量或增加 RAM,绝不能增加 Swap。对于小型服务器,sudo apt install -y zram-tools 可提供存放在 RAM 中的压缩 Swap,并在 /etc/default/zramswap 中进行配置。它的速度远快于 Swap 文件,但会占用 RAM 来节省 RAM。因此,它适用于冷页面,不适用于需要真实工作内存的构建任务。
为什么您的编码代理看起来像是挂起了
这是小型代理服务器上最容易被误判的故障。命令没有返回任何内容,代理一直等待,会话看起来像是卡住了。实际上,进程被内核的内存不足(OOM)终止程序终止了。它收到了 SIGKILL,因此无法输出错误、刷新日志,也无法告知代理发生了什么。代理只能看到空结果,没有退出消息。
内核确实会记录此事件:
sudo dmesg -T | grep -iE "out of memory|killed process"
sudo journalctl -k -b | grep -i oom实际日志行如下:
[Thu Aug 6 11:02:14 2026] Out of memory: Killed process 4711 (node) total-vm:4210880kB, anon-rss:3820104kB, file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:8236kB oom_score_adj:0anon-rss表示该进程终止时占用的内存量。请注意内核选择了哪个进程:内核主要根据内存使用量评分,因此通常会终止语言服务器或代理,而不是那个把服务器推到内存上限的构建进程。这正是症状看起来像“代理出故障”的原因。
在 Docker 中,同一事件会留下更明确的迹象。容器以代码 137 退出,也就是 128 加信号 9。
docker ps -a
docker inspect "$(docker ps -lq)" | grep -i oomkilled"OOMKilled": true确认容器触及了内存限制,而不是自行崩溃。
解决方法是为占用资源较多的命令单独设置上限,让构建进程终止,而不是让代理终止:
systemd-run --user --scope -p MemoryMax=4G -- npm run build现在,构建进程会在 4 GB 处被终止,而代理仍可继续运行。这样,神秘的挂起就会变成普通的失败命令,并显示可读的退出代码。这需要 systemd 用户会话,因此如果服务器只能通过 SSH 访问,请在该服务器上运行 loginctl enable-linger $USER。MemoryHigh=会在达到阈值时限制进程,而不是终止它。对于希望其缓慢完成的构建,这通常是更合适的设置。
使用 Compose 统一设置内存上限
如果代理工具运行在容器中,请将上限写入 Compose 文件,使其在每次运行时都生效。
services:
agent:
image: node:22-bookworm
deploy:
resources:
limits:
memory: 2g
cpus: "1.5"Docker Compose v2 会在普通 docker compose up 上应用 deploy.resources.limits,因此不涉及 swarm 模式。旧版 mem_limit: 2g 键仍然可用。Compose 内存限制完整指南介绍了预留内存,以及容器达到上限时会发生什么。如果服务器尚未安装 Docker,请先在 VPS 上安装 Docker。
有一个容易忽略的问题,可能让人排查一下午。即使将容器限制为 2 GB,容器仍会读取主机的 /proc/meminfo 和 CPU 数量,因为这两项都不会进行命名空间隔离。在一台拥有八个 vCPU 的主机上,测试运行器如果根据 CPU 数量选择 worker 数量,就会在 2 GB 容器中启动 8 个 worker,随后以 137 状态退出。请手动设置这些数值:
npx jest --maxWorkers=2
export NODE_OPTIONS=--max-old-space-size=1536--max-old-space-size 的单位是 MB,用于限制 V8 堆。请将其设置为低于容器内存限制的值,这样 Node 会抛出可读的错误,而不是直接消失:
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory这条消息很有用,因为它会指出触发的限制以及触发该限制的进程。OOM killer 从来不会提供这些信息。
在一台主机上运行多个代理会话
按会话规划,而不是按用户规划。同一代码仓库上的两个会话仍然意味着两个语言服务器、内存中的两组构建缓存,以及在两个代理同时繁忙时运行的两组测试。这就是团队行的内存需求会增加到 16 GB 的原因。
为每个用户设置硬上限,避免某个失控会话耗尽整台主机的资源:
id -u alice
sudo mkdir -p /etc/systemd/system/user-1001.slice.d
printf '[Slice]\nMemoryMax=6G\n' | sudo tee /etc/systemd/system/user-1001.slice.d/limit.conf
sudo systemctl daemon-reload
systemctl show user-1001.slice -p MemoryMax将 1001 替换为 id -u 输出的 UID。用户登录后,systemctl show 应输出 MemoryMax=6442450944。当该用户会话中的所有进程总内存使用量超过 6 GB 时,内核会终止其 slice 中的一个进程,其他会话仍可继续运行。对于以服务而不是终端进程运行的代理,应将 MemoryMax= 放入其 unit 文件中;当您 将代理作为始终运行的服务自行托管 时,应采用这种方式。
FAQ
编程代理需要 2 GB RAM 吗?
对于代理进程本身来说,需要。对于它执行的任务来说,通常不够。代理进程的内存占用约为 250 MB,但一个 TypeScript 语言服务器在中型代码仓库中可能达到 2000 MB,仅此一项就可能让 2 GB 的服务器开始使用 swap。2 GB 适合编辑配置文件和运行小型脚本。对于需要编译或运行测试套件的任务,至少使用 4 GB RAM。
在 VPS 上运行编程代理需要 GPU 吗?
如果代理通过 API 调用云端模型,则不需要。这类工作负载受网络限制,因此普通 CPU VPS 更合适;使用 GPU 只会让 GPU 以更高的价格闲置。只有在同一台服务器上运行模型本身时才需要 GPU。此时需要考虑的是 VRAM 和模型大小,而不是 RAM。
应该为代理 VPS 添加多少 swap?
添加相当于 RAM 一半的 swap,最多约 4 GB。swap 可以应对短时间的内存超额使用,因为内核会将不活跃的内存页移到磁盘,而不是直接终止进程。但它不会增加可用内存。如果 vmstat 1 在 si 和 so 列中显示持续的流量,说明服务器正在发生 thrashing。此时应减少并行 worker 数量,或升级到更高规格的方案。
为什么编程代理会在构建过程中冻结?
构建进程几乎肯定被内核的 OOM killer 终止了。OOM killer 会发送 SIGKILL,因此不会输出任何信息,代理则会一直等待一个永远不会写满的管道。运行 sudo dmesg -T | grep -i "killed process",查看进程名称及其 anon-rss 值。可通过 systemd-run --user --scope -p MemoryMax=4G 限制构建资源并减少 worker 数量来解决,也可以升级到更高的 RAM 规格。