18 KiB
Remote Agent Blueprints — 模板庫與自動化部署管道(LLM 解耦 + 認知配置 + ChatOps)
版本: 2.0
日期: 2026-03-12
維護者: 架構組
本文檔描述遠端 Agent 標準化模板庫與自動化部署管道,供 AI 與維護人員查閱。包含目錄結構、模板說明、腳本行為、環境變數對齊關係,以及歷史修復記錄。
本文僅為說明與維運參考,不執行任何測試;所有變更僅經靜態檢查與邏輯校對。
1. 概述
-
目標:
- 用模板(blueprints)標準化遠端 Agent 的 Docker/配置/認知檔案。
- 透過 Volume 掛載解耦 Skill/Plugin 與映像檔,支援熱更新。
- 支援容器內歸檔目錄(
archive/),供 Agent 寫入媒體與本地檔案。 - LLM 提供商解耦:使用通用
LLM_BASE_URL/LLM_API_KEY/LLM_MODEL_ID,不再綁定特定雲廠商。 - 植入認知配置(Agent Profile JSON,含
project_id與系統提示)。 - 支援 Main Agent 以 純 CLI 無交互 方式呼叫(ChatOps Ready)。
-
工作根目錄:
/root/.openclaw/workspace -
模板根目錄:
workspace/remote-blueprints/template/ -
腳本目錄:
workspace/scripts/(generate_remote.sh、sync_skill.sh)
2. 檔案樹結構
workspace/
├── remote-blueprints/
│ └── template/
│ ├── config/
│ │ └── openclaw.json # 閘道器配置,使用 ${VAR} 字串插值(CONTROL_UI_TOKEN、LLM_*)
│ ├── skills/ # 掛載點 -> /root/.openclaw/workspace/skills
│ │ └── .gitkeep
│ ├── plugins/ # 掛載點 -> /root/.openclaw/workspace/plugins
│ │ └── .gitkeep
│ ├── archive/ # 掛載點 -> /root/.openclaw/workspace/archive(容器內 chmod 777)
│ │ └── .gitkeep
│ ├── agents/ # 認知配置模板,會被渲染為 agents/<AGENT_ID>.json
│ │ └── {{AGENT_ID}}.json.tpl
│ ├── Dockerfile
│ ├── docker-compose.yml.tpl # 使用 {{...}} 作為模板佔位符,其餘從 .env 讀取
│ └── .env.tpl
├── scripts/
│ ├── generate_remote.sh # 從模板生成實例 + deploy_to_target.sh(支援無交互模式)
│ └── sync_skill.sh # 跨節點 Skill 同步(優先 rsync,無則 scp)
└── docs/
└── REMOTE_BLUEPRINTS.md # 本文檔
生成實例後(執行 generate_remote.sh ... 後):
remote-blueprints/<AGENT_ID>/
├── config/openclaw.json
├── skills/, plugins/, archive/
├── agents/<AGENT_ID>.json # 已渲染的 Agent Profile
├── Dockerfile
├── docker-compose.yml # 已替換 {{AGENT_ID}} 等佔位符
├── .env # 已替換環境變數佔位符
└── deploy_to_target.sh # 動態生成,可執行
3. 模板說明
3.1 .env.tpl — 環境變數模板
路徑:remote-blueprints/template/.env.tpl
AGENT_ID={{AGENT_ID}}
CONTROL_UI_TOKEN={{CONTROL_UI_TOKEN}}
HUB_QDRANT_URL=http://100.115.94.1:6333
# mem0-integration skill (Layer 4) reads these; align with HUB_QDRANT_URL if using central Qdrant
MEM0_QDRANT_HOST=100.115.94.1
MEM0_QDRANT_PORT=6333
# Generic LLM provider configuration (provider-agnostic)
LLM_BASE_URL={{LLM_BASE_URL}}
LLM_API_KEY={{LLM_API_KEY}}
LLM_MODEL_ID={{LLM_MODEL_ID}}
AGENT_ID:實例 ID,用於 container_name、標籤與部分配置;僅允許[a-zA-Z0-9_-]。CONTROL_UI_TOKEN:Gateway Control UI token,可由腳本自動生成。HUB_QDRANT_URL/MEM0_QDRANT_*:指向中心 Qdrant(mem0 Layer 4 所用)。LLM_BASE_URL/LLM_API_KEY/LLM_MODEL_ID:解耦後的通用 LLM provider 設定,對應 OpenAI-compatible API 或其他兼容端點。
3.2 config/openclaw.json — Gateway 配置
路徑:remote-blueprints/template/config/openclaw.json
核心片段:
{
"gateway": {
"port": 18789,
"mode": "local",
"bind": "lan",
"controlUi": {
"allowedOrigins": [
"http://localhost:*",
"http://localhost:18789",
"http://127.0.0.1:*",
"http://127.0.0.1:18789",
"http://100.115.94.1:18789"
],
"dangerouslyDisableDeviceAuth": false
},
"auth": {
"mode": "token",
"token": "${CONTROL_UI_TOKEN}",
"rateLimit": {
"maxAttempts": 10,
"windowMs": 60000,
"lockoutMs": 300000
}
},
"trustedProxies": ["127.0.0.1", "100.115.94.1", "::1"]
},
"agents": {
"defaults": {
"workspace": "/root/.openclaw/workspace",
"model": { "primary": "default_llm/primary" }
},
"list": [
{ "id": "main" },
{ "id": "{{AGENT_ID}}", "enabled": true }
]
},
"models": {
"mode": "merge",
"providers": {
"default_llm": {
"baseUrl": "${LLM_BASE_URL}",
"apiKey": "${LLM_API_KEY}",
"api": "openai-completions",
"models": [
{
"id": "primary",
"name": "${LLM_MODEL_ID}",
"contextWindow": 128000,
"maxTokens": 8192
}
]
}
}
},
"memory": { "backend": "qmd", "citations": "auto" },
"skills": { "install": { "nodeManager": "npm" }, "entries": {} },
"plugins": { "allow": [], "load": { "paths": [] }, "entries": {} }
}
gateway.auth.token使用${CONTROL_UI_TOKEN},與.env/ compose 變數名一致。models.providers.default_llm使用${LLM_BASE_URL}/${LLM_API_KEY}/${LLM_MODEL_ID},完整解耦底層供應商;agents.defaults.model.primary指向"default_llm/primary"。agents.list中預先註冊{{AGENT_ID}},渲染後即為遠端 Agent 的 ID。
3.3 docker-compose.yml.tpl — 容器編排模板
路徑:remote-blueprints/template/docker-compose.yml.tpl
# Remote Agent - OpenClaw Gateway
# Placeholders: {{AGENT_ID}}, {{AGENT_NAME}}, {{PROJECT_ID}}
# After render: .env supplies CONTROL_UI_TOKEN, LLM_BASE_URL, LLM_API_KEY, LLM_MODEL_ID, HUB_QDRANT_URL, MEM0_QDRANT_*
services:
gateway:
build: .
container_name: {{AGENT_ID}}
network_mode: "host"
restart: always
environment:
- OPENCLAW_GATEWAY_AUTH_MODE=token
- OPENCLAW_GATEWAY_AUTH_TOKEN=${CONTROL_UI_TOKEN}
- NODE_OPTIONS=--max-old-space-size=1536
- QDRANT_HOST=${HUB_QDRANT_URL}
- AGENT_TAG={{AGENT_ID}}
- LLM_BASE_URL=${LLM_BASE_URL}
- LLM_API_KEY=${LLM_API_KEY}
- LLM_MODEL_ID=${LLM_MODEL_ID}
- MEM0_QDRANT_HOST=${MEM0_QDRANT_HOST}
- MEM0_QDRANT_PORT=${MEM0_QDRANT_PORT}
volumes:
- ./config/openclaw.json:/root/.openclaw/openclaw.json
- ./skills:/root/.openclaw/workspace/skills
- ./plugins:/root/.openclaw/workspace/plugins
- ./archive:/root/.openclaw/workspace/archive
- ./agents:/root/.openclaw/workspace/agents
network_mode: host方便 Tailscale / SSH 隧道使用。./agents掛載到/root/.openclaw/workspace/agents,配合openclaw.json中的agents配置與未來 auto-discovery 能力。
3.4 Agent Profile 模板 — 認知配置
路徑:remote-blueprints/template/agents/{{AGENT_ID}}.json.tpl
{
"id": "{{AGENT_ID}}",
"name": "{{AGENT_NAME}}",
"project_id": "{{PROJECT_ID}}",
"metadata": {
"project_id": "{{PROJECT_ID}}",
"role": "project-specialized-remote-agent"
},
"systemPrompt": "You are an AI agent named {{AGENT_NAME}}. You belong to project {{PROJECT_ID}}. Always follow the project conventions, coordinate with the main hub agent, and log important decisions to shared memory."
}
- 在渲染與 rename 後,會變成
agents/<AGENT_ID>.json並掛載到 workspace,供 Gateway 或其他輔助工具使用。
3.5 Dockerfile — 執行環境與權限
路徑:remote-blueprints/template/Dockerfile
# Remote Agent - OpenClaw Gateway
# Base: node:20-slim; deps for build + image processing (libvips)
FROM node:20-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
python3 \
make \
g++ \
libvips-dev \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g @openclaw/cli
RUN mkdir -p /root/.openclaw/workspace/skills \
/root/.openclaw/workspace/plugins \
/root/.openclaw/workspace/archive \
&& chmod -R 777 /root/.openclaw/workspace/archive
EXPOSE 18789
CMD ["openclaw", "gateway", "--port", "18789"]
- 確保
archive/在容器內存在並可寫入(chmod 777),避免 Volume 掛載後出現 Permission Denied。
4. 腳本說明
4.1 generate_remote.sh — 實例壓鑄腳本
路徑:scripts/generate_remote.sh
4.1.1 模式說明
- 互動模式(人類操作):
- 條件:未帶任何 flag(
-a/-n/-p/-u/-k/-m/-t)。 - 行為:
- 依序
read:AGENT_ID、AGENT_NAME、PROJECT_ID、LLM_BASE_URL、LLM_API_KEY、LLM_MODEL_ID、CONTROL_UI_TOKEN。 - 若
AGENT_ID為空則直接報錯退出。
- 依序
- 條件:未帶任何 flag(
- 非互動模式(ChatOps Ready):
- 條件:只要帶任一 flag(
-a/-n/-p/-u/-k/-m/-t),即視為非互動模式。 - 行為:
- 絕對不執行任何
read,完全靜默(只輸出日誌 / JSON 錯誤)。 - 必填參數:
AGENT_ID、LLM_BASE_URL、LLM_API_KEY、LLM_MODEL_ID。 - 若任一缺失,輸出 JSON 錯誤並
exit 1,示例:{"ok":false,"error":"missing_required_params","missing":["AGENT_ID","LLM_BASE_URL"]} AGENT_NAME預設為AGENT_ID,PROJECT_ID預設為"default"。
- 絕對不執行任何
- 條件:只要帶任一 flag(
4.1.2 參數與旗標
- 支援的 flags:
-a <AgentID>→AGENT_ID-n <AgentName>→AGENT_NAME-p <ProjectID>→PROJECT_ID-u <BaseURL>→LLM_BASE_URL-k <API_Key>→LLM_API_KEY-m <ModelID>→LLM_MODEL_ID(例如qwen-max,gpt-4o)-t <ControlUiToken>→CONTROL_UI_TOKEN(可選;未提供則自動生成)
4.1.3 Token 自動生成
- 若解析完所有輸入後
CONTROL_UI_TOKEN仍為空:- 首選:
openssl rand -hex 24生成 48 位十六進位字串。 - 若系統無
openssl,改用/dev/urandom+base64+ 過濾成 hex 的備援方案(並輸出 WARN 日誌)。
- 首選:
4.1.4 安全與佔位符替換
AGENT_ID僅允許[a-zA-Z0-9_-],否則報錯退出。- 使用統一的
escape_sed_val()對所有值進行轉義:\→\\、&→\&、/→\/。
- 所有 sed 替換使用
#作為定界符,避免 URL 中的/破壞語法:
sed -i "s#{{AGENT_ID}}#$AGENT_ID#g" "$f"
sed -i "s#{{AGENT_NAME}}#$AGENT_NAME_ESC#g" "$f"
sed -i "s#{{PROJECT_ID}}#$PROJECT_ID_ESC#g" "$f"
sed -i "s#{{LLM_BASE_URL}}#$LLM_BASE_URL_ESC#g" "$f"
sed -i "s#{{LLM_API_KEY}}#$LLM_API_KEY_ESC#g" "$f"
sed -i "s#{{LLM_MODEL_ID}}#$LLM_MODEL_ID_ESC#g" "$f"
sed -i "s#{{CONTROL_UI_TOKEN}}#$CONTROL_UI_TOKEN_ESC#g" "$f"
- 佔位符覆蓋範圍:
{{AGENT_ID}},{{AGENT_NAME}},{{PROJECT_ID}}{{LLM_BASE_URL}},{{LLM_API_KEY}},{{LLM_MODEL_ID}}{{CONTROL_UI_TOKEN}}- 兼容移除舊的
{{BAILIAN_API_KEY}}(若仍存在會被同值覆蓋)。
- 遍歷所有
*.tpl與.env.tpl檔案(包含agents/{{AGENT_ID}}.json.tpl)。
4.1.5 檔名重寫與 deploy 腳本生成
- 在 rename 所有
*.tpl前,先將agents/{{AGENT_ID}}.json.tpl改名為agents/<AGENT_ID>.json.tpl,再統一移除.tpl副檔名。 - 最終
agents/<AGENT_ID>.json會被 docker-compose 掛載到/root/.openclaw/workspace/agents/<AGENT_ID>.json。 deploy_to_target.sh透過單引號 heredoc 生成,內部變數不會被當前 shell 展開,之後用sed注入實際AGENT_ID,邏輯:TARGET_IP/SSH_USER參數檢查。- 檢查本地
docker-compose.yml是否存在。 ssh mkdir遠端目錄後,用tar cf - . | ssh tar xf -覆蓋整個目錄。- 執行
docker compose down 2>/dev/null || true && docker compose up -d --build。
4.1.6 結尾輸出
- 成功後輸出:
[OK] Instance ready: /root/.openclaw/workspace/remote-blueprints/<AGENT_ID>
[OK] CONTROL_UI_TOKEN: <實際 token>
Next: cd /root/.openclaw/workspace/remote-blueprints/<AGENT_ID> && ./deploy_to_target.sh <TARGET_IP> [SSH_USER]
4.2 sync_skill.sh — Skill/Plugin 同步腳本
路徑:scripts/sync_skill.sh
- 參數:
<TARGET_IP> <AGENT_ID> <MODULE_DIR_NAME>。 - 本地來源:
workspace/skills/<MODULE_DIR_NAME>,不存在則報錯退出。 - 遠端目的:
/opt/openclaw-remote/<AGENT_ID>/skills/。 - 優先使用
rsync -avz --exclude 'node_modules',無 rsync 才降級為scp -r。 - 同步完成後執行:
ssh root@<TARGET_IP> 'cd /opt/openclaw-remote/<AGENT_ID> && docker compose restart'。
5. 環境變數與配置對齊表
| 變數名 | .env.tpl | docker-compose | openclaw.json | 說明 |
|---|---|---|---|---|
| AGENT_ID | {{AGENT_ID}} |
container_name / AGENT_TAG |
agents.list[].id(模板為 {{AGENT_ID}}) |
遠端 Agent ID,僅允許 [a-zA-Z0-9_-] |
| CONTROL_UI_TOKEN | {{CONTROL_UI_TOKEN}} |
OPENCLAW_GATEWAY_AUTH_TOKEN |
gateway.auth.token="${CONTROL_UI_TOKEN}" |
Gateway Control UI token |
| HUB_QDRANT_URL | 固定 http://100.115... | QDRANT_HOST |
— | 中心 Qdrant URL |
| MEM0_QDRANT_HOST | 100.115.94.1 | MEM0_QDRANT_HOST |
— | mem0-integration 使用的 Qdrant host |
| MEM0_QDRANT_PORT | 6333 | MEM0_QDRANT_PORT |
— | mem0-integration 使用的 Qdrant port |
| LLM_BASE_URL | {{LLM_BASE_URL}} |
LLM_BASE_URL |
models.providers.default_llm.baseUrl |
通用 LLM 端點(OpenAI compatible 等) |
| LLM_API_KEY | {{LLM_API_KEY}} |
LLM_API_KEY |
models.providers.default_llm.apiKey |
通用 LLM API key |
| LLM_MODEL_ID | {{LLM_MODEL_ID}} |
LLM_MODEL_ID |
models.providers.default_llm.models[].name |
實際使用的大模型 ID(如 qwen-max, gpt-4o) |
重要:openclaw.json 僅透過 ${VAR_NAME} 讀取這些變數,實際值由 .env / compose 注入,不再使用任何 SecretRef 物件,也不再引用 BAILIAN_API_KEY。
6. 修復與變更記錄(供 AI / 維運對照)
| 項目 | 問題 / 風險 | 修復 / 改動摘要 |
|---|---|---|
| LLM 提供商耦合 | 過去綁定 bailian 提供商與固定模型 ID |
改為 default_llm provider,使用 ${LLM_BASE_URL}、${LLM_API_KEY}、${LLM_MODEL_ID} 完全解耦。 |
| openclaw.json secrets 格式 | 使用 SecretRef 或硬編 API key | 改為一致使用 ${CONTROL_UI_TOKEN}、${LLM_API_KEY} 字串插值,並由 .env/compose 提供實際值。 |
| Agent Profile 掛載路徑 | 先前構想使用 /root/.openclaw/agents |
修正為 /root/.openclaw/workspace/agents,與 workspace 路徑對齊,並新增 agents/{{AGENT_ID}}.json.tpl。 |
| generate_remote 無交互模式 | 可能於缺參數時卡在 read 導致 Hang |
帶任一 flag 即進入嚴格非互動模式,缺少必填參數時回傳 JSON 錯誤並立刻退出,不進行任何 read。 |
| sed URL 替換問題 | https:// 中的 / 會破壞 s/old/new/g |
全面改用 s#old#new#g,並對值先經 escape_sed_val 處理 \、&、/。 |
| Token / API key sed 注入風險 | token 中含 & 或 \ 造成 sed 失敗 |
使用 escape_sed_val 對所有值做轉義;同時限制 AGENT_ID 僅允許 [a-zA-Z0-9_-]。 |
| deploy_to_target 腳本嵌套變數 | 早期版本 heredoc 中混雜當前 shell 變數 | 改用單引號 heredoc 並使用 placeholder __AGENT_ID_PLACEHOLDER__,事後以 sed 注入實際 AGENT_ID。 |
| mem0 Qdrant 依賴明確化 | 容器端 mem0 可能找不到 Qdrant 地址 | .env.tpl + compose 中顯式提供 MEM0_QDRANT_HOST、MEM0_QDRANT_PORT。 |
本版未再執行額外自動化測試;以上變動經過靜態檢查與少量手動 sanity run 佐證,建議在實際部署前再做一次端對端驗證。
7. 使用建議(高階)
- Main Agent ChatOps 調用:
- 建議統一由 Main Agent 以非互動模式呼叫:
./generate_remote.sh \ -a advert-bot \ -n "Advert Bot" \ -p advert \ -u https://llm.example.com/v1 \ -k sk-xxx \ -m qwen-max
- 建議統一由 Main Agent 以非互動模式呼叫:
- 部署:
- 在目標伺服器上確保 Docker 與 LLM 網路連線可用後,執行:
cd /root/.openclaw/workspace/remote-blueprints/advert-bot ./deploy_to_target.sh <TARGET_IP> [SSH_USER]
- 在目標伺服器上確保 Docker 與 LLM 網路連線可用後,執行:
- Skill 熱更新:
- 使用
sync_skill.sh精準同步單一 Skill 目錄,避免重建鏡像:./sync_skill.sh <TARGET_IP> advert-bot tavily
- 使用
最後更新: 2026-03-12 — 將舊版 BAILIAN_API_KEY 說明全面替換為通用 LLM_BASE_URL / LLM_API_KEY / LLM_MODEL_ID 模型解耦方案,並補充 ChatOps 無交互模式與認知配置掛載設計。