关于 model-migrate-flagos
用于将上游 vLLM 模型迁移到 FL 插件的技能。它按步骤指导源码适配、兼容性修补、注册、验证、基准测试及端到端检查。
主要功能
- 01解析模型名与路径
- 02检索上游及 HuggingFace 资料
- 03应用兼容性补丁
- 04验证导入、API 与注册
- 05执行基准及端到端测试
适用场景
- 01为 FL 插件添加上游模型
- 02上游更新后重新迁移
- 03排查模型适配与服务错误
- 04对照上游进行端到端验证
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ flagos-ai/ skills --skill model-migrate-flagos安装后在 Claude Code 中输入/model-migrate-flagos确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSE.txtREADME_zh.mdREADME.mdreferences/compatibility-patches.mdoperational-rules.mdprocedure.mdscripts/benchmark.she2e_config.template.jsone2e_eval.pye2e_remote_serve.she2e_test_prompts.jsonrequest.shserve.shvalidate_migration.py详细介绍
FL 插件 — 模型迁移技能
用法
/model-migrate-flagos <model_name> [upstream_folder] [plugin_folder]
| 参数 | 必填 | 默认值 |
|---|---|---|
model_name | 是 | — |
upstream_folder | 否 | /tmp/vllm-upstream-ref |
plugin_folder | 否 | 当前工作目录 |
执行
第 1 步:解析参数并验证路径
从用户输入中提取:
{{model_name}}= 第一个参数(必填,snake_case){{upstream_folder}}= 第二个参数或/tmp/vllm-upstream-ref{{plugin_folder}}= 第三个参数或当前工作目录
如果 {{upstream_folder}} 不存在,询问用户是否要克隆该目录。如果 {{plugin_folder}} 不存在,则报错退出。
→ 告知用户:确认解析出的模型名称和路径。
第 2 步:加载参考资料并解析占位符
读取以下文件(相对于此 SKILL.md):
references/procedure.md— 分步迁移流程references/compatibility-patches.md— 0.13.0 补丁目录references/operational-rules.md— 沟通、TaskList、bash 规则和韧性要求
流程中会引用 scripts/ 目录下的可执行脚本:
scripts/validate_migration.py— 自动化代码审查(第 6 步)scripts/benchmark.sh— 基准测试验证(第 9 步)scripts/serve.sh— 在本地提供模型服务(第 10.1 步,也用于 E2E)scripts/request.sh— 测试请求(第 10.2 步)scripts/e2e_eval.py— E2E 正确性验证(第 11 步)scripts/e2e_test_prompts.json— E2E 测试提示词(5 个文本 + 5 个多模态)scripts/e2e_config.template.json— E2E 配置模板(复制为e2e_config.json并填写)scripts/e2e_remote_serve.sh— 通过 SSH 管理远程机器上的 GT 服务
然后调查上游源码和 HuggingFace,以解析所有占位符:
| 占位符 | 获取方式 |
|---|---|
{{model_name}} | 直接取自参数 |
{{model_name_lower}} | model_name 的小写形式(通常相同,例如 qwen3_5)——用于文件路径 |
{{MODEL_DISPLAY_NAME}} | 从上游代码或 HF 模型卡获取 |
{{ModelClassName}} | 从上游模型类获取(PascalCase) |
{{model_type}} | 从 HF config.json 的 model_type 字段获取 |
{{ConfigClassName}} | 从上游获取,或根据 model_type 推导 |
{{skill_root}} | 此技能文件夹的绝对路径(即包含此 SKILL.md 的目录) |
不同模型的命名规范各不相同——务必根据实际源码核实,切勿猜测。
→ 告知用户:列出所有解析出的值。如有任何不明确之处,请使用 AskUserQuestion。
第 3 步:执行流程
解析完占位符后,按顺序执行 procedure.md 中的每个步骤。在“先复制再修补”步骤中应用 compatibility-patches.md 中的补丁。全程遵循 operational-rules.md。
→ 告知用户:开始前输出编号计划。在每个步骤的节点报告进度。
脚本参考
| 脚本 | 步骤 | 描述 |
|---|---|---|
validate_migration.py | 6 | 自动导入、API 和注册检查 |
benchmark.sh | 9 | 使用虚拟权重运行 vllm bench throughput |
serve.sh | 10、11 | 启动本地 vLLM 服务(端口 8122,VLLM_FL_PREFER_ENABLED=false) |
request.sh | 10 | 快速冒烟测试请求 |
e2e_eval.py | 11 | 与上游 GT 服务进行 Token 级比较 |
e2e_test_prompts.json | 11 | 5 个文本 + 5 个多模态测试提示词 |
e2e_config.template.json | 11 | 配置模板(GT 机器、本地端口、评估参数) |
e2e_remote_serve.sh | 11 | 基于 SSH 的 GT 服务生命周期管理(启动/停止/状态/日志) |
示例
示例 1:典型的新模型
User says: "/model-migrate-flagos kimi_k25"
Actions:
1. Parse → model_name=kimi_k25, defaults for upstream/plugin paths
2. Clone upstream, find vllm/model_executor/models/kimi_k25.py
3. Discover it wraps DeepseekV2 → follow kimi_k25 (wrapper) pattern
4. Copy file, apply P1+P2 patches, create config bridge
5. Register, validate, test, benchmark, serve+request
6. E2E verification against upstream GT
Result: kimi_k25 fully working in plugin, all 11 steps passed
示例 2:上游更新后重新运行
User says: "migrate qwen3_5 again, upstream updated"
Actions:
1. Idempotent re-run — overwrite existing files with fresh upstream copy
2. Re-apply patches, re-validate, re-test
3. Re-run E2E to confirm no regression
Result: qwen3_5 updated to match latest upstream, no regressions
故障排查
一般原则:发生任何运行时错误时,首先对比 vLLM 上游代码与插件适配代码,以及已安装的 0.13.0 环境。差异对比是找到根因最快的方法。完整流程请参阅 operational-rules.md § Debugging Priority: Upstream-First。
| 问题 | 常见原因 | 解决方法 |
|---|---|---|
复制后打补丁时出现 ImportError | 缺少 P1 修复(相对导入改为绝对导入) | 确认所有 from .xxx 都已转换为 from vllm.* 或 from vllm_fl.* |
AttributeError: module 'vllm' has no attribute X | 0.13.0 中不存在该 API | 查看 compatibility-patches.md 中的 P3;添加存根或移除 |
| vLLM 无法识别配置 | model_type 不匹配或缺少配置桥接 | 确认 _CONFIG_REGISTRY[model_type] 与 HF config.json 完全一致 |
| 注册未生效 | 类名或导入路径有误 | 与 __init__.py 中的现有注册项对比 |
基准测试因配置字段出现 KeyError | 配置桥接缺少字段 | 对比上游配置类与桥接代码;为缺失字段添加默认值 |
| 基准测试/服务因 OOM 或“内存不足”而失败 | GPU 被其他进程占用 | 终止 GPU 进程:nvidia-smi --query-compute-apps=pid --format=csv,noheader | xargs -r kill -9,然后重试。绝不可跳过这些步骤。 |
| 模型输出乱码 | 合并投影使用了 ColumnParallelLinear,但子维度不同(TP 分片不匹配) | 重写 __init__,使用 MergedColumnParallelLinear(output_sizes=[...])。参见 compatibility-patches.md 中的 P8 |
AssertionError: Duplicate op name | 子类从与父类不同的模块路径导入自定义算子 | 使用与父模块相同的导入路径(例如 vllm_fl.ops.fla,而不是 vllm_fl.models.fla_ops)。参见 P11 |
CUDA 图预热期间,fused_recurrent_* 出现 AttributeError | 使用 nn.Module.__init__(self) 重写 __init__ 时,漏掉了继承的 _forward_core 所需的属性 | 创建父类 __init__ 中的所有属性,尤其是自定义算子。参见 P12 |
| E2E:无法连接本地服务 | serve.sh 的端口与 e2e_config.json 中的本地端口不一致 | 确保二者使用相同端口(默认为 8122) |
| E2E:无法连接 GT 服务 | GT 机器宕机,或 Docker/conda 环境有误 | 检查 e2e_remote_serve.sh status,或手动通过 SSH 连接 |
| E2E:较早的 token 发生分歧(前 5 个 token) | 权重加载错误、TP 分片错误 | 检查 load_weights、stacked_params_mapping、MergedColumnParallelLinear |
| E2E:较晚出现轻微分歧(第 15 个及之后的 token) | 不同算子实现带来的数值噪声 | 通常可以接受;请在报告中说明 |
VLLM_FL_PREFER_ENABLED=false 时 resolve_op 失败 | 算子未在分发机制中注册,且没有回退方案 | 在算子导入代码中添加 try/except,回退到 flag_gems |
评论
支持 Markdown