harbor-qwen-grpo-experiment / docs /AUTODL_SETUP.md
keryszhan's picture
发布Harbor代码智能体强化学习实验报告
ec5809e verified
|
Raw History Blame Contribute Delete
51.8 kB

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集群。

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 项目根目录执行:

make mac-preflight
make prepare-sources
make package-autodl

生成:

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

在上传文件所在目录执行:

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 当前目录中的压缩包。

预期校验结果:

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

先查看当前环境:

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 中实际可用的环境名:

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 验证的环境后再继续。

在激活环境后安装项目依赖:

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

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

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 不报告依赖冲突。

验证项目导入:

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

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

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

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

这组结果说明 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 尚未创建时,不能执行或不要求通过:

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正常,然后构建并推送固定运行镜像:

make buildkit-status
make agent-runtime-build

.env必须包含:

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 可能连接后长期无响应,必须启用:

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 各自执行:

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白名单, 至少保留以下来源:

100.104.0.0/16       # ACK管控网段
10.20.0.0/16         # 本项目VPC网段
<Mac出口IPv4>/32  51.195.241.248
<AutoDL出口IPv4>/32. 36.140.113.200

Mac和AutoDL可分别执行以下命令获取当前出口IPv4:

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保存为:

/Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml

设置权限并验证:

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,可幂等执行:

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:

KUBECONFIG_PATH=/Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml
KUBE_CONTEXT=<该文件的current-context>

实际context可用以下命令取得:

kubectl --kubeconfig /Users/keryszhang/.kube/harbor-qwen-grpo/ack-admin-public.yaml \
  config current-context

7.5 AutoDL运行KubeConfig--done

将harbor-runner的公网KubeConfig保存为:

/root/ack-public-kubeconfig.yaml

设置权限、确认公网端点并验收命名空间权限:

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采用命名空间级最小权限,以下结果正常:

kubectl cluster-info   -> 可能因不能列出kube-system Service而返回Forbidden
kubectl get nodes      -> 因不能读取集群级Node而返回Forbidden
kubectl get namespace  -> 因不能读取集群级Namespace而返回Forbidden

不要为了消除这些提示而扩大权限。AutoDL的.env只保存文件路径和实际context:

KUBECONFIG_PATH=/root/ack-public-kubeconfig.yaml
KUBE_CONTEXT=<该文件的current-context>

7.6 项目网络验收--done

先在Mac完成make ack-prepare,使两个namespace内的镜像拉取Secret存在;然后把更新后的 项目脚本同步到AutoDL并执行:

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必须显式配置:

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。

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重建:

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生成两套。同时保持:

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后,断开连接它仍会继续运行。)

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。另一个终端验证:

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导出链路:

make buildkit-smoke

该命令使用临时目录生成一个不访问网络的scratch镜像,经AutoDL本机mTLS tunnel交给ACK BuildKit构建,再把OCI归档流回AutoDL并验证index.json。无论成功或失败,临时上下文和输出 都会删除;它不会推送镜像,也不会修改现有PVC内容之外的正常BuildKit缓存。

成功标志:

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. 确认“自定义服务”中:
  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:

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/<id>/v1。
  • RLLM_GATEWAY_PORT:rLLM Gateway在AutoDL容器内部监听的端口,不是公网映射端口号。
  • 必须验证 Authorization、/v1/models、流式响应及30/60/120分钟长连接。实例重启后重新确认公网地址。Canary 成功但长连接不稳定时,应使用带固定 EIP 的阿里云 ECS HTTPS 中继。

8.6 从 ACK 反向验证 Gateway--done

在AutoDL执行:

make network-smoke

它实际执行的路径是:

AutoDL上的kubectl
→ 请求ACK API创建临时Pod
→ ACK临时Pod从ACR拉取infra-curl镜像
→ ACK临时Pod请求AutoDL公网Gateway
→ 验证/models
→ 删除临时Pod

预期输出:

ACK Pod can reach the GPU model gateway.

8.7 全量预检--done

保持 buildkit-tunnel 在 tmux 中运行,然后执行:

make preflight

预期输出:

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 执行:

    make ack-prepare
    
  3. Mac 执行:

    make buildkit-up
    
  4. AutoDL 更新自己的 .env、放置 KubeConfig 和 BuildKit客户端证书。

  5. AutoDL 执行:

    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。执行:

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 能识别的 <tool_call> 结构。

Qwen Code 必须使用自动模式,让模型自主决定何时调用工具、何时结束。因此,强制 required 虽能通过测试,却不能支撑真实的长程代码任务。当前基模不适合直接进入10条任务测试和GRPO训练。

项目现已把默认 harness 切换为 mini-swe-agent 文本动作模式,绕开原生 function calling。将以下配置补充到 AutoDL .env:

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,会超过模型上限:

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。

重新上传源码包后依次执行:

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;
  • 资源峰值、单任务时长和费用可接受。

通过后:

make train

10. 2026-08-11当前AutoDL交接状态

CVM侧已经完成:

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配置:

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 设置:

NCCL_P2P_DISABLE=1

该配置后,两卡隔离测试通过:

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。