面向 AI 助手:本页的 Markdown 版本位于 https://ark.volcengine.com/region:cn-beijing/docs/configure-self-hosted-environment.md,全部文档索引见 https://ark.volcengine.com/llms.txt。

配置并运行自托管环境

本文介绍如何从零配置自托管环境(Self-hosted Environment),选择 Go、Python 或 Java SDK 启动 Worker,并完成一次完整的 Session 工具执行。

你将完成什么#

  • 在控制台创建 self_hosted 类型的环境
  • 为 Worker 配置并安全保存 API Key
  • 选择 Go、Python 或 Java SDK,在企业主机启动 Worker
  • 创建绑定自托管环境的 Session
  • 发送用户消息,让 Agent 在企业主机执行工具
  • 验证工具执行结果、Session 终态和 Worker 状态

核心概念#

概念 说明
Environment Agent 运行时配置,type 为 self_hosted 时表示自托管环境
Worker 企业部署的进程,轮询 Work Queue 并在企业 Sandbox 中执行工具调用
Work Item 方舟为需要工具执行的 Session 生成的任务项,Work ID 与 Session ID 一致
API Key Worker 和业务应用调用方舟接口时使用的鉴权凭证。Worker 使用的 API Key 权限取决于所属账号、项目和凭证策略,不会自动限制为只能访问某个 Environment

工作流程#

以下是自托管环境端到端的工作流程:

  1. 企业管理员创建自托管 Environment,并为 Worker 准备 API Key。
  2. 企业运维人员在企业主机启动 Worker,Worker 开始轮询 Work Queue。
  3. 业务应用使用业务 API Key 创建 Session,建立事件流后发送用户消息。
  4. 方舟控制面生成 Work Item,Worker 领取并 Ack。
  5. Worker 在企业 Sandbox 中执行工具调用(Bash、文件读写、自定义工具)。
  6. Worker 将 Tool Result 回传方舟,驱动下一轮推理。
  7. 重复步骤 5-6,直到 Session 进入 idle 或终态。
  8. Worker 完成 Work Item,继续轮询。

前置条件#

开始前,请确认以下条件已满足:

  • 已开通 Managed Agents 服务,并已创建 Agent(参见 快速入门)
  • 准备一台企业管理的 Linux 主机或隔离容器,具备以下条件:
    • /bin/bash 可用
    • /workspace 目录可写
    • 已选择一种 Ark Runtime SDK,并按对应仓库 README 准备运行环境:Go、Python 或 Java
  • Worker 主机能够通过出站 HTTPS 访问方舟 API(https://ark.cn-beijing.volces.com/api/v3),无需开放入站端口
  • 业务应用所在主机已安装 curl 和 jq
  • 准备业务 API Key(用于创建 Session,由业务应用持有)
  • 准备 Worker 使用的方舟 API Key,由 Worker 主机持有

第 1 步:创建自托管环境#

在控制台的 Environments 页面或使用 API 创建自托管环境。

使用 API 创建环境:

Bash
curl -sS https://ark.cn-beijing.volces.com/api/v3/environments \
  -H "Authorization: Bearer $ARK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-self-hosted-env",
    "description": "自托管环境,用于执行企业内部工具",
    "config": {
      "type": "self_hosted"
    }
  }'

响应示例:

{
  "id": "env-20260822120000-xxxxx",
  "type": "environment",
  "name": "my-self-hosted-env",
  "config": {
    "type": "self_hosted"
  },
  "created_at": "2026-08-22T04:00:00Z"
}

将返回的 id 记录为 ENVIRONMENT_ID,后续步骤会用到。

第 2 步:配置 Worker API Key#

为 Worker 准备一个可访问当前账号和项目中 Managed Agents 资源的方舟 API Key。API Key 的创建方法,详情请参见 API Key 管理。

配置 Worker 主机的环境变量:

bash
export MA_ENVIRONMENT_ID="env-20260822120000-xxxxx"
export MA_WORKDIR="/workspace"
export ARK_API_KEY="<WORKER_API_KEY>"
# Optional: set ARK_BASE_URL only when overriding the SDK default endpoint.
export ARK_BASE_URL="https://ark.cn-beijing.volces.com/api/v3"

将 ARK_API_KEY 设置为 Worker 使用的方舟 API Key。SDK 会同时使用 MA_ENVIRONMENT_ID 定位 Work Queue,但该 ID 不会改变 API Key 的权限范围。

第 3 步:准备 Worker 主机#

在企业 Linux 主机上创建工作目录,并选择一种 SDK 安装。各 SDK 的运行环境和安装方式以官方仓库 README 为准:

bash
mkdir -p /workspace
cd /workspace

cat > /workspace/input.csv <<'CSV'
department,requests,resolved
sales,120,114
support,95,91
operations,80,79
CSV

test -s /workspace/input.csv

该固定输入用于步骤 5 的首次工具调用。test 返回状态码 0,表示文件已创建且内容非空。

按照 Go SDK 仓库 README 安装:

bash
go mod init self-hosted-worker
go get github.com/volcengine/ark-runtime-go@latest

按照 Python SDK 仓库 README 安装:

bash
python -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
python -m pip install --upgrade arkruntime

按照 Java SDK 仓库 README,在 Maven 项目的 pom.xml 中添加依赖:

xml
<dependency>
  <groupId>com.volcengine</groupId>
  <artifactId>ark-runtime</artifactId>
  <version><VERSION></version>
</dependency>

检查以下条件:

  • /bin/bash 可用且 Worker 进程有执行权限
  • /workspace 目录可读写
  • 出站 HTTPS 可达 https://ark.cn-beijing.volces.com/api/v3
  • 准备 Agent 需要访问的企业文件或内部服务

第 4 步:启动常驻 Worker#

使用 SDK 启动 EnvironmentWorker。以下示例会持续 Poll Work Queue,领取 Work Item 后在 MA_WORKDIR 下为每个 Session 创建独立工作目录。

创建 main.go:

go
package main

import (
    "context"
    "log"
    "os"
    "os/signal"
    "syscall"

    "github.com/volcengine/ark-runtime-go/arkruntime"
    "github.com/volcengine/ark-runtime-go/arkruntime/lib/environments"
)

func main() {
    apiKey := os.Getenv("ARK_API_KEY")
    baseURL := os.Getenv("ARK_BASE_URL")
    envID := os.Getenv("MA_ENVIRONMENT_ID")
    workdir := os.Getenv("MA_WORKDIR")
    if apiKey == "" || envID == "" {
        log.Fatal("ARK_API_KEY and MA_ENVIRONMENT_ID are required")
    }
    if workdir == "" {
        workdir = "/workspace"
    }

    clientOptions := make([]arkruntime.ConfigOption, 0, 1)
    if baseURL != "" {
        clientOptions = append(clientOptions, arkruntime.WithBaseUrl(baseURL))
    }
    client := arkruntime.NewClientWithApiKey(apiKey, clientOptions...)
    worker := environments.NewEnvironmentWorkerForClient(client, environments.EnvironmentWorkerOptions{
        EnvironmentID: envID,
        WorkerID:      os.Getenv("MA_WORKER_ID"),
        Workdir:       workdir,
    })

    log.Printf("worker starting for environment %s", envID)
    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
    defer stop()
    if err := worker.Run(ctx); err != nil {
        log.Fatalf("worker exited with error: %v", err)
    }
}

创建 worker.py:

python
import os
import signal
import sys

from arkruntime import Ark
from arkruntime.selfhosted import ClientAPI, EnvironmentWorker, EnvironmentWorkerOptions


def required_env(name):
    value = os.environ.get(name, "")
    if not value:
        raise RuntimeError(f"{name} is required")
    return value


client_options = {"api_key": required_env("ARK_API_KEY")}
if os.environ.get("ARK_BASE_URL"):
    client_options["base_url"] = os.environ["ARK_BASE_URL"]

client = Ark(**client_options)

worker = EnvironmentWorker(
    ClientAPI(client),
    EnvironmentWorkerOptions(
        environment_id=required_env("MA_ENVIRONMENT_ID"),
        worker_id=os.environ.get("MA_WORKER_ID", ""),
        workdir=os.environ.get("MA_WORKDIR", "/workspace"),
    ),
)

print(f"worker starting for environment {os.environ['MA_ENVIRONMENT_ID']}", file=sys.stderr)
for sig in (signal.SIGINT, signal.SIGTERM):
    signal.signal(sig, lambda _signum, _frame: worker.close())

try:
    worker.run()
finally:
    worker.close()
    client.close()

在 Maven 项目的 src/main/java/ 目录下创建 SelfHostedWorkerExample.java:

java
import com.volcengine.ark.runtime.selfhosted.EnvironmentWorker;
import com.volcengine.ark.runtime.selfhosted.SelfHostedClient;

public class SelfHostedWorkerExample {
    public static void main(String[] args) {
        String environmentId = requiredEnv("MA_ENVIRONMENT_ID");
        String workerId = System.getenv("MA_WORKER_ID");
        String workdir = envOrDefault("MA_WORKDIR", "/workspace");

        SelfHostedClient.Builder clientBuilder = new SelfHostedClient.Builder()
                .apiKey(requiredEnv("ARK_API_KEY"));
        String baseUrl = System.getenv("ARK_BASE_URL");
        if (baseUrl != null && !baseUrl.isEmpty()) {
            clientBuilder.baseUrl(baseUrl);
        }

        SelfHostedClient client = clientBuilder.build();

        EnvironmentWorker worker = new EnvironmentWorker(
                client,
                new EnvironmentWorker.Options()
                        .environmentId(environmentId)
                        .workerId(workerId)
                        .workdir(workdir));

        System.out.printf("worker starting for environment %s%n", environmentId);
        Runtime.getRuntime().addShutdownHook(new Thread(worker::close, "ark-self-hosted-worker-shutdown"));
        try {
            worker.run();
        } finally {
            worker.close();
        }
    }

    private static String requiredEnv(String name) {
        String value = System.getenv(name);
        if (value == null || value.isEmpty()) {
            throw new IllegalArgumentException(name + " is required");
        }
        return value;
    }

    private static String envOrDefault(String name, String defaultValue) {
        String value = System.getenv(name);
        return value == null || value.isEmpty() ? defaultValue : value;
    }
}

启动 Worker:

bash
go mod tidy
go run main.go
bash
python worker.py
bash
mvn -q exec:java -Dexec.mainClass=SelfHostedWorkerExample

期望日志输出:

worker starting for environment env-20260822120000-xxxxx
polling work queue...

EnvironmentWorker 会持续 Poll Work Queue,队列为空时保持等待,不产生 Session。回到控制台 Environment 详情页,Worker 连接状态应显示为"在线"。

第 5 步:创建 Session,建立事件流并发送任务#

5.1 创建 Session#

业务应用使用自己的 API Key 创建 Session。生产环境中,建议不要复用 Worker 使用的 API Key:

bash
export ARK_API_KEY="<business-api-key>"
export ARK_BASE_URL="https://ark.cn-beijing.volces.com/api/v3"

export SESSION_RESPONSE=$(curl -sS https://ark.cn-beijing.volces.com/api/v3/sessions \
  -H "Authorization: Bearer $ARK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent": "agent-20260729160000-xxxxx",
    "environment_id": "env-20260822120000-xxxxx"
  }')

export SESSION_ID=$(echo $SESSION_RESPONSE | jq -r '.id')
echo "Session ID: $SESSION_ID"

响应示例:

{
  "id": "sesn-20260822120100-xxxxx",
  "status": "idle",
  "environment_id": "env-20260822120000-xxxxx"
}

5.2 订阅 Session 事件流#

在另一个终端中,通过 流式获取会话事件 建立 SSE 连接:

Bash
curl -N "https://ark.cn-beijing.volces.com/api/v3/sessions/$SESSION_ID/events/stream" \
  -H "Authorization: Bearer $ARK_API_KEY" \
  -H "Accept: text/event-stream"

等待服务端返回 : ready 后,再发送用户消息。SSE 只推送连接建立后产生的事件;如果先发送消息,业务应用会遗漏已产生的事件。

5.3 发送首个事件启动 Agent#

仅创建 Session 不会触发任务。通过 发送会话事件 提交第一条 user.message 事件后,方舟才会生成 Work Item 并将其写入自托管 Environment 的 Work Queue:

Bash
curl -sS "https://ark.cn-beijing.volces.com/api/v3/sessions/$SESSION_ID/events" \
  -H "Authorization: Bearer $ARK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [{
      "type": "user.message",
      "content": [{
        "type": "text",
        "text": "读取 /workspace/input.csv,生成汇总报告并写入 /workspace/output.md"
      }]
    }]
  }'

第 6 步:验证执行结果#

6.1 Worker 侧#

Worker 日志中应看到以下关键事件:

text
work claimed: work_id=sesn-20260822120100-xxxxx
session started: session_id=sesn-20260822120100-xxxxx
tool call: bash, command=cat /workspace/input.csv
tool call: write, path=/workspace/output.md
session completed: session_id=sesn-20260822120100-xxxxx
work completed: work_id=sesn-20260822120100-xxxxx

确认 /workspace/output.md 已生成,内容符合预期。

6.2 业务应用侧#

在步骤 5.2 建立的 SSE 连接中,确认收到以下事件:

text
user.message          读取 /workspace/input.csv,生成汇总报告
agent.tool_use        bash: cat /workspace/input.csv
agent.tool_result     (bash 执行结果)
agent.tool_use        write: /workspace/output.md
agent.tool_result     (write 执行结果)
agent.message         已完成,汇总报告保存至 /workspace/output.md
session.status_idle

6.3 控制台侧#

在 Environment 详情页确认:

页面 预期结果
概览 Worker 在线,执行期间 running 数量增加,结束后回落
Work Items 可按 Session ID 找到本轮 Work Item,状态流转为 queued → starting → active → stopped

生产部署方式#

常驻 Worker#

适用于 VM、独立容器或已有隔离节点直接执行。EnvironmentWorker.run() / EnvironmentWorker.Run() 管理完整生命周期:Poll、Ack、Heartbeat、工具执行、结果回传和 Work Complete。

需要扩容时,优先启动多个 Worker 进程或 Pod,并为每个实例设置独立的 MA_WORKER_ID。不要让多个 Worker 共享同一个 Session 工作目录。

每 Session 独立 Sandbox#

适用于 Kubernetes 每 Session 一个 Pod。Poller 负责领取 Work Item 并创建 Pod,Pod 内调用 SDK 的 HandleItem / handle_item 负责该 Work Item 的完整生命周期。

go
poller := environments.NewWorkPollerForClient(ctx, client, environments.WorkPollerOptions{
    EnvironmentID: envID,
})

for poller.Next() {
    work := poller.Current()
    createPod(work)
}

worker := environments.NewEnvironmentWorkerForClient(client, environments.EnvironmentWorkerOptions{
    Workdir: "/workspace",
})
worker.HandleItem(ctx, environments.HandleItemOptions{
    WorkID:        os.Getenv("MA_WORK_ID"),
    EnvironmentID: os.Getenv("MA_ENVIRONMENT_ID"),
    SessionID:     os.Getenv("MA_SESSION_ID"),
})

运行与排障#

现象 检查项 处理方式
Worker 未连接 API Key、Environment ID、网络 检查 Worker 主机上的 ARK_API_KEY 是否有效且能访问当前账号和项目,确认出站 HTTPS 可达
Work 长时间排队 Worker 在线状态、Worker 实例数量 确认 Worker 在线,必要时增加 Worker 实例
Heartbeat 失败 租约已过期、系统时间偏差 Worker 会自动退出,可重新 Poll 领取
重复工具调用 Tool Call ID 幂等 服务端以 Tool Call ID 为幂等键,重复回传不会重复执行
Session 无结果 Work 与 Session Events 分别检查 确认 Work 已被领取且处于 active,同时检查 Events 是否有错误事件

清理资源#

确认产物已转存后,按依赖顺序清理:

Bash
# 1. 停止 Worker(Ctrl+C 或 kill)
# 2. 确认没有运行中的 Work
# 3. 删除测试 Session
curl -sS -X DELETE "https://ark.cn-beijing.volces.com/api/v3/sessions/$SESSION_ID" \
  -H "Authorization: Bearer $ARK_API_KEY"

# 4. 删除测试 Environment
curl -sS -X DELETE "https://ark.cn-beijing.volces.com/api/v3/environments/$ENVIRONMENT_ID" \
  -H "Authorization: Bearer $ARK_API_KEY"