Prhub

#51666 [CI][AMD] Persist the openai-harmony tiktoken vocab cache across jobs

原始 PR 作者 stefankoncarevic 合并时间 2026-08-11 14:11 文件变更 2 提交数 6 评论 13 代码增减 +44 / -5

执行摘要

AMD CI 持久化 harmony vocab 缓存并放宽文件模式校验

PR body 记录了故障实例:amd-ci #11876 中 mi355_1: Entrypoints Integration (API Server OpenAI - Part 2) 上 8 个 TestGPTOSSChat 用例 4 个失败,报 openai_harmony.HarmonyError: error downloading or loading vocab file。openai-harmony 不内置 tiktoken vocab,首次使用时下载并缓存在 $TMPDIR/tiktoken-rs-cache,而 AMD 原生 CI 的 TMPDIR 是 job 级路径,导致每个 job 都在请求时从 openaipublic.blob.core.windows.net 重新下载且无重试,任何网络抖动都会变成测试中途的 500。作者强调这不是某个 PR 引入的回归,惰性下载自 #22340 就存在,只是切换原生执行后才让缓存成为可能。ci-bake-rocm.sh 的改动动机来自共享 AMD workspace 的文件可执行位漂移导致 CI Docker context 校验误报。

值得快速阅读。重点看两个设计:一是用 TIKTOKEN_RS_CACHE_DIR 把第三方运行时缓存重定向到持久卷、并让容器内外路径保持一致的写法;二是 core.fileMode=false + git diff 退出码分段,区分内容差异与 git 执行失败,避免共享工作区文件模式漂移误杀 CI。对维护 AMD/ROCm CI 的同学尤其有价值。

讨论亮点

本 PR 没有实质性的代码讨论线程。claude[bot] 因 PR 来自 fork 而跳过自动 review(原话:"This pull request is from a fork — automated review is disabled."),维护者 AndreasKaratzas 直接批准("LGTM")。技术判断集中在 PR body:作者明确指出故障根因是 job 级 TMPDIR 使 tiktoken vocab 缓存每次作废、请求时无重试下载,并提出"只有第一个 job 下载 3.6 MB,之后全部读磁盘"的收益;对缓存 key 随 URL 变化自动失效的设计也做了说明,无需手工清理。issue 评论中的 13 条消息全部是 /ci run 触发记录。

实现拆解

  1. 重定向缓存根目录.buildkite/scripts/hardware_ci/run-amd-test.shinitialize_native_environment()):新增 TIKTOKEN_RS_CACHE_DIR="${HF_HOME}/tiktoken-rs-cache",并纳入 exportmkdir -p 预创建清单。HF_HOME 由脚本保证指向持久卷,这样缓存生命周期从单 job 变为跨 job。
  2. 容器内外路径一致:在 CONTAINER_PREFLIGHTmkdir -p 中加入 $TIKTOKEN_RS_CACHE_DIR,并在 docker run 参数中注入 -e "TIKTOKEN_RS_CACHE_DIR=${HF_MOUNT}/tiktoken-rs-cache",确保容器内 openai-harmony 进程与宿主机共用同一持久缓存。由于缓存文件名由下载 URL 派生(正文给出哈希 fb374d...),vocab 版本更新会自动换 key,无需手动清理。
  3. 修复 ROCm 构建上下文校验.buildkite/scripts/ci-bake-rocm.shvalidate_ci_build_context_source()):将 git diff 改为 git -c core.fileMode=false diff,只忽略共享工作区可执行位漂移,仍在有真实内容变化时拒绝构建上下文;同时用 worktree_diff_status / staged_diff_status 分段处理退出码,>1 视为 git 执行失败并输出错误,1 时打印前 50 条差异供排障。
  4. 验证与测试配套:未新增自动化测试文件,按 Test Plan 做了 bash -n 语法检查、确认缓存位置跟随 TMPDIR、以及打印缓存文件哈希验证版本换 key 三项目手动验证。
文件 模块 状态 重要度
.buildkite/scripts/hardware_ci/run-amd-test.sh 硬件 CI modified 3.9
.buildkite/scripts/ci-bake-rocm.sh 构建脚本 modified 4.03

关键符号

initialize_native_environment validate_ci_build_context_source

关键源码片段

.buildkite/scripts/hardware_ci/run-amd-test.sh infrastructure

核心改动文件:通过 TIKTOKEN_RS_CACHE_DIR 将 openai-harmony 的 tiktoken vocab 缓存从 job 级 TMPDIR 重定向到持久卷 HF_HOME,并在容器 preflight 与 docker run 环境变量中透传,直接修复每 job 重复下载导致的 500 失败。

# 把 openai-harmony 的 tiktoken vocab 缓存指到持久卷 HF_HOME
# 默认行为是缓存在 $TMPDIR 下,而 AMD CI 的 $TMPDIR 是 job 级的
# 因此每个 job 都要在请求时重新下载 vocab 并可能中途失败
TIKTOKEN_RS_CACHE_DIR="${HF_HOME}/tiktoken-rs-cache"
: "${HF_HUB_DOWNLOAD_TIMEOUT:=300}"
: "${HF_HUB_ETAG_TIMEOUT:=60}"
# 导出全部缓存路径相关环境变量,确保子进程和容器前检都可见
export TMPDIR VLLM_RPC_BASE_PATH
export TORCHINDUCTOR_CACHE_DIR TRITON_CACHE_DIR VLLM_CACHE_ROOT XDG_CACHE_HOME
export HF_HOME HF_DATASETS_CACHE HF_HUB_DOWNLOAD_TIMEOUT HF_HUB_ETAG_TIMEOUT
export TIKTOKEN_RS_CACHE_DIR
# 预创建所有缓存目录,任一步失败即中止环境初始化
mkdir -p "${TMPDIR}" \
    "${TORCHINDUCTOR_CACHE_DIR}" \
    "${TRITON_CACHE_DIR}" \
    "${VLLM_CACHE_ROOT}" \
    "${XDG_CACHE_HOME}" \
    "${HF_HOME}" \
    "${TIKTOKEN_RS_CACHE_DIR}" \
    "${HF_DATASETS_CACHE}" || return 1
.buildkite/scripts/ci-bake-rocm.sh core-logic

第三个提交加入的修复:validate_ci_build_context_source() 用 core.fileMode=false 忽略共享工作区可执行位漂移,并分段处理 git diff 退出码,避免 ROCm CI Docker context 校验误报,与 PR 的 CI 稳定性主题一致。

# 共享 AMD 工作区可能呈现可执行位漂移
# 上下文模式来自 pinned Git 树,因此只忽略文件系统模式变化
# 继续拒绝任何真实内容变化
if ! git -C "${source_root}" -c core.fileMode=false diff \
        --quiet --no-ext-diff --ignore-submodules=none --; then
    # git diff 退出码 1 表示有差异,>1 表示 git 本身执行失败
    git -C "${source_root}" -c core.fileMode=false diff \
        --quiet --no-ext-diff --ignore-submodules=none -- \
        || worktree_diff_status=$?
    if (( worktree_diff_status > 1 )); then
        printf 'Failed to inspect tracked CI worktree changes (git diff exited %s)\n' \
            "${worktree_diff_status}" >&2
        return 1
    fi
    echo "Tracked worktree changes cannot be omitted from the CI Docker context" >&2
    # 打印前 50 条差异,便于定位问题
    git -C "${source_root}" -c core.fileMode=false diff \
        --no-ext-diff --ignore-submodules=none --name-status -- \
        | sed -n '1,50p' >&2 || true
    git -C "${source_root}" -c core.fileMode=false diff \
        --no-ext-diff --ignore-submodules=none --summary -- \
        | sed -n '1,50p' >&2 || true
    return 1
fi

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

  • 缓存路径一致性:run-amd-test.sh 容器注入用 ${HF_MOUNT}/tiktoken-rs-cache,宿主机初始化用 ${HF_HOME}/...,若未来 HF_MOUNTHF_HOME 映射错位,容器内会写错位置或重复下载;当前脚本两者对应同一持久卷。
  • 并发首写竞态:多个 job 首次同时下载同一 vocab 文件到同一目录,若 openai-harmony 非原子写入可能产生半文件;属于低概率低影响。
  • 文件模式校验放宽:ci-bake-rocm.sh 中 core.fileMode=false 会同时忽略真实的可执行位变更(例如新增脚本忘记 chmod +x),可能在 CI 构建上下文校验时漏检此类问题。
  • 无自动化测试:改动全部在 CI 脚本,依赖手动验证;git diff 退出码分段逻辑(>1 视为失败)依赖 git 语义,未来 git 行为变化可能影响判定。
  • 首次 job 仍依赖网络:缓存只在第一次 job 下载,若首次下载时网络故障,该 job 仍可能重演 500;但影响面从所有 job 缩小为单个 job。

影响范围限定在 AMD/ROCm 硬件 CI(Buildkite amd-ci),尤其 gpt-oss entrypoints 测试(TestGPTOSSChat 8 例中 4 例曾失败)。改动后:后续 job 不再从 openaipublic.blob.core.windows.net 下载 vocab,3.6 MB 只被首次 job 拉取一次;消除了请求时下载 + 无重试带来的中途 500,显著降低测试 flake;ci-bake-rocm.sh 的校验放宽影响所有走 ROCm Docker 上下文构建的 job,能容忍共享工作区的模式伪差异;对用户服务与 vLLM 运行时零影响,纯 CI 基础设施变更。

CI 脚本变更 缺少自动化测试 依赖环境变量约定 并发缓存首次写入

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论