带有反重力管理智能体及GenAI SDK的状态型远程沙箱
借助 GenAI SDK 的反重力管理代理:在多轮操作中保持远程 Ubuntu 沙箱运行,通过环境 ID 重新连接并获取工作区快照。
来源: Orchestrating with Antigravity: A Crescendo of Agents (Part 1)
有些开发者始终沉浸在终端世界中。如果某个工具无法通过 bash 编写脚本,他们就会直接放弃使用,他们的日常 AI 工作流程依赖于诸如 gemini-cli 及其更新的版本 antigravity-cli(简称 agy)这样的命令行工具。这就是所谓的“BashOps”工作方式,与那些更喜欢图形化工具的“ClickOps”群体形成对比。
然而,当需要处理的任务增多时,这种工作方式就会遇到瓶颈。同时运行多个编码工具、处理多轮状态循环以及跟踪文件变更,往往意味着要同时管理分布在多个虚拟桌面上的六到十二个终端窗口,这很快就会成为一种心理负担。解决这一问题的第一个方法就是持久化:为每个工具提供一个在多次调用之间依然存在的workspace。第二个方法则是利用 git worktrees安全地运行并行本地子工具,这属于另一个话题。
在这里,我们将通过 Google GenAI SDK 以及预览版代理模型 antigravity-preview-05-2026,探讨带状态功能的远程沙箱如何与 Google 的 Antigravity 托管代理协同工作。您将了解如何重新连接到容器环境,以及如何通过本地终端将代理的工作区拉回到自己的机器上。关于托管代理的架构及其运行机制,已有诸多详细阐述,例如 Philipp Schmid 对托管代理内部工作原理的解析。本文的重点则是通过编程方式控制这些代理,从而构建自动化流程。
实际应用中的带状态代理
在传统的智能体 API 调用中不存在内存机制。你发送提示语,智能体回复后,工作空间就会消失。如果你希望它编辑上一轮生成的文件,就必须将整个文件重新放入提示语中。这会消耗更多令牌,增加延迟,使得多轮代码生成变得缓慢且成本高昂。
Antigravity 的解决方案是有状态远程沙箱。将 "remote" 作为环境参数传入,SDK 会负责处理以下事项:
- 在 Google Cloud 中创建一个私有的、受保护的 Ubuntu 容器;
- 智能体在該容器内运行;
- 调用结束后容器仍会保持运行状态,并返回一个
environment_id用于标识该容器; - 后续的调用都可以连接到同一个容器,且文件系统保持不变。
最直观的验证方式就是查看相关代码。
示例:被迫离开 Python 的 IPO 分析师
为说明这一理念,这里有一个脚本,用于协调一个具有状态的三轮智能体会话。该智能体扮演 IPO 分析师的角色:第一轮负责研究某家公司的公开上市信息并保存为 Markdown 报告;第二轮重新连接到同一个容器,打开该报告并将其转换为带有自定义样式表的 HTML 仪表板,同时生成对应的图片;第三轮则下载整个工作区的快照。
通过使用标准的 Google GenAI Python SDK,并传入 environment="remote" 参数来调用预览智能体模型,即可实现这些具有状态的功能。
import os
import requests
import tarfile
from google import genai
client = genai.Client()
print("🚀 Turn 1: Launching SRE/Financial Agent in remote Ubuntu Sandbox...")
# Turn 1: Launch agent to research and write a report in a remote sandbox
interaction_1 = client.interactions.create(
agent="antigravity-preview-05-2026",
input="Research SpaceX IPO and save report as spacex-report.md.",
environment="remote" # Launches a remote Ubuntu sandbox
)
env_id = interaction_1.environment_id
print(f"✅ Turn 1 Complete. Container Environment ID: {env_id}")
print("\n🔄 Turn 2: Re-attaching to same container and converting to HTML...")
# Turn 2: Re-attach to the SAME sandbox and preserve conversation memory
interaction_2 = client.interactions.create(
agent="antigravity-preview-05-2026",
environment=env_id, # ← Re-attaches to same sandbox
previous_interaction_id=interaction_1.id, # ← Preserves conversation memory
input="Convert that spacex-report.md file into a clean index.html webpage" +
" with styling and generate a custom nanobanana image."
)
print("✅ Turn 2 Complete.")
print("\n📦 Turn 3: Downloading the entire container snapshot (.tar) locally...")
# Turn 3: Download the entire sandbox environment state (.tar) locally
api_key = os.environ.get("GEMINI_API_KEY")
response = requests.get(
f"https://generativelanguage.googleapis.com/v1beta/files/environment-{env_id}:download",
params={"alt": "media"},
headers={"x-goog-api-key": api_key},
)
tar_path = "snapshot_env.tar"
with open(tar_path, "wb") as f:
f.write(response.content)
print(f"✅ Snapshot downloaded to {tar_path}. Extracting...")
with tarfile.open(tar_path) as tar:
tar.extractall(path="./workspace_extract")
# Wow! We've dumped the remote agent workspace locally!
print("🎉 Workspace extracted successfully! Check ./workspace_extract/")
该脚本的逐步操作流程:
- 启动并调查。Google会在一台Ubuntu机器上启动一个容器,这是一台拥有真实磁盘的实体机器,随后代理程序开始执行调查任务。
- 继续处理并转换格式。第二步会将Markdown格式转换为HTML格式。虽然第一步本可以直接生成HTML,但这种分步处理方式显得有些多余,不过它证明了可以将当前的工作暂存起来,明天再继续处理,且会保留完整的会话状态,甚至可以通过聊天应用继续操作。
- 在本地获取结果。这一环节让整个过程更具真实感。该容器中包含一个实际的工作空间,可能还有克隆的代码仓库以及新增的单元测试。在这次运行中,容器里存放着第一步生成的Markdown报告、第二步生成的
index.html文件、一张图片以及一份样式表。
在浏览器中打开 index.html 即可看到生成的仪表板,其中包含用于展示投资案例的多空分析板块。
示例:开发一款儿童小游戏
构建软件时也适用同样的思路。以一款教孩子认钟的游戏为例,它要解决的具体问题是:即使孩子擅长算术,也可能在将模拟时钟的指针位置——比如19:45——转换为对应的数字时间字符串时遇到困难。一旦得到数字形式,计算诸如08:45加上或减去20分钟之类的时间差就变得很简单了。这个障碍纯粹是视觉上的,因此一款能连接两者概念的游戏就非常有用。
他们的目标是用 Flutter 开发一款跨平台的移动游戏,部分原因是频繁的旅行使得能够在飞行途中离线使用的手机应用变得非常实用。最初,一个带状态管理的脚本被用来制作第一个原型。该脚本收到了详细的多步骤指令,要求其读取产品需求文件、实现游戏功能、启动本地服务器、截取屏幕截图,并在 GitHub 上提交 pull request。
该脚本的核心部分使用 google-genai SDK 来配置远程沙箱环境、挂载 git 仓库,然后下载并解压最终的工作区快照:
from google import genai
import requests, os
client = genai.Client()
api_key = os.environ["GEMINI_API_KEY"]
gh_token = os.environ.get("GITHUB_TOKEN") # optional: enables the agent to push a PR
# Mount the git repo AND inject the GitHub token as a file into the sandbox
sources = [
{"type": "repository",
"source": "https://github.com/palladius/orologia.io",
"target": "/workspace"},
{"type": "inline",
"target": "/workspace/.github_token",
"content": gh_token}, # ← secret injection!
]
# The prompt tells the agent exactly what to build
prompt = """
You are an expert full-stack developer agent.
The repo orologia.io is mounted at /workspace.
1. Read docs/PRD.md and implement a beautiful clock-learning game...
2. Make it stunning: analog clock with rotating hands, digital display, ..
3. Optionally screenshot it, then commit and open a PR using the token
at /workspace/.github_token.
""" # Full prompt: https://github.com/palladius/orologia.io/blob/main/solutions/20260615-antigravity-managed-agents/run-agent-prototype.py
# Launch remote stateful sandbox agent
interaction = client.interactions.create(
agent="antigravity-preview-05-2026",
input=prompt,
environment={"type": "remote", "sources": sources}
)
# Download final snapshot locally
url = ...
response = requests.get(url, headers={"x-goog-api-key": api_key}, params={"alt": "media"})
该智能体没有直接着手开发复杂的 Flutter 应用,而是用纯 HTML、CSS 和 JavaScript 编写了一个快速的临时原型。仅需一次输入即可获得关于时钟行为及其反馈循环的描述,它便在大约一分钟内生成了一个具有响应功能的时钟应用。此外,它还设计了交互选项,将模拟时间与多个数字按钮对应起来。
这体现了单智能体快速原型设计的价值。要扩展到多个原型则是另一回事,因为同时让多个子智能体共同实现完整的 Flutter 游戏时,普通的命令行循环就会显得力不从心。要安全地处理这类问题,就需要使用独立的 git 工作树以及专用的协调机制。
远程智能体适用于哪些场景
自然而然会产生的问题是,这些远程代理究竟有什么用处。有人可能会认为在本地主机上做任何事情都会更便捷。另一种更有意思的观点是将它们视为“代理用 Dockerfile”的第一步:首先在本地进行实验,然后逐步用自定义脚本、工具配置文件夹以及可能的云服务账户密钥来构建代理容器。不久之后,你就拥有了一个可重复、自包含且安全的沙箱环境,代理可以在其中访问互联网,而 git clone 与 API 密钥的结合则能发挥巨大作用。
实用建议:
- 如果是临时性调查,可以跳过此步骤,使用网页界面或本地命令行工具会快得多。
一个重复性使用的例子是容器化的家庭旅行规划工具,你只需指定目的地、日期和限制条件即可。它的运作方式有点像经过微调的模型,不同之处在于整个文件系统都是可观察和可调整的,因此之后你可以下载生成的 index.html 文件。在一次运行中,一个代理仅根据三个提示语就制定了完整的岛屿旅行计划,其中包括行程地图和可验证的预订链接,其中前两个提示语保持不变。
采用前的注意事项
对于此类设置,有一些必要的检查事项:
- 快照可能包含代理程序所看到的所有内容,包括克隆的仓库以及您挂载的任何凭据。请将tar文件视为敏感信息,除非确实必要,否则不要将服务账户密钥放入沙箱中。
- 此处的模型名称仅为阶段性预览版本。请刻意固定该名称,同时要做好功能和接口可能会发生变化的准备。
- 请将环境ID保存在持久存储的位置。一旦丢失,就无法重新关联该环境。
- 在依赖“明天再试”式的处理流程之前,先了解有状态沙箱的收费情况及其有效期。
相关阅读
- 结合 Git Worktrees、Conductor 与 Antigravity 2.0 的并行编码代理——协调代理、各代理独立的 Git Worktrees 以及基于问题的任务跟踪机制如何帮助在大约五小时内完成十余项 SRE 功能的开发,同时涵盖有关 HITL 问题及合并流程优化的经验教训。
- 将 Apps Script 工作负载卸载到 Gemini 托管代理的 Linux 沙箱中——探讨如何利用 Google Apps Script 驱动持久化的 Linux 沙箱,通过 ggsrun 将文件上传至 Drive,规避 50 MB 及令牌限制,并运行 Playwright、FFmpeg 和 esbuild 等工具的任务。