创建工作区
每种后端有各自的持久化模型与目录布局,选择与目标环境匹配的标签页:- 本地
- Docker
- E2B
- Daytona
- Kubernetes
- OpenSandbox
LocalWorkspace 把状态直接持久化在主机文件系统的 workdir 之下,重启后重新打开同一目录即可。目录布局如下:{workdir}/
├── .mcp # 已注册的 MCP 客户端配置(JSON 数组)
├── data/ # 卸载的多模态内容(按 SHA-256 去重)
├── skills/ # 技能子目录,各含一份 SKILL.md
│ └── .skills # 名称/哈希索引,用于去重
└── sessions/ # 各会话的 context.jsonl 与工具结果文件
from agentscope.workspace import LocalWorkspace
workspace = LocalWorkspace(
workdir="/data/my-workspace",
default_mcps=[],
skill_paths=["./skills/web-search"],
)
await workspace.initialize()
DockerWorkspace 把主机 workdir 挂载到容器内的 /workspace,因此下面的目录位于主机上,容器重启后依然存在。不传 workdir 则得到一个纯临时容器,可写层随容器一起消失。{workdir}/ # 主机目录,挂载到容器内 /workspace
├── .mcp # 已注册的 MCP 客户端配置(JSON 数组)
├── data/ # 卸载的多模态内容
├── skills/ # 技能子目录,各含一份 SKILL.md
└── sessions/ # 各会话的 context.jsonl 与工具结果文件
from agentscope.workspace import DockerWorkspace
workspace = DockerWorkspace(
base_image="python:3.11-slim",
workdir="/data/docker-workspaces/agent-1", # 挂载到 /workspace
node_version="20",
extra_pip=["numpy", "pandas"],
default_mcps=[],
skill_paths=["./skills/web-search"],
)
await workspace.initialize()
E2BWorkspace 以沙箱文件系统本身作为持久化层,没有主机 workdir。每个沙箱的 E2B 元数据中记录了 workspace_id;重启后工作区通过 AsyncSandbox.list(...) 查找并用 connect(sandbox_id=...) 重连。暂停会保留磁盘状态,恢复后原样还原。$workdir/ # 沙箱内部
├── .mcp # 已注册的 MCP 客户端配置(JSON 数组)
├── data/ # 卸载的多模态内容
├── skills/ # 技能子目录,各含一份 SKILL.md
└── sessions/ # 各会话的 context.jsonl 与工具结果文件
from agentscope.workspace import E2BWorkspace
workspace = E2BWorkspace(
template="base",
api_key="your-e2b-api-key", # 或设置 E2B_API_KEY 环境变量
timeout_seconds=300,
default_mcps=[],
skill_paths=["./skills/web-search"],
)
await workspace.initialize()
DaytonaWorkspace 面向 Daytona 部署,以沙箱文件系统作为持久化层,没有主机 workdir。每个沙箱的 Daytona 标签中记录了 workspace_id;重启后工作区按该标签重新挂接,沿用沙箱的磁盘状态。$workdir/ # 沙箱内部
├── .mcp # 已注册的 MCP 客户端配置(JSON 数组)
├── data/ # 卸载的多模态内容
├── skills/ # 技能子目录,各含一份 SKILL.md
└── sessions/ # 各会话的 context.jsonl 与工具结果文件
from agentscope.workspace import DaytonaWorkspace
workspace = DaytonaWorkspace(
api_key="your-daytona-api-key", # "" 时读取 SDK 的环境配置
api_url="", # 可选,用于自建部署
timeout_seconds=300,
extra_pip=["numpy", "pandas"],
default_mcps=[],
skill_paths=["./skills/web-search"],
)
await workspace.initialize()
K8sWorkspace 在 Kubernetes 集群上为每个工作区运行一个 Pod,并挂载一个 PVC 作为持久化层,下面的文件系统在 Pod 重启后依然存在。重启后工作区按工作区标识派生的名称重新挂接 Pod 与 PVC。设置 delete_pvc_on_close=True 可在关闭工作区时一并删除 PVC。/workspace/ # Pod 内部,由 PVC 支撑
├── .mcp # 已注册的 MCP 客户端配置(JSON 数组)
├── data/ # 卸载的多模态内容
├── skills/ # 技能子目录,各含一份 SKILL.md
└── sessions/ # 各会话的 context.jsonl 与工具结果文件
from agentscope.workspace import K8sWorkspace
workspace = K8sWorkspace(
namespace="agentscope", # Pod 与 PVC 所在的命名空间
kubeconfig=None, # None 时使用集群内配置
image="python:3.11-slim", # 容器镜像
storage_size="1Gi", # 支撑文件系统的 PVC 大小
default_mcps=[],
skill_paths=["./skills/web-search"],
)
await workspace.initialize()
OpenSandboxWorkspace 面向 OpenSandbox 部署,以沙箱文件系统作为持久化层,没有主机 workdir。每个沙箱在 agentscope.workspace.id 元数据键下记录了 workspace_id;重启后工作区按该键过滤 list_sandbox_infos(...),恢复匹配的沙箱并原样还原磁盘状态。/workspace/ # 沙箱内部(SANDBOX_WORKDIR)
├── .mcp # 已注册的 MCP 客户端配置(JSON 数组)
├── data/ # 卸载的多模态内容
├── skills/ # 技能子目录,各含一份 SKILL.md
└── sessions/ # 各会话的 context.jsonl 与工具结果文件
from agentscope.workspace import OpenSandboxWorkspace
workspace = OpenSandboxWorkspace(
image="python:3.11-slim",
api_key="your-opensandbox-api-key", # 或使用 SDK 的环境变量回退
domain="your-opensandbox-domain", # 可选,用于自建部署
protocol="http",
timeout_seconds=300,
extra_pip=["numpy", "pandas"],
default_mcps=[],
skill_paths=["./skills/web-search"],
)
await workspace.initialize()
initialize() 时在沙箱内自举,extra_pip 的包会与网关基础依赖一并装入。由于精简基础镜像冷启动时要执行数分钟的 apt-get + uv + pip,自举命令使用更长的单命令超时;除非确认镜像已预装环境,否则请保持 request_timeout_seconds 的默认值(与自举预算一致)。default_mcps 与 skill_paths 是种子输入:仅在首次 initialize() 时填充全新的工作区。重启后工作区从持久化的 .mcp 文件恢复 MCP 列表,重复传入种子不会产生效果。集成智能体
工作区从两条路径接入Agent:作为工具、MCP 与技能的来源,以及作为上下文压缩的卸载器:
from agentscope.agent import Agent
from agentscope.tool import Toolkit
from agentscope.workspace import LocalWorkspace
workspace = LocalWorkspace(workdir="./my-workspace")
await workspace.initialize()
agent = Agent(
name="coder",
system_prompt="你是一个编程助手。",
model=model,
toolkit=Toolkit(
tools=await workspace.list_tools(),
mcps=await workspace.list_mcps(),
skills_or_loaders=await workspace.list_skills(),
),
offloader=workspace,
)
| 路径 | 接入方式 | 智能体获得的能力 |
|---|---|---|
| 资源 | Toolkit(tools=..., mcps=..., skills_or_loaders=...) | 工作区中可用的内置工具、MCP 工具与技能 |
| 卸载 | Agent(offloader=workspace) | 上下文压缩触发或工具结果超限时,智能体调用 workspace.offload_context() / offload_tool_result(),并以返回的引用路径替代原始内容 |
list_tools() 返回的工具已绑定到工作区的执行后端,在沙箱类工作区上会在容器或沙箱内部运行。若要把自己构造的工具绑定到同一环境,通过 workspace.get_backend() 获取后端并传给工具构造函数,参见切换工具后端。
工作区以扁平列表的形式暴露资源,当工具过多、无法全部保持激活时,可以把它们划分为若干
ToolGroup。将分组传入 Toolkit(tool_groups=[...]) 后,智能体通过内置的元工具按需激活;只有保留的 basic 组始终在线。from agentscope.tool import Toolkit, ToolGroup
mcps = await workspace.list_mcps()
skills = await workspace.list_skills()
toolkit = Toolkit(
tools=await workspace.list_tools(), # 始终激活(basic 组)
tool_groups=[
ToolGroup(name="search", description="Web 搜索与检索。",
mcps=[m for m in mcps if m.name.startswith("search")]),
ToolGroup(name="coding", description="代码编辑技能。",
skills_or_loaders=skills),
],
)