# AutoDL 准备、验收与后续执行顺序 > 当前状态(2026-08-30):项目已完成统一64K P0并阶段性归档;腾讯云CVM、云硬盘和相关计费资源已经释放,原k3s/BuildKit/sandbox不在线。本文是历史安装与未来重建手册;旧EIP、KubeConfig、PVC、端口转发和AutoDL公网映射均不得假设仍然有效。历史运行中需要设置`NCCL_P2P_DISABLE=1`规避Direct P2P死锁。 本文的环境安装与验收命令仍适用;涉及ACK/ACR的旧资源名称只用于理解方案演进。AutoDL只运行训练、Harbor/rLLM/verl和k3s控制客户端,不安装Docker、kubeadm、kubelet或本地Kubernetes集群。 ```mermaid flowchart LR subgraph Mac["💻 Mac:管理与镜像准备"] M1["✅ 项目源码与配置"] M2["✅ Docker 构建环境"] M3["✅ ACK 管理员 KubeConfig"] M4["⏭️ 镜像 SWE 基础镜像"] end subgraph Aliyun["☁️ 阿里云"] ACR["✅ ACR 镜像仓库"] subgraph ACK["✅ ACK 集群"] API["✅ 公网 API Server"] RBAC["✅ RAM + Kubernetes RBAC"] BK["✅ Rootful BuildKit"] PVC["✅ 100 GiB 构建缓存"] POD["🟡 SWE 任务 Pod"] end end subgraph AutoDL["🖥️ AutoDL GPU"] ENV["✅ Conda / Harbor / rLLM"] DATA["✅ SWE-Smith 100 条"] VLLM["✅ vLLM + Qwen2.5-Coder-7B"] GW["✅ 公网模型 Gateway"] TUNNEL["✅ BuildKit Tunnel"] CANARY["🟡 单任务 Canary"] end M2 --> ACR M3 --> API ENV --> CANARY DATA --> CANARY CANARY --> API API --> POD POD --> BK BK --- PVC TUNNEL --> BK POD --> GW GW --> VLLM M4 --> ACR ACR -.下一步替代 Docker Hub.-> BK classDef done fill:#d9f7e5,stroke:#21a366,color:#123; classDef partial fill:#fff2cc,stroke:#d6a100,color:#123; classDef next fill:#dcecff,stroke:#3478c9,color:#123; class M1,M2,M3,ACR,API,RBAC,BK,PVC,ENV,DATA,VLLM,GW,TUNNEL done; class POD,CANARY partial; class M4 next; ``` ## 1.Mac 生成并上传源码包--done 在 Mac 项目根目录执行: ```bash make mac-preflight make prepare-sources make package-autodl ``` 生成: ```text output/bundles/harbor-qwen-grpo-autodl-source.tar.gz output/bundles/harbor-qwen-grpo-autodl-source.tar.gz.sha256 ``` 同时上传压缩包和 `.sha256` 文件到 AutoDL。源码包会排除 `.env`、`.secrets`、日志、状态、输出和 Git 元数据,不包含任何凭证。 ## 2. AutoDL 校验和解压--done 在上传文件所在目录执行: ```bash cd /root/autodl-tmp sha256sum harbor-qwen-grpo-autodl-source.tar.gz tar -xzf harbor-qwen-grpo-autodl-source.tar.gz cd /root/autodl-tmp/harbor-qwen-grpo-experiment ``` 校验文件由 Mac 生成,第二列可能记录 Mac 上的绝对路径;因此这里只读取第一列哈希值,再校验 AutoDL 当前目录中的压缩包。 预期校验结果: ```text harbor-qwen-grpo-autodl-source.tar.gz: OK ``` 如果 Mac 重新执行了 `make prepare-sources` 或修改了本项目源码,应重新打包、上传并校验,不能只覆盖零散文件。 ## 3. Conda 环境准备--done 选择已经能够正常使用 A800、NVIDIA 驱动、CUDA 和 PyTorch 的 AutoDL 基础镜像。项目要求 Python 3.12;这里的“3.12”指 Python 版本,不是 PyTorch 版本。 清理缓存和坏残留 ``` set -euo pipefail echo "== before ==" df -h / du -h --max-depth=1 /root | sort -hr | head -30 du -h --max-depth=1 /root/miniconda3 | sort -hr | head -30 || true du -h --max-depth=1 /root/.cache | sort -hr | head -30 || true echo "== clean pip/conda caches ==" python -m pip cache purge || true conda clean -a -y || true echo "== clean common build/runtime caches ==" rm -rf /root/.cache/pip rm -rf /root/.cache/torch rm -rf /root/.cache/triton rm -rf /tmp/pip-* /tmp/tmp* echo "== clean broken pip leftovers ==" rm -rf /root/miniconda3/lib/python3.12/site-packages/~orch* rm -rf /root/miniconda3/lib/python3.12/site-packages/~umpy* rm -rf /root/miniconda3/envs/harbor-grpo/lib/python3.12/site-packages/~orch* rm -rf /root/miniconda3/envs/harbor-grpo/lib/python3.12/site-packages/~umpy* echo "== after ==" df -h / du -h --max-depth=1 /root | sort -hr | head -30 du -h --max-depth=1 /root/miniconda3 | sort -hr | head -30 || true ``` 先查看当前环境: ```bash source /root/miniconda3/etc/profile.d/conda.sh conda env list python --version nvidia-smi python -c 'import torch; print(torch.__version__, torch.version.cuda, torch.cuda.is_available(), torch.cuda.device_count())' ``` 若 AutoDL 预装环境已是 Python 3.12 且 PyTorch 能访问全部 GPU,优先克隆该已验证环境。将下面的 `<源环境名>` 替换为 `conda env list` 中实际可用的环境名: ```bash source /root/miniconda3/etc/profile.d/conda.sh conda create -n harbor-grpo --clone base -y conda activate harbor-grpo ``` 不要为了切换 Python 小版本直接覆盖基础环境中已经验证的 PyTorch/CUDA 组合。如果基础环境不是 Python 3.12,应换用匹配镜像,或另建经过 CUDA 验证的环境后再继续。 在激活环境后安装项目依赖: ```bash cd /root/autodl-tmp/harbor-qwen-grpo-experiment source /root/miniconda3/etc/profile.d/conda.sh conda activate harbor-grpo set -a source .env set +a pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main conda install -c conda-forge make gettext openssl curl tmux -y # kubectl 1.36.1: KUBECTL_VERSION=v1.36.1 KUBECTL_BASE="https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64" curl -fL -o /tmp/kubectl "${KUBECTL_BASE}/kubectl" curl -fL -o /tmp/kubectl.sha256 "${KUBECTL_BASE}/kubectl.sha256" echo "$(cat /tmp/kubectl.sha256) /tmp/kubectl" | sha256sum --check install -m 0755 /tmp/kubectl "$CONDA_PREFIX/bin/kubectl" kubectl version --client # buildctl v0.20.2: BUILDKIT_VERSION=v0.20.2 BUILDKIT_BASE=https://github.com/moby/buildkit/releases/download BUILDKIT_FILE=buildkit-${BUILDKIT_VERSION}.linux-amd64.tar.gz BUILDKIT_URL=${BUILDKIT_BASE}/${BUILDKIT_VERSION}/${BUILDKIT_FILE} curl -fL -o /tmp/buildkit.tgz "$BUILDKIT_URL" tar -xzf /tmp/buildkit.tgz -C /tmp tar -xzf buildkit-v0.20.2.linux-amd64.tar.gz -C /tmp install -m 0755 /tmp/bin/buildctl "$CONDA_PREFIX/bin/buildctl" buildctl --version # crane 示例固定为 v0.20.3;下载后应在 GitHub Release 页面核对 SHA-256: CRANE_VERSION=v0.20.3 CRANE_BASE=https://github.com/google/go-containerregistry/releases/download CRANE_FILE=go-containerregistry_Linux_x86_64.tar.gz CRANE_URL=${CRANE_BASE}/${CRANE_VERSION}/${CRANE_FILE} curl -fL -o /tmp/crane.tgz "$CRANE_URL" tar -xzf /tmp/crane.tgz -C /tmp crane tar -xzf go-containerregistry_Linux_x86_64.tar.gz -C /tmp crane install -m 0755 /tmp/crane "$CONDA_PREFIX/bin/crane" crane version # 工具总检: for cmd in conda python pip kubectl buildctl crane curl openssl make envsubst tmux; do command -v "$cmd" || exit 1 done cp .env.example .env pip install "https://github.com/adithyaxx/flash-attention/releases/download/v2.8.3/flash_attn-2.8.3+cu13torch2.11cxx11abiTRUE-cp312-cp312-linux_x86_64.whl" 手动下载flash_attn-2.8.1+cu12torch2.8cxx11abiFALSE-cp312-cp312-linux_x86_64.whl pip install flash_attn-2.8.1+cu12torch2.8cxx11abiFALSE-cp312-cp312-linux_x86_64.whl SKIP_FLASH_ATTN=1 make install-conda ``` ## 5. AutoDL 本地验收(ACK 尚未创建也可以完成) ### 5.1 源码完整性--done ```bash cd /root/autodl-tmp/harbor-qwen-grpo-experiment test -f Makefile && echo 'PASS: Makefile' test -f .env.example && echo 'PASS: .env.example' test -d scripts && echo 'PASS: scripts' test -d upstream/harbor && echo 'PASS: upstream/harbor' test -d upstream/rllm && echo 'PASS: upstream/rllm' test -f .env && echo "PASS: .env" ``` 五项都必须显示 `PASS`。 ### 5.2 Conda、Python及依赖--done ```bash source /root/miniconda3/etc/profile.d/conda.sh conda activate harbor-grpo echo "$CONDA_DEFAULT_ENV" which python python --version python -m pip --version python -m pip check ``` 验收标准: - 环境名为 `harbor-grpo`; - Python 为 3.12.x; - `which python` 指向当前 Conda 环境; - `pip check` 不报告依赖冲突。 验证项目导入: ```bash PYTHONPATH="$PWD/src:$PWD/upstream/rllm:${PYTHONPATH:-}" python - <<'PY' import harbor import rllm import verl import harbor_qwen_grpo_experiment print("PASS: Harbor, rLLM, verl and project imports") PY ``` ### 5.3 GPU及真实 CUDA 运算--done ```bash nvidia-smi nvidia-smi --query-gpu=index,name,memory.total,driver_version --format=csv python - <<'PY' import torch print("torch:", torch.__version__) print("torch CUDA build:", torch.version.cuda) print("CUDA available:", torch.cuda.is_available()) print("GPU count:", torch.cuda.device_count()) for i in range(torch.cuda.device_count()): print(i, torch.cuda.get_device_name(i)) assert torch.cuda.is_available(), "PyTorch cannot access CUDA" x = torch.randn(2048, 2048, device="cuda") y = x @ x torch.cuda.synchronize() print("PASS: CUDA matrix multiplication", y.mean().item()) PY ``` 验收标准: - `CUDA available: True`; - 显示预期的 4 或 8 张 A800; - CUDA 矩阵计算完成,无驱动、CUDA或显存错误。 ### 5.4 命令及架构--done ```bash for cmd in conda python pip kubectl buildctl crane curl openssl make envsubst tmux; do if command -v "$cmd" >/dev/null 2>&1; then printf 'PASS: %-10s %s\n' "$cmd" "$(command -v "$cmd")" else printf 'FAIL: %s\n' "$cmd" fi done uname -m kubectl version --client buildctl --version crane version cd /root/autodl-tmp/harbor-qwen-grpo-experiment source /root/miniconda3/etc/profile.d/conda.sh conda activate harbor-grpo python --version python - <<'PY' import torch import flash_attn import vllm import transformers print("torch:", torch.__version__) print("torch CUDA:", torch.version.cuda) print("vllm:", vllm.__version__) print("transformers:", transformers.__version__) print("CUDA available:", torch.cuda.is_available()) print("GPU count:", torch.cuda.device_count()) print("flash-attn:", flash_attn.__version__) PY python -m pip check ``` 验收标准:全部命令显示 `PASS`,`uname -m` 为 `x86_64`,三个客户端能够输出版本。AutoDL 上缺少 `docker` 和 `git` 是本方案的正常状态。 ### 5.5 公网、DNS及 ACR--done ```bash curl -I --connect-timeout 10 https://www.aliyun.com getent hosts ${ACR_PUBLIC_REGISTRY_HOST} curl -I --connect-timeout 10 \ https://${ACR_PUBLIC_REGISTRY_HOST}/v2/ curl -4 --connect-timeout 10 https://ifconfig.me echo curl -sS -o /dev/null \ --connect-timeout 10 \ -w 'Aliyun: http=%{http_code} remote_ip=%{remote_ip} tls_verify=%{ssl_verify_result}\n' \ https://www.aliyun.com/ getent ahostsv4 \ ${ACR_PUBLIC_REGISTRY_HOST} curl -sS -o /dev/null \ --connect-timeout 10 \ -w 'ACR: http=%{http_code} remote_ip=%{remote_ip} tls_verify=%{ssl_verify_result}\n' \ https://${ACR_PUBLIC_REGISTRY_HOST}/v2/ printf 'AutoDL public IPv4: ' curl -4 -sS --connect-timeout 10 https://ifconfig.me/ip echo ``` ![](/Users/keryszhang/Library/Application%20Support/marktext/images/2026-07-30-16-08-36-image.png) 这组结果说明 AutoDL 到阿里云的公网出站网络验证已经通过。 | 检查项 | 结果 | 含义 | | ------------ | ---------------- | ----------------------------------------------- | | 阿里云公网访问 | `403` | 网络、DNS、TCP、TLS 均正常;403 是网站/WAF拒绝 curl 请求,不是网络故障 | | ACR DNS | `47.95.181.38` | 解析正常 | | ACR `/v2/` | `401` | 完全符合预期:Registry 可达,但请求未携带认证 | | TLS | `tls_verify=0` | 两个 HTTPS 站点的证书校验正常 | | AutoDL 出口 IP | `36.140.113.200` | 已获得当前公网出口地址 | 所以当前链路成立: ``` AutoDL → 公网出口 36.140.113.200 → 阿里云公网 → 北京 ACR 47.95.181.38:443 ``` `Aliyun 403` 不需要处理。阿里云门户可能根据 User-Agent、数据中心出口 IP 或 WAF 策略拒绝命令行访问;它已经证明连接成功。 `ACR 401` 是最佳预期结果,表示: ``` DNS成功 → TCP成功 → TLS成功 → Registry服务成功 → 缺少登录凭证 ``` 注意 `36.140.113.200` 不一定是长期固定 IP。AutoDL 实例重启、迁移或网络调整后应重新执行: ``` curl -4 -sS https://ifconfig.me/ip ``` 不要永久假设它不会变化。 ### 5.6 ACK 创建前验收结论 以下全部通过,AutoDL 本地准备才算完成: - 源码包 SHA-256 为 `OK`; - 项目与两个上游源码目录齐全; - Conda、Python 3.12、依赖导入和 `pip check` 通过; - 4/8 张 A800 全部可见,CUDA 计算通过; - 必需命令齐全且为 Linux AMD64; - AutoDL 能访问公网和 ACR; - 已记录当前 AutoDL 出口 IP。 ACK 尚未创建时,不能执行或不要求通过: ```text kubectl cluster-info make autodl-ack-network make buildkit-tunnel make buildkit-status make network-smoke make preflight ``` ## 5.7 设置目录&下载模型&验证--done 设置模型和缓存目录 ``` mkdir -p /root/autodl-tmp/models mkdir -p /root/autodl-tmp/cache/huggingface mkdir -p /root/autodl-tmp/logs # export HF_HOME=/root/autodl-tmp/cache/huggingface export MODEL_DIR=/root/autodl-tmp/models/Qwen2.5-Coder-7B-Instruct export MODELSCOPE_CACHE="/root/autodl-tmp/cache/modelscope" export MODEL_ID="Qwen/Qwen2.5-Coder-7B-Instruct" mkdir -p "$MODEL_DIR" "$MODELSCOPE_CACHE" df -h /root/autodl-tmp ``` 确保下载前至少有40GB可用空间,最好扩容到100GB以上。 安装官方Hugging Face下载工具: ``` conda activate harbor-grpo python -m pip install -U modelscope modelscope --version # python -m pip install -U huggingface_hub ``` 下载固定revision: ``` modelscope download \ --model "$MODEL_ID" \ --revision master \ --local_dir "$MODEL_DIR" #hf download Qwen/Qwen2.5-Coder-7B-Instruct \ --revision c03e6d358207e414f1eca0bb1891e29f1db0e242 \ --local-dir "$MODEL_DIR" ``` 验证: ``` du -sh "$MODEL_DIR" test -f "$MODEL_DIR/config.json" && test -f "$MODEL_DIR/model.safetensors.index.json" && echo "PASS: model files" ``` 验证tokenizer: ``` python - <<'PY' from transformers import AutoTokenizer path = "/root/autodl-tmp/models/Qwen2.5-Coder-7B-Instruct" tokenizer = AutoTokenizer.from_pretrained(path, local_files_only=True) print("PASS:", tokenizer.__class__.__name__, tokenizer.vocab_size) PY ``` ## 5.8 生成模型API Token--done ``` mkdir -p /root/.config/harbor-qwen-grpo chmod 700 /root/.config/harbor-qwen-grpo umask 077 openssl rand -hex 32 > /root/.config/harbor-qwen-grpo/model-api-key chmod 600 /root/.config/harbor-qwen-grpo/model-api-key ``` 将文件中的值填入AutoDL项目`.env`: ``` CANARY_MODEL_API_KEY=<读取 /root/.config/harbor-qwen-grpo/model-api-key 的内容> ``` 不要把Token写入Qwen Code的`settings.json`。Qwen Code官方推荐通过环境变量或`envKey`读取凭证。 在6008启动单卡vLLM 进入tmux: ``` tmux new -s vllm-canary ``` 在tmux内执行: ``` cd /root/autodl-tmp/harbor-qwen-grpo-experiment source /root/miniconda3/etc/profile.d/conda.sh conda activate harbor-grpo export MODEL_DIR=/root/autodl-tmp/models/Qwen2.5-Coder-7B-Instruct export MODEL_NAME=Qwen2.5-Coder-7B-Instruct export MODEL_API_KEY="$(tr -d '\r\n' < /root/.config/harbor-qwen-grpo/model-api-key)" CUDA_VISIBLE_DEVICES=0 vllm serve "$MODEL_DIR" \ --served-model-name "$MODEL_NAME" \ --host 0.0.0.0 \ --port 6008 \ --dtype bfloat16 \ --max-model-len 32768 \ --max-num-seqs 2 \ --gpu-memory-utilization 0.85 \ --enable-auto-tool-choice \ --tool-call-parser hermes \ --api-key "$MODEL_API_KEY" cd /root/autodl-tmp/harbor-qwen-grpo-experiment source /root/miniconda3/etc/profile.d/conda.sh conda activate harbor-grpo set -a source .env set +a exec vllm serve "$KLEAR_MODEL_PATH" \ --served-model-name "$KLEAR_SERVED_MODEL_NAME" \ --host 0.0.0.0 \ --port 6008 \ --api-key "$CANARY_MODEL_API_KEY" \ --max-model-len 65536 \ --max-num-seqs "${KLEAR_VLLM_MAX_NUM_SEQS:-4}" \ --max-num-batched-tokens "${KLEAR_VLLM_MAX_NUM_BATCHED_TOKENS:-32768}" \ --gpu-memory-utilization "${KLEAR_VLLM_GPU_MEMORY_UTILIZATION:-0.90}" \ --enable-chunked-prefill \ --enable-prefix-caching ``` 看到服务启动完成后,按`Ctrl-b`再按`d`离开tmux,但不停止服务。 查看: ``` tmux ls tmux attach -t vllm-canary ``` ### 5.8.1 预构建 mini-swe-agent-plus 运行镜像 使用Plus前先确认BuildKit tunnel正常,然后构建并推送固定运行镜像: ```bash make buildkit-status make agent-runtime-build ``` `.env`必须包含: ```bash MINI_SWE_AGENT_PLUS_RUNTIME_SCHEMA=v3 ACK_MINI_SWE_AGENT_PLUS_BASE_IMAGE=${ACK_REGISTRY_PREFIX}/infra-mini-swe-agent-plus:${MINI_SWE_AGENT_PLUS_VERSION} ACK_MINI_SWE_AGENT_PLUS_IMAGE=${ACK_REGISTRY_PREFIX}/infra-mini-swe-agent-plus:${MINI_SWE_AGENT_PLUS_VERSION}-${MINI_SWE_AGENT_PLUS_RUNTIME_SCHEMA} ``` 构建从Registry中已验收的固定revision旧镜像增量生成v3,不重新访问GitHub或PyPI。 Canary任务Pod通过initContainer复制自包含的Python 3.12与Plus环境, Plus启动后恢复任务原有Python环境,任务命令继续使用任务镜像自带的`python3`。Harbor安装 阶段只进行本地命令、固定revision和运行时schema检查,不访问GitHub或PyPI。 ## 5.9 本地接口验收--done ``` export MODEL_API_KEY="$(tr -d '\r\n' < /root/.config/harbor-qwen-grpo/model-api-key)" curl --fail --silent --show-error \ -H "Authorization: Bearer $MODEL_API_KEY" \ http://127.0.0.1:6008/v1/models | python -m json.tool ``` 基础生成测试: ``` curl --fail --silent --show-error \ http://127.0.0.1:6008/v1/chat/completions \ -H "Authorization: Bearer $MODEL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "Qwen/Qwen2.5-Coder-7B-Instruct", "messages": [ { "role": "user", "content": "Write a Python function that returns the nth Fibonacci number." } ], "temperature": 0.2, "max_tokens": 512 }' | python -m json.tool ``` 同时观察: ``` watch -n 1 nvidia-smi ``` ## 5.10 从Mac验证AutoDL公网入口--done 复制AutoDL控制台6008对应地址后,在Mac执行: ``` 6008公网地址 https://uu242790-b362-d570d0a7.nma1.seetacloud.com:8448 export CANARY_URL='https://uu242790-b362-d570d0a7.nma1.seetacloud.com:8448/v1' read -s MODEL_API_KEY curl --fail --silent --show-error \ -H "Authorization: Bearer $MODEL_API_KEY" \ "$CANARY_URL/models" | python3 -m json.tool ``` 验收标准: - DNS能够解析; - TLS/HTTP连接成功; - 返回模型列表; - 不带Token时返回401; - 带Token时返回200; - 模型名称与`.env`的`MODEL_NAME`完全一致。 如果Mac无法访问,不要创建ACK;ACK同样无法访问该入口。 ## 5.11安装并测试Qwen Code--done 检查Node: ``` git clone https://gitee.com/mirrors/nvm.git /root/.nvm cd /root/.nvm git checkout v0.40.3 export NVM_DIR="$HOME/.nvm" source "$NVM_DIR/nvm.sh" export NVM_NODEJS_ORG_MIRROR=https://npmmirror.com/mirrors/node nvm install 22 nvm use 22 node -v npm -v ``` 项目固定Qwen Code 0.16.2: ``` npm config set registry https://registry.npmmirror.com npm install -g @qwen-code/qwen-code@0.16.2 qwen --version ``` 预期 `qwen --version`: ``` 0.16.2 ``` 连接本地vLLM: ``` cd /root/autodl-tmp/harbor-qwen-grpo-experiment export OPENAI_API_KEY="$(tr -d '\r\n' < /root/.config/harbor-qwen-grpo/model-api-key)" export OPENAI_BASE_URL=http://127.0.0.1:6008/v1 export OPENAI_MODEL=Qwen/Qwen2.5-Coder-7B-Instruct qwen \ --auth-type openai \ --model "$OPENAI_MODEL" \ --openai-api-key "$OPENAI_API_KEY" \ --openai-base-url "$OPENAI_BASE_URL" \ --approval-mode plan \ --prompt "Read README.md, Makefile, and scripts/50_train_grpo.sh. Explain this project in 5 bullets. Do not guess." ``` 首轮只用`plan`验证模型连接和工具格式。真正的Harbor Sandbox自动执行时才切换到`yolo`,并使用Qwen Code的任务超时限制。 ### ACK Sandbox 的 Qwen Code 安装路径 ACK Sandbox 不复用 AutoDL 主机上的 Node.js。每个任务环境会独立安装或检测 Qwen Code。由于 ACK 到 `raw.githubusercontent.com` 可能连接后长期无响应,必须启用: ```dotenv APPLY_QWEN_PREINSTALL_PATCH=1 ``` 补丁行为如下: - 已存在指定版本 Qwen Code:直接跳过安装。 - ACK 未预装:从 `nodejs.org` 安装固定 Node.js 22.17.0,再从 npm 安装 `QWEN_CODE_VERSION`。 - Docker/Daytona:继续使用 Harbor 原始 NVM 安装方式。 运行 Canary 前,可从 ACK Pod 验证 `nodejs.org` 和 npm;不再要求 ACK 访问 `raw.githubusercontent.com`。正式批量训练仍建议使用 `docker/qwen-code-overlay.Dockerfile` 预装依赖,以减少每条轨迹的启动时间和外网波动。 ## 6. `.env` 与凭证分工 源码包不包含 `.env`。Mac 和 AutoDL 各自执行: ```bash cp .env.example .env chmod 600 .env ``` 两台机器的 `.env` 不是同一个文件:路径项必须填写各自机器上的绝对路径,“凭证分工”同时说明三件事: 1. 凭证在哪里生成。 2. 凭证长期保存在哪里。 3. 哪个组件在运行时使用它。 不是所有凭证都需要“上传”。 | 凭证 | 生成/获取位置 | 保存位置 | 是否传输 | | -------------------- | -------------- | ------------------- | --------------------------------------- | | ACR用户名和固定密码 | 阿里云ACR控制台 | Mac的`.secrets/acr/` | Mac通过`ack-prepare`写入ACK Secret;不传AutoDL | | ACK管理员KubeConfig | ACK控制台 | Mac | 从ACK下载到Mac,不上传回ACK | | ACK运行KubeConfig | ACK控制台/RBAC | AutoDL | 从ACK下载到AutoDL,权限应低于管理员 | | BuildKit CA证书 | Mac | Mac、AutoDL、ACK | CA证书可分发 | | BuildKit CA私钥 | Mac | 只保留在Mac | 绝不上传AutoDL或ACK | | BuildKit server证书/私钥 | Mac | Mac、ACK Secret | 通过`ack-prepare`传到ACK,不传AutoDL | | BuildKit client证书/私钥 | Mac | Mac、AutoDL | 安全复制到AutoDL,不传Sandbox | | 模型Gateway Token | AutoDL配置 | AutoDL的`.env` | 请求模型时使用,不应长期写入任务目录 | | `.env` | Mac和AutoDL分别创建 | 各自本机 | 不互相整体复制,也不上传ACK | 数据流可以理解为: ``` 阿里云ACK │ ├── 下载管理员KubeConfig ──→ Mac └── 下载受限KubeConfig ────→ AutoDL Mac ├── ACR用户名/密码 ─────────→ ACK imagePullSecret ├── BuildKit CA+server证书 ─→ ACK Kubernetes Secret └── CA+client证书 ──────────→ AutoDL AutoDL ├── 使用受限KubeConfig访问ACK ├── 使用client证书连接BuildKit └── 保存模型Gateway Token ``` 具体目录建议 Mac: ``` harbor-qwen-grpo-experiment/ ├── .env └── .secrets/ ├── acr/ │ ├── username │ └── password └── buildkit/ ├── ca.pem ├── ca-key.pem ├── server-cert.pem ├── server-key.pem ├── client-cert.pem └── client-key.pem ``` AutoDL只需要: ``` /root/ack-public-kubeconfig.yaml /root/.config/harbor-qwen-grpo/buildkit/ca.pem /root/.config/harbor-qwen-grpo/buildkit/client-cert.pem /root/.config/harbor-qwen-grpo/buildkit/client-key.pem 项目目录/.env ``` ACK里最终保存: ``` harbor-qwen-grpo namespace └── acr-pull:ACR拉取凭证 harbor-qwen-build namespace ├── acr-pull:ACR拉取/推送凭证 └── buildkit-server-tls:CA、server-cert、server-key ``` 关键安全边界: - AutoDL不要保存ACR固定密码。 - AutoDL不要使用`ack-admin`管理员KubeConfig,应使用`harbor-runner`受限KubeConfig。 - `ca-key.pem`永远只留在Mac。 - 不要把整个`.secrets`目录打包上传。 - Mac和AutoDL分别维护自己的`.env`,因为KubeConfig和证书路径不同。 - 所有KubeConfig、私钥、密码文件执行: ``` chmod 600 <文件> ``` 所以,“上传到对应资源”只适用于部分凭证;KubeConfig的方向恰好相反,它是从ACK下载到Mac或AutoDL。 ## 7. ACK 双用户授权、KubeConfig与双端验收 本项目使用两个独立RAM用户,不能共用KubeConfig: | RAM用户 | 使用位置 | RAM系统策略 | Kubernetes RBAC | 用途 | | --------------- | ------ | ------------------------ | ------------------ | ----------------------------------- | | `ack-admin` | Mac | `AliyunCSFullAccess` | 仅当前实验集群的管理员 | 初始化namespace、Secret和BuildKit,执行集群运维 | | `harbor-runner` | AutoDL | `AliyunCSReadOnlyAccess` | 两个项目namespace的开发人员 | 创建任务Pod/Job、exec、读取日志、端口转发及项目Secret | 若用户还持有`PowerUserAccess`,应解除该策略。`harbor-runner`不能授予集群管理员, AutoDL也不能复制或使用`ack-admin`的KubeConfig。 ### 7.1 前置网络条件--done 获取公网KubeConfig前,ACK API Server必须已启用公网访问。若使用CLB监听ACL白名单, 至少保留以下来源: ```text 100.104.0.0/16 # ACK管控网段 10.20.0.0/16 # 本项目VPC网段 /32 51.195.241.248 /32. 36.140.113.200 ``` Mac和AutoDL可分别执行以下命令获取当前出口IPv4: ```bash curl -4 -sS https://ifconfig.me/ip echo ``` AutoDL重启后出口IP可能变化;连接突然超时时,应先复查出口IP和ACL。 ### 7.2 创建RAM登录凭证和系统权限--done 使用阿里云主账号进入`RAM控制台 -> 身份管理 -> 用户`: 1. 为`ack-admin`保留`AliyunCSFullAccess`。 2. 为`harbor-runner`保留`AliyunCSReadOnlyAccess`。 3. 在各用户的`认证管理 -> 登录信息`中启用控制台登录并设置密码。 RAM控制台密码不能查看明文;忘记时只能由主账号重置。它不是ACR固定密码、AccessKey、 KubeConfig或服务器登录密码,也不写入项目`.env`。 ### 7.3 授权顺序--done 权限和namespace存在先后依赖,按以下顺序操作: 1. 主账号进入`ACK控制台 -> 授权管理 -> RAM用户 -> ack-admin -> 管理权限`。 2. 为`ack-admin`添加当前`harbor-qwen-grpo-experiment`集群、全部namespace、预置角色`管理员`。 3. 使用`ack-admin`登录ACK控制台,获取它自己的长期公网KubeConfig。 4. Mac使用管理员KubeConfig创建`harbor-qwen-grpo`和`harbor-qwen-build`。 5. 主账号回到授权管理,为`harbor-runner`添加两条权限: - `harbor-qwen-grpo`:`开发人员`; - `harbor-qwen-build`:`开发人员`。 6. 使用`harbor-runner`登录ACK控制台,获取它自己的长期公网KubeConfig。 KubeConfig由当前登录身份签发。不能用主账号下载一份后同时复制给Mac和AutoDL, 也不能把管理员KubeConfig改名后当作运行KubeConfig。 ### 7.4 Mac管理员KubeConfig--done 将`ack-admin`的公网KubeConfig保存为: ```text /Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml ``` 设置权限并验证: ```bash chmod 600 /Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml kubectl --kubeconfig /Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml \ config view --minify -o jsonpath='{.clusters[0].cluster.server}{"\n"}' kubectl --kubeconfig /Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml \ cluster-info kubectl --kubeconfig /Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml \ get nodes -o wide kubectl --kubeconfig /Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml \ auth can-i '*' '*' --all-namespaces ``` API地址应为ACK公网端点,节点应为`Ready`,最后一条应返回`yes`。 若尚未创建namespace,可幂等执行: ```bash ADMIN_KUBECONFIG=/Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml kubectl --kubeconfig "${ADMIN_KUBECONFIG}" create namespace harbor-qwen-grpo \ --dry-run=client -o yaml | kubectl --kubeconfig "${ADMIN_KUBECONFIG}" apply -f - kubectl --kubeconfig "${ADMIN_KUBECONFIG}" create namespace harbor-qwen-build \ --dry-run=client -o yaml | kubectl --kubeconfig "${ADMIN_KUBECONFIG}" apply -f - ``` Mac的`.env`填写管理员文件及其实际context: ```text KUBECONFIG_PATH=/Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml KUBE_CONTEXT=<该文件的current-context> ``` 实际context可用以下命令取得: ```bash kubectl --kubeconfig /Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml \ config current-context ``` ### 7.5 AutoDL运行KubeConfig--done 将`harbor-runner`的公网KubeConfig保存为: ```text /root/ack-public-kubeconfig.yaml ``` 设置权限、确认公网端点并验收命名空间权限: ```bash chmod 600 /root/ack-public-kubeconfig.yaml kubectl --kubeconfig /root/ack-public-kubeconfig.yaml config get-contexts kubectl --kubeconfig /root/ack-public-kubeconfig.yaml \ config view --minify -o jsonpath='{.clusters[0].cluster.server}{"\n"}' kubectl --kubeconfig /root/ack-public-kubeconfig.yaml get --raw=/version kubectl --kubeconfig /root/ack-public-kubeconfig.yaml auth can-i create pods -n harbor-qwen-grpo kubectl --kubeconfig /root/ack-public-kubeconfig.yaml auth can-i create jobs.batch -n harbor-qwen-grpo kubectl --kubeconfig /root/ack-public-kubeconfig.yaml auth can-i create pods/exec -n harbor-qwen-grpo kubectl --kubeconfig /root/ack-public-kubeconfig.yaml auth can-i get pods/log -n harbor-qwen-grpo kubectl --kubeconfig /root/ack-public-kubeconfig.yaml auth can-i get secrets -n harbor-qwen-grpo kubectl --kubeconfig /root/ack-public-kubeconfig.yaml auth can-i create pods/portforward -n harbor-qwen-build kubectl --kubeconfig /root/ack-public-kubeconfig.yaml auth can-i get secrets -n harbor-qwen-build ``` 上述`auth can-i`检查应全部返回`yes`。`harbor-runner`采用命名空间级最小权限,以下结果正常: ```text kubectl cluster-info -> 可能因不能列出kube-system Service而返回Forbidden kubectl get nodes -> 因不能读取集群级Node而返回Forbidden kubectl get namespace -> 因不能读取集群级Namespace而返回Forbidden ``` 不要为了消除这些提示而扩大权限。AutoDL的`.env`只保存文件路径和实际context: ```text KUBECONFIG_PATH=/root/ack-public-kubeconfig.yaml KUBE_CONTEXT=<该文件的current-context> ``` ### 7.6 项目网络验收--done 先在Mac完成`make ack-prepare`,使两个namespace内的镜像拉取Secret存在;然后把更新后的 项目脚本同步到AutoDL并执行: ```bash make autodl-ack-network ``` 该命令检查AutoDL公网出口、ACR公网端点、ACK API `/version`、Pod/Job/exec/log/ port-forward/Secret权限,以及`ack-prepare`创建的镜像拉取Secret。 失败时按以下顺序排查: 1. AutoDL出口IP是否仍在ACK API Server ACL中。 2. AutoDL`.env`中的`KUBECONFIG_PATH`和`KUBE_CONTEXT`是否匹配运行KubeConfig。 3. Mac是否已执行`make ack-prepare`。 4. `harbor-runner`是否仅对两个正确namespace获得`开发人员`权限。 5. 是否误将Mac管理员KubeConfig或旧KubeConfig复制到了AutoDL。 ## 8. BuildKit 通道、Gateway 与全量预检 BuildKit在ACK中使用`moby/buildkit:v0.20.2` rootful镜像和privileged容器。ACK托管 节点可能将`/proc/sys/user/max_user_namespaces`设置为0,rootless镜像会因此以 `failed to start the child`退出。Builder必须放在独立CPU节点池,不与业务负载混部; 它不挂载宿主机Docker socket,缓存仅写入专用PVC。 ### 8.1 BuildKit PVC StorageClass--done ACK集群可能安装多个StorageClass但不设置默认项。BuildKit缓存PVC必须显式配置: ```text ACK_BUILDKIT_STORAGE_CLASS=alicloud-disk-topology-alltype ACK_BUILDKIT_CACHE_SIZE=100Gi ACK_BUILDKIT_GC_KEEP_STORAGE=80000000000 ``` `alicloud-disk-topology-alltype`使用`WaitForFirstConsumer`,会在Pod确定调度节点和可用区后 创建可用云盘,适合测试集群。可用StorageClass可由Mac管理员查询: `ACK_BUILDKIT_GC_KEEP_STORAGE`传给BuildKit `v0.20.2`的 `--oci-worker-gc-keepstorage`,必须填写纯数字字节数;`80000000000`表示80GB,不能写成 `80GB`。 ```bash kubectl --kubeconfig "$KUBECONFIG_PATH" --context "$KUBE_CONTEXT" \ get storageclass -o wide ``` 若旧`buildkit-cache`一直为`Pending`,事件显示`no storage class is set`,说明该PVC在 创建时没有StorageClass。`storageClassName`不能在现有PVC上修改;确认PVC从未绑定且没有 数据后,删除并由`make buildkit-up`重建: ```bash kubectl --kubeconfig "$KUBECONFIG_PATH" --context "$KUBE_CONTEXT" \ delete pvc buildkit-cache -n harbor-qwen-build make buildkit-up ``` ### 8.2 AutoDL 放置客户端证书--done 在Mac项目目录执行: ``` cd /Users/keryszhang/Documents/Tool-using-agent-rl/harbor-qwen-grpo-experiment make buildkit-certs ``` 生成目录: ``` .secrets/buildkit/ ├── ca.pem ├── ca-key.pem ├── server-cert.pem ├── server-key.pem ├── client-cert.pem └── client-key.pem ``` 分工如下: - `ca.pem`:Mac、ACK、AutoDL都需要 - `server-cert.pem`、`server-key.pem`:Mac通过`make ack-prepare`写入ACK - `client-cert.pem`、`client-key.pem`:安全上传到AutoDL - `ca-key.pem`:只留在Mac,不能上传 在AutoDL创建目录: ``` mkdir -p /root/.config/harbor-qwen-grpo/buildkit chmod 700 /root/.config/harbor-qwen-grpo/buildkit ``` 通过AutoDL文件上传功能,把以下三个Mac文件上传过去: ``` ca.pem client-cert.pem client-key.pem ``` 然后执行: ``` chmod 600 /root/.config/harbor-qwen-grpo/buildkit/*.pem ``` AutoDL的`.env`填写: ``` BUILDKIT_CA_CERT_PATH=/root/.config/harbor-qwen-grpo/buildkit/ca.pem BUILDKIT_CLIENT_CERT_PATH=/root/.config/harbor-qwen-grpo/buildkit/client-cert.pem BUILDKIT_CLIENT_KEY_PATH=/root/.config/harbor-qwen-grpo/buildkit/client-key.pem ``` 这些证书必须来自同一次`make buildkit-certs`。不要分别在Mac和AutoDL生成两套。同时保持: ```text ACK_BUILDKIT_ADDRESS=tcp://127.0.0.1:1234 ACK_BUILDKIT_LOCAL_PORT=1234 ACK_BUILDKIT_SERVER_NAME=127.0.0.1 ``` ### 8.3 启动长期端口转发--done 在AutoDL独立 tmux 窗口运行: (服务器上保持后台终端会话的工具,`make buildkit-tunnel`是一个需要持续运行的前台进程。如果SSH或网页终端断开,普通终端中的进程可能退出;放进tmux后,断开连接它仍会继续运行。) ```bash cd /root/autodl-tmp/harbor-qwen-grpo-experiment set -a source .env set +a source /root/miniconda3/etc/profile.d/conda.sh conda activate harbor-grpo tmux new -s buildkit make buildkit-tunnel ``` 使用 `Ctrl-b d` 脱离 tmux。另一个终端验证: ```bash make buildkit-status ``` `buildkit-tunnel` 会循环重连,但网络断开时正在进行的单次构建仍可能失败。10题 Canary 的并发固定为 2;长期高并发应改为固定 EIP 的安全构建中继。 脱离但不停止: ``` 先按 Ctrl-b,再按 d ``` 查看: ``` tmux ls ``` 重新进入: ``` tmux attach -t buildkit ``` 停止时,在窗口里按`Ctrl-C`,或者: ``` tmux kill-session -t buildkit ``` AutoDL实例关机后tmux也会停止,重新开机需要重新启动隧道。 ### 8.4 BuildKit 实际构建验收--done `make buildkit-status`只能证明客户端可列出远端worker。启动Canary前,还需要验证构建上下文 上传、Dockerfile执行和OCI导出链路: ```bash make buildkit-smoke ``` 该命令使用临时目录生成一个不访问网络的`scratch`镜像,经AutoDL本机mTLS tunnel交给ACK BuildKit构建,再把OCI归档流回AutoDL并验证`index.json`。无论成功或失败,临时上下文和输出 都会删除;它不会推送镜像,也不会修改现有PVC内容之外的正常BuildKit缓存。 成功标志: ```text BuildKit smoke build passed; temporary context and OCI output were removed. ``` ### 8.5 模型 Gateway--done AutoDL 个人账号使用控制台提供的 6006(测试) 或 6008(正式) 公网映射,<公网地址>是ACK Pod能够访问的AutoDL模型服务公网入口。 AutoDL无需自己购买域名。实例运行后,平台自动把容器内的6006和6008映射为公网地址。 操作顺序: 1. AutoDL控制台进入对应实例。 2. 确认“自定义服务”中: - 6006协议:HTTP https://u242790-a781-ab64f41e.nma1.seetacloud.com:8448 - 6008协议:HTTP https://uu242790-a781-ab64f41e.nma1.seetacloud.com:8448 3. 在实例详情或“自定义服务”入口点击对应端口的“复制地址”。 4. 得到类似: ``` https://u39-xxxx.nmb2.seetacloud.com:8443 ``` 这是完整公网入口;不能把AutoDL SSH地址或内网IP填进去。AutoDL官方说明6006/6008会映射成可访问的“域名+端口”。 AutoDL当前实例将rLLM Gateway的 `127.0.0.1:6006` 和Canary vLLM的 `127.0.0.1:6008` 映射为两个不同的公网 HTTPS origin: ```text cd /root/autodl-tmp/harbor-qwen-grpo-experiment test -f .env || cp .env.example .env chmod 600 .env nano .env MODEL_NAME=ricdomolm/mini-coder-4b CANARY_MODEL_BASE_URL=https://uu242790-9c17-e7970d4a.nma1.seetacloud.com:8448/v1 CANARY_MODEL_API_KEY=<从受限密钥文件读取,不在文档中记录明文> RLLM_GATEWAY_PORT=6006 RLLM_GATEWAY_PUBLIC_URL=https://u242790-9c17-e7970d4a.nma1.seetacloud.com:8448 ``` - `CANARY_MODEL_BASE_URL`:ACK Sandbox在10题Canary中直接请求vLLM。 - `RLLM_GATEWAY_PUBLIC_URL`:正式GRPO中,ACK Sandbox请求rLLM Gateway;只填写公网 origin,不带 `/v1`,rLLM 会为每个 rollout 自动追加 `/sessions//v1`。 - `RLLM_GATEWAY_PORT`:rLLM Gateway在AutoDL容器内部监听的端口,不是公网映射端口号。 - 必须验证 Authorization、`/v1/models`、流式响应及30/60/120分钟长连接。实例重启后重新确认公网地址。Canary 成功但长连接不稳定时,应使用带固定 EIP 的阿里云 ECS HTTPS 中继。 ### 8.6 从 ACK 反向验证 Gateway--done 在AutoDL执行: ```bash make network-smoke ``` 它实际执行的路径是: ``` AutoDL上的kubectl → 请求ACK API创建临时Pod → ACK临时Pod从ACR拉取infra-curl镜像 → ACK临时Pod请求AutoDL公网Gateway → 验证/models → 删除临时Pod ``` 预期输出: ```text ACK Pod can reach the GPU model gateway. ``` ### 8.7 全量预检--done 保持 `buildkit-tunnel` 在 tmux 中运行,然后执行: ```bash make preflight ``` 预期输出: ```text Preflight passed. ``` ## 9. 从当前状态开始的跨平台执行顺序 ### 阶段 A:ACK 创建前,可并行--done | 工作线 | 执行位置 | 操作 | 当前依赖 | 结果 | | --- | ------ | ----------------------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | A1 | AutoDL | 完成第5节本地验收,记录出口 IP | 已上传源码包 | done | | A2 | Mac | 再次确认两个基础镜像已在 ACR,执行 `make buildkit-certs` | `.env` 和 OpenSSL | Certificate request self-signature ok
subject=CN=harbor-gpu-controller
BuildKit mTLS certificates created: /Users/keryszhang/Documents/Tool-using-agent-rl/harbor-qwen-grpo-experiment/.secrets/buildkit
Set the five BUILDKIT_*_PATH values in .env to these files. | | A3 | AutoDL | 启动并验证本地模型服务;准备6006/6008公网映射 | GPU和Conda环境 | done | | A4 | AutoDL | 可选执行 `make pull` 预取 SWE-smith 数据 | `make install-conda` 已通过 | Done. Use 'rllm dataset info  /root/.rllm/datasets/swesmith      100 examples swesmith' to view details. fields: task_id, task_path, instruction, question, ground_truth, harbor_task_name, harbor_task_digest, harbor_category, data_source | | A5 | 阿里云控制台 | 最后复核ACK测试版配置、余额和计费项 | VPC、交换机、ACR已就绪 | done | A1~A5可以并行。此阶段不要运行 `make ack-prepare`、`make buildkit-up` 或任何需要 Kubernetes API 的命令。 ### 阶段 B:创建 ACK,主体串行--done 1. 阿里云创建测试版 ACK 集群并等待“运行中”。 2. 阿里云开启 API Server 公网访问;ACL加入当前 AutoDL 出口 IP并保留ACK要求的系统网段。 3. 按第7节先为`ack-admin`配置当前集群管理员权限并获取其公网KubeConfig。 4. 不把KubeConfig内容粘贴到项目文档;只记录受限文件路径、context和验证命令。 5. Mac创建两个项目namespace后,为`harbor-runner`配置两条namespace级`开发人员`权限并获取其公网KubeConfig。 6. Mac管理员执行`kubectl cluster-info`和`kubectl get nodes -o wide`;AutoDL受限账户执行`kubectl get --raw=/version`及命名空间级`auth can-i`检查。 步骤2和3可在集群运行后并行;步骤4依赖权限完成;步骤5依赖KubeConfig、ACL和RBAC都生效。 ### 阶段 C:初始化 ACK,必须按顺序--done 1. Mac 更新 `.env` 中的 `KUBECONFIG_PATH`、`KUBE_CONTEXT` 和证书路径。 2. Mac 执行: ```bash make ack-prepare ``` 3. Mac 执行: ```bash make buildkit-up ``` 4. AutoDL 更新自己的 `.env`、放置 KubeConfig 和 BuildKit客户端证书。 5. AutoDL 执行: ```bash make autodl-ack-network ``` `make autodl-ack-network` 依赖 `make ack-prepare` 已经创建两个 namespace,因此不能提前运行。`make buildkit-tunnel` 依赖 `make buildkit-up` 已经部署 BuildKit,因此也不能提前运行。 ### 阶段 D:联调,可部分并行--done 1. AutoDL 在 tmux 中运行 `make buildkit-tunnel`。 2. AutoDL 运行 `make buildkit-status`。 3. AutoDL 模型 Gateway 保持运行。? 4. AutoDL 运行 `make network-smoke`,验证 ACK Pod → AutoDL Gateway。 5. AutoDL 运行 `make preflight`。 步骤1和3可并行准备;步骤2依赖步骤1;步骤4依赖 Gateway、ACK namespace、ACR Secret及网络同时就绪;步骤5是最终汇总门槛。 ### 阶段 E:Canary 与训练,严格串行放行 Oracle 阶段在 AutoDL `.env` 中设置 `CURATION_ORACLE_VERIFIER_TIMEOUT_SEC=480` 和 `CURATION_ALLOW_SHORTFALL=true`。单任务 verifier 超时后由 ingest 拒绝,不阻断同批 Oracle; 冻结集允许少于目标 100 条。 Canary 前必须完成 Oracle、`dataset-freeze` 和 `dataset-register`;`make canary` 从 `TRAIN_DATASET_NAME` 的冻结 validation split 确定性选题。任务 Dockerfile 依赖的 SWE-Smith 基础镜像需已同步到 ACR。执行: ```bash make canary ``` make canary报错解决: - 将 SWE-Smith 基础镜像同步到 ACR 公网仓库。 - 解决 BuildKit 访问 ACR 私网认证地址超时的问题。 - 制作离线基础镜像,解决构建阶段无法获取 Git 分支的问题。 - 解决 ACK Sandbox 无法访问 GitHub、导致 Qwen Code 安装超时的问题。 - Canary 首次完整跑通 Agent 和 Verifier:`Trials=1,Exceptions=0`,但奖励为 `0`。 - 检查轨迹后发现只有用户和模型回复,没有实际工具调用。 - 分别测试工具调用: - `tool_choice=required`:成功生成结构化 `tool_calls`。 - `tool_choice=auto`:失败,只输出 Markdown 包裹的普通 JSON。 当前基模的问题并非完全不能调用工具,而是不能在自动模式下可靠遵循工具调用协议。Qwen2.5-Coder-7B 更擅长代码生成,但工具格式遵循能力较弱:它把调用内容写进普通文本,而没有输出 Hermes 能识别的 `` 结构。 Qwen Code 必须使用自动模式,让模型自主决定何时调用工具、何时结束。因此,强制 `required` 虽能通过测试,却不能支撑真实的长程代码任务。当前基模不适合直接进入10条任务测试和GRPO训练。 项目现已把默认 harness 切换为 mini-swe-agent 文本动作模式,绕开原生 function calling。将以下配置补充到 AutoDL `.env`: ```bash HARBOR_AGENT=mini-swe-agent MINI_SWE_AGENT_VERSION=2.3.0 MINI_SWE_AGENT_CONFIG_FILE=configs/agents/mini-swe-agent-text.yaml MINI_SWE_AGENT_MAX_TOKENS=2048 MINI_SWE_AGENT_STEP_LIMIT=100 MINI_SWE_AGENT_COST_LIMIT=0 ACK_POD_READY_TIMEOUT_SEC=480 CANARY_TASKS=1 CANARY_CONCURRENCY=1 CANARY_MAX_RETRIES=1 ``` `mini-swe-agent-plus`使用独立旧版CLI适配。32768上下文下把单步输出限制为896;实测 1024输出预算与31745输入token合计32769,会超过模型上限: ```bash MINI_SWE_AGENT_PLUS_MAX_TOKENS=896 CANARY_TASKS=10 CANARY_CONCURRENCY=4 CANARY_MAX_RETRIES=0 ``` `scripts/lib.sh`遵循标准dotenv优先级:调用方显式导出的变量优先于`.env`。因此也可用 `CANARY_TASKS=10 CANARY_CONCURRENCY=4 CANARY_MAX_RETRIES=0 make canary`临时覆盖,不需要反复改写`.env`。 重新上传源码包后依次执行: ```bash make preflight make network-smoke make canary ``` 单任务通过标准:`Exceptions=0`,轨迹包含多轮 `agent` 与 Shell observation,verifier 文件完整。reward 可以为 0,但不能只有普通文本回答。 mini-swe-agent 的任务仓库固定为 `/testbed`。每个动作都在新 Shell 中执行,不能依赖上一步设置的 `REPO_PATH` 等临时变量;命令应使用相对路径或显式以 `cd /testbed &&` 开头。当前文本动作配置最多执行 100 步;达到步数或上下文上限时按正常 rollout 截断并继续 verifier。 只有满足以下条件才执行 `make train`: - 10/10任务均能创建Sandbox并结束; - 10/10均有可解析ATIF轨迹; - 10/10均有verifier reward,reward可以为0但不能缺失; - BuildKit没有异常重启或持续断线; - 无Sandbox OOM、Gateway/API超时和残留Pod/Job; - 资源峰值、单任务时长和费用可接受。 通过后: ```bash make train ``` ## 10. 2026-08-11当前AutoDL交接状态 CVM侧已经完成: ```text oracle_total=1440 oracle_accepted=981 train/validation/test=350/75/75 repositories=77/70 freeze_ready=true ``` 正式导出包为 `swesmith-20260808-v2-poc-curated.tar.gz`,大小29377680字节,SHA-256为 `8ce630ad5850c1b0456802cb26230257bb7a0b4ca76be50b643534c3248ced05`。AutoDL已完成import、register和status,结果为350/75/75;Canary与单卡GRPO smoke均已完成。 已验证的单卡GRPO smoke配置: ```bash TRAIN_NNODES=1 TRAIN_N_GPUS_PER_NODE=1 TRAIN_TENSOR_PARALLEL_SIZE=1 TRAIN_GPU_MEMORY_UTILIZATION=0.35 TRAIN_MODEL_DTYPE=bf16 TRAIN_ENABLE_SLEEP_MODE=false TRAIN_FREE_CACHE_ENGINE=false TRAIN_PARAM_OFFLOAD=false TRAIN_OPTIMIZER_OFFLOAD=false TRAIN_REF_PARAM_OFFLOAD=false ``` `TRAIN_MODEL_DTYPE=bf16`让训练模型直接以BF16加载;`TRAIN_GPU_MEMORY_UTILIZATION=0.35`将单卡rollout vLLM占用从约40GiB降至可完成backward的范围。CPU offload默认关闭;只有实测显存不足时才逐项启用。 单卡smoke峰值训练显存分配约42.70GiB并完成 `training/global_step=1`。两卡初次初始化异常的根因不是FSDP:原始 `all_reduce` 在Direct P2P/CUMEM路径同样死锁。当前机器先在 `.env` 设置: ```bash NCCL_P2P_DISABLE=1 ``` 该配置后,两卡隔离测试通过: ```bash make fsdp2-smoke ``` 该命令输出 `FSDP2_SMOKE_PASSED`;随后传统FSDP1两卡完整GRPO也完成4/4 rollout、backward、optimizer step、权重同步和global step 1,峰值分配/预留约38.29/39.91GiB。因此无需为了通信故障把完整训练迁移到FSDP2。注意 `NCCL_P2P_DISABLE=1` 仅用于已复现Direct P2P死锁的机器。 现阶段质量诊断使用 `TRAIN_TASK_IDS` 精确选择train任务,`TRAIN_SMOKE_GROUP_SIZE`、`TRAIN_SMOKE_PARALLEL_TASKS`、`TRAIN_SMOKE_AGENT_STEP_LIMIT` 和 `TRAIN_SMOKE_SESSION_TIMEOUT_SEC` 缩短A/B;每次smoke自动创建带UTC run ID的独立experiment/checkpoint/episode目录。rank 32在默认 `dummy_dtensor` 路径产生2048-token乱码,改用 `TRAIN_ROLLOUT_LOAD_FORMAT=safetensors` 后已恢复合法动作。正式训练前必须得到非零学习信号,并验证实际LoRA更新后的再次同步。 ## 11. 五卡分离PPO环境(已完成40步验收) PPO已在AutoDL完成4卡trainer加1卡独立vLLM的40K训练验收。本节固定与现有AutoDL/GRPO不同的资源门槛;公共的模型路径、Gateway、BuildKit和ACK配置继续复用前文。 - actor/critic trainer使用单机4×80GB FSDP,rollout使用另1×80GB运行唯一TP=1 vLLM;五张卡必须同时空闲。 - 已验证训练边界为40K、900秒、并发8。历史6卡colocated尝试会随world size复制vLLM,不能用作分离拓扑替代品。 - 启动前停止独立Canary `vllm serve`,并确认没有其他Ray、训练、Canary或Oracle作业占用GPU/ACK。 - critic使用独立value head、optimizer和BF16 model-only checkpoint;actor只保存LoRA adapter,参数和optimizer offload按已验证配置启用,reference KL关闭。 - PPO入口继续复用现有preflight,不新增PPO专用目标;训练模式只跳过必须已停止的独立Canary vLLM存活探测,其余Python、Kubernetes、RBAC、Registry和BuildKit门禁保持启用。两卡`make fsdp2-smoke`的历史结果不能替代四卡门禁。 - 末步已验证actor adapter约177.5MiB、critic约14.11GiB;每次新运行仍须检查系统内存、磁盘、每rank显存和checkpoint体积。 PPO特有参数、验收和故障记录见[`PPO_TRAINING_RUNBOOK.md`](PPO_TRAINING_RUNBOOK.md)。