欢迎咨询GPU算力租赁服务,新客户首月享85折优惠!
18155129905 |周一至周五 9:00-18:00
在线咨询 商务合作

bash 修复部分问题

1.诊断:

#!/usr/bin/env bash
# ============================================================================
# collect-diag.sh — H100 现场一键离线诊断采集(全程只读,不改任何东西)
#
# 用途:部署失败时,把定位根因所需的全部信息一次性采全,写成一个 txt 带回。
#
# 用法(在目标机上,插好 U 盘后):
#     sudo bash /mnt/usb/collect-diag.sh
#   报告会自动写到【脚本所在目录】下的 diag-report-时间.txt,
#   也就是直接落到 U 盘里,拔下来带回发给工程师即可。
#
# 安全性:全程只跑 nvidia-smi / lspci / dmesg / docker inspect|logs / cat 这类
#   查看命令,绝不 up / down / restart / 删改任何文件或服务。可放心多跑几次。
#
# 若运行时报 “$'\r': command not found” 或 “bad interpreter”,是 Windows 换行符,
#   先执行: sed -i 's/\r$//' /mnt/usb/collect-diag.sh   再重新跑。
# ============================================================================

# 故意不用 set -e:要的就是“某条命令失败也继续,尽量多采集”。

SELF_DIR="$(cd "$(dirname "$0")" 2>/dev/null && pwd || echo /tmp)"
TS="$(date +%Y%m%d-%H%M 2>/dev/null || echo manual)"
OUT="${1:-$SELF_DIR/diag-report-$TS.txt}"

# 若脚本所在目录不可写(U 盘只读挂载等),退回 /tmp
if ! ( : > "$OUT" ) 2>/dev/null; then
  OUT="/tmp/diag-report-$TS.txt"
  : > "$OUT" 2>/dev/null
fi

STACK_HOME="${STACK_HOME:-/opt/llm-stack}"
COMPOSE_DIR="${COMPOSE_DIR:-$STACK_HOME/compose}"
HEALTH_DIR="${HEALTH_DIR:-/data/runtime/health}"

sec() {
  {
    echo ""
    echo "=================================================================="
    echo "### $*"
    echo "=================================================================="
  } | tee -a "$OUT"
}

run() {  # run "一条完整命令(可含管道)"
  {
    echo ""
    echo "----- \$ $* -----"
  } >> "$OUT"
  eval "$*" >> "$OUT" 2>&1 || echo "[命令返回非0或不存在,已跳过]" >> "$OUT"
}

echo "诊断报告将写入: $OUT"
echo "采集中,请稍候(约 20-40 秒)..."

sec "0. 基本信息"
run "date"
run "hostname"
run "uptime"
run "uname -a"
run "head -3 /etc/os-release"

sec "1. NVIDIA 驱动版本"
run "nvidia-smi --query-gpu=driver_version --format=csv,noheader | head -1"
run "cat /proc/driver/nvidia/version"

sec "2. ★GPU 同构性总表(最关键:8 张卡的 name/显存/算力/device_id 是否完全一致)"
run "nvidia-smi --query-gpu=index,name,memory.total,memory.used,pstate,power.draw --format=csv"
run "nvidia-smi --query-gpu=index,name,compute_cap,vbios_version,serial,pci.bus_id,pci.device_id --format=csv"

sec "3. nvidia-smi -q 全量(含每卡 Product Name / Product Architecture / Board Part Number / Serial)"
run "nvidia-smi -q"

sec "4. PCI 层面看这 8 张卡([10de:xxxx] device-id 不一致即为不同 SKU;并看 PCIe 链路速率/宽度)"
run "lspci -nn | grep -i -E 'nvidia|3d controller'"
for b in $(lspci -nn 2>/dev/null | grep -i -E 'nvidia' | grep -i -E '3d|vga' | awk '{print $1}'); do
  {
    echo ""
    echo ">>> PCI $b <<<"
    lspci -vvv -s "$b" 2>/dev/null | grep -i -E 'controller|LnkCap:|LnkSta:|ACSCtl'
  } >> "$OUT" 2>&1
done

sec "5. GPU 互联拓扑(本次无 NVLink/纯 PCIe,看 P2P 路径)"
run "nvidia-smi topo -m"

sec "6. dmesg 中的 NVRM / Xid 报错(硬件或驱动层错误,最能暴露坏卡/掉卡)"
run "dmesg -T 2>/dev/null | grep -i -E 'nvrm|xid|nvidia' | tail -150"

sec "7. 所有容器状态"
run "docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'"

sec "8. ★实际部署参数 .env(看真实 DS_UTIL / 策略 / maxlen / 各小模型 util)"
run "cat '$COMPOSE_DIR/.env'"

sec "9. ★DeepSeek 容器实际启动命令 + 退出状态(ExitCode/OOMKilled/Error)"
run "docker inspect vllm-public-llm --format '镜像: {{.Config.Image}}'"
run "docker inspect vllm-public-llm --format '启动命令: {{json .Config.Cmd}}'"
run "docker inspect vllm-public-llm --format '退出码={{.State.ExitCode}} OOMKilled={{.State.OOMKilled}} Error={{.State.Error}} 重启次数={{.RestartCount}}'"
run "docker inspect vllm-public-llm --format '环境变量:{{println}}{{range .Config.Env}}{{println .}}{{end}}'"

sec "10. ★★DeepSeek 完整根因日志(真正的 AssertionError 所在,即 'see root cause above' 的 above)"
if [ -f "$HEALTH_DIR/vllm-public-llm.log" ]; then
  run "tail -n 400 '$HEALTH_DIR/vllm-public-llm.log'"
fi
run "docker logs vllm-public-llm --tail 400 2>&1"

sec "11. 其它未恢复服务日志尾部(连锁排查用)"
for c in litellm-public litellm-gc litellm-smt vllm-gc-embed vllm-gc-rerank vllm-smt-embed vllm-smt-rerank vllm-smt-llm nginx-gateway; do
  {
    echo ""
    echo ">>> $c <<<"
    docker logs "$c" --tail 40 2>&1 || echo "[无此容器或无日志]"
  } >> "$OUT" 2>&1
done

sec "12. 共生小服务健康状态一览"
run "docker ps -a --format '{{.Names}}\t{{.Status}}' | grep -E 'embed|rerank|ocr|smt-llm|public-llm'"

sec "13. systemd 栈服务"
run "systemctl status llm-stack.service --no-pager -l 2>/dev/null | head -30"

sec "14. /data 挂载与磁盘占用(确认数据盘在位、未写满)"
run "df -h /"
run "df -h /data"
run "mountpoint /data"
run "findmnt /data"

sec "15. conda 环境(mlops 是否创建成功)"
run "ls -1 /opt/miniconda3/envs 2>/dev/null"

{
  echo ""
  echo "=================================================================="
  echo "采集完成 → $OUT"
  echo "把这个 txt 拷回来发给工程师即可。"
  echo "=================================================================="
} | tee -a "$OUT"

2.预留空间stop-models-for-235b.sh:

#!/usr/bin/env bash
# ============================================================================
# stop-models-for-235b.sh — 停掉全部 8 个 vLLM 模型容器,腾空所有 GPU 给 235B 测试
#   - 只停吃显存的 vLLM 容器;nginx / litellm / 监控 / webui / 控制台 保持运行(不吃显存)。
#   - 用 docker stop(可逆):之后 docker start <名字> 即可逐个起回来,再自行编排落卡。
#   - 诊断自愈按安全策略【不会】自动重建 vLLM,停了就是停了,放心。
#
# 用法: sudo bash stop-models-for-235b.sh
# ============================================================================
set -uo pipefail

VLLM="vllm-public-llm vllm-gc-embed vllm-gc-rerank vllm-gc-ocr vllm-smt-llm vllm-smt-embed vllm-smt-rerank vllm-smt-ocr"

echo "===== 停止全部 vLLM 模型容器 ====="
for c in $VLLM; do
  if docker ps --format '{{.Names}}' | grep -qx "$c"; then
    docker stop "$c" >/dev/null 2>&1 && echo "  已停 $c" || echo "  停止失败 $c"
  else
    echo "  跳过(本就未运行) $c"
  fi
done

echo "===== 等 8 秒让显存释放 ====="
sleep 8

echo "===== 各卡显存占用(应都接近 0 MiB)====="
nvidia-smi --query-gpu=index,name,memory.used,memory.total --format=csv

echo ""
echo "GPU 已腾空。下一步建议:"
echo "  1) 测 235B(4 张好卡 TP=4):"
echo "       sudo bash set-235b-tp4.sh \"0,1,3,5\"      # 换成你确认的 4 张好卡"
echo "       docker logs -f vllm-public-llm            # 看是否 Application startup complete"
echo ""
echo "  2) 235B 起好后,按需逐个起回小模型(落到你想要的卡上再编排):"
echo "       docker start vllm-gc-embed                # 其余同理"
echo "       可选: vllm-gc-embed vllm-gc-rerank vllm-gc-ocr vllm-smt-llm vllm-smt-embed vllm-smt-rerank vllm-smt-ocr"
echo ""
echo "  3) 调整某个小模型落哪几张卡 / util:"
echo "       sudo /opt/llm-stack/runtime/place-gpus.sh        # 搬家(落卡)"
echo "       sudo /opt/llm-stack/runtime/tune-util.sh show    # 看/调显存占比"
echo "       或用控制台⑥(GPU 编排)。"
echo ""
echo "注:此时网关对未启动的服务会返回 502,属测试期正常现象。"
echo "全部恢复:把上面 8 个 docker start 起一遍即可;或重启机器由开机自启拉起。"

3。设置模型占卡set-235b-tp4.sh:

#!/usr/bin/env bash
# ============================================================================
# set-235b-tp4.sh — 把公用方 235B 从 TP=8 改成 TP=4,落到 4 张好卡
#   为什么 TP=4:你这个是 FP8 块量化(块=128)版,1536÷8=192 不整除 → TP=8 数学上
#   不可行;1536÷4=384÷128=3 整除 → TP=4 可行。
#   注意:TP=4 时每卡权重≈55G(TP=8 的两倍),util 必须够大,默认 0.85。
#   ⚠ 请尽量选 4 张【好卡且其上没有大占用】的卡;若 OOM,降低 util 或换卡。
#
# 用法(机器上):
#   sudo bash set-235b-tp4.sh "0,1,3,5"        # 引号内填 4 张好卡(0-7)
#   sudo bash set-235b-tp4.sh "0,1,3,5" 0.80   # 第二个参数自定 util(OOM 时调小)
# ============================================================================
set -uo pipefail
CARDS="${1:-0,1,3,5}"
UTIL="${2:-0.85}"
COMPOSE=/opt/llm-stack/compose
TS=$(date +%Y%m%d-%H%M)

n=$(echo "$CARDS" | tr ',' '\n' | grep -c .)
[ "$n" = "4" ] || { echo "必须正好 4 张卡,你给的是 $n 张:$CARDS"; exit 1; }
[ -f "$COMPOSE/docker-compose.fallback-235b.yml" ] || { echo "没找到 235B 叠加层,请先 sudo /opt/llm-stack/runtime/switch-to-235b.sh 切到 235B 再跑本脚本。"; exit 1; }

cd "$COMPOSE" || exit 1
cp -n .env ".env.bak-$TS"

# 1) TP=4 + 抬高 util(TP=4 每卡权重翻倍,原 0.40 装不下)
grep -q '^Q235_TP='   .env && sed -i "s/^Q235_TP=.*/Q235_TP=4/"        .env || echo "Q235_TP=4"        >> .env
grep -q '^Q235_UTIL=' .env && sed -i "s/^Q235_UTIL=.*/Q235_UTIL=$UTIL/" .env || echo "Q235_UTIL=$UTIL" >> .env

# 2) 落卡:用一个小叠加层覆盖 NVIDIA_VISIBLE_DEVICES(不动原 overlay)
cat > docker-compose.235btp4.yml <<EOF
services:
  vllm-public-llm:
    environment:
      NVIDIA_VISIBLE_DEVICES: "$CARDS"
      CUDA_DEVICE_ORDER: "PCI_BUS_ID"
EOF

echo "[*] Q235_TP=4  Q235_UTIL=$UTIL  卡=$CARDS"
echo "[*] 重建 vllm-public-llm(三层叠加:base + fallback-235b + 235btp4)..."
docker compose -f docker-compose.yml -f docker-compose.fallback-235b.yml -f docker-compose.235btp4.yml up -d --force-recreate vllm-public-llm

echo ""
echo "[*] 235B 加载约 3-8 分钟,实时看日志:"
echo "      docker logs -f vllm-public-llm"
echo "    成功标志:出现 'Application startup complete',docker ps 里 vllm-public-llm 为 healthy。"
echo "    若日志再出现 '... not divisible by ... 128' = 卡数仍非 4,检查 NVIDIA_VISIBLE_DEVICES。"
echo "    若 OOM/显存不足 = 同卡有小模型抢显存,重跑并把 util 调小,例如:sudo bash set-235b-tp4.sh \"$CARDS\" 0.70"
echo ""
echo "回滚:cp $COMPOSE/.env.bak-$TS $COMPOSE/.env; rm $COMPOSE/docker-compose.235btp4.yml; sudo /opt/llm-stack/runtime/switch-to-235b.sh"

4.修复配置重启动make-235b-persistent.sh, 步骤: sudo bash set-235b-tp4.sh "0,1,3,5" # 1) 切 235B TP=4 落好卡(生成两个叠加层) sudo bash make-235b-persistent.sh # 2) 打补丁,让重启也带上这两个叠加层 sudo bash /opt/llm-stack/runtime/stack-up.sh # 3) 不用真重启,跑一遍验证幂等 docker ps | grep public-llm # 仍是 235B/healthy 就对了:

#!/usr/bin/env bash
# ============================================================================
# make-235b-persistent.sh — 让 235B 配置扛得住重启
#   坑:开机自启的 stack-up.sh 默认只加载 docker-compose.yml + docker-compose.placement.yml,
#       【不加载】235B 的 fallback-235b.yml,也不加载 set-235b-tp4.sh 生成的 235btp4.yml。
#       不补这一刀,重启后公用方会退回 DeepSeek、落卡也丢。
#   做法:给 stack-up.sh 打补丁——这两个叠加层"文件存在即开机自动带上",且顺序正确
#         (base -> placement -> fallback-235b -> 235btp4,最后者覆盖落卡)。幂等,可重复跑。
#
# 跑这个之前请先跑过 set-235b-tp4.sh(它会生成那两个叠加层)。
# 用法: sudo bash make-235b-persistent.sh
# ============================================================================
set -uo pipefail
SU=/opt/llm-stack/runtime/stack-up.sh
TS=$(date +%Y%m%d-%H%M)
[ -f "$SU" ] || { echo "找不到 $SU"; exit 1; }

echo "===== 打补丁前:stack-up.sh 当前加载逻辑 ====="
grep -nE 'docker-compose.*\.yml|files\+?=' "$SU" || true

cp -n "$SU" "$SU.bak-$TS"

# 先去掉可能已存在的这两行(避免重复/顺序乱),再在 placement 行后按正确顺序插入
awk '
  index($0, "docker-compose.fallback-235b.yml ]] && files+=") > 0 { next }
  index($0, "docker-compose.235btp4.yml ]] && files+=")     > 0 { next }
  { print }
  index($0, "docker-compose.placement.yml ]] && files+=") > 0 {
    print "[[ -f docker-compose.fallback-235b.yml ]] && files+=(-f docker-compose.fallback-235b.yml)"
    print "[[ -f docker-compose.235btp4.yml ]]     && files+=(-f docker-compose.235btp4.yml)"
  }
' "$SU" > "$SU.tmp" && mv "$SU.tmp" "$SU"
chmod +x "$SU"

echo ""
echo "===== 打补丁后 ====="
grep -nE 'docker-compose.*\.yml|files\+?=' "$SU" || true
echo ""

if grep -q 'fallback-235b.yml ]] && files' "$SU"; then
  echo "成功:开机/重启时会自动带上 fallback-235b + 235btp4,235B 与落卡不再丢。"
  echo "不必真重启即可幂等验证(它会按补丁后的叠加层重拉一遍):"
  echo "    sudo bash $SU"
  echo "    docker inspect vllm-public-llm --format '{{json .Config.Cmd}} NVD={{range .Config.Env}}{{println .}}{{end}}' | grep -iE 'qwen235|VISIBLE'"
else
  echo "⚠ 没找到 placement 锚点行——你机器上的 stack-up.sh 版本可能不同。"
  echo "  把 $SU 的内容发我,我给你手改。回滚: cp $SU.bak-$TS $SU"
fi

5.按需拉取: docker start vllm-gc-embed 等等,或者place-gpus.sh/tune-util.sh

6.修复litellm,fix-litellm.sh

 #!/usr/bin/env bash
# ============================================================================
# fix-litellm.sh — 修三套 litellm 离线起不来(502 的根)
#   根因:configs/litellm/{public,gc,smt}.yaml 里 enable_prometheus: true,
#   离线镜像缺 prometheus 依赖 → worker 一启动就崩、三个一起死 → 4000 没人听 →
#   nginx 连不上报 Connection refused → 凡走 litellm 的(embed/chat/ocr)全 502。
#   修法:关掉 enable_prometheus,重启三个 litellm,再刷新 nginx 上游缓存。
#
# 用法(机器上):  sudo bash fix-litellm.sh
# 若报 $'\r' 错:  sed -i 's/\r$//' fix-litellm.sh   再跑。
# ============================================================================
CFG=/opt/llm-stack/configs/litellm
TS=$(date +%Y%m%d-%H%M)
OUT=/tmp/litellm-fix-$TS.log

echo "===== 0. 留底:修复前真实报错(stderr,健康日志里没有的那段) =====" | tee "$OUT"
docker logs litellm-public --tail 150 >> "$OUT" 2>&1
echo "(已存 $OUT)"

echo "===== 1. 关闭 enable_prometheus(三套配置,改前自动备份) ====="
for f in public gc smt; do
  y="$CFG/$f.yaml"
  [ -f "$y" ] || { echo "  跳过(无 $y)"; continue; }
  cp -n "$y" "$y.bak-$TS"
  sed -i 's/enable_prometheus:[[:space:]]*true/enable_prometheus: false/I' "$y"
  printf "  %-12s -> " "$f.yaml"; grep -i enable_prometheus "$y" || echo "(本无此项)"
done

echo "===== 2. 重启三个 litellm(重读配置) ====="
docker restart litellm-public litellm-gc litellm-smt
echo "   等 25 秒让它们起来..."
sleep 25

echo "===== 3. 刷新 nginx 上游 IP 缓存(消除 502) ====="
docker restart nginx-gateway
sleep 6

echo "===== 4. 验证 ====="
docker ps --format '{{.Names}}\t{{.Status}}' | grep -E 'litellm|nginx' | tee -a "$OUT"
echo "--- 经 8080 网关(200=通) ---" | tee -a "$OUT"
for p in public gc smt; do
  curl -s -o /dev/null -w "  /v1/$p/models  HTTP=%{http_code}\n" "http://localhost:8080/v1/$p/models" | tee -a "$OUT"
done

echo "===== 5. 修复后日志尾 ====="
docker logs litellm-public --tail 30 2>&1 | tee -a "$OUT"

echo ""
echo "三个 litellm 变 healthy 且 HTTP=200 即成功;网页/opencode 随即可用。"
echo "若仍失败:把 $OUT 带回来(里面有真实报错)。"
echo "回滚:cp $CFG/public.yaml.bak-$TS $CFG/public.yaml(gc/smt 同理)后 docker restart litellm-public litellm-gc litellm-smt。"

7,修复文档:fix-delivery-doc.sh

 #!/usr/bin/env bash
# ============================================================================
# fix-delivery-doc.sh — 在交付文档最前面插入"现场实测勘误",更正自动生成的错误内容
#   作用对象:/opt/llm-stack/DELIVERY.md 及其副本 /opt/llm-stack/docs/DELIVERY.md
#   做法:不去 sed 改正文(易改坏),而是在最顶部插入一段权威勘误,注明"与下文冲突
#         以本节为准"。可重复运行(带 BEGIN/END 标记,重跑会先删旧勘误再插新的)。
#
# 用法:先按你【最终跑通的状态】改下面几个变量,再:
#   sudo bash fix-delivery-doc.sh
# 若报 $'\r':sed -i 's/\r$//' fix-delivery-doc.sh 再跑。
# ============================================================================

# ===================== 按现场最终状态填写(改这里) =====================
PUBLIC_MODEL="Qwen3-235B-A22B-Thinking-2507"  # 公用方最终实际用的模型
PUBLIC_TP="4"                                  # 公用方并行度(235B-FP8 只能 4)
PUBLIC_CARDS="0,1,3,5"                          # 公用方落的 4 张好卡
BAD_CARDS="2,4"                                 # 确认有问题、不可用于大模型的卡(显示 Graphics Device)
SMT_LLM_CARDS="6,7"                             # SMT 27B 已搬到的卡
# =======================================================================

set -uo pipefail
TS=$(date +%Y%m%d-%H%M)
DOCS=(/opt/llm-stack/DELIVERY.md /opt/llm-stack/docs/DELIVERY.md)

read -r -d '' ERRATA <<EOF || true
<!-- ERRATA-BEGIN -->
# ★ 现场实测勘误(更新于 ${TS},与下文冲突处以本节为准)

> 本文件下半部分由安装脚本在**首启前**自动生成,部分内容是按设计预期写的;经现场
> 8×H100 实测,以下几处需更正。**实际交付状态以本节为准。**

## 1. 硬件勘误
- 8 张卡中 **${BAD_CARDS} 号为非标/有问题卡**:\`nvidia-smi\` 显示为 \`NVIDIA Graphics Device\`(非 H100)、功率 700W(SXM 芯片魔改 PCIe),不参与任何大模型部署。
- 本批 H100 **未配 NVLink 桥**,且为**双路服务器跨槽(topo 显示 SYS)**,卡间走 PCIe,无 NVLink。
- 已用 \`/etc/modprobe.d/disable-nvlink.conf\`(\`NVreg_NvLinkDisable=1\`)关闭 NVLink;如需恢复:删该文件 + \`update-initramfs -u\` + 重启。

## 2. 公用大模型勘误(最重要)
- 文档下文写"公用方 = DeepSeek-V4-Flash、占满 8 卡、tp8-ep"——**在本机起不到**:无 NVLink 导致专家并行(EP)的 all-to-all 失败,且 dev 镜像 torch.compile 报 InductorError。
- **实际公用方已改为:\`${PUBLIC_MODEL}\`,TP=${PUBLIC_TP},落卡 ${PUBLIC_CARDS}。**
- 若仍要用 DeepSeek:必须加 \`--enforce-eager\`(关 torch.compile)+ 改 tp4 + 落到好卡,且 **不要用 dp-ep**(仍带 EP,会同样失败)。无 NVLink 机器策略阶梯应为 **tp8-ep → tp8 → tp4**(跳过 dp-ep)。

## 3. Qwen3-235B(FP8)勘误
- 此为 **FP8 块量化(块=128)版,只能 TP=4**:1536÷8=192 不被 128 整除,**TP=8 在数学上不可行**(vLLM 直接报 \`not divisible by ... block_n = 128\`)。
- 入口脚本/文档中"TP=8 默认、别改小"的说法对**本 FP8 版无效**,请按 TP=4 使用。

## 4. SMT 对话模型(Qwen3.6-27B)勘误
- 已从问题卡搬到 **${SMT_LLM_CARDS} 号卡**,运行正常。

## 5. 监控勘误
- 三套 litellm 配置已**关闭 \`enable_prometheus\`**(离线镜像缺 prometheus 依赖会导致 litellm worker 崩溃、进而全网关 502)。
- 影响:Grafana 里 **litellm 层**的请求/延迟/token 面板无数据;**vLLM 引擎自身指标、所有推理/路由/网页/API 功能均不受影响**。联网补齐依赖后可改回 \`true\` 恢复。

## 6. 本次现场修复清单
- 关闭 litellm \`enable_prometheus\` 并重启三套 litellm + nginx → 解决全网关 502。
- 公用方改为 ${PUBLIC_MODEL} TP=${PUBLIC_TP}(避开 ${BAD_CARDS} 号坏卡)。
- SMT 27B 迁至 ${SMT_LLM_CARDS} 号卡。
<!-- ERRATA-END -->

EOF

for DOC in "${DOCS[@]}"; do
  [ -f "$DOC" ] || { echo "跳过(不存在):$DOC"; continue; }
  cp -n "$DOC" "$DOC.bak-$TS"
  # 重跑:先删旧勘误块(BEGIN..END),避免重复插入
  sed -i '/<!-- ERRATA-BEGIN -->/,/<!-- ERRATA-END -->/d' "$DOC"
  tmp=$(mktemp)
  { printf '%s\n\n' "$ERRATA"; cat "$DOC"; } > "$tmp" && mv "$tmp" "$DOC"
  echo "已更新:$DOC (原文件备份 $DOC.bak-$TS)"
done

echo ""
echo "完成。打开 /opt/llm-stack/DELIVERY.md,最顶部即为现场勘误。"
echo "如需重改:改本脚本顶部变量后再跑一次即可(会自动替换旧勘误)。"

8.可选修复端口:

   #!/usr/bin/env bash
# ============================================================================
# fix-litellm-port.sh — 排查并修复 litellm 因端口被占用起不来
#   litellm 容器内部监听 4000;宿主机映射:4001(public) / 4002(gc) / 4003(smt)。
#   端口冲突典型现象:容器 Exited、报 "port is already allocated" / "address already in use"。
#   常见原因:旧/重复容器没删干净仍占着端口;或宿主机别的进程占了。
#
# 用法:
#   sudo bash fix-litellm-port.sh          # 只诊断(安全,只读)
#   sudo bash fix-litellm-port.sh --fix    # 诊断 + 删掉重名旧 litellm 容器并重建
# ============================================================================
set -uo pipefail
FIX="${1:-}"
COMPOSE=/opt/llm-stack/compose

echo "===== 1. 宿主机谁在听 4000-4003(带进程/pid)====="
if command -v ss >/dev/null 2>&1; then
  ss -ltnp 2>/dev/null | grep -E ':400[0-3]\b' || echo "  (4000-4003 没有监听)"
else
  netstat -ltnp 2>/dev/null | grep -E ':400[0-3]\b' || echo "  (4000-4003 没有监听)"
fi

echo ""
echo "===== 2. 所有 litellm 相关容器(含已退出/重复的,看端口绑定)====="
docker ps -a --format '{{.Names}}\t{{.Status}}\t{{.Ports}}' | grep -iE 'litellm|:400[0-3]' || echo "  (无)"

echo ""
echo "===== 3. 三个 litellm 的启动错误 / 端口报错 ====="
for c in litellm-public litellm-gc litellm-smt; do
  st=$(docker inspect "$c" --format '{{.State.Status}} {{.State.Error}}' 2>/dev/null || echo "无此容器")
  echo "  $c  -> $st"
  docker logs "$c" 2>&1 | grep -iE 'address already in use|port is already allocated|bind.*fail' | tail -2 | sed 's/^/        /'
done

if [ "$FIX" != "--fix" ]; then
  cat <<EOF

只诊断完成。判断与手动修法:
  · 若上面没看到 "already allocated/in use" → 不是端口问题(很可能是 enable_prometheus,用 fix-litellm.sh)。
  · 占端口的是某个【旧 docker 容器】(第2节里多出来的): docker rm -f <那个容器名>
  · 占端口的是【宿主机进程】(第1节里有 pid=NNN):先确认不是要紧服务,再 kill NNN
  · 清完后重建三个 litellm:  sudo bash $0 --fix
EOF
  exit 0
fi

echo ""
echo "===== 4. 自动修:删掉重名 litellm 容器,按当前叠加层重建 ====="
cd "$COMPOSE" || { echo "找不到 $COMPOSE"; exit 1; }
# 235B 切换会让 litellm-public 带 fallback 叠加层,重建时要带上
files=(-f docker-compose.yml)
[ -f docker-compose.fallback-235b.yml ] && files+=(-f docker-compose.fallback-235b.yml)
echo "  用叠加层:${files[*]}"
docker rm -f litellm-public litellm-gc litellm-smt 2>/dev/null || true
docker compose "${files[@]}" --env-file .env up -d litellm-public litellm-gc litellm-smt
echo "  等 20 秒..."; sleep 20
docker restart nginx-gateway; sleep 5

echo ""
echo "===== 5. 验证 ====="
docker ps --format '{{.Names}}\t{{.Status}}' | grep -E 'litellm|nginx'
for p in public gc smt; do
  curl -s -o /dev/null -w "  /v1/$p/models HTTP=%{http_code}\n" "http://localhost:8080/v1/$p/models"
done
echo ""
echo "若第4步重建后仍报端口占用 = 占端口的不是这三个容器,而是【别的容器或宿主机进程】。"
echo "回到第1、2节找到真正占用者(看 pid / 容器名),docker rm -f 它 或 kill 它,再重跑 --fix。"

9.修复deepseek问题: sed -i '/--enable-auto-tool-choice/a\ --enforce-eager' /opt/llm-stack/configs/vllm/deepseek-launch.sh sudo /opt/llm-stack/runtime/switch-llm.sh ds tp4 docker logs -f vllm-public-llm 10.其他 手动处理litevllm问题: sed -i 's/enable_prometheus: true/enable_prometheus: false/' /opt/llm-stack/configs/litellm/{public,gc,smt}.yaml docker restart litellm-public litellm-gc litellm-smt nginx-gateway

验证(可选,第三条): curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/v1/gc/models 出 200 就成了。

想留后路就先抄一条备份(可选): cp /opt/llm-stack/configs/litellm/{public,gc,smt}.yaml /tmp/ 验证跑起来测试:

   ① 先看模型有没有注册上:
curl -s http://localhost:8080/v1/public/models
能列出 Qwen3-235B-A22B-Thinking-2507 就对了。

② 真正发一句对话测:
curl http://localhost:8080/v1/public/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"Qwen3-235B-A22B-Thinking-2507","messages":[{"role":"user","content":"你好,简单介绍下你自己"}]}'
返回 JSON 里有 content 正文就是通了(Thinking 模型会先有思考段,正常)。

③ 如果上面 502/不通,绕开网关直连容器看是模型还是网关的问题:
docker exec vllm-public-llm curl -s http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"Qwen3-235B-A22B-Thinking-2507","messages":[{"role":"user","content":"你好"}]}'
上一篇
修复llm命令
微信二维码
微信咨询
扫码添加企业微信
获取专属算力方案
微信号:HCKJ2106
电话