跳到主要内容

Private Cloud 部署

Private Cloud 适合把一组团队任务放到你们自己的服务器或虚拟机上执行。团队成员在 Agentrix Web 应用里创建任务,任务会被派发到这组 runner;代码仓库、系统依赖和本地凭据都留在你们管理的环境里。

适用场景​

  • 团队想共用一组稳定的 Linux runner,而不是依赖每个人的开发机。
  • 仓库、内网依赖、构建工具或模型网关只能在公司网络里访问。
  • 需要给团队成员开放任务入口,但不想把 runner secret 分发给每个人。
  • 需要多台机器承载同一个 private cloud,并受订阅中的机器数量上限限制。

如果只是个人本地使用,优先看 CLI 安装 或 桌面应用安装。

前置条件​

  • Agentrix 账号已开通 Private Cloud 权限。
  • 一台可长期运行的 Linux 服务器或虚拟机。
  • 服务器可以访问 Agentrix 后端 API。使用官方服务时默认是 https://agentrix.xmz.ai;自部署时替换为你的 API 地址。
  • 已安装 Node.js 18+、npm、git,以及任务需要的 agent CLI,比如 Claude Code 或 Codex。
  • 服务器上有一个专门运行 Agentrix 的系统用户,比如 agentrix。

依赖安装和检查方式见 依赖项。启动前可以先运行 agentrix doctor。

创建 Private Cloud​

  1. 打开 Agentrix Web 应用。
  2. 进入 Settings -> Private Clouds。
  3. 点击右上角菜单,选择创建新的 Private Cloud。
  4. 创建后进入详情页,复制 runner secret。

runner secret 用来注册 runner 机器,相当于这组 runner 的机器令牌。它不等同于邀请链接,不要发给普通成员,也不要提交到代码仓库。

如果创建入口不可用,通常是当前订阅没有开启 Private Cloud,或者数量已经达到上限。

在服务器上启动 runner​

在 runner 服务器上安装 CLI 和必要 agent:

npm install -g @agentrix/cli
npm install -g @anthropic-ai/claude-code

如果你要执行 Codex 类型任务,再安装 Codex CLI:

npm install -g @codex-ai/codex-cli

用 runner secret 启动 daemon:

export AGENTRIX_SERVER_URL=https://agentrix.xmz.ai
export AGENTRIX_WEBAPP_URL=https://agentrix.xmz.ai
export AGENTRIX_HOME_DIR=/opt/agentrix
export CLOUD_AUTH_TOKEN=<runner-secret>

agentrix start
agentrix status

自部署环境需要把 AGENTRIX_SERVER_URL 和 AGENTRIX_WEBAPP_URL 改成自己的地址。CLOUD_AUTH_TOKEN 存在时,CLI 会跳过浏览器登录流程,用该 secret 生成并注册 cloud runner 机器。

用 Docker 镜像启动 runner​

CLI Docker 镜像适合不想在宿主机上单独安装 Node.js、Claude Code、Codex 和沙箱依赖的 runner。镜像默认执行 agentrix daemon,启动时必须提供 CLOUD_AUTH_TOKEN,也就是 Private Cloud 详情页里的 runner secret。

docker run -d \
--name agentrix-runner \
--restart unless-stopped \
-e AGENTRIX_SERVER_URL=https://agentrix.xmz.ai \
-e AGENTRIX_WEBAPP_URL=https://agentrix.xmz.ai \
-e CLOUD_AUTH_TOKEN=<runner-secret> \
-e AGENTRIX_BASE_URL=https://api.xmz.ai \
-e AGENTRIX_API_KEY=<llm-gateway-api-key> \
-e GITLAB_BASE_URL=https://gitlab.example.com \
-e GITLAB_TOKEN=<gitlab-token> \
-e AGENTRIX_GITLAB_USE_AS_PROXY=true \
-v agentrix-home:/home/agentrix/.agentrix \
-v agentrix-workspaces:/home/agentrix/.agentrix/workspaces \
ghcr.io/xmz-ai/agentrix/agentrix-cli:latest

自部署环境需要把 AGENTRIX_SERVER_URL 和 AGENTRIX_WEBAPP_URL 换成自己的 Agentrix 地址;如果你们维护自己的镜像,也可以把镜像名换成自有 registry 里的 agentrix-cli 镜像。AGENTRIX_API_KEY 在这里是 LLM 网关密钥,runner 注册和任务鉴权仍然使用 CLOUD_AUTH_TOKEN。

容器启动 agentrix daemon 或 agentrix start 前,会自动执行 agentrix llm-config apply,根据环境变量生成 Claude、Codex、PI 和 Gemini 的配置:

配置默认路径
Claude Code/home/agentrix/.claude/settings.json
Codex/home/agentrix/.codex/config.toml
PI$AGENTRIX_PI_HOME/models.json 和 settings.json,默认是 /home/agentrix/.pi/agent
Gemini$AGENTRIX_GEMINI_HOME/settings.json,默认是 $AGENTRIX_HOME_DIR/config/gemini/settings.json

自动配置默认只写入缺失文件,不覆盖已有配置。缺少 AGENTRIX_API_KEY 且没有可读的 AGENTRIX_API_KEY_FILE 时,entrypoint 会在启动 daemon 前报错退出。需要重建配置时设置 AGENTRIX_LLM_CONFIG_FORCE=true;如果你想完全自己挂载配置文件,设置 AGENTRIX_LLM_AUTO_CONFIG=false。

如果容器需要访问私有 GitLab,可以同时传入 GITLAB_BASE_URL 和 GITLAB_TOKEN。已认证的 Private Cloud runner 在未配置 AGENTRIX_GITLAB_BIND_USER 时默认使用 false:token 只保存在 runner 本地,不会把公共 bot 绑定为每个 runner owner 的 Git 身份。AGENTRIX_GITLAB_USE_AS_PROXY=true 独立控制 proxy node 注册。多台 runner 可以安全复用同一组 bot 配置,API 发起 Git 操作时会从在线节点中选择一个。只有 PAT 确实代表当前 Agentrix 用户,并且需要出现在该用户的 GitServer 和仓库列表中时,才应设置 AGENTRIX_GITLAB_BIND_USER=true。

常用变量如下:

变量默认值说明
AGENTRIX_API_KEY—LLM 网关密钥,用于生成 Claude、Codex、PI 和 Gemini 配置
AGENTRIX_API_KEY_FILE—从文件读取 LLM 网关密钥,适合 Docker secret
AGENTRIX_BASE_URLhttps://api.xmz.aiLLM 网关地址;Codex 配置会自动使用该地址下的 /v1
AGENTRIX_CODEX_MODELgpt-5.5Codex 默认模型
AGENTRIX_PI_MODEL同 AGENTRIX_CODEX_MODELPI 默认模型
AGENTRIX_CLAUDE_MODELclaude-sonnet-4-6Claude 默认模型
AGENTRIX_CLAUDE_FAST_MODELclaude-haiku-4-5Claude fast model
AGENTRIX_CLAUDE_SUBAGENT_MODEL同 AGENTRIX_CLAUDE_MODELClaude subagent model
AGENTRIX_GEMINI_IMAGE_MODELgemini-2.5-flash-imageGemini 图片模型
AGENTRIX_CLAUDE_HOME/home/agentrix/.claudeClaude Code 配置目录
AGENTRIX_CODEX_HOME/home/agentrix/.codexCodex 配置目录
AGENTRIX_PI_HOME/home/agentrix/.pi/agentPI 配置目录;也兼容 PI_CODING_AGENT_DIR
AGENTRIX_CLAUDE_PATH/usr/local/bin/claudeClaude Code 二进制路径
AGENTRIX_CODEX_PATH/usr/local/bin/codexCodex 二进制路径
AGENTRIX_GEMINI_HOME$AGENTRIX_HOME_DIR/config/geminiGemini 配置目录
CLOUD_AUTH_TOKEN_FILE—从文件读取 runner secret,适合 Docker secret
AGENTRIX_EVENT_FORWARD_WS_URL—企业事件转发接收服务地址,见下文"事件转发"
AGENTRIX_EVENT_FORWARD_TOKEN_FILE—从文件读取事件转发认证 token,适合 Docker secret
GITLAB_BASE_URL—自动配置的 GitLab 站点 URL
GITLAB_API_URL<base-url>/api/v4自动配置 GitLab 时使用的 API URL
GITLAB_TOKEN—GitLab token,写入本地加密 store,并在启用用户绑定时同步为 API 侧 credential
GITLAB_TOKEN_FILE—从文件读取 GitLab token,适合 Docker secret
AGENTRIX_GITLAB_BIND_USERfalse是否把 GitLab 账号绑定到 runner owner 的 Agentrix 用户;只有个人 PAT 才应设为 true
AGENTRIX_GITLAB_USE_AS_PROXYtrue是否把当前 runner 注册为 Git proxy node
AGENTRIX_GITLAB_AUTO_CONFIGtrue设为 false 可禁用 GitLab 自动配置

镜像还会在启动时检查并补齐全局 Git 身份,默认是 Agentrix <[email protected]>。如需使用团队身份,可以设置 AGENTRIX_GIT_USER_NAME 和 AGENTRIX_GIT_USER_EMAIL。

用 systemd 托管​

生产环境建议用 systemd 或同类进程管理器托管 daemon。先确认 agentrix 的真实路径:

command -v agentrix

如果还没有专用系统用户,先创建一个:

sudo useradd --system --create-home --home-dir /opt/agentrix --shell /usr/sbin/nologin agentrix

创建环境变量文件:

sudo mkdir -p /etc/agentrix
sudo install -m 600 /dev/null /etc/agentrix/private-cloud.env
sudoedit /etc/agentrix/private-cloud.env

写入以下内容:

AGENTRIX_SERVER_URL=https://agentrix.xmz.ai
AGENTRIX_WEBAPP_URL=https://agentrix.xmz.ai
AGENTRIX_HOME_DIR=/opt/agentrix
CLOUD_AUTH_TOKEN=<runner-secret>

创建 /etc/systemd/system/agentrix-private-cloud.service:

[Unit]
Description=Agentrix Private Cloud Runner
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=agentrix
WorkingDirectory=/opt/agentrix
EnvironmentFile=/etc/agentrix/private-cloud.env
ExecStart=/usr/local/bin/agentrix daemon
ExecStop=/usr/local/bin/agentrix stop
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

把 ExecStart 和 ExecStop 中的路径替换为 command -v agentrix 的输出。systemd 下使用 agentrix daemon,因为 agentrix start 会拉起后台 daemon 后退出。然后启动服务:

sudo mkdir -p /opt/agentrix
sudo chown -R agentrix:agentrix /opt/agentrix
sudo systemctl daemon-reload
sudo systemctl enable --now agentrix-private-cloud
sudo systemctl status agentrix-private-cloud

查看日志:

journalctl -u agentrix-private-cloud -f
tail -f /opt/agentrix/logs/daemon.log

验证 runner 在线​

回到 Settings -> Private Clouds,进入对应 cloud 详情页,确认 runner 数量显示为在线,例如 1/3。也可以在服务器上运行:

sudo systemctl status agentrix-private-cloud
agentrix status
agentrix doctor

如果 daemon 由 systemd 以 agentrix 用户运行,命令行检查也要使用同一个 AGENTRIX_HOME_DIR 环境。

如果状态正常,但 Web 应用里暂时没有变化,等几秒后刷新列表。runner 通过 WebSocket 上报在线状态,网络抖动或 daemon 重启时会有短暂延迟。

邀请团队成员​

Private Cloud owner 可以在详情页生成邀请链接。成员打开链接并登录后,会把这个 private cloud 绑定到自己的账号。

邀请链接只用于加入成员,不用于启动 runner。成员加入后可以在创建任务时选择这个 private cloud,但看不到 runner secret。

在任务里使用​

创建新任务时,在 runner 或执行环境选择器里选择对应的 private cloud。通过 agentrix-run 提交任务时,使用对应的 cloud-* runner ID:

agentrix-run \
--prompt "Run the test suite and fix failures" \
--runner-id cloud-xxx

更多 CI 用法见 agentrix-run。

事件转发​

事件转发让 runner 把任务互动的全量 task event(用户消息、assistant 回复、tool 调用与结果、worker 生命周期事件、task-usage-report 等计量事件)主动外推到企业自建的 WebSocket 接收服务。数据从 runner 直连企业内网服务,不经过第三方,适合对接审计、归档、消息通知等内部系统。

启用条件(两者同时满足):

  • runner 运行在 cloud 模式(配置了 CLOUD_AUTH_TOKEN)。local 模式消息端到端加密,转发密文没有意义,不支持。
  • 配置了 AGENTRIX_EVENT_FORWARD_WS_URL。设置即启用,无需其他开关。

配置​

变量必填说明
AGENTRIX_EVENT_FORWARD_WS_URL是(设置即启用)企业 WS 接收服务地址,ws:// 或 wss://
AGENTRIX_EVENT_FORWARD_TOKEN否握手时放入 Authorization: Bearer <token> header,由接收端自行校验
AGENTRIX_EVENT_FORWARD_RETENTION_HOURS否,默认 24已确认(acked)事件在本地 outbox 的保留时长
AGENTRIX_EVENT_FORWARD_MAX_DB_MB否,默认 512本地 outbox 体积上限,超限时从最旧事件开始丢弃并打 WARN

Docker 镜像额外支持 AGENTRIX_EVENT_FORWARD_TOKEN_FILE,用法与 CLOUD_AUTH_TOKEN_FILE 相同。

工作机制​

  • 事件先持久化到 runner 本地 outbox($AGENTRIX_HOME_DIR/forward/outbox.db),daemon 内的转发服务按游标批量推送。daemon 重启、接收端宕机期间事件不丢,重连后按 cursor 回放。
  • 投递语义是 at-least-once:接收端必须按 eventId 幂等去重。
  • cursor 是 runner 级单调递增序号,多台 runner 汇聚到同一个接收端时,按 machineId 分别记录 cursor。
  • 转发不承诺服务端全局 sequence(发送时可能尚未回填)。需要任务内全序或 100% 对账时,用 REST GET /v1/tasks/:taskId/events 兜底;只在 API 侧产生、从不下发到 runner 的纯服务端事件也不会被转发。
  • outbox 超过体积上限被迫丢弃未确认事件时,重连后的首个 events 帧会带 droppedBeforeCursor 字段标记 gap。
  • 转发状态通过 daemon 日志查看($AGENTRIX_HOME_DIR/logs/daemon.log,搜索 [FORWARD])。

协议​

原生 WebSocket + JSON 文本帧,接收端可用任何语言实现:

// CLI → 接收端:连接后握手(cloudId 为该 runner 所属的 private cloud)
{ "type": "hello", "protocolVersion": 1, "machineId": "machine-xxx", "cloudId": "cloud-xxx", "hostname": "runner-01", "cliVersion": "0.45.0" }

// 接收端 → CLI:握手确认。resumeFromCursor 可选,声明自己已消费到的 cursor;
// 省略时由 runner 本地已确认的 cursor 决定回放起点
{ "type": "hello-ack", "resumeFromCursor": 12345 }

// CLI → 接收端:事件批次(droppedBeforeCursor 仅在 outbox 曾丢弃未确认事件时出现)
{ "type": "events", "events": [
{ "cursor": 12346, "eventId": "evt-xxx", "taskId": "task-xxx", "chatId": "chat-xxx",
"eventType": "task-message", "direction": "outbound",
"eventData": { /* 完整事件 payload,如 TaskMessageEventData */ },
"createdAt": "2026-07-02T08:00:00.000Z" }
] }

// 接收端 → CLI:累积确认(确认 cursor 及之前的全部事件)
{ "type": "ack", "cursor": 12346 }

direction 为 outbound 表示 worker 产生的事件(assistant 回复、tool 调用、生命周期事件等),inbound 表示下发给 runner 的事件(用户消息、任务创建/恢复的初始消息等)。心跳使用 WebSocket 协议层的 ping/pong 帧,应用层无需处理。

参考接收端实现​

一个最小可用的 Node 接收服务(npm install ws 后运行):

const { WebSocketServer } = require('ws');

const seenEventIds = new Set(); // 生产环境换成持久化存储
const cursors = new Map(); // machineId -> 已确认 cursor

const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', (socket, request) => {
const auth = request.headers.authorization;
if (process.env.FORWARD_TOKEN && auth !== `Bearer ${process.env.FORWARD_TOKEN}`) {
socket.close(4401, 'unauthorized');
return;
}

let machineId = null;
socket.on('message', (raw) => {
const frame = JSON.parse(raw);

if (frame.type === 'hello') {
machineId = frame.machineId;
const resumeFromCursor = cursors.get(machineId) ?? 0;
socket.send(JSON.stringify({ type: 'hello-ack', resumeFromCursor }));
console.log(`runner ${machineId} connected, resume from ${resumeFromCursor}`);
return;
}

if (frame.type === 'events') {
if (frame.droppedBeforeCursor) {
console.warn(`gap: events before cursor ${frame.droppedBeforeCursor} were dropped`);
}
for (const event of frame.events) {
if (seenEventIds.has(event.eventId)) continue; // at-least-once 去重
seenEventIds.add(event.eventId);
console.log(`[${event.direction}] ${event.eventType} task=${event.taskId} cursor=${event.cursor}`);
// 在这里写入你的审计 / 归档 / 通知系统
}
const last = frame.events[frame.events.length - 1];
cursors.set(machineId, last.cursor);
socket.send(JSON.stringify({ type: 'ack', cursor: last.cursor }));
}
});
});

console.log('forward receiver listening on :8080');

安全建议​

  • runner secret 泄露后,应停止旧 runner,并重新创建 private cloud 或联系管理员处理。
  • 用单独的低权限系统用户运行 daemon。
  • 确保 AGENTRIX_HOME_DIR、环境变量文件和日志目录权限受控。
  • 不要把 runner secret 写进仓库、CI 明文变量或多人共享的 shell 配置。
  • runner 服务器一般只需要主动访问 Agentrix API,不需要暴露公网入站端口。

常见问题​

runner 没有上线​

检查 CLOUD_AUTH_TOKEN 是否在 daemon 进程环境里生效,systemd 场景下重点看 EnvironmentFile。再确认 AGENTRIX_SERVER_URL 指向正确 API,并查看 daemon.log。

启动时打开了浏览器登录​

这说明 daemon 没有读到 CLOUD_AUTH_TOKEN。重新导出环境变量,或重启 systemd 服务并检查环境变量文件权限。

任务一直排队​

先确认 private cloud 详情页里有在线 runner。然后在 runner 上运行 agentrix doctor,检查 git、Claude Code、Codex 和沙箱依赖是否缺失。任务级日志在 $AGENTRIX_HOME_DIR/logs/worker-<taskId>.log。

提示 token 无效或 cloud 不存在​

通常是复制了错误的 secret,或者 runner 连接到了错误的 Agentrix API。重新复制详情页里的 runner secret,并确认 AGENTRIX_SERVER_URL 使用同一个部署环境。