A **快照** 是一个由 Docker 镜像支持的可复用文件系统包。当您想从自定义文件系统镜像启动沙盒时,请构建或捕获快照。
您也可以从运行中的沙盒捕获快照——安装软件包、写入数据文件或配置状态,然后对结果进行快照并将其作为新的起点复用。
从 Docker 镜像构建快照
通过指向任何 Docker 镜像来构建快照。调用会阻塞直到快照就绪(默认超时为 60 秒;对于大型镜像请增加超时时间)。
from langsmith.sandbox import SandboxClient
client = SandboxClient()
snapshot = client.create_snapshot(
"python",
docker_image="python:3.12-slim",
fs_capacity_bytes=1 * 1024**3, # 1 GiB
)
print(snapshot.id)
const client = new SandboxClient();
const snapshot = await client.createSnapshot(
"python",
"python:3.12-slim",
1_073_741_824, // 1 GiB
);
console.log(snapshot.id);
私有镜像仓库
传递镜像仓库凭据(或预先注册的 registry_id / registryId)来从私有镜像仓库拉取。
snapshot = client.create_snapshot(
"internal-python",
docker_image="registry.example.com/internal/python:3.12",
fs_capacity_bytes=2 * 1024**3,
registry_url="https://registry.example.com",
registry_username="me",
registry_password=os.environ["REGISTRY_PASSWORD"],
timeout=600,
)
const snapshot = await client.createSnapshot(
"internal-python",
"registry.example.com/internal/python:3.12",
2_147_483_648,
{
registryUrl: "https://registry.example.com",
registryUsername: "me",
registryPassword: process.env.REGISTRY_PASSWORD,
timeout: 600,
},
);
从 Dockerfile 构建快照
当您有本地 Dockerfile 但不想先将镜像发布到镜像仓库时,请直接从 Dockerfile 及其构建上下文构建快照。LangSmith 会启动一个临时构建器沙盒,上传上下文,在其中运行构建并使用 BuildKit将生成的镜像捕获为快照。构建完成后,构建器沙盒会自动销毁。
调用会阻塞直到快照就绪(默认超时为 60 秒;对于大型或慢速构建请增加超时时间)。 fs_capacity_bytes 必须足够大以容纳构建上下文、中间层和最终镜像。
from langsmith.sandbox import SandboxClient
client = SandboxClient()
snapshot = client.create_snapshot_from_dockerfile(
"my-app",
dockerfile="Dockerfile",
fs_capacity_bytes=2 * 1024**3, # 2 GiB
context=".", # build context directory (default: current directory)
)
print(snapshot.id)
const client = new SandboxClient();
const snapshot = await client.createSnapshotFromDockerfile(
"my-app",
"Dockerfile",
2_147_483_648, // 2 GiB
{ context: "." },
);
console.log(snapshot.id);
构建参数和目标阶段
传递 build_args / buildArgs 来设置 Docker ARG 值,以及 target 来在多阶段构建的特定阶段停止。
snapshot = client.create_snapshot_from_dockerfile(
"my-app",
dockerfile="Dockerfile",
fs_capacity_bytes=2 * 1024**3,
build_args={"PYTHON_VERSION": "3.12", "ENV": "prod"},
target="runtime",
)
const snapshot = await client.createSnapshotFromDockerfile(
"my-app",
"Dockerfile",
2_147_483_648,
{
buildArgs: { PYTHON_VERSION: "3.12", ENV: "prod" },
target: "runtime",
},
);
流式传输构建日志
向 on_build_log / onBuildLog 传递回调函数以接收构建运行时产生的 stdout 和 stderr,这在显示进度或调试构建失败时非常有用。
snapshot = client.create_snapshot_from_dockerfile(
"my-app",
dockerfile="Dockerfile",
fs_capacity_bytes=2 * 1024**3,
on_build_log=lambda line: print(line, end=""),
)
const snapshot = await client.createSnapshotFromDockerfile(
"my-app",
"Dockerfile",
2_147_483_648,
{ onBuildLog: (line) => process.stdout.write(line) },
);
加速冷构建
vcpus / vCpus 和 mem_bytes / memBytes 调整临时构建器沙盒的规格。构建在 BuildKit 加上原生 snapshotter 的层拷贝内运行,默认情况下它们会争用单个核心,因此为构建器额外分配一个 vCPU 可以大幅缩短冷构建的墙上时间。
snapshot = client.create_snapshot_from_dockerfile(
"my-app",
dockerfile="Dockerfile",
fs_capacity_bytes=2 * 1024**3,
vcpus=2,
mem_bytes=4 * 1024**3, # 4 GiB
timeout=600,
)
const snapshot = await client.createSnapshotFromDockerfile(
"my-app",
"Dockerfile",
2_147_483_648,
{
vCpus: 2,
memBytes: 4_294_967_296, // 4 GiB
timeout: 600,
},
);
从运行中的沙盒捕获快照
从现有快照启动沙盒,安装软件包或准备数据,然后将结果捕获为新快照。返回的快照的 source_sandbox_id 会被设置为它所捕获自的沙盒,并且可以用作后续任何 snapshot_id 的 create_sandbox call.
sb = client.create_sandbox(snapshot_id=base_snapshot_id, name="setup-box")
sb.run("pip install numpy pandas scikit-learn", timeout=180)
sb.write("/opt/config.yaml", "model: gpt-5\n")
# Capture the current filesystem as a new snapshot
snapshot = sb.capture_snapshot("ml-ready")
print(snapshot.id, snapshot.source_sandbox_id)
sb.delete()
# Boot fresh sandboxes pre-loaded with those dependencies
with client.sandbox(snapshot_id=snapshot.id) as sb:
sb.run("python -c 'import numpy; print(numpy.__version__)'")
assert sb.read("/opt/config.yaml") == b"model: gpt-5\n"
const running = await client.createSandbox(baseSnapshotId, { name: "setup-box" });
await running.run("pip install numpy pandas scikit-learn", { timeout: 180 });
await running.write("/opt/config.yaml", "model: gpt-5\n");
const snapshot = await running.captureSnapshot("ml-ready");
console.log(snapshot.id, snapshot.source_sandbox_id);
await running.delete();
const sandbox = await client.createSandbox(snapshot.id);
try {
await sandbox.run("python -c 'import numpy; print(numpy.__version__)'");
const cfg = await sandbox.read("/opt/config.yaml");
console.log(new TextDecoder().decode(cfg));
} finally {
await sandbox.delete();
}
调整捕获时间
capture_snapshot 会阻塞直到新快照准备就绪。请提高 timeout 参数(默认 60 秒)如果您的文件系统很大或存储后端很慢。
snapshot = sb.capture_snapshot("ml-ready-v2", timeout=600)
const snapshot = await sb.captureSnapshot("ml-ready-v2", { timeout: 600 });
列出、获取和删除快照
# List all snapshots in the workspace
snapshots = client.list_snapshots()
for s in snapshots:
print(s.id, s.name, s.status)
# Fetch a single snapshot by ID
snapshot = client.get_snapshot("550e8400-e29b-41d4-a716-446655440000")
# Delete a snapshot (fails if any sandbox still references it)
client.delete_snapshot(snapshot.id)
const snapshots = await client.listSnapshots();
for (const s of snapshots) {
console.log(s.id, s.name, s.status);
}
const snapshot = await client.getSnapshot("550e8400-e29b-41d4-a716-446655440000");
await client.deleteSnapshot(snapshot.id);
停止和启动沙箱
沙箱可以停止和重启而不会丢失文件系统状态。您在上一次运行期间写入的文件在沙箱重新启动后仍然存在。
sb = client.create_sandbox(snapshot_id=snapshot.id, name="my-vm")
sb.run("echo 'hello' > /tmp/state.txt")
# Stop the sandbox — preserves files on disk
sb.stop()
# Later: start it again (blocks until ready, default timeout=120s)
sb.start()
result = sb.run("cat /tmp/state.txt")
assert result.stdout.strip() == "hello"
const sb = await client.createSandbox(snapshot.id, { name: "my-vm" });
await sb.run("echo 'hello' > /tmp/state.txt");
await sb.stop();
await sb.start();
const result = await sb.run("cat /tmp/state.txt");
console.log(result.stdout.trim()); // "hello"
您也可以通过客户端直接按名称停止和启动(client.stop_sandbox(name) / client.start_sandbox(name) 在 Python 中, client.stopSandbox(name) / client.startSandbox(name) 在 TypeScript 中)。