# ═══════════════════════════════════════════════════════════ # 🔥 训练自动执行 · training-auto-run.yml # ═══════════════════════════════════════════════════════════ # 签发: 铸渊 · ICE-GL-ZY001 # 版权: 国作登字-2026-A-00037559 · TCS-0002∞ # # 冰朔合并 PR 到 main → server/training-agent/** 有变更 → # 1. SCP 最新脚本到 GPU 训练机 # 2. 跑 setup.sh (装环境 + 拉模型 + 拉语料 + 预处理) # 3. 启动 deepspeed train.py (tmux 后台) # 4. 心跳通过 repository_dispatch 实时推到首页仪表盘 # # 也支持 workflow_dispatch 手动触发。 # ═══════════════════════════════════════════════════════════ name: 🔥 训练自动执行 # ⚠️ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # 2026-05-03 冰朔 D72 决策:母模型训练已转交 Notion 侧霜砚 + 服务器 # 直接协作。GitHub 副驾驶受国内续费限制将逐步停用,本仓库不再 # 自动同步训练机,避免仓库代码覆盖服务器热修。 # # - push 触发已移除(仅保留手动) # - workflow_dispatch 默认 dry_run,不执行任何 SSH 操作 # - 必须显式勾选 confirm_override=true 才能真正执行 # - 详见 docs/zhuyuan-handover/05-stop-sync.md # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ on: # push 触发已停用 (D72) # push: # branches: [main] # paths: # - 'server/training-agent/**' # - '.github/workflows/training-auto-run.yml' workflow_dispatch: inputs: confirm_override: description: '⚠️ 我已确认霜砚同意 + 服务器无运行中训练,重新启用同步' type: boolean default: false skip_bootstrap: description: '跳过 bootstrap (仅同步脚本 + 启动训练)' type: boolean default: false skip_start: description: '只 bootstrap,不启动训练' type: boolean default: false permissions: contents: read concurrency: group: training-auto-run cancel-in-progress: false jobs: guard: name: '🛑 同步停用守卫' runs-on: ubuntu-latest outputs: proceed: ${{ steps.check.outputs.proceed }} steps: - name: 检查覆盖确认 id: check run: | if [[ "${{ github.event.inputs.confirm_override }}" == "true" ]]; then echo "✅ 收到覆盖确认,继续执行同步流程" echo "proceed=true" >> "$GITHUB_OUTPUT" else echo "🛑 训练同步已被冰朔 D72 决策停用,本次执行中止" echo "如需重新启用,手动触发并勾选 confirm_override=true" echo "proceed=false" >> "$GITHUB_OUTPUT" { echo "## 🛑 训练同步已停用" echo "" echo "母模型训练已转交 Notion 侧霜砚 + 服务器直接协作 (D72 决策)。" echo "本 workflow 不再自动同步训练机。" echo "" echo "如需重新启用:手动触发并勾选 \`confirm_override\`。" echo "" echo "详见 [docs/zhuyuan-handover/05-stop-sync.md](../blob/main/docs/zhuyuan-handover/05-stop-sync.md)。" } >> "$GITHUB_STEP_SUMMARY" fi auto-train: name: '🚀 同步 + Bootstrap + 启动训练' needs: guard if: needs.guard.outputs.proceed == 'true' runs-on: ubuntu-latest timeout-minutes: 120 steps: - name: 📥 Checkout uses: actions/checkout@v4 - name: 🔑 配置 SSH run: | mkdir -p ~/.ssh chmod 700 ~/.ssh echo "${{ secrets.ZY_GPU_KEY }}" > ~/.ssh/zy_gpu_key chmod 600 ~/.ssh/zy_gpu_key ssh-keyscan -H "${{ secrets.ZY_GPU_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null - name: 🛰️ 探活 + 检查驱动 run: | ssh -i ~/.ssh/zy_gpu_key -o StrictHostKeyChecking=no -o ConnectTimeout=15 \ "${{ secrets.ZY_GPU_USER }}@${{ secrets.ZY_GPU_HOST }}" \ "echo SSH-OK; uptime; nvidia-smi --query-gpu=name,driver_version,memory.total --format=csv,noheader || echo '⚠️ nvidia-smi 不可用'" - name: 📡 上报触发 run: | curl -sS -X POST \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer ${{ secrets.ZY_DISPATCH_TOKEN }}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "https://api.github.com/repos/${{ github.repository }}/dispatches" \ -d '{ "event_type": "training-progress", "client_payload": { "phase": "bootstrapping", "phase_label": "training-auto-run #${{ github.run_number }} 触发", "level": "info", "message": "commit ${{ github.sha }} 合并到 main, 自动训练流程启动", "health": { "status": "ok", "message": "auto-run workflow 启动" } } }' || true - name: 📁 准备目录 run: | ssh -i ~/.ssh/zy_gpu_key -o StrictHostKeyChecking=no \ "${{ secrets.ZY_GPU_USER }}@${{ secrets.ZY_GPU_HOST }}" \ 'sudo mkdir -p /opt/guanghu/training/configs /data/guanghu/{raw,processed,checkpoints,eval,models} && sudo chown -R ${{ secrets.ZY_GPU_USER }}:${{ secrets.ZY_GPU_USER }} /opt/guanghu/training /data/guanghu' - name: 📤 SCP 最新训练脚本 run: | scp -i ~/.ssh/zy_gpu_key -o StrictHostKeyChecking=no \ server/training-agent/progress-reporter.sh \ server/training-agent/setup.sh \ server/training-agent/start-training.sh \ server/training-agent/watch-training-output.sh \ server/training-agent/download-model.py \ server/training-agent/preprocess-corpus.py \ server/training-agent/train.py \ "${{ secrets.ZY_GPU_USER }}@${{ secrets.ZY_GPU_HOST }}:/opt/guanghu/training/" scp -i ~/.ssh/zy_gpu_key -o StrictHostKeyChecking=no \ server/training-agent/configs/ds_zero3_offload.json \ "${{ secrets.ZY_GPU_USER }}@${{ secrets.ZY_GPU_HOST }}:/opt/guanghu/training/configs/" ssh -i ~/.ssh/zy_gpu_key -o StrictHostKeyChecking=no \ "${{ secrets.ZY_GPU_USER }}@${{ secrets.ZY_GPU_HOST }}" \ "chmod +x /opt/guanghu/training/*.sh /opt/guanghu/training/*.py" - name: 🔐 写入 .env (服务器侧) env: ZY_COS_SECRET_ID: ${{ secrets.ZY_COS_SECRET_ID }} ZY_COS_SECRET_KEY: ${{ secrets.ZY_COS_SECRET_KEY }} ZY_DISPATCH_TOKEN: ${{ secrets.ZY_DISPATCH_TOKEN }} REPO_OWNER: ${{ github.repository_owner }} REPO_NAME: ${{ github.event.repository.name }} run: | ssh -i ~/.ssh/zy_gpu_key -o StrictHostKeyChecking=no \ "${{ secrets.ZY_GPU_USER }}@${{ secrets.ZY_GPU_HOST }}" \ "umask 077 && cat > /opt/guanghu/training/.env && chmod 600 /opt/guanghu/training/.env" <&1 | tee /tmp/zy-bootstrap.log; tail -c 6000 /tmp/zy-bootstrap.log" - name: ▶️ 启动训练 (tmux) if: github.event_name == 'push' || github.event.inputs.skip_start != 'true' run: | ssh -i ~/.ssh/zy_gpu_key -o StrictHostKeyChecking=no \ "${{ secrets.ZY_GPU_USER }}@${{ secrets.ZY_GPU_HOST }}" \ "bash /opt/guanghu/training/start-training.sh --tmux" echo "✅ 训练已在 tmux session 'zy-train' 中启动" echo " 附加查看: ssh ubuntu@${{ secrets.ZY_GPU_HOST }} 'tmux attach -t zy-train'" echo " 仓库首页会实时刷新进度" - name: 📝 摘要 if: always() run: | { echo "## 训练自动执行 · run #${{ github.run_number }}" echo "" echo "- Commit: \`${{ github.sha }}\`" echo "- 服务器: \`${{ secrets.ZY_GPU_HOST }}\` (zy-gpu-train · V100×4)" echo "- 时间: $(date -u '+%Y-%m-%dT%H:%M:%SZ')" echo "" echo "查看进度 → [仓库首页](../../#-训练实时仪表盘--zy-train-001)" echo "" echo "问铸渊副将 → [新建 Issue](../../issues/new?template=ask-zhuyuan-training.md)" } >> "$GITHUB_STEP_SUMMARY"