把 Agent Harness 部署到云端:多路径速成课
这门课把前面构建的 agent harness 带到云端。重点不是「把代码塞进服务器」,而是把 control plane、execution plane、状态、文件、sandbox、观测和 eval 全部放到能长期运行的结构中。

Quick Win: boot the harness on your laptop in about 15 minutes
先在本地启动 harness。确认三件事:FastAPI 能接收请求,agent run 能写入 durable state,artifact 能写入本地或模拟的 object store。你不需要一开始就部署到云;先让结构跑通。
下载 companion zip,解压后在 coding agent 中打开根目录。根目录的 AGENTS.md 是 agent 的 brief:它告诉 agent 项目如何安装、如何探测 SDK、如何启动 harness、哪些 cloud backends 还没有连接。先让 agent plan,再执行。
Read AGENTS.md, then boot Maya's harness locally so I can see it run.
1. Run the SDK probe at the end of AGENTS.md to confirm the installed
`openai-agents` version and that the core imports work.
2. Install dependencies (`make install`) and copy `.env.example` to `.env`.
Do not add any keys yet; the harness must boot without them.
3. Start the harness (`make run`, which serves on `http://localhost:8000`).
4. In a second shell, request `GET /health` and show me the exact response.
完成条件是:agent 报告 openai-agents 版本,harness 持续运行,GET /health 返回:
{
"status": "ok",
"model": "gpt-5.4-mini",
"backends": { "postgres": false, "sandbox": false, "r2": false }
}
这个 response 是 control plane 在说真话:它活着,知道 model,但可选 backends 还未接入。后续每个 decision 都会把一个 false 变成 true,并用验证证明它确实连上了。
Four learning tracks, pick yours
| 路径 | 适合谁 | 目标 |
|---|---|---|
| Reader | 非工程读者、领导者 | 理解部署结构和风险。 |
| Beginner | 第一次部署 agent 的工程师 | 本地 harness、基础容器、最小云部署。 |
| Intermediate | 团队工程师 | 加入 Neon、R2、sandbox、observability。 |
| Advanced | 生产团队 | CI eval、blue/green、scale-to-zero、恢复和迁移策略。 |
The sprint at a glance
本课是一场部署 sprint:先明确 harness/sandbox 分离,再选五组件 stack,然后按 9 个决策让 coding agent 建立项目、容器化、部署、接入状态、文件、sandbox、观测和 eval。
What you'll have at the end
你会得到一个云端 agent harness:浏览器或 API 调用 FastAPI;harness 管理状态和凭据;sandbox 执行不可信代码;R2 保存 artifact;Neon 保存会话、运行、trace 和 audit;Phoenix 提供观测;CI 用 eval 阻止回归。
Vocabulary you'll meet in this course
- Harness: 控制层,接收请求、管理凭据、组织运行。
- Sandbox: 执行层,运行 agent 生成或调用的代码。
- Control plane: 负责身份、状态、策略、审计。
- Execution plane: 负责隔离执行和临时工作区。
- Manifest: harness 传给 sandbox 的最小授权说明。
- Presigned URL: 只允许访问一个对象或路径的短期 URL。
Are you ready?
你应该已经理解 OpenAI Agents SDK、sessions、tools、guardrails、Cloudflare R2 或类似 object store、Postgres 以及前面课程里的 sandbox 概念。
Rough edges to know about up front
部署 agent 比部署普通 web app 更容易出错,因为它同时碰到模型、文件、状态、长期运行、第三方 API、sandbox 和审计。不要把所有 credentials 放进 sandbox。不要让 sandbox 直接访问数据库。不要把 artifact 留在 ephemeral filesystem。
TL;DR, the four claims this course defends
- agent deployment 的核心是 harness/sandbox 分离。
- 五组件 stack 足以支撑严肃的第一版生产系统。
- observability 和 eval 是架构 surface,不是上线后再补的插件。
- 最贵的通常不是云基础设施,而是模型调用和错误重试。
The shape of what you're building


Stack primer: what each component actually is
Stack primer 1: Docker and containers
container 把运行环境打包为镜像。你的 harness 应该能在本地和云端用同一个镜像启动,这样「works on my machine」才不会成为部署策略。
你会遇到四个词:Dockerfile 是构建镜像的 recipe;base image 是起点,例如 python:3.12-slim;multi-stage build 用一个 image 编译、另一个更小 image 运行;registry 是存放 built images 的地方。deploy flow 是:build image → push registry → cloud runtime pull and run。
Stack primer 2: FastAPI
FastAPI 是 harness 的 HTTP 层。它处理请求、认证、streaming、webhook、admin endpoints 和 health checks。agent orchestration 放在它后面。
最小 mental model:FastAPI app 创建 app object,用 decorators 标记 endpoints,例如 @app.post("/runs")。Pydantic models 校验 request/response shape。Uvicorn 是真正运行 app 的 server。agent harness 的 endpoint 不应该在 route handler 里做所有事情;route handler 负责创建 run、写状态、启动 orchestration,并返回可观察结果。
Stack primer 3: Neon Postgres
Neon 提供 serverless Postgres,用于会话、运行、artifact metadata、trace metadata、audit log 和 eval dataset。它是系统记录,不是临时缓存。
本课最小 schema 有五张表:sessions、runs、traces、artifacts、audit_log。migration 是 versioned SQL script,必须进入 repo。app 使用 pooled endpoint;migration 使用 direct endpoint。使用 asyncpg 时要从 Neon connection string 中去掉它不支持的 query params(例如某些 channel_binding 设置),但保留 TLS requirement。
Stack primer 4: Cloudflare R2
R2 存文件和 artifact。harness 持有根凭据,sandbox 只收到短期 presigned URL。这样 sandbox 可以读写指定对象,但无法列出或访问整个 bucket。
文件不要放在 container local disk,也不要长期留在 sandbox /workspace。local disk 和 sandbox workspace 都是 ephemeral。artifact 的 source of truth 是 R2;Postgres 只保存 metadata:object key、content type、size、hash、created_by_run、retention policy。
Part 1: The deployment problem
Concept 1: "Works on my machine" is not deployment
本地能跑只证明依赖和 happy path 成立。部署要求你回答:凭据在哪里?状态在哪里?文件在哪里?失败后怎么恢复?谁能看 trace?哪个版本服务流量?怎样回滚?
Concept 2: The harness/sandbox split, control plane vs execution plane
harness 持有 authority;sandbox 执行工作。两者之间只传递 Manifest、输入和结果。这个边界让你可以允许 agent 写文件和运行命令,而不把数据库 root 凭据交给它。
Concept 3: What the SDK needs from cloud infrastructure, five surfaces
SDK 需要五个基础设施 surface:HTTP entrypoint、durable state、file/artifact storage、isolated execution 和 observability/evals。少一个,系统就只能演示,不能生产。
五个 surface 对应五类 production question:
| Surface | 回答的问题 | 缺失时的失败 |
|---|---|---|
| HTTP entrypoint | 用户或其他服务如何调用 harness? | 只能本地 demo |
| Durable state | run、session、audit 如何跨 restart 保留? | container 重启后失忆 |
| File/artifact storage | 输入输出文件在哪里? | artifact 丢失或塞满 ephemeral disk |
| Isolated execution | 不可信代码在哪里运行? | harness secrets 暴露 |
| Observability/evals | 如何知道系统对不对? | 只能靠用户投诉发现回归 |
Part 2: The five-component stack
Concept 4: FastAPI as the harness web layer
FastAPI 接收用户请求,创建 run,调用 SDK,stream 输出,写 audit,并把耗时任务交给 background/durable workflow。它不应该直接把不可信代码跑在自己进程里。
Concept 5: Azure Container Apps as the harness runtime

Azure Container Apps 给 harness 一个托管容器运行时:managed HTTPS、secrets、revision、scale-to-zero、autoscale 和 traffic split。对于第一版生产部署,它足够简单。
Concept 6: Neon Postgres for durable state

durable state 至少包括 sessions、runs、traces、artifacts 和 audit log。每个 run 都要能回答:谁发起、用了哪个 agent、用了哪些 tool、输出了哪些 artifact、失败在哪里。
最小 schema 可以从这个形状开始:
create table sessions (
id text primary key,
user_id text not null,
created_at timestamptz not null default now()
);
create table runs (
id text primary key,
session_id text references sessions(id),
agent_name text not null,
status text not null,
started_at timestamptz not null default now(),
completed_at timestamptz
);
create table artifacts (
id text primary key,
run_id text references runs(id),
object_key text not null,
content_type text,
sha256 text,
created_at timestamptz not null default now()
);
create table audit_log (
id bigserial primary key,
run_id text references runs(id),
action text not null,
payload jsonb not null,
created_at timestamptz not null default now()
);
实际 production schema 会更宽,但这些表让你从第一天就能 debug 和审计。
Concept 7: Cloudflare R2 for files and artifacts

不要把重要输出留在 sandbox 的 /workspace。把 artifact 写到 R2,用 metadata 记录在 Postgres。sandbox 只拿最小权限的短期 URL。
presigned URL 是安全边界的一部分:harness 用 root credentials 生成短期 URL;sandbox 只看到这条 URL。它不能 list bucket,不能读别的 prefix,不能长期复用。manifest 应描述要读写的 objects,而不是泄露 storage credentials。
Part 3: The execution plane
Concept 8: Sandbox execution capabilities
sandbox 需要文件系统、shell、网络策略、内存/会话管理、资源限制和清理机制。它不是小型服务器;它是临时执行环境。
Concept 9: Choosing a sandbox provider
选择 sandbox provider 时看隔离强度、启动速度、文件挂载、网络控制、日志、成本、区域和 SDK 集成。Cloudflare Sandbox、E2B 或自建方案都要满足同一组约束。
Concept 10: The harness-to-sandbox handoff

handoff 的关键是 Manifest。它说明 sandbox 能看到哪些文件、能写到哪里、能调用哪些 MCP tools、预算和超时是多少。不要把完整 .env 传过去。
# Mounts go inside entries, keyed by their path in the workspace.
manifest = {
"mounts": {
"/workspace/data": {"type": "r2", "bucket": "agent-artifacts"}
}
}
# Keep the defaults and add one: a passed list REPLACES the default,
# so concatenate rather than passing [Skills(...)] alone.
tools = default_tools + [skills_tool]
# The client reads E2B_API_KEY from the environment; the options carry the
# required sandbox_type. The sandbox rides on RunConfig, not a Runner kwarg.
Part 4: Observability and Evals as Architectural Surfaces
Concept 11: Observability as an architectural surface

observability 不是「上线后看日志」。它是设计时就要加的 surface:每次 run 有 run_id,每个 tool call、model call、artifact、approval、error 都能通过它串起来。
Concept 12: Evals as an architectural surface

eval 需要真实 trace。把生产失败样本提升到 golden dataset,让 CI 在未来阻止同类回归。部署系统如果不能喂 eval,就只能靠人工记忆。
Part 5: The Deployment Lab
Decision 0: probe the SDK and reconcile the brief
先让 coding agent 检查当前 SDK API,而不是凭记忆写代码。版本变化会影响 sessions、RunConfig、sandbox 参数和 tracing。
Decision 1: scaffold the harness
创建 FastAPI app、settings、routes、agent runner、database module、artifact storage module、tests 和 AGENTS.md。
要求 coding agent 先写最小垂直 slice:GET /health 和 POST /runs。POST /runs 初版可以返回 stubbed result,但必须创建 run row 或 in-memory placeholder,并写 structured log。不要一开始就接所有 cloud backends。
Scaffold the harness with a minimal vertical slice:
- FastAPI app
- settings module
- GET /health
- POST /runs
- agent runner abstraction
- tests for /health and /runs
Do not wire cloud services yet. Stub them behind interfaces.
Decision 2: containerize the harness
写 Dockerfile,固定 Python 版本,安装依赖,暴露 health endpoint,并在本地用 container 跑通 smoke test。
containerization 的验收不是“Dockerfile 存在”,而是从 fresh image 启动后 health check 通过:
docker build -t agent-harness:local .
docker run --rm -p 8000:8000 --env-file .env agent-harness:local
curl http://localhost:8000/health
如果 container 只能在本机 venv 中工作,说明 deployment still depends on your laptop。
Decision 3: deploy to Azure Container Apps
创建 container app、secret、environment variables、revision 和 ingress。确认 health check、logs 和 rollback 路径。
deployment 需要同时验证四件事:public URL 可访问、revision 可见、secret 没打印到 logs、rollback path 明确。不要等到 incident 才第一次找 rollback button。
Decision 4: wire Neon Postgres for durable state
建立 schema,迁移,使用 pooled endpoint 给 app,direct endpoint 给 migration。去掉 channel_binding 等 asyncpg 不支持的参数。
Decision 5: wire Cloudflare R2 for files and artifacts
创建 bucket、prefix policy 和 presigned URL helper。harness 生成 scoped URL,sandbox 使用它写 artifact。
Decision 6: wire sandbox execution
把 sandbox client 放在 harness 后面。Manifest 中只传最小工具、最小文件、最小预算和超时。
Decision 7: wire observability
所有 run 写 structured logs、trace metadata、audit row。把 Phoenix 或 OpenTelemetry 连接到同一个 run_id。
Decision 8: wire the eval suite
建立最小 golden dataset,在 CI 中运行输出 eval、tool-use eval 和 trace sanity check。
最小 CI gate 不需要很复杂,但必须存在:
name: evals
on:
pull_request:
push:
branches: [main]
jobs:
evals:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v3
- run: uv sync
- run: uv run pytest tests/evals
生产失败样本要能提升为 golden dataset row。否则 deployment 和 eval discipline 是断开的。
Decision 9: production checklist
上线前检查 secrets、rollback、rate limit、cost cap、sandbox cleanup、R2 lifecycle、DB backups、eval gate 和 incident runbook。
用 checklist 做最终 gate:
| Area | Required before traffic |
|---|---|
| Secrets | no secret in logs、rotation path documented |
| Rollback | previous ACA revision can receive 100% traffic |
| Database | migrations applied、backups configured、pooled endpoint used |
| R2 | lifecycle cleanup、prefix policy、presigned URL expiry |
| Sandbox | no DB credentials、cleanup on failure、timeout and budget |
| Observability | run_id links logs、traces、audit rows |
| Evals | CI gate runs on PR、nightly run exists |
| Cost | model budget and sandbox spend alerts |
Part 6: Honest Frontiers
Concept 13: Cost economics of a cloud agent harness

小规模时,Azure、Neon、R2 和 sandbox 的基础设施成本通常低于模型调用。真正的成本风险来自长上下文、重复运行、无界 fan-out 和没有 eval 的回归。
Concept 14: Multi-region considerations
多区域会带来数据驻留、延迟、artifact 复制、trace 聚合和 failover 复杂度。第一版通常先单区域,除非合规或用户延迟明确要求多区域。
Concept 15: When to migrate off the recipe

迁移不是重写架构。触发器可能是成本、区域、sandbox 能力、合规、流量或团队平台标准。替换组件时,保持 control/execution 分离不变。
Concept 16: What the deployment doesn't solve
部署不能解决错误 prompt、坏工具、缺失 eval、不清楚 authority、没有 audit、没有业务 owner。云只让系统持续运行;它不自动让系统正确。
Five things not to do
不要把 root credentials 放进 sandbox。不要让 sandbox 直连数据库。不要把文件留在 ephemeral workspace。不要在没有 eval 的情况下升级 prompt。不要在没有 rollback 的情况下切流量。
Part 7: Closing
Concept 17: The deployed harness as the realization

部署后的 harness 是前面课程的实现形态:agent loop、有状态、artifact、sandbox、approval、trace 和 eval 全部进入一个能长期运行的系统。
One-day workshop variant
半天做本地 harness 和 Docker;半天部署到 ACA、接 Neon、R2 和最小 observability。eval 和 sandbox 深化可以作为第二天内容。
Cheat sheet
| Surface | 推荐第一版 | 原则 |
|---|---|---|
| HTTP | FastAPI | harness 接收请求,不执行不可信代码。 |
| Runtime | Azure Container Apps | container、secrets、revision、scale-to-zero。 |
| State | Neon Postgres | 所有 run 可追溯。 |
| Files | Cloudflare R2 | artifact 离开 sandbox。 |
| Execution | sandbox provider | 最小 Manifest,隔离运行。 |
| Observability | Phoenix / OpenTelemetry | run_id 串联所有事实。 |
| Evals | CI gate | 生产失败变 regression test。 |
Quick reference: deployment commands
# Local dev (Beginner track)
uv sync
uv run fastapi dev app/main.py
# Pin: openai-agents>=0.17,<0.18
uv add "openai-agents>=0.17,<0.18"
# Cloud deployment (Intermediate / Advanced): Azure Container Apps
az containerapp up --name agent-harness --resource-group rg-agent --environment env-agent
# Tear-down (cost discipline)
az containerapp delete --name agent-harness --resource-group rg-agent
# Neon Postgres (console.neon.com)
# Strip channel_binding from the connection string before asyncpg; keep sslmode=require.
# Use the pooled endpoint for the app; the direct (non-pooled) endpoint for migrations.
Companion download
配套材料应包含 AGENTS brief、schema migration、FastAPI scaffold、Dockerfile、deployment checklist、eval dataset 和 smoke tests。
References
阅读 Azure Container Apps、FastAPI、Neon、Cloudflare R2、OpenTelemetry、Phoenix、OpenAI Agents SDK 和你选择的 sandbox provider 的官方文档。把文档版本写进规则文件,避免 coding agent 使用过期 API。