沙盒功能目前处于私密预览阶段。随着我们的迭代,API 和功能可能会发生变化。注册等待列表 以获取访问权限。
LangSmith SDK 提供了一个用于创建和交互沙盒的编程接口。
# uv
uv add "langsmith[sandbox] @ git+https://github.com/langchain-ai/langsmith-sdk#subdirectory=python"
# pip
pip install "langsmith[sandbox] @ git+https://github.com/langchain-ai/langsmith-sdk#subdirectory=python"
Python 的 [sandbox] 额外依赖会安装 websockets,这支持实时流式传输和 timeout=0。如果没有它,run() 会自动回退到 HTTP。对于 TypeScript,请安装可选的 ws 包以支持 WebSocket 流式传输:
创建并运行沙盒
每个沙盒都从一个快照 启动——一个由 Docker 镜像支持的文件系统镜像。选择一个现有快照或创建一个新快照(完整的构建/捕获/CRUD 流程请参见快照 );以下每个示例都使用你已有的 snapshot_id / snapshotId。
from langsmith . sandbox import SandboxClient
# 客户端使用环境变量中的 LANGSMITH_ENDPOINT 和 LANGSMITH_API_KEY
client = SandboxClient ()
# 选择一个现有快照,或使用 client.create_snapshot(...) 构建一个
snapshot_id = "550e8400-e29b-41d4-a716-446655440000"
# 从快照创建一个沙盒并运行代码
with client . sandbox ( snapshot_id = snapshot_id ) as sb :
result = sb . run ( "python -c 'print(2 + 2)'" )
print ( result . stdout ) # "4\n"
print ( result . success ) # True
运行命令
每次 run() 调用都会返回一个包含 stdout、stderr、exit_code 和 success 的 ExecutionResult。
with client . sandbox ( snapshot_id = snapshot_id ) as sb :
result = sb . run ( "echo 'Hello, World!'" )
print ( result . stdout ) # "Hello, World!\n"
print ( result . stderr ) # ""
print ( result . exit_code ) # 0
print ( result . success ) # True
# 失败的命令会返回非零退出码
result = sb . run ( "exit 1" )
print ( result . success ) # False
print ( result . exit_code ) # 1
流式输出
对于长时间运行的命令,可以使用回调或 CommandHandle 实时流式输出。
使用回调进行流式传输
import sys
with client . sandbox ( snapshot_id = snapshot_id ) as sb :
result = sb . run (
"make build" ,
timeout = 600 ,
on_stdout = lambda s : print ( s , end = "" ),
on_stderr = lambda s : print ( s , end = "" , file = sys . stderr ),
)
print ( f " \n 构建 { '成功' if result . success else '失败' } " )
使用 CommandHandle 进行流式传输
设置 wait=False 以获取 CommandHandle,从而完全控制输出流。
with client . sandbox ( snapshot_id = snapshot_id ) as sb :
handle = sb . run ( "make build" , timeout = 600 , wait = False )
print ( f "命令 ID: { handle . command_id } " )
for chunk in handle :
prefix = "OUT" if chunk . stream == "stdout" else "ERR"
print ( f "[ { prefix } ] { chunk . data } " , end = "" )
result = handle . result
print ( f " \n 退出码: { result . exit_code } " )
发送标准输入和终止命令
with client . sandbox ( snapshot_id = snapshot_id ) as sb :
handle = sb . run (
"python -c 'name = input( \" Name: \" ); print(f \" Hello {name}\" )'" ,
timeout = 30 ,
wait = False ,
)
for chunk in handle :
if "Name:" in chunk . data :
handle . send_input ( "World \n " )
print ( chunk . data , end = "" )
result = handle . result
终止正在运行的命令:
with client . sandbox ( snapshot_id = snapshot_id ) as sb :
handle = sb . run ( "python server.py" , timeout = 0 , wait = False )
for chunk in handle :
print ( chunk . data , end = "" )
if "Ready" in chunk . data :
break
handle . kill ()
重新连接到正在运行的命令
如果客户端断开连接,可以使用命令 ID 重新连接:
with client . sandbox ( snapshot_id = snapshot_id ) as sb :
handle = sb . run ( "make build" , timeout = 600 , wait = False )
command_id = handle . command_id
# 稍后,可能在不同的进程中
handle = sb . reconnect ( command_id )
for chunk in handle :
print ( chunk . data , end = "" )
result = handle . result
文件操作
在沙盒中读写文件:
with client . sandbox ( snapshot_id = snapshot_id ) as sb :
# 写入文件
sb . write ( "/app/script.py" , "print('Hello from file!')" )
# 运行脚本
result = sb . run ( "python /app/script.py" )
print ( result . stdout ) # "Hello from file!\n"
# 读取文件(返回字节)
content = sb . read ( "/app/script.py" )
print ( content . decode ()) # "print('Hello from file!')"
# 写入二进制文件
sb . write ( "/app/data.bin" , b " \x00\x01\x02\x03 " )
命令生命周期和 TTL
沙盒守护进程通过两种超时机制管理命令会话的生命周期:
会话 TTL(已完成的命令) :命令完成后,其会话会在内存中保留一段 TTL 时间。在此窗口期内,你可以重新连接以检索输出。TTL 过期后,会话将被清理。
空闲超时(正在运行的命令) :没有连接客户端的正在运行的命令将在空闲超时后被终止(默认:5 分钟)。每次客户端连接时,空闲计时器都会重置。设置为 -1 表示没有空闲超时。
组合生命周期选项
with client . sandbox ( snapshot_id = snapshot_id ) as sb :
# 长时间运行的任务:30 分钟空闲超时,1 小时会话 TTL
handle = sb . run (
"python train.py" ,
timeout = 0 , # 无命令超时
idle_timeout = 1800 , # 30 分钟无客户端后终止
ttl_seconds = 3600 , # 退出后会话保留 1 小时
wait = False ,
)
# 即发即忘:无空闲超时,无限 TTL
handle = sb . run (
"python background_job.py" ,
timeout = 0 ,
idle_timeout =- 1 , # 永不因空闲而终止
ttl_seconds =- 1 , # 永久保留会话
wait = False ,
)
设置 kill_on_disconnect=True(Python)或 killOnDisconnect: true(TypeScript)可以在最后一个客户端断开连接时立即终止命令,而不是等待空闲超时。
服务 URL(Python)
通过经过身份验证的 URL 访问在沙盒内运行的 HTTP 服务。你可以在浏览器中打开它,从代码中调用它,或与队友共享它。
with client . sandbox ( snapshot_id = snapshot_id ) as sb :
sb . run ( "python -m http.server 8000" , timeout = 0 , wait = False )
svc = sb . service ( port = 8000 )
# 在浏览器中打开
print ( svc . browser_url )
# 或使用内置辅助工具发出请求(身份验证会自动注入)
resp = svc . get ( "/api/data" )
resp = svc . post ( "/api/data" , json = { "key" : "value" })
更多详情,包括用例、REST API 访问和完整的 FastAPI 示例,请参见服务 URL 。
TCP 隧道(Python)
像访问本地服务一样访问沙盒内运行的任何 TCP 服务。隧道会打开一个本地 TCP 端口,并通过 WebSocket 将连接转发到沙盒内的目标端口。
import psycopg2
# 从官方 postgres:16 镜像构建的快照
sb = client . create_sandbox ( snapshot_id = postgres_snapshot_id )
pg_handle = sb . run (
"POSTGRES_HOST_AUTH_METHOD=trust docker-entrypoint.sh postgres" ,
timeout = 0 ,
wait = False ,
)
import time; time . sleep ( 6 ) # 等待 Postgres 启动
try :
with sb . tunnel ( remote_port = 5432 , local_port = 25432 ) as t :
conn = psycopg2 . connect (
host = "127.0.0.1" ,
port = t . local_port ,
user = "postgres" ,
)
cursor = conn . cursor ()
cursor . execute ( "SELECT version()" )
print ( cursor . fetchone ())
conn . close ()
finally :
pg_handle . kill ()
client . delete_sandbox ( sb . name )
隧道适用于任何 TCP 服务(Redis、HTTP 服务器等),并且你可以同时打开多个隧道:
with sb . tunnel ( remote_port = 5432 , local_port = 25432 ) as t1 , \
sb . tunnel ( remote_port = 6379 , local_port = 26379 ) as t2 :
# 同时使用 Postgres 和 Redis
pass
异步支持(Python)
Python SDK 提供了完整的异步客户端:
from langsmith . sandbox import AsyncSandboxClient
async def main ():
async with AsyncSandboxClient () as client :
async with await client . sandbox ( snapshot_id = snapshot_id ) as sb :
result = await sb . run ( "python -c 'print(1 + 1)'" )
print ( result . stdout ) # "2\n"
await sb . write ( "/app/test.txt" , "async content" )
content = await sb . read ( "/app/test.txt" )
print ( content . decode ())
# 异步流式传输
handle = await sb . run ( "make build" , timeout = 600 , wait = False )
async for chunk in handle :
print ( chunk . data , end = "" )
result = await handle . result
# 异步服务 URL
svc = await sb . service ( port = 8000 )
resp = await svc . get ( "/api/data" )
url = await svc . get_service_url ()
token = await svc . get_token ()
跟踪沙盒活动
通过 run() 的 env 参数传递 LangSmith 跟踪环境变量,以发送从沙盒内运行的代码中产生的跟踪信息。在进程退出前调用 flush() 以确保所有跟踪信息都被发送。
from langsmith . sandbox import SandboxClient
client = SandboxClient ()
tracing_env = {
"LANGSMITH_API_KEY" : "lsv2_pt_..." ,
"LANGSMITH_ENDPOINT" : "https://api.smith.langchain.com" ,
"LANGSMITH_TRACING" : "true" ,
"LANGSMITH_PROJECT" : "my-sandbox-traces" ,
}
with client . sandbox ( snapshot_id = snapshot_id ) as sandbox :
sandbox . run ( "pip install langsmith" , timeout = 120 , env = tracing_env )
result = sandbox . run ( "python3 my_agent.py" , env = tracing_env )
print ( result . stdout )
在沙盒内部,任何经过 LangSmith 插桩的代码(@traceable、LangChain、LangGraph)都会自动从注入的环境变量中获取跟踪配置。
务必在沙盒进程退出前调用 flush() —— Python 中使用 langsmith.Client().flush(),TypeScript 中使用 await new Client().flush()。否则,跟踪信息可能会丢失,因为容器在命令完成时会被销毁。
错误处理
两个 SDK 都提供了类型化的异常用于特定错误处理:
from langsmith . sandbox import (
SandboxClientError , # 基础异常
ResourceCreationError , # 资源创建失败
ResourceNotFoundError , # 资源不存在
ResourceTimeoutError , # 操作超时
SandboxNotReadyError , # 沙盒尚未就绪
SandboxConnectionError , # 网络/WebSocket 错误
CommandTimeoutError , # 命令超时
QuotaExceededError , # 达到配额限制
)
try :
with client . sandbox ( snapshot_id = snapshot_id ) as sb :
result = sb . run ( "sleep 999" , timeout = 10 )
except CommandTimeoutError as e :
print ( f "命令超时: { e } " )
except ResourceNotFoundError as e :
print ( f " { e . resource_type } 未找到: { e } " )
except SandboxClientError as e :
print ( f "错误: { e } " )
将这些文档连接 到 Claude、VSCode 等,通过 MCP 获取实时答案。