> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentscope.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 运行工作区

> 在任意后端上创建工作区，并接入智能体

运行一个工作区分两步：在与目标环境匹配的后端上创建工作区，再把它的资源交给智能体。

## 创建工作区

每种后端有各自的持久化模型与目录布局，选择与目标环境匹配的标签页：

<Tabs>
  <Tab title="本地">
    `LocalWorkspace` 把状态直接持久化在主机文件系统的 `workdir` 之下，重启后重新打开同一目录即可。目录布局如下：

    ```
    {workdir}/
    ├── .mcp           # 已注册的 MCP 客户端配置（JSON 数组）
    ├── data/          # 卸载的多模态内容（按 SHA-256 去重）
    ├── skills/        # 技能子目录，各含一份 SKILL.md
    │   └── .skills    # 名称/哈希索引，用于去重
    └── sessions/      # 各会话的 context.jsonl 与工具结果文件
    ```

    ```python theme={null}
    from agentscope.workspace import LocalWorkspace

    workspace = LocalWorkspace(
        workdir="/data/my-workspace",
        default_mcps=[],
        skill_paths=["./skills/web-search"],
    )
    await workspace.initialize()
    ```
  </Tab>

  <Tab title="Docker">
    `DockerWorkspace` 把主机 `workdir` 挂载到容器内的 `/workspace`，因此下面的目录位于主机上，容器重启后依然存在。不传 `workdir` 则得到一个纯临时容器，可写层随容器一起消失。

    ```
    {workdir}/         # 主机目录，挂载到容器内 /workspace
    ├── .mcp           # 已注册的 MCP 客户端配置（JSON 数组）
    ├── data/          # 卸载的多模态内容
    ├── skills/        # 技能子目录，各含一份 SKILL.md
    └── sessions/      # 各会话的 context.jsonl 与工具结果文件
    ```

    ```python theme={null}
    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()
    ```
  </Tab>

  <Tab title="E2B">
    `E2BWorkspace` 以沙箱文件系统本身作为持久化层，没有主机 `workdir`。每个沙箱的 E2B 元数据中记录了 `workspace_id`；重启后工作区通过 `AsyncSandbox.list(...)` 查找并用 `connect(sandbox_id=...)` 重连。暂停会保留磁盘状态，恢复后原样还原。

    ```
    $workdir/          # 沙箱内部
    ├── .mcp           # 已注册的 MCP 客户端配置（JSON 数组）
    ├── data/          # 卸载的多模态内容
    ├── skills/        # 技能子目录，各含一份 SKILL.md
    └── sessions/      # 各会话的 context.jsonl 与工具结果文件
    ```

    ```python theme={null}
    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()
    ```
  </Tab>

  <Tab title="Daytona">
    `DaytonaWorkspace` 面向 [Daytona](https://www.daytona.io) 部署，以沙箱文件系统作为持久化层，没有主机 `workdir`。每个沙箱的 Daytona 标签中记录了 `workspace_id`；重启后工作区按该标签重新挂接，沿用沙箱的磁盘状态。

    ```
    $workdir/          # 沙箱内部
    ├── .mcp           # 已注册的 MCP 客户端配置（JSON 数组）
    ├── data/          # 卸载的多模态内容
    ├── skills/        # 技能子目录，各含一份 SKILL.md
    └── sessions/      # 各会话的 context.jsonl 与工具结果文件
    ```

    ```python theme={null}
    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()
    ```
  </Tab>

  <Tab title="Kubernetes">
    `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 与工具结果文件
    ```

    ```python theme={null}
    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()
    ```
  </Tab>

  <Tab title="OpenSandbox">
    `OpenSandboxWorkspace` 面向 [OpenSandbox](https://github.com/agentscope-ai/opensandbox) 部署，以沙箱文件系统作为持久化层，没有主机 `workdir`。每个沙箱在 `agentscope.workspace.id` 元数据键下记录了 `workspace_id`；重启后工作区按该键过滤 `list_sandbox_infos(...)`，恢复匹配的沙箱并原样还原磁盘状态。

    ```
    /workspace/        # 沙箱内部（SANDBOX_WORKDIR）
    ├── .mcp           # 已注册的 MCP 客户端配置（JSON 数组）
    ├── data/          # 卸载的多模态内容
    ├── skills/        # 技能子目录，各含一份 SKILL.md
    └── sessions/      # 各会话的 context.jsonl 与工具结果文件
    ```

    ```python theme={null}
    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` 的默认值（与自举预算一致）。
  </Tab>
</Tabs>

<Note>
  `default_mcps` 与 `skill_paths` 是种子输入：仅在首次 `initialize()` 时填充全新的工作区。重启后工作区从持久化的 `.mcp` 文件恢复 MCP 列表，重复传入种子不会产生效果。
</Note>

## 集成智能体

工作区从两条路径接入 `Agent`：作为工具、MCP 与技能的来源，以及作为上下文压缩的卸载器：

```python theme={null}
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()` 获取后端并传给工具构造函数，参见[切换工具后端](/versions/2.0.5dev/zh/building-blocks/tool/python-tool#切换工具后端)。

<Tip>
  工作区以扁平列表的形式暴露资源，当工具过多、无法全部保持激活时，可以把它们划分为若干 `ToolGroup`。将分组传入 `Toolkit(tool_groups=[...])` 后，智能体通过内置的[元工具](/versions/2.0.5dev/zh/building-blocks/tool/manage-tools)按需激活；只有保留的 `basic` 组始终在线。

  ```python theme={null}
  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),
      ],
  )
  ```
</Tip>
