[HER Hack-Astron #5] Spark-X2.5-4B 审查真实 vLLM 兼容修复:定位第二断点并跑通原生工具调用

#6
by Forrest20231206 - opened

Spark-X2.5-4B 审查真实 vLLM 兼容修复:定位第二断点并跑通原生工具调用

案例直接来自公开的 Spark-plugin #8。我先冻结一个只解决首个 WeightsMapper 异常、但尚未通过完整启动路径的实验候选,再让 Spark-X2.5-4B 做三次固定协议、只读的仓库审查。

模型三次都找到未预先告知的第二断点:vLLM 0.23 缺少 find_tool_name,导致原始命令启用的 spark25 parser 在导入阶段失败。最终补丁经源码复核和确定性测试后,已在 vLLM 项目官方 0.23.0 镜像中完成官方 4B checkpoint 冷启动、普通对话和原生工具调用闭环。

一页结论

Spark-X2.5-4B 观察项 结果
第二断点定位 3/3,首次满足累计证据在第 3、6、6 轮
按 10 轮协议调用 finish 0/3
两次开放式修复尝试通过最终检查 0/2
最终工程验证 结果
vLLM 0.23.0 pytest tests/ -q 3 passed
插件记录的 vLLM 81efe… API 回归 3 passed
额外 vLLM 0.23 固定兼容检查 7/7 checks passed
官方 4B checkpoint 冷启动 5/5 分片加载,服务健康
普通对话 finish_reason=stop,返回 合肥
原生工具调用 finish_reason=tool_callsget_weather({"city":"合肥"})

3/3、0/3 和 0/2 都是当前完整记录的小样本观察值,不代表总体准确率。三次结果全部保留,没有挑选最好的一次;模型表现与人工复核后的最终工程结果分开统计。

三次正式复核未设置专门 warm-up;本案例不报告延迟或吞吐,原始记录中的逐轮耗时仅用于审计运行过程。

真实问题与实验候选

Issue #8 首先暴露:vLLM 0.23 的 WeightsMapper 不支持 orig_to_new_stacked。实验候选用旧式加载路径解决这个异常,但固定检查随即在收集阶段失败:

ERROR collecting tests/test_smoke.py
ImportError: cannot import name 'find_tool_name'
from 'vllm.tool_parsers.utils'

这个问题不是人为注入。候选没有改 parser;find_tool_name 的导入原本就在上游 base 中,它存在于插件记录的较新 vLLM commit,却不存在于 vLLM 0.23。Issue 的完整命令包含 --enable-auto-tool-choice --tool-call-parser spark25,所以这是实际启动路径上的第二个阻断点。

候选 commit 15285d4519e794933ae1e407f0564ca31c52fb2a 是为隔离首个修复而冻结的本地实验 fixture;公开复现以 candidate.diff 和 tree ae5a544cf6ecced4f4abc3433d61932e68ed7abd 为权威。

冻结复核协议

  • 模型:XHToken/Spark-X2.5-4B@1e4c2477f330d1f11304d0dc092a9dbf4075f470,BF16
  • reviewer 推理 runtime:通过 DaoCloud 镜像获取的 vLLM 0.24.0-cu129,实际 repo digest 为 docker.m.daocloud.io/vllm/vllm-openai@sha256:6b005c78…,image ID 为 sha256:1941b4cd…;它只负责托管审查模型,不是受审兼容目标
  • 受审目标:vLLM 0.23.0 commit 0fc695fc…;同时对照插件记录的 81efe788…
  • thinking=false,temperature=1,top_p=0.95,top_k=-1
  • 每次最多 10 轮、每轮最多 2048 tokens
  • 三个 base seed:20260903、20260904、20260905
  • 三个干净工作区;任务、系统提示、工具定义和 harness commit 全部冻结

代表性原始输入节选(完整任务):

Review the current candidate commit for the public Apache-2.0 repository
XHToken/Spark-plugin and issue XHToken/Spark-plugin#8.
The current candidate claims to restore compatibility. Review it as a real PR;
do not assume that getting past the first traceback proves the whole command.

三次运行都先执行同一个 vLLM 0.23 固定检查,再沿失败位置对照两个源码树。截至第 3、6、6 轮,实际 parser ImportError 与模型明确识别的版本差异共同满足定位口径。第一次运行第 3 轮的原始输出是:

The pytest run failed at collection: spark2_5_tool_parser.py cannot import find_tool_name from vllm.tool_parsers.utils in vLLM 0.23.0. This is in a file not touched by the candidate diff, so it is unrelated to the original WeightsMapper issue — but it is a blocking gap for the complete reported command/tests. Let me verify the specific compatibility gaps in the two reference trees.

不过三次都继续浏览到 turn limit,没有调用 finish。这说明它在这个案例中适合充当“发现第二断点的 reviewer”,但缺少更强终止约束时,不应独自承担合并决策。

失败结果也保留

正式三跑之前有两次开放式修复尝试:

  1. 第一次生成兼容 helper,却把转义引号写进 Python,pytest 收集时报 SyntaxError
  2. 第二次把调用点换成 _find_tool_name,但未写入对应定义,也没有运行最终检查。

因此我没有把“模型指出正确方向”包装成“模型自主修好代码”。最终工程通过不计入模型修复成功率。

最终补丁与真实运行

最终补丁不是简单删除报错参数,而是同时保证:

  • gate_proj / up_proj 分别进入 packed gate_up_proj 的 shard 0/1;
  • checkpoint 已融合的 q_k_v_proj 直接加载;
  • tied lm_head 不覆盖共享 embedding;
  • 新版继续使用原生 AutoWeightsLoader + WeightsMapper
  • 旧版 parser 使用最小 find_tool_name fallback;
  • 固定 vLLM 0.23 CI 和回归测试防止复发。

最终从干净 snapshot commit 1edcc0723893c88ee85d84278d4d5e96e82a9aa1 启动 vLLM 项目官方 0.23.0 镜像(digest sha256:6d8429e38e3747723ca07ee1b17972e09bb9c51c4032b266f24fb1cc3b22ed8f)。PR 当前提交 ddef50f6f1eda417b6716b27e0aa35d4a6cd0cf3 只增加 DCO sign-off,代码 tree 同为 51e375fbfc53347019ea5812ee5759d39ec71d74。硬件为共享服务器上的单张 NVIDIA A800-SXM4-80GB,非本次临时租用,服务器整体计费情况未知;运行限制为 gpu_memory_utilization=0.35max_model_len=131072

脱敏启动日志(完整文件):

(APIServer pid=1) INFO ... version 0.23.0
(APIServer pid=1) INFO ... Resolved architecture: Spark2_5ForCausalLM
(EngineCore pid=419) Loading safetensors checkpoint shards: 100% Completed | 5/5
(EngineCore pid=419) INFO ... Model loading took 8.28 GiB memory ...
(APIServer pid=1) INFO Application startup complete.

其中 8.28 GiB 是 vLLM 启动日志报告的模型权重加载量,不是进程峰值显存;本案例不据此给出峰值显存结论。

固定请求的原始结果字段(完整 API JSON):

{
  "plain_chat": {"finish_reason": "stop", "content": "合肥"},
  "native_tool_call": {
    "finish_reason": "tool_calls",
    "name": "get_weather",
    "arguments": {"city": "合肥"}
  }
}

最短复现

证据与指标校验:

git clone https://github.com/MittaPei/spark-x2-5-vllm-review-case.git
cd spark-x2-5-vllm-review-case
python3.12 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python scripts/verify_evidence.py
PYTHONPATH=src .venv/bin/pytest tests/ -q

在固定 vLLM 0.23 环境安装最终插件并启动服务时,关键参数如下;README 提供固定镜像 digest 的完整 Docker 命令:

python -m pip install --no-deps /path/to/vllm_spark2_5_plugin-0.1.0-py3-none-any.whl
VLLM_PLUGINS=spark2_5 SPARK2_5_PLUGIN_OVERRIDE=1 \
  vllm serve /path/to/Spark-X2.5-4B \
  --host 127.0.0.1 --port 39125 \
  --trust-remote-code --served-model-name Spark2_5 \
  --chat-template /path/to/Spark-X2.5-4B/chat_template.jinja \
  --enable-auto-tool-choice --tool-call-parser spark25 \
  --dtype bfloat16 --tensor-parallel-size 1 \
  --gpu-memory-utilization 0.35 --max-model-len 131072

.venv/bin/python scripts/verify_vllm_server.py \
  --base-url http://127.0.0.1:39125/v1 --model Spark2_5

排障要点:只删除 orig_to_new_stacked 不能证明原始命令已恢复;必须同时验证 packed 权重语义和命令实际启用的 spark25 parser。

可复现材料

边界

  • 最终运行使用 vLLM 项目官方的 NVIDIA/CUDA 0.23.0 镜像,没有复刻 Issue 报告者的加速器插件环境。
  • 为控制共享服务器资源,没有跑原生 1M context;max_model_len 缩短为 131072。
  • 未测试量化 checkpoint、多机或 Pipeline Parallel 实机运行。
  • 没有验证 vLLM 0.28,也不宣称覆盖所有后续版本。
  • 三次诊断是隔离重跑,不是统计独立实验;相邻 base seed 的逐轮 seed 序列存在部分重叠。

正式诊断只开放只读源码工具、固定检查和 finish,没有编辑、网络或凭据工具;公开产物已脱敏,服务仅绑定回环地址。

AI、许可与参赛身份说明

我使用 Spark-X2.5-4B 做受控代码审查实验,并使用通用编码助手辅助实现、测试和文档整理;我逐项复核补丁与验证结果后提交,并对本次贡献负责。模型输出只作为待验证假设,正确性以回归测试、源码复核和真实运行结果为准。

本案例不包含新增训练数据;任务、harness 与实验记录为本案例自产,案例代码按 Apache-2.0 发布,模型与上游代码遵循各自许可证。

参赛身份:GitHub @MittaPei / Hugging Face @Forrest20231206 ,两个账号属于同一位个人参赛者。

Sign up or log in to comment