SCH:在 AWS 账户里给编程 Agent 搭一个低成本沙盒

HN Vibe Coding Practices 2026-09-14T05:43:51.691966

简介

一个周五早上,我合上了笔记本电脑,而一个编程 Agent 还在云端的轻量容器里继续干活。几个小时后我重新打开电脑,分支已经可以审查了,运行环境早已自动销毁,远程算力只花了几美分。这个数字还不包括模型推理费用,那是单独计算的。

要做到这一点,我得先回答两个问题:

  1. 我真的需要让自己的电脑或一台远程机器跑满八小时循环吗?
  2. 能不能让 Agent 在无人值守的情况下工作,同时又不用自己搭一套沙盒系统?

这篇文章就是我的答案:SCH,一个基于 AWS AgentCore 的无服务器编程框架。

过去两年,冒出了不少以“工程”结尾的概念。上下文工程把注意力从单条提示词转向了下一步能拿到的信息。Geoffrey Huntley 的 Ralph Wiggum 循环——说白了就是 while :; do cat PROMPT.md | claude-code; done——展示了 bash 循环能做到什么程度:每次迭代都用全新的上下文,状态存在磁盘上。之后又出现了循环工程、图工程、框架工程。概念名字换得很快;我搭 SCH 主要需要三个概念:

更新的模型加上这三个要素的研究进展,也改变了工作单元的粒度。一个任务可以无人值守地跑几个小时,跨越多个会话和检查点,甚至跑上好几天。这就带来了两个实际问题。

  1. 总得有人守着机器。循环跑八小时,就意味着笔记本得开八小时,或者我得租一台远程服务器,还得更新它、记得关掉它。

  2. 长时间循环会助长 YOLO 模式。只要工具层弹出授权请求,无人值守的任务就停住了。开着权限校验时,很容易出现这种情况:回来一看,Agent 早在十二分钟前就卡住了,就等着你说一句“好的,继续”。于是很多人干脆用上 --dangerously-skip-permissions--auto--yolo 这类选项。

会话越长,出意外状况的机会就越多。如果在笔记本上开着自动批准跑,那么维持循环的这台机器往往同时存着 SSH 密钥、云平台凭证和个人数据。一旦从单个会话扩展到跨不同分支和任务的三四个会话,问题就更明显了:笔记本变成了多个 Agent 共用的主机,可操作的空间很大。

隔离能缩小出错的波及范围,但前提是网络访问和权限要跟任务匹配。沙箱限制太严,Agent 会在第一条被拒的命令上停下;限制太松,无非是把问题挪到了别处。

过去几周,我一直在找一套方案,既能隔离运行时、跑异步的分离任务,又能至少兼容 OpenCode 和 Claude Code。我还希望不用自己维护服务器和沙箱规则。

由于我平时大量用 AWS,早就接触过 Amazon Bedrock AgentCore Runtime。最贴切的类比是:它是一个专门用来托管 AI Agent 的 Lambda——无服务器运行时,按量付费,会话彼此隔离。空闲超时一到,运行时消失,算力归零。后面我会贴出大约十天断续使用下来统计的数据。

SCH - Serverless Coding Harness 就是这么来的。现在已在 c-daniele/sch 公开。我需要的时候,AgentCore 会启动一个远程 harness,我可以从终端连上去。运行时干完活就终止;SCH 会保存状态,把改动带回本地工作副本或另一个分支。

架构设计上有一条原则:持久化应该落在检查点(checkpoint)里,而不是运行时(runtime)。只要仓库、agent 会话和 git 历史都能恢复,就没有理由让 microVM 一直跑着。SCH 目前还只是一个概念验证(proof of concept),保留了一些早期的设计决策,而且只能在 AWS 上运行。它的局限性我后面会讲。

比起 Claude Code on the web、Codex cloud 或 Copilot 的 coding agent,SCH 需要更多的配置工作。作为回报,仓库、会话、检查点和推理都留在我的 AWS 账户里,由我自己定义的 IAM 策略管控,也不会把我绑死在某一个 harness 或者服务商上。

我的工作流有哪些变化

SCH 把本地 CLI 和一个 ARM 镜像搭配起来,这个镜像在 AgentCore microVM 里运行 OpenCode、Claude Code 或 Pi。工作区状态存在 S3,改动通过 Git 回流,用不着的时候就把运行时删掉。

SCH 的三种用法:交接、工作台和批处理

下面的命令假设 SCH 已经部署完成。前置条件和首次部署参见 README 的快速上手部分。

1. 本地头脑风暴,交接出去,用手机盯进度

这是我处理正经活儿时最常用的模式。我先在笔记本上用 OpenCode 头脑风暴,直到目标、要改哪些文件、要跑哪些测试、什么算完成都定清楚。等上下文就绪、本地状态也适合启动任务时,我就把整段对话发到远程工作区,让 agent 接着做:

# Export the local OpenCode conversation, seed a branch from local HEAD,
# import the conversation remotely and start the headless task (implies --continue):
sch task my-project --handoff --branch change/plan-a \
  "implement what we agreed, run the tests, fix what breaks"
#> a1b2c3...          # returns immediately; laptop can go offline

# Any time later - reads S3, does not wake the microVM:
sch status my-project
#> state        : succeeded
#> continuation : resumed prior session
#> checkpoint   : confirmed

# The branch lands locally, fast-forward only; review at your pace:
sch fetch my-project

从现在起,笔记本可有可无。每个工作区在 Telegram 群里对应一个话题(topic),消息带 [workspace] 前缀。里程碑、待办清单更新、工具活动摘要、心跳失联告警,以及最后带检查点状态的任务结果,我都会收到。

无头任务按设计自动批准执行。交互式会话则多了一个中介式「分离模式」:会话启动后用 Ctrl+] 让它继续跑,agent 请求权限时,我手机上会收到「批准/拒绝」按钮。我的回复会送回 harness 钩子。如果十分钟内没响应(SCH_APPROVAL_TIMEOUT_S),就退回 harness 里配置的策略。在话题里输入自由文本,会通过 task --continue 变成后续提示词。我可以直接在手机上打一句「顺便把 README 也更新一下」,让 harness 接着干。

2. 隔离的 AWS 工作台

另一个场景是给主要用 AWS 服务的开发者准备一个隔离工作台。只要把合适的策略挂到 AgentCore Runtime 的 IAM 角色上,远程 harness 就能读取 CloudWatch 日志组、检查 IAM 策略、试做一个 Lambda、访问 DynamoDB 表,而不必继承工作站的凭据。

sch run aws-lab       # fresh remote workspace, straight into the OpenCode TUI
sch web aws-lab       # same backend, in a browser tab
sch acp aws-lab       # same backend, from Zed over ACP

镜像里装了 AWS CLI、AWS MCP Server、AWS Documentation MCP Server 和常见开发工具。Bedrock 推理用的也是同一个执行角色。默认角色是 ReadOnlyAccess 加上调用 Bedrock 的权限:做 POC 很方便,但用于生产数据就太宽了,应该针对每个工作区收窄。会话结束,这个 microVM 就被销毁。

3. 跨多个 harness 与提供商的任务待办

第三个工作流,我从一批已经写好规格、测试和验收标准的任务开始。它们可以无人值守地运行,各自在自己的分支上,甚至换用不同的编码 agent:

sch task svc-a --branch change/a --harness opencode "implement change A per docs/specs/a.md"
sch task svc-b --branch change/b --harness claude   "implement change B per docs/specs/b.md"
sch task svc-c --branch change/c --harness pi --model <bedrock-model-id> "port module C as planned"

sch dashboard         # every workspace on one screen: task state, heartbeat age, checkpoint
sch fetch svc-a && sch fetch svc-b && sch fetch svc-c

工具(harness)在创建工作区时就固定下来了。默认走执行角色访问 Bedrock,但我也可以配置别的提供方,而不用把密钥塞进镜像或检查点里。每个并行会话各占一条分支,sch fetch 只接受快进式合并;真出了冲突,会在本地 git merge 时暴露出来。

运行(Run)与任务(Task)

交互式命令和无头命令提供的保证并不一样。

头脑风暴、探索各种可能方案时,我一般用交互式命令。等任务(一个或一组)定义得足够复杂,我就退出交互会话,改用 task,这样能腾出手做别的事,必要时还能把笔记本合上。完整命令一览见 README。

为什么 AgentCore 适合这套工作流

SCH 依赖 AgentCore Runtime 的四个特性。

每个会话相互隔离。 AgentCore 把每个会话跑在独立的 Firecracker 微虚拟机里,各自拥有内核、CPU、内存和文件系统。会话结束后,微虚拟机被销毁,内存也会清理干净。这样编码工具拿到的是一台用完即弃的机器:从已知镜像启动,与其他会话不共享任何状态。

权限通过 IAM 控制。 在虚拟机内部,CLI、SDK 和 MCP 服务器拿到的是运行时执行角色(execution role)的临时凭证。我可以授权调用 Bedrock、读取指定的 AWS API、写入某个 S3 前缀,而不用从笔记本上拷贝密钥。不过微虚拟机并不会让一个权限过大的角色变安全:真正的安全边界还取决于 IAM 策略和网络配置。

托管生命周期。AgentCore 会终止空闲会话。默认的 idleRuntimeSessionTimeout 为 15 分钟,最短可缩短到 60 秒;maxLifetime 将单个会话限制在 8 小时以内。忙碌中的会话会在健康检查时返回 HealthyBusy,从而避免计时器在 Agent 工作时打断它。8 小时的上限也迫使 SCH 必须支持检查点与重启机制。

适合 harness 运行的资源与启动速度。每个会话分配 2 个 vCPU 和 8 GB 内存;镜像必须是 linux/arm64,且不能超过 2 GB。这对我日常使用的编码 harness 和测试套件来说已经够用,但如果是特别重的构建任务,就需要换用别的运行时。实测下来,一个冷启动的 workspace 几秒内就能就绪,其中包括从 S3 恢复数据以及引导 harness。

CPU 只在真正运算时计费,而内存只要会话还活着就会持续产生费用。这种计费方式适合那种大部分时间都在等待 LLM 响应的进程,当然,等待也并非完全免费。具体数字在成本部分详述。

SCH 如何分离运行时与状态

整个架构分为三层:

会话的生命周期是:sch shell → SigV4 调用 → microVM 启动 → L2 恢复 → harness 引导 → 工作 → 在停止或空闲时从 L1 到 L2 做检查点。下一条命令可以在新的 microVM 中从 L2 重启。

模型与供应商

镜像里每个 harness 都通过执行角色预先配置好了 Amazon Bedrock,因此默认用法无需任何外部供应商密钥。

要用其他供应商,SCH 只会把 ~/.sch/env 中明确列出的一组变量转发到运行时。shim 会把它们存放在一块不参与检查点的临时区域:密钥能到达 harness,但绝不会进入镜像或 S3。当工作区需要直接与 GitHub 交互时,同样的机制也能转发 GITHUB_TOKEN

为什么默认用 OpenCode

这三个 harness 共享同一套基本的状态管理,但 SCH 是围绕 OpenCode 构建的,一些功能也反映了它的架构。同一个后端可以用本地 TUI 通过 sch attach 访问,用浏览器通过 sch web 访问,或用编辑器通过 ACP 和 sch acp 访问。Claude Code 可以通过一个适配器来配合 runtask 和 ACP 使用。Pi 最适合无头任务,目前在 SCH 中还不支持远程审批、替代界面或移交。

无头任务如何工作

提交后在不到一秒内返回一个 task_id,客户端随即关闭连接。shim 以无头模式启动 harness,并告诉 AgentCore 该会话正忙,这样空闲计时器在它工作时不会打断它。七小时的应用超时低于 AgentCore 的限制,也给 shim 留下足够时间记录结果、完成检查点。--model 选项可以更改单次调用的模型,选择结果会记录在状态里。

迁移代码:探索用同步,委派用 git

交互式会话我用文件同步;对于自主任务,git 原生模式更合适。

无论哪种模式,工作站的 git 凭据都不会被复制进去。代码包通过隧道的文件通道传输,远程 agent 不会主动推送,除非显式启用 GITHUB_TOKEN 直接访问 GitHub。

我最初并不打算开放任何对 GitHub 的直接访问。但这样一来就没法跟 GitHub Actions 和其他远程流水线交互,于是我把它改成按需开启:谁需要,就自己显式提供 GITHUB_TOKEN;否则,运行时依然只靠 Git 代码包工作。

大约十来天间断使用下来的成本

我从八月初就开始测试 SCH,但直到 8 月 28 日之前,使用都太零散,不足以反映我平时的流程。所以我把分析范围收窄到 2026 年 8 月 29 日到 9 月 9 日:一共 12 个自然日,其中 9 天有实际活动。

AgentCore 并没有发布类似“已用分钟数”的指标,所以我从 eu-west-1 区域 CloudWatch 的 AWS/Bedrock-AgentCore 命名空间里重建了用量数据。用 ActiveSessionCount 统计实际挂钟分钟数,用 CPUUsed-vCPUHoursMemoryUsed-GBHours 作为计费量。数据来自每日的 GetMetricData 查询,于 9 月 12 日导出,因此涵盖的每一天都是完整的。

计算中采用的价格是 每 vCPU 小时 $0.0895,只对实际用到的 CPU 计费;内存则是 每 GB 小时 $0.00945。内存按秒计费,依据会话到该时刻为止的峰值内存用量,最小计费量 128 MB。如果进程涨到 7 GB 后又把内存释放了,会话结束前计费值仍按 7 GB 算。

这些数字让我重新审视了 SCH 的优化优先级:

  1. 内存约占成本的 78%,CPU 约占 22%。编程代理大部分时间都在等模型响应。等待期间 CPU 不产生费用,但只要会话还活着,内存每秒都在计费。

  2. 闲置时间才是关键杠杆。SCH 会在无操作 15 分钟后停止会话,这个时间可以配置,从 60 秒到 8 小时都行。按大约 7.5 GB 内存算,每个因超时被终止的会话,那 15 分钟的尾巴要花掉约 0.018 美元;用 sch stop 就能省下这笔钱。所以,缩短闲置超时和压缩内存占用,比优化 CPU 使用更有意义。

我拿这些数字和 at4g.large 做了对比,这是配置最接近的 EC2 规格,2 个 vCPU 加 8 GB 内存。在 eu-west-1 区域,它大约每小时 0.074 美元,再加上每月约 8.8 美元的 100 GB gp3 存储费用。同一时期内的对比如下:

实际使用的每一小时,AgentCore 大约贵 24%,0.092 美元对 0.074 美元。但按我这种间歇性的使用方式,会话之间不保留计算资源,让它比一台常开的虚拟机便宜大约七倍。按同样的费率折算到一个月,和一直开着的 t4g.large 相比,盈亏平衡点大约在每月 680 到 700 个会话小时。即便对比一台会认真关停的虚拟机,EBS 的固定成本也让 AgentCore 在每月约 490 个会话小时以下保持优势。这个计算还没算上打补丁的时间,以及难免有人忘了关虚拟机的情况。一个开发者或小团队每天用几个小时代理,离这些门槛还差得远。

这些数字是从 CloudWatch 指标里还原出来的,和 Cost Explorer 的汇总视图一致。在我的使用中,S3、日志和 Lambda 这些附带成本可以忽略不计。推理费用不在此列,而且往往占了大头,所以总成本主要取决于选了哪家提供商和哪个模型,而不只是运行时。

这算不上完整的基准测试:统计窗口很短,使用也是断断续续的,而且只覆盖了一个开发者。团队规模更大时,成本主要会随会话时长增长。AgentCore 的托管会话存储目前还是公开预览版,AWS 已经宣布正式版之前价格会调整。它现在还没有作为独立费用项显示,也不包含在 3.45 美元里。

为什么选 AgentCore 而不是其他方案

EC2 不是唯一的替代方案。Fargate、AgentCore Instances 和托管型 agent 各自解决同一问题的不同部分。

ECS Fargate。 Fargate 也能缩容到零,对这类工作负载价格区间也差不多:按 eu-west-1 的 ARM 费率,我这些 37.5 个会话小时估算下来,1 vCPU 大约 2.3 美元,2 vCPU 大约 3.5 美元,而 AgentCore 是 3.45 美元。所以价格并不是 SCH 的决定性因素。用 Fargate 的话,我得自己搭每会话寻址、空闲超时、忙碌信号、工作区存储和带认证的调用。这些基础能力 AgentCore 已经提供了,而且因为 microVM 是预先初始化好的,在我的测试里工作区几秒就能恢复。我没有做并排对比测试:这个比较是把服务文档和一次 AgentCore 的实测结果放在一起看。

AgentCore Instances。 这项服务也提供运行在你 AWS 账户中、由 AWS 管理的 EC2 实例上的 agent。你需要为实例、管理费和 EBS 存储付费,即使机器已经停止也要付存储费;作为交换,会话最长可以持续 14 天。这个选项更适合超过八小时或者需要保留大量本地状态的工作负载。对 SCH 来说,我反而更喜欢八小时的上限,因为它能强制频繁做检查点。

托管型智能体。Claude Code 网页版、Codex 云端版,以及 Copilot 的编码智能体,已经能让你合上笔记本、少折腾环境配置。而 SCH 满足的是我另一类需求:把代码仓库、会话、检查点和推理过程都留在自己的 AWS 账号里,受我自己定义的 IAM 策略管辖,同时还能自由选择执行框架和模型供应商。SCH 目前走的是带公网出口的网络。AgentCore 本身也支持 VPC、安全组、私有端点和 PrivateLink 入站,只是这套配置我还没在 SCH 上验证过。

今天哪些人可能用得上

团队场景目前还需要验证,这里并不是在推荐企业采用。SCH 只是把智能体的运行环境集中起来,它并不判断智能体的行为是否正确。就算跑在 microVM 里,给执行角色开过大的权限依然危险。Telegram 也只是我个人工作流里一个顺手的接入方式,不会是我建议当作公司标准的控制平面。

局限

接下来要做什么:更精简的镜像、护栏、VPC 和身份

接下来的计划,大致按优先级排序:

这个模式并非 AWS 专属:每个会话一个沙箱、检查点存放在对象存储、用云身份作为权限边界。不过,想移植到其他云就得重写 shim 和基础设施,这不在当前路线图的计划内。

完整的源代码、规格文档、架构图和验证脚本都在 c-daniele/sch。

想试试的话,可以从 sch run aws-lab 开始,它会创建一个用完即弃的工作台,然后在一个你可以随时丢弃的分支上跑 sch task --branch。最有价值的问题反馈请附上 sch status 的输出,尤其是恢复过程中的竞态问题和审批超时的情况。

参考资料

查看原文