blaxel-sdk
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBlaxel Skill Reference
Blaxel技能参考
What is Blaxel
什么是Blaxel
Blaxel (https://blaxel.ai) is a cloud platform that gives AI agents their own compute environments. Its flagship product is perpetual sandboxes: instant-launching microVMs that resume from standby in under 25ms and scale to zero after a few seconds of inactivity.
You use Blaxel primarily to:
- Spin up a sandbox, install dependencies, run a dev server, and expose a live preview URL
- Build and deploy sandbox templates (custom Docker images) for reusable environments
- Deploy AI agents, MCP servers, and batch jobs as serverless endpoints
SDKs: TypeScript () and Python ()
CLI: (install from https://docs.blaxel.ai/cli-reference/introduction)
Docs: https://docs.blaxel.ai
@blaxel/coreblaxelblBlaxel(https://blaxel.ai)是一款为AI Agent提供专属计算环境的云平台。其旗舰产品是永久沙箱:可即时启动的microVM,从待机状态恢复耗时不到25毫秒,闲置几秒后自动缩容至零。
你主要可以用Blaxel来:
- 创建沙箱、安装依赖、启动开发服务器并暴露实时预览URL
- 构建并部署沙箱模板(自定义Docker镜像)以实现可复用环境
- 将AI Agent、MCP服务器和批处理作业部署为无服务器端点
SDK:TypeScript()和Python()
CLI:(从https://docs.blaxel.ai/cli-reference/introduction安装)
文档:https://docs.blaxel.ai
@blaxel/coreblaxelblAuthentication
身份验证
The SDK authenticates using these sources in priority order:
- Blaxel CLI, when logged in
- Environment variables in file (
.env,BL_WORKSPACE)BL_API_KEY - System environment variables
- Blaxel configuration file ()
~/.blaxel/config.yaml
Log in locally (recommended for development):
shell
bl login YOUR-WORKSPACEOr set environment variables (for remote/CI environments):
shell
export BL_WORKSPACE=your-workspace
export BL_API_KEY=your-api-keyWhen running on Blaxel itself, authentication is automatic.
SDK按以下优先级顺序从这些来源获取认证信息:
- 已登录的Blaxel CLI
- 文件中的环境变量(
.env,BL_WORKSPACE)BL_API_KEY - 系统环境变量
- Blaxel配置文件()
~/.blaxel/config.yaml
本地登录(推荐用于开发环境):
shell
bl login YOUR-WORKSPACE或设置环境变量(用于远程/CI环境):
shell
export BL_WORKSPACE=your-workspace
export BL_API_KEY=your-api-key在Blaxel自身环境中运行时,身份验证会自动完成。
Sandbox workflow (primary use case)
沙箱工作流(主要用例)
This is the most common workflow: create a sandbox, run commands in it, and get a preview URL.
这是最常见的工作流:创建沙箱、在其中运行命令并获取预览URL。
Step 1: Create a sandbox
步骤1:创建沙箱
Use a public image from the Blaxel Hub (https://github.com/blaxel-ai/sandbox/tree/main/hub):
- — minimal Linux
blaxel/base-image:latest - — Node.js
blaxel/node:latest - — Next.js
blaxel/nextjs:latest - — Vite
blaxel/vite:latest - — Expo (React Native)
blaxel/expo:latest - — Python
blaxel/py-app:latest
Or use a custom template image you deployed yourself.
Declare the ports you need at creation time. Ports cannot be added after creation. Ports 80, 443, and 8080 are reserved.
typescript
import { SandboxInstance } from "@blaxel/core";
const sandbox = await SandboxInstance.createIfNotExists({
name: "my-sandbox",
image: "blaxel/base-image:latest",
memory: 4096,
ports: [{ target: 3000, protocol: "HTTP" }],
});python
from blaxel.core import SandboxInstance
sandbox = await SandboxInstance.create_if_not_exists({
"name": "my-sandbox",
"image": "blaxel/base-image:latest",
"memory": 4096,
"ports": [{"target": 3000, "protocol": "HTTP"}],
})Use / to reuse an existing sandbox by name or create a new one.
createIfNotExistscreate_if_not_existsAlways prefer this over a get-then-create fallback. Deleted sandboxes are kept in state for a few minutes (so their logs stay accessible), which means a plain can return a dead sandbox whose gateway and preview URLs fail with workload-not-found. checks the status for you and recreates the sandbox when the existing record is , , , or . As of 0.2.88 / 0.2.55, it also waits out the brief window right after a delete, so delete-then-recreate works directly. On older SDK versions that window can throw "Unable to create sandbox after 3 attempts" — wait a moment and retry, or upgrade. If you must use , check before reusing the instance.
TERMINATEDgetcreateIfNotExistsFAILEDTERMINATEDTERMINATINGDELETING@blaxel/coreblaxelDELETINGgetsandbox.status- — 极简Linux
blaxel/base-image:latest - — Node.js
blaxel/node:latest - — Next.js
blaxel/nextjs:latest - — Vite
blaxel/vite:latest - — Expo(React Native)
blaxel/expo:latest - — Python
blaxel/py-app:latest
或使用你自己部署的自定义模板镜像。
创建时需声明所需端口,端口无法在创建后添加。端口80、443和8080为保留端口。
typescript
import { SandboxInstance } from "@blaxel/core";
const sandbox = await SandboxInstance.createIfNotExists({
name: "my-sandbox",
image: "blaxel/base-image:latest",
memory: 4096,
ports: [{ target: 3000, protocol: "HTTP" }],
});python
from blaxel.core import SandboxInstance
sandbox = await SandboxInstance.create_if_not_exists({
"name": "my-sandbox",
"image": "blaxel/base-image:latest",
"memory": 4096,
"ports": [{"target": 3000, "protocol": "HTTP"}],
})使用 / 按名称复用现有沙箱或创建新沙箱。
createIfNotExistscreate_if_not_exists始终优先使用此方法,而非先获取再创建的回退方案。已删除的沙箱会在状态保留几分钟(以便日志可访问),这意味着直接调用可能返回已失效的沙箱,其网关和预览URL会因workload-not-found失败。会帮你检查状态,当现有记录处于、、或状态时,会重新创建沙箱。从 0.2.88 / 0.2.55版本开始,它还会在删除后的短暂窗口等待,因此删除后可直接重新创建。在旧版SDK中,该窗口可能会抛出"Unable to create sandbox after 3 attempts"错误——请稍等片刻后重试,或升级SDK。如果必须使用,请在复用实例前检查。
TERMINATEDgetcreateIfNotExistsFAILEDTERMINATEDTERMINATINGDELETING@blaxel/coreblaxelDELETINGgetsandbox.statusStep 2: Write files and run commands
步骤2:写入文件并运行命令
typescript
// Write files
await sandbox.fs.write("/app/package.json", JSON.stringify({
name: "my-app",
scripts: { dev: "astro dev --host 0.0.0.0 --port 3000" },
dependencies: { "astro": "latest" }
}));
// Or write multiple files at once
await sandbox.fs.writeTree([
{ path: "src/pages/index.astro", content: "<h1>Hello</h1>" },
{ path: "astro.config.mjs", content: "import { defineConfig } from 'astro/config';\nexport default defineConfig({});" },
], "/app");
// Execute a command and wait for it to finish
const install = await sandbox.process.exec({
name: "install",
command: "npm install",
workingDir: "/app",
waitForCompletion: true,
timeout: 60, // seconds (default 600; 0 = no auto-kill with keepAlive)
});
// Start a long-running dev server (don't wait for completion)
const devServer = await sandbox.process.exec({
name: "dev-server",
command: "npm run dev",
workingDir: "/app",
waitForPorts: [3000], // returns once port 3000 is open
});python
await sandbox.fs.write("/app/package.json", '{"name":"my-app","scripts":{"dev":"astro dev --host 0.0.0.0 --port 3000"},"dependencies":{"astro":"latest"}}')
await sandbox.fs.write_tree([
{"path": "src/pages/index.astro", "content": "<h1>Hello</h1>"},
{"path": "astro.config.mjs", "content": "import { defineConfig } from 'astro/config';\nexport default defineConfig({});"},
], "/app")
install = await sandbox.process.exec({
"name": "install",
"command": "npm install",
"working_dir": "/app",
"wait_for_completion": True,
"timeout": 60, # seconds (default 600; 0 = no auto-kill with keep_alive)
})
dev_server = await sandbox.process.exec({
"name": "dev-server",
"command": "npm run dev",
"working_dir": "/app",
"wait_for_ports": [3000],
})IMPORTANT: Dev servers must bind to (not ) to be reachable through preview URLs. Use or the env variable.
0.0.0.0localhost--host 0.0.0.0HOSTtypescript
// 写入文件
await sandbox.fs.write("/app/package.json", JSON.stringify({
name: "my-app",
scripts: { dev: "astro dev --host 0.0.0.0 --port 3000" },
dependencies: { "astro": "latest" }
}));
// 或一次性写入多个文件
await sandbox.fs.writeTree([
{ path: "src/pages/index.astro", content: "<h1>Hello</h1>" },
{ path: "astro.config.mjs", content: "import { defineConfig } from 'astro/config';\nexport default defineConfig({});" },
], "/app");
// 执行命令并等待完成
const install = await sandbox.process.exec({
name: "install",
command: "npm install",
workingDir: "/app",
waitForCompletion: true,
timeout: 60, // 秒(默认600;0表示启用keepAlive时不自动终止)
});
// 启动长期运行的开发服务器(不等待完成)
const devServer = await sandbox.process.exec({
name: "dev-server",
command: "npm run dev",
workingDir: "/app",
waitForPorts: [3000], // 端口3000开放后返回
});python
await sandbox.fs.write("/app/package.json", '{"name":"my-app","scripts":{"dev":"astro dev --host 0.0.0.0 --port 3000"},"dependencies":{"astro":"latest"}}')
await sandbox.fs.write_tree([
{"path": "src/pages/index.astro", "content": "<h1>Hello</h1>"},
{"path": "astro.config.mjs", "content": "import { defineConfig } from 'astro/config';\nexport default defineConfig({});"},
], "/app")
install = await sandbox.process.exec({
"name": "install",
"command": "npm install",
"working_dir": "/app",
"wait_for_completion": True,
"timeout": 60, # 秒(默认600;0表示启用keep_alive时不自动终止)
})
dev_server = await sandbox.process.exec({
"name": "dev-server",
"command": "npm run dev",
"working_dir": "/app",
"wait_for_ports": [3000],
})重要提示:开发服务器必须绑定到(而非)才能通过预览URL访问。使用或环境变量。
0.0.0.0localhost--host 0.0.0.0HOSTStep 3: Create a preview URL
步骤3:创建预览URL
typescript
const preview = await sandbox.previews.createIfNotExists({
metadata: { name: "app-preview" },
spec: { port: 3000, public: true },
});
const url = preview.spec?.url;
// url => https://xxxx.us-pdx-1.preview.bl.runpython
preview = await sandbox.previews.create_if_not_exists({
"metadata": {"name": "app-preview"},
"spec": {"port": 3000, "public": True},
})
url = preview.spec.urlFor private previews, set and create a token:
public: falsetypescript
const preview = await sandbox.previews.createIfNotExists({
metadata: { name: "private-preview" },
spec: { port: 3000, public: false },
});
const token = await preview.tokens.create(new Date(Date.now() + 10 * 60 * 1000));
// Access: preview.spec?.url + "?bl_preview_token=" + token.valuetypescript
const preview = await sandbox.previews.createIfNotExists({
metadata: { name: "app-preview" },
spec: { port: 3000, public: true },
});
const url = preview.spec?.url;
// url => https://xxxx.us-pdx-1.preview.bl.runpython
preview = await sandbox.previews.create_if_not_exists({
"metadata": {"name": "app-preview"},
"spec": {"port": 3000, "public": True},
})
url = preview.spec.url如需私有预览,设置并创建令牌:
public: falsetypescript
const preview = await sandbox.previews.createIfNotExists({
metadata: { name: "private-preview" },
spec: { port: 3000, public: false },
});
const token = await preview.tokens.create(new Date(Date.now() + 10 * 60 * 1000));
// 访问方式:preview.spec?.url + "?bl_preview_token=" + token.valueStep 4: Manage the sandbox
步骤4:管理沙箱
typescript
// Reconnect to an existing sandbox. Careful: get can return a recently
// deleted sandbox still in TERMINATED state — check status before reuse,
// or use createIfNotExists which handles this for you.
const sandbox = await SandboxInstance.get("my-sandbox");
// List files
const { subdirectories, files } = await sandbox.fs.ls("/app");
// Read a file
const content = await sandbox.fs.read("/app/src/pages/index.astro");
// Get process info / logs
const proc = await sandbox.process.get("dev-server");
const logs = proc.logs; // available if waitForCompletion was true
// Kill a process
await sandbox.process.kill("dev-server");
// Delete the sandbox (all data is erased)
await sandbox.delete();python
sandbox = await SandboxInstance.get("my-sandbox")
result = await sandbox.fs.ls("/app")
content = await sandbox.fs.read("/app/src/pages/index.astro")
proc = await sandbox.process.get("dev-server")typescript
// 重新连接到现有沙箱。注意:get可能返回最近删除但仍处于TERMINATED状态的沙箱——复用前请检查状态,
// 或使用createIfNotExists,它会自动处理这种情况。
const sandbox = await SandboxInstance.get("my-sandbox");
// 列出文件
const { subdirectories, files } = await sandbox.fs.ls("/app");
// 读取文件
const content = await sandbox.fs.read("/app/src/pages/index.astro");
// 获取进程信息/日志
const proc = await sandbox.process.get("dev-server");
const logs = proc.logs; // 仅当waitForCompletion为true时可用
// 终止进程
await sandbox.process.kill("dev-server");
// 删除沙箱(所有数据将被清除)
await sandbox.delete();python
sandbox = await SandboxInstance.get("my-sandbox")
result = await sandbox.fs.ls("/app")
content = await sandbox.fs.read("/app/src/pages/index.astro")
proc = await sandbox.process.get("dev-server")proc.logs available if wait_for_completion was True
proc.logs仅当wait_for_completion为True时可用
await sandbox.process.kill("dev-server")
await sandbox.delete()
undefinedawait sandbox.process.kill("dev-server")
await sandbox.delete()
undefinedSandbox templates (custom images)
沙箱模板(自定义镜像)
When you need a reusable environment (e.g. an Astro project with all deps pre-installed), create a template:
shell
bl new sandbox my-astro-template
cd my-astro-templateThis creates: , , , .
blaxel.tomlDockerfileentrypoint.shMakefileCustomize the Dockerfile. Always include the sandbox-api binary:
dockerfile
FROM node:22-alpine
WORKDIR /app
COPY /sandbox-api /usr/local/bin/sandbox-api
RUN npm install -g astro
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]The entrypoint.sh must start the sandbox-api:
bash
#!/bin/sh
/usr/local/bin/sandbox-api &
while ! nc -z 127.0.0.1 8080; do sleep 0.1; done
echo "Sandbox API ready"当你需要可复用环境(例如预安装所有依赖的Astro项目)时,创建模板:
shell
bl new sandbox my-astro-template
cd my-astro-template这会创建:、、、。
blaxel.tomlDockerfileentrypoint.shMakefile自定义Dockerfile。务必包含sandbox-api二进制文件:
dockerfile
FROM node:22-alpine
WORKDIR /app
COPY /sandbox-api /usr/local/bin/sandbox-api
RUN npm install -g astro
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]entrypoint.sh必须启动sandbox-api:
bash
#!/bin/sh
/usr/local/bin/sandbox-api &
while ! nc -z 127.0.0.1 8080; do sleep 0.1; done
echo "Sandbox API ready"Optionally start a process via the sandbox API:
可选:通过sandbox API启动进程:
curl http://127.0.0.1:8080/process -X POST -d '{"workingDir":"/app","command":"npm run dev","waitForCompletion":false}' -H "Content-Type: application/json"
curl http://127.0.0.1:8080/process -X POST -d '{"workingDir":"/app","command":"npm run dev","waitForCompletion":false}' -H "Content-Type: application/json"
wait
Deploy the template:
```shell
bl deployThen retrieve the IMAGE_ID and use it to create sandboxes:
shell
bl get sandboxes my-astro-template -ojson | jq -r '.[0].spec.runtime.image'typescript
const sandbox = await SandboxInstance.createIfNotExists({
name: "project-sandbox",
image: "IMAGE_ID",
memory: 4096,
ports: [{ target: 3000, protocol: "HTTP" }],
});wait
部署模板:
```shell
bl deploy然后获取IMAGE_ID并用于创建沙箱:
shell
bl get sandboxes my-astro-template -ojson | jq -r '.[0].spec.runtime.image'typescript
const sandbox = await SandboxInstance.createIfNotExists({
name: "project-sandbox",
image: "IMAGE_ID",
memory: 4096,
ports: [{ target: 3000, protocol: "HTTP" }],
});Tutorials and Examples
教程与示例
Sandboxes
沙箱
Agents
Agent
Core CLI commands
核心CLI命令
For CLI commands that may prompt for input (like confirmations), add to auto-confirm when running in non-interactive / no-TTY environments (e.g. scripts, CI, agents).
-y| Command | Purpose |
|---|---|
| Authenticate to workspace |
| Initialize new resource from template |
| Build and deploy resource to Blaxel |
| Deploy from a specific directory |
| Run resource locally for testing |
| Run locally with hot reload |
| List resources |
| Watch a sandbox deployment status |
| Remove resource |
| Open interactive terminal in sandbox |
| Interactive chat with deployed agent |
| Execute a deployed batch job |
对于可能提示输入(如确认信息)的CLI命令,在非交互式/无TTY环境(如脚本、CI、Agent)中运行时,添加参数自动确认。
-y| 命令 | 用途 |
|---|---|
| 认证到工作区 |
| 从模板初始化新资源 |
| 构建并部署资源到Blaxel |
| 从指定目录部署 |
| 本地运行资源进行测试 |
| 本地运行并启用热重载 |
| 列出资源 |
| 监控沙箱部署状态 |
| 删除资源 |
| 在沙箱中打开交互式终端 |
| 与已部署的Agent进行交互式聊天 |
| 执行已部署的批处理作业 |
blaxel.toml structure
blaxel.toml结构
toml
name = "my-resource"
type = "sandbox" # sandbox, agent, function, job, volume-template
[env]
NODE_ENV = "development" # NOT for secrets — use Variables-and-secrets
[runtime]
memory = 4096 # MB
generation = "mk3"toml
name = "my-resource"
type = "sandbox" # sandbox, agent, function, job, volume-template
[env]
NODE_ENV = "development" # 不要用于存储密钥——使用Variables-and-secrets
[runtime]
memory = 4096 # MB
generation = "mk3"timeout = 900 # seconds (agents max 900, jobs max 86400)
timeout = 900 # 秒(Agent最大900,作业最大86400)
Ports (sandbox only)
端口(仅沙箱可用)
[[runtime.ports]]
name = "dev-server"
target = 3000
protocol = "tcp"
undefined[[runtime.ports]]
name = "dev-server"
target = 3000
protocol = "tcp"
undefinedImportant gotchas
重要注意事项
- Ports must be declared at sandbox creation time — they cannot be added later
- Ports 80, 443, 8080 are reserved by Blaxel
- Dev servers must bind to , not
0.0.0.0, for preview URLs to worklocalhost - ~50% of sandbox memory is reserved for the in-memory filesystem (tmpfs). Use volumes for extra storage
- Sandboxes auto-scale to zero after ~5s of inactivity. State is preserved in standby and resumes in <25ms
- Deleted sandboxes stay visible in state for a few minutes (for log access). A plain
TERMINATEDcan return one; usegetor checkcreateIfNotExistsbefore reusesandbox.status - Process is in seconds (default 600). It bounds
timeout: when exceeded, the call throws a timeout error (HTTP 422) but the process keeps running — re-attach withwaitForCompletion/process.getinstead of assuming it failed. Withprocess.waitit auto-kills the process after the timeout (0 = no auto-kill). Ordinary long-running processes (e.g. dev servers started withkeepAlive) are not auto-killed by itwaitForPorts - holds the HTTP request open while the process runs (and is capped at ~58s over the sandbox MCP server). For long processes, start without it and block with
waitForCompletioninsteadprocess.wait(name, { maxWait }) - also accepts
process.exec(per-process environment variables),env, andrestartOnFailuremaxRestarts - Every process stdout/stderr line is exported as telemetry by default — heavy log volume causes real CPU contention. See "Disable process log export" below
- Secrets should never go in — use the Variables-and-secrets page in the Console
[env]
- 端口必须在沙箱创建时声明——无法在创建后添加
- 端口80、443、8080被Blaxel保留
- 开发服务器必须绑定到而非
0.0.0.0,否则预览URL无法正常工作localhost - 约50%的沙箱内存被预留用于内存文件系统(tmpfs)。如需额外存储,请使用卷
- 沙箱闲置约5秒后自动缩容至零。待机状态下会保留状态,恢复耗时<25毫秒
- 已删除的沙箱会在状态保留几分钟(以便访问日志)。直接调用
TERMINATED可能返回此类沙箱;请使用get或复用前检查createIfNotExistssandbox.status - 进程以秒为单位(默认600)。它限制
timeout:超时后,调用会抛出超时错误(HTTP 422),但进程仍会继续运行——请使用waitForCompletion/process.get重新连接,而非假设进程已失败。启用process.wait时,超时后会自动终止进程(0表示不自动终止)。普通长期运行的进程(如使用keepAlive启动的开发服务器)不会被自动终止waitForPorts - 会在进程运行期间保持HTTP请求打开(通过沙箱MCP服务器的上限约为58秒)。对于长时间运行的进程,请不使用该参数启动,而是通过
waitForCompletion阻塞等待process.wait(name, { maxWait }) - 还支持
process.exec(进程级环境变量)、env和restartOnFailure参数maxRestarts - 默认情况下,进程的每一行stdout/stderr都会作为遥测数据导出——大量日志会导致CPU资源竞争。请参阅下方"禁用进程日志导出"
- 密钥绝不能放在中——请使用控制台中的Variables-and-secrets页面
[env]
Sandbox best practices
沙箱最佳实践
Full reference: https://docs.blaxel.ai/Sandboxes/best-practices
Bulk file upload: zip + writeBinary + unzip
批量文件上传:压缩包 + writeBinary + 解压
Never write many files with one per file — each call is a network round trip (~100ms), so a few hundred files takes minutes. Bundle them into a zip, upload it with one call, and unzip inside the sandbox: 2 calls instead of N.
fs.writewriteBinarytypescript
import AdmZip from "adm-zip";
const zip = new AdmZip();
for (const f of files) zip.addFile(f.path, Buffer.from(f.content));
await sandbox.fs.writeBinary("/tmp/project.zip", zip.toBuffer());
await sandbox.process.exec({
name: "unzip",
command: "unzip -o /tmp/project.zip -d /app/project && rm /tmp/project.zip",
waitForCompletion: true,
});python
import io, zipfile
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
for f in files:
zf.writestr(f["path"], f["content"])
await sandbox.fs.write_binary("/tmp/project.zip", buf.getvalue())
await sandbox.process.exec({
"name": "unzip",
"command": "unzip -o /tmp/project.zip -d /app/project && rm /tmp/project.zip",
"wait_for_completion": True,
})For a handful of files, (one batched call) is enough. If is missing from your sandbox image, extract with instead, or install in your template image.
fs.writeTreeunzippython3 -m zipfile -e /tmp/project.zip /app/projectunzip绝不要为多个文件分别调用——每次调用都是一次网络往返(约100毫秒),几百个文件需要耗时数分钟。将它们打包成压缩包,通过一次调用上传,然后在沙箱内解压:仅需2次调用而非N次。
fs.writewriteBinarytypescript
import AdmZip from "adm-zip";
const zip = new AdmZip();
for (const f of files) zip.addFile(f.path, Buffer.from(f.content));
await sandbox.fs.writeBinary("/tmp/project.zip", zip.toBuffer());
await sandbox.process.exec({
name: "unzip",
command: "unzip -o /tmp/project.zip -d /app/project && rm /tmp/project.zip",
waitForCompletion: true,
});python
import io, zipfile
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
for f in files:
zf.writestr(f["path"], f["content"])
await sandbox.fs.write_binary("/tmp/project.zip", buf.getvalue())
await sandbox.process.exec({
"name": "unzip",
"command": "unzip -o /tmp/project.zip -d /app/project && rm /tmp/project.zip",
"wait_for_completion": True,
})对于少量文件,使用(一次批量调用)即可。如果沙箱镜像中缺少,可改用解压,或在模板镜像中安装。
fs.writeTreeunzippython3 -m zipfile -e /tmp/project.zip /app/projectunzipPersist project state across sandbox recreations
跨沙箱重建持久化项目状态
Do not re-clone a repo and re-run on every cold boot. The sandbox filesystem is erased on deletion (TTL expiry or explicit delete), but you have durable options:
npm install- Volumes: durable block storage attached at sandbox creation (). Put the project workspace and dependency cache on a volume; recreation re-attaches it and skips the re-pull. See ./references for full examples.
volumes: [{ name, mountPath }] - Agent Drive: shared filesystem mountable into running sandboxes (private preview). Good for state shared across several sandboxes.
- Template images: bake heavy dependencies into a custom sandbox image so cold boots start pre-installed.
Also remember: idle sandboxes go to standby (free, resumes in <25ms) — prefer letting a sandbox idle with a TTL over deleting and rebuilding it on every session.
不要每次冷启动都重新克隆仓库并运行。沙箱文件系统在删除(TTL过期或手动删除)时会被清除,但你有以下持久化选项:
npm install- 卷:在沙箱创建时挂载的持久块存储()。将项目工作区和依赖缓存放在卷上;重建沙箱时会重新挂载,无需重新拉取。请参阅./references获取完整示例。
volumes: [{ name, mountPath }] - Agent Drive:可挂载到运行中沙箱的共享文件系统(私有预览版)。适用于在多个沙箱之间共享状态。
- 模板镜像:将重型依赖打包到自定义沙箱镜像中,冷启动时即可直接使用预安装的依赖。
另外请记住:闲置沙箱会进入待机状态(免费,恢复耗时<25毫秒)——相比每次会话都删除并重建沙箱,更推荐让沙箱进入待机状态并设置TTL。
Disable process log export
禁用进程日志导出
By default every stdout/stderr line from sandbox processes is exported as structured telemetry. A chatty process (verbose dev server, trace-level poller) can emit thousands of lines per minute, and that export load is a known cause of CPU contention inside the sandbox.
Two ways to turn it off:
- Per sandbox: set the env var on the sandbox (e.g.
SANDBOX_DISABLE_PROCESS_LOGGING=truein your template Dockerfile, or in the sandbox env at creation).ENV SANDBOX_DISABLE_PROCESS_LOGGING=true - Workspace-wide: an admin can disable process logging for all sandboxes in Console > Workspace settings.
You lose the process logs in the Blaxel Console; reading logs through the SDK/API (, log streaming) still works.
process.get默认情况下,沙箱进程的每一行stdout/stderr都会作为结构化遥测数据导出。输出频繁的进程(如 verbose 开发服务器、跟踪级轮询器)每分钟可能输出数千行,这种导出负载是沙箱内部CPU资源竞争的已知原因。
有两种关闭方式:
- 单沙箱级:在沙箱上设置环境变量(例如在模板Dockerfile中添加
SANDBOX_DISABLE_PROCESS_LOGGING=true,或在创建沙箱时设置环境变量)。ENV SANDBOX_DISABLE_PROCESS_LOGGING=true - 工作区级:管理员可在控制台>工作区设置中为所有沙箱禁用进程日志。
禁用后,你将无法在Blaxel控制台中查看进程日志;但通过SDK/API(、日志流)读取日志仍然可用。
process.getCommon antipatterns to flag when reviewing integrations
审查集成时需注意的常见反模式
| Antipattern | Symptom | Fix |
|---|---|---|
get-then-create instead of | workload-not-found on gateway/preview URL after a delete + quick recreate (sandbox returned in | |
| Re-pulling repo + reinstalling deps on every cold boot | minutes of startup on every session | volume or Agent Drive for the workspace; template image for deps |
One | restore takes minutes (N network round trips) | zip + |
| Verbose stdout with log export left on | CPU spikes during compiles/heavy output | |
| Deleting sandboxes on idle | cold rebuild on every return visit | let standby handle idleness; use |
| 反模式 | 症状 | 修复方案 |
|---|---|---|
使用get-then-create而非 | 删除后快速重建沙箱时,网关/预览URL出现workload-not-found错误(返回的沙箱处于 | 使用 |
| 每次冷启动都重新拉取仓库并重新安装依赖 | 每次会话启动耗时数分钟 | 使用卷或Agent Drive存储工作区;使用模板镜像存储依赖 |
为多个文件分别调用 | 恢复耗时数分钟(N次网络往返) | 使用压缩包 + |
| 输出频繁且日志导出处于启用状态 | 编译/大量输出期间CPU飙升 | 设置 |
| 闲置时删除沙箱 | 每次返回都需冷重建 | 让沙箱进入待机状态处理闲置;使用 |
Agent Drive (shared filesystem)
Agent Drive(共享文件系统)
Agent Drive is a distributed filesystem backed by SeaweedFS that can be mounted to multiple sandboxes or agents at any time, including while they are already running. Unlike volumes (block storage attached only at sandbox creation), drives support concurrent read-write access from multiple sandboxes and can be attached/detached dynamically.
This feature is currently in private preview. During the preview, Agent Drive is only available in theregion. Both drive and sandbox must be in this region.us-was-1
Use cases:
- Passing data between sandboxes without intermediary services
- Storing tool outputs and context histories for other agents
- Sharing datasets across multiple agents
- Creating a shared filesystem cache of package dependencies
Agent Drive是基于SeaweedFS的分布式文件系统,可随时挂载到多个沙箱或Agent,包括它们正在运行时。与卷(仅在沙箱创建时挂载的块存储)不同,Drive支持多个沙箱并发读写访问,且可动态挂载/卸载。
此功能目前处于私有预览阶段。预览期间,Agent Drive仅在区域可用。Drive和沙箱必须位于同一区域。us-was-1
适用场景:
- 无需中间服务即可在沙箱之间传递数据
- 为其他Agent存储工具输出和上下文历史
- 在多个Agent之间共享数据集
- 创建包依赖的共享文件系统缓存
Create a drive
创建Drive
typescript
import { DriveInstance } from "@blaxel/core";
const drive = await DriveInstance.createIfNotExists({
name: "my-drive",
region: "us-was-1",
displayName: "My Project Drive", // optional; defaults to name
labels: { env: "dev", project: "x" }, // optional
});python
from blaxel.core.drive import DriveInstance
drive = await DriveInstance.create_if_not_exists(
{
"name": "my-drive",
"region": "us-was-1",
"display_name": "My Project Drive",
"labels": {"env": "dev", "project": "x"},
}
)typescript
import { DriveInstance } from "@blaxel/core";
const drive = await DriveInstance.createIfNotExists({
name: "my-drive",
region: "us-was-1",
displayName: "My Project Drive", // 可选;默认值为name
labels: { env: "dev", project: "x" }, // 可选
});python
from blaxel.core.drive import DriveInstance
drive = await DriveInstance.create_if_not_exists(
{
"name": "my-drive",
"region": "us-was-1",
"display_name": "My Project Drive",
"labels": {"env": "dev", "project": "x"},
}
)Mount a drive to a sandbox
将Drive挂载到沙箱
typescript
import { SandboxInstance } from "@blaxel/core";
const sandbox = await SandboxInstance.get("my-sandbox");
await sandbox.drives.mount({
driveName: "my-drive",
mountPath: "/mnt/data",
drivePath: "/", // optional; defaults to root of the drive
});python
from blaxel.core import SandboxInstance
sandbox = await SandboxInstance.get("my-sandbox")
await sandbox.drives.mount(
drive_name="my-drive",
mount_path="/mnt/data",
drive_path="/",
)Once mounted, any file written to the mount path inside the sandbox is stored on the drive and persists even after the sandbox is deleted.
typescript
import { SandboxInstance } from "@blaxel/core";
const sandbox = await SandboxInstance.get("my-sandbox");
await sandbox.drives.mount({
driveName: "my-drive",
mountPath: "/mnt/data",
drivePath: "/", // 可选;默认值为Drive根目录
});python
from blaxel.core import SandboxInstance
sandbox = await SandboxInstance.get("my-sandbox")
await sandbox.drives.mount(
drive_name="my-drive",
mount_path="/mnt/data",
drive_path="/",
)挂载后,沙箱内挂载路径下写入的任何文件都会存储在Drive上,即使沙箱被删除也会保留。
Mount a subdirectory
挂载子目录
typescript
await sandbox.drives.mount({
driveName: "my-drive",
mountPath: "/app/project",
drivePath: "/projects/alpha",
});python
await sandbox.drives.mount(
drive_name="my-drive",
mount_path="/app/project",
drive_path="/projects/alpha",
)typescript
await sandbox.drives.mount({
driveName: "my-drive",
mountPath: "/app/project",
drivePath: "/projects/alpha",
});python
await sandbox.drives.mount(
drive_name="my-drive",
mount_path="/app/project",
drive_path="/projects/alpha",
)List, unmount, and delete drives
列出、卸载和删除Drive
typescript
// List mounted drives on a sandbox
const mounts = await sandbox.drives.list();
// List all drives
const drives = await DriveInstance.list();
// Unmount
await sandbox.drives.unmount("/mnt/data");
// Delete a drive
await DriveInstance.delete("my-drive");
// or instance-level:
const drive = await DriveInstance.get("my-drive");
await drive.delete();python
mounts = await sandbox.drives.list()
drives = await DriveInstance.list()
await sandbox.drives.unmount("/mnt/data")
await DriveInstance.delete("my-drive")typescript
// 列出沙箱上已挂载的Drive
const mounts = await sandbox.drives.list();
// 列出所有Drive
const drives = await DriveInstance.list();
// 卸载
await sandbox.drives.unmount("/mnt/data");
// 删除Drive
await DriveInstance.delete("my-drive");
// 或实例级操作:
const drive = await DriveInstance.get("my-drive");
await drive.delete();python
mounts = await sandbox.drives.list()
drives = await DriveInstance.list()
await sandbox.drives.unmount("/mnt/data")
await DriveInstance.delete("my-drive")or instance-level:
或实例级操作:
drive = await DriveInstance.get("my-drive")
await drive.delete()
CLI: `bl get drives`drive = await DriveInstance.get("my-drive")
await drive.delete()
CLI命令:`bl get drives`Full Agent Drive example
Agent Drive完整示例
typescript
import { SandboxInstance, DriveInstance } from "@blaxel/core";
// 1. Create a drive
const drive = await DriveInstance.createIfNotExists({
name: "agent-storage",
region: "us-was-1",
});
// 2. Create a sandbox (use image ID from custom template)
const sandbox = await SandboxInstance.createIfNotExists({
name: "my-agent-sandbox",
image: "my-sandbox-image-id",
memory: 2048,
region: "us-was-1",
});
// 3. Mount the drive
await sandbox.drives.mount({
driveName: "agent-storage",
mountPath: "/mnt/storage",
drivePath: "/",
});
// 4. Write a file to the mounted drive
await sandbox.fs.write("/mnt/storage/hello.txt", "Hello from the drive!");
// 5. Read it back
const content = await sandbox.fs.read("/mnt/storage/hello.txt");
console.log(content); // "Hello from the drive!"
// 6. List mounted drives
const mounts = await sandbox.drives.list();
console.log(mounts);python
import asyncio
from blaxel.core.drive import DriveInstance
from blaxel.core import SandboxInstance
async def main():
drive = await DriveInstance.create_if_not_exists(
{"name": "agent-storage", "region": "us-was-1"}
)
sandbox = await SandboxInstance.create_if_not_exists(
{
"name": "my-agent-sandbox",
"image": "my-sandbox-image-id",
"memory": 2048,
"region": "us-was-1",
}
)
await sandbox.drives.mount(
drive_name="agent-storage",
mount_path="/mnt/storage",
drive_path="/",
)
await sandbox.fs.write("/mnt/storage/hello.txt", "Hello from the drive!")
content = await sandbox.fs.read("/mnt/storage/hello.txt")
print(content)
mounts = await sandbox.drives.list()
print(mounts)
asyncio.run(main())typescript
import { SandboxInstance, DriveInstance } from "@blaxel/core";
// 1. 创建Drive
const drive = await DriveInstance.createIfNotExists({
name: "agent-storage",
region: "us-was-1",
});
// 2. 创建沙箱(使用自定义模板的镜像ID)
const sandbox = await SandboxInstance.createIfNotExists({
name: "my-agent-sandbox",
image: "my-sandbox-image-id",
memory: 2048,
region: "us-was-1",
});
// 3. 挂载Drive
await sandbox.drives.mount({
driveName: "agent-storage",
mountPath: "/mnt/storage",
drivePath: "/",
});
// 4. 向挂载的Drive写入文件
await sandbox.fs.write("/mnt/storage/hello.txt", "Hello from the drive!");
// 5. 读取文件
const content = await sandbox.fs.read("/mnt/storage/hello.txt");
console.log(content); // "Hello from the drive!"
// 6. 列出已挂载的Drive
const mounts = await sandbox.drives.list();
console.log(mounts);python
import asyncio
from blaxel.core.drive import DriveInstance
from blaxel.core import SandboxInstance
async def main():
drive = await DriveInstance.create_if_not_exists(
{"name": "agent-storage", "region": "us-was-1"}
)
sandbox = await SandboxInstance.create_if_not_exists(
{
"name": "my-agent-sandbox",
"image": "my-sandbox-image-id",
"memory": 2048,
"region": "us-was-1",
}
)
await sandbox.drives.mount(
drive_name="agent-storage",
mount_path="/mnt/storage",
drive_path="/",
)
await sandbox.fs.write("/mnt/storage/hello.txt", "Hello from the drive!")
content = await sandbox.fs.read("/mnt/storage/hello.txt")
print(content)
mounts = await sandbox.drives.list()
print(mounts)
asyncio.run(main())Other Blaxel resources
其他Blaxel资源
Agents Hosting
Agent托管
Deploy AI agents as serverless auto-scaling HTTP endpoints. Framework-agnostic (LangChain, CrewAI, Claude SDK, etc.).
shell
bl new agent将AI Agent部署为无服务器自动扩缩容HTTP端点。支持任意框架(LangChain、CrewAI、Claude SDK等)。
shell
bl new agentdevelop in src/agent.ts or src/agent.py
在src/agent.ts或src/agent.py中开发
bl serve # test locally
bl deploy # deploy
bl chat AGENT-NAME # query
Sync endpoint handles requests up to 100s, async endpoint up to 10 minutes.
Docs: https://docs.blaxel.ai/Agents/Overviewbl serve # 本地测试
bl deploy # 部署
bl chat AGENT-NAME # 查询
同步端点处理最长100秒的请求,异步端点最长处理10分钟的请求。
文档:https://docs.blaxel.ai/Agents/OverviewMCP Servers Hosting
MCP服务器托管
Deploy custom tool servers following the MCP protocol.
shell
bl new mcp部署遵循MCP协议的自定义工具服务器。
shell
bl new mcpimplement in src/server.ts or src/server.py
在src/server.ts或src/server.py中实现
bl serve --hotreload # test locally
bl deploy
Agents connect to deployed MCP servers via SDK:
```typescript
const tools = await blTools(["functions/my-mcp-server"]);Every sandbox also exposes its own built-in MCP server at with tools for process management, filesystem, and code generation.
Docs: https://docs.blaxel.ai/Functions/Overview
https://<SANDBOX_URL>/mcpbl serve --hotreload # 本地测试
bl deploy
Agent通过SDK连接到已部署的MCP服务器:
```typescript
const tools = await blTools(["functions/my-mcp-server"]);每个沙箱还会在暴露内置MCP服务器,提供进程管理、文件系统和代码生成工具。
文档:https://docs.blaxel.ai/Functions/Overview
https://<SANDBOX_URL>/mcpBatch Jobs
批处理作业
Scalable compute for parallel background tasks (minutes to hours).
shell
bl new job用于并行后台任务的可扩缩计算(耗时数分钟到数小时)。
shell
bl new jobimplement in src/index.ts or src/index.py
在src/index.ts或src/index.py中实现
bl deploy
bl run job NAME --data '{"tasks": [...]}'
Max 24h per task. Set `maxConcurrentTasks` in blaxel.toml.
Docs: https://docs.blaxel.ai/Jobs/Overviewbl deploy
bl run job NAME --data '{"tasks": [...]}'
每个任务最长耗时24小时。在blaxel.toml中设置`maxConcurrentTasks`。
文档:https://docs.blaxel.ai/Jobs/OverviewResources
资源
- Deployment configuration reference: https://docs.blaxel.ai/deployment-reference
- CLI command reference: https://docs.blaxel.ai/cli-reference/introduction
Read individual SDK files for detailed explanations and code examples:
- ./references/sdk-python.md
- ./references/sdk-typescript.md
Each SDK README contains:
- An overview of the SDK
- Requirements
- Code examples for working with sandboxes, volumes, agents, batch jobs, MCP
- Additional useful information
For additional documentation, see: https://docs.blaxel.ai/llms.txt
- 部署配置参考:https://docs.blaxel.ai/deployment-reference
- CLI命令参考:https://docs.blaxel.ai/cli-reference/introduction
阅读各个SDK文件获取详细说明和代码示例:
- ./references/sdk-python.md
- ./references/sdk-typescript.md
每个SDK README包含:
- SDK概述
- 要求
- 沙箱、卷、Agent、批处理作业、MCP的代码示例
- 其他有用信息
更多文档请参阅:https://docs.blaxel.ai/llms.txt