mcpField
F
flash

flash

github.com/runpod云与 DevOps4714.0k 次安装2 天前更新
代码仓库

关于 flash

Runpod Flash 是用于在 Runpod GPU 和 CPU Worker 上开发、部署 Python 函数的技能,采用代码优先流程:开发时远程执行并热重载,完成后部署为端点。

主要功能

  1. 01在远程 GPU 或 CPU Worker 上运行函数
  2. 02热重载与实时 Worker 日志
  3. 03将函数部署为稳定端点
  4. 04支持队列式和负载均衡路由
  5. 05连接现有端点或部署镜像

适用场景

  1. 01迭代开发 GPU 推理函数
  2. 02调试时查看 Worker 日志
  3. 03将测试通过的函数部署为端点
  4. 04通过 Python 调用现有端点

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/runpod/runpod-plugins-official --skill flash

安装后在 Claude Code 中输入/flash确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
client-external-image.eval.md
connect-existing-endpoint.eval.md
cpu-gpu-pipeline.eval.md
dev-loop-iteration.eval.md
lb-multi-route-api.eval.md
qb-gpu-function.eval.md
volume-cache-model-load.eval.md
evals/fixtures/dev-loop/
main.py
reference/
api.md
patterns.md
setup-and-cli.md

详细介绍

Runpod Flash

对于明确要求提供 Dockerfile/模板项目的请求,请使用 runpod-build-template。除非用户选择代码优先的工作流,否则不要用 Flash 替代 该交付内容。

在本地编写代码,使用 flash dev 迭代——它会通过热重载和实时工作器日志,在远程 Runpod GPU/CPU 上运行你的函数——然后使用 flash deploy 部署。Endpoint 负责配置资源。

runpod-flash 会按自己的节奏发布,因此 flash --help 和 flash <command> --help 是命令列表的权威来源——本技能提供心智模型、决策规则和帮助输出中未涵盖的注意事项。断定某个子命令或标志不可用之前,请先通过 pip show runpod-flash 确认已安装的版本。

遇到任何多步骤操作,先看完整示例。 Flash 已用于经过验证的端到端流程——03 variant B (whisper endpoint via flash) 和 08 (fine-tune → serve);完整索引见 runpod/golden-paths/README.md。规划部署之前,请先打开相应流程——其中包含本技能仅作概述的操作顺序和成本清理步骤。

按需查阅——本技能在正文中保留了心智模型和注意事项;详情见 reference/:

需求阅读
安装、身份验证、flash init 和完整的 flash 命令列表reference/setup-and-cli.md
Endpoint(...) 构造函数参数、NetworkVolume/PodTemplate/EndpointJob、GPU 和 CPU 枚举表reference/api.md
实用模式——选择模型、预热工作器的模型加载、CPU→GPU 流水线、并行调用reference/patterns.md

快速开始:uv tool install runpod-flash → flash login(或 export RUNPOD_API_KEY=...)→ flash init my-project → flash dev。详情见 reference/setup-and-cli.md。

开发与部署

  • flash dev——迭代开发。 本地服务器运行在 :8888,但经过装饰的函数会在远程 GPU/CPU 工作器上执行。保存时热重载,并将工作器日志实时传输到终端。无需等待构建、上传或部署——开发期间一直使用它。
  • flash deploy——部署上线。 构建制品并部署稳定的端点。速度较慢(构建 + 上传 + 配置资源);只有代码在 flash dev 下运行正常后才执行。

flash dev 只会将函数体发送到工作器,因此模块级名称若导致 NameError,会立即在这里暴露。flash deploy 会导入整个模块,可能掩盖这个问题(见注意事项 #1)。使用 flash dev 开发,就能先发现问题。

自主开发循环

flash dev 是一个长期运行的服务。请遵循三条规则:

  • 在后台运行——不要等待它结束。
  • 将输出写入日志文件。
  • 通过 HTTP 驱动它。

捕获的日志是远程工作进程的实时流(冷启动、模型加载、print 输出、回溯)——读取日志以进行调试。

flash dev > /tmp/flash-dev.log 2>&1 &                          # background; never run it blocking
for i in $(seq 1 60); do grep -q "flash dev  localhost:" /tmp/flash-dev.log && break; sleep 2; done  # bounded ~2min; if it never appears, check the log for errors
URL=$(grep -o "localhost:[0-9]*" /tmp/flash-dev.log | head -1)               # actual port (8888 bumps if taken)
curl -s "$URL/main/predict" -d '{"data": {...}}'               # dispatches to the remote worker
  • 从日志中读取实际 URL——如果 8888 端口被占用,flash 会自动切换到其他端口,并输出 ✓ flash dev localhost:<port> 以及路由表。
  • 路由按文件划分命名空间:main.py 中的 /predict 会通过 /main/predict 提供服务。
  • 两种路由形式,对应两种请求体形式(不匹配时会返回 422,并在 loc 中指出缺少的字段):
    • 负载均衡(@api.post("/predict"))→ POST /main/predict,请求体在顶层包含参数:处理函数 def predict(data: dict) 需要 {"data": {...}}(而不是裸对象)。
    • 基于队列(裸 @Endpoint 装饰器)→ POST /main/runsync(本地开发服务仅生成 /runsync;生产环境还会提供 /run),请求体需要在 input 中双重包装:处理函数 def synthesize(data: dict) 需要 {"input": {"data": {...}}}。外层的 input 是队列封套;内层的键是处理函数的参数名。
  • 编辑处理函数并保存——热重载会重新同步请求体;只需重新发送请求,无需重新部署。添加 --auto-provision 可跳过首次调用时的冷启动。完成后运行 kill %1。

Endpoint:三种模式

完整的构造函数参数以及 GPU/CPU 枚举表,请参阅 reference/api.md。

模式 1:你的代码(基于队列的装饰器)

一个函数 = 一个拥有独立工作进程的端点。

from runpod_flash import Endpoint, GpuGroup

@Endpoint(name="my-worker", gpu=GpuGroup.AMPERE_80, workers=5, dependencies=["torch"])
async def compute(data):
    import torch  # MUST import inside function (cloudpickle)
    return {"sum": torch.tensor(data, device="cuda").sum().item()}

result = await compute([1, 2, 3])
模式 2:你的代码(负载均衡路由)

多个 HTTP 路由共享一个工作进程池。

from runpod_flash import Endpoint, GpuGroup

api = Endpoint(name="my-api", gpu=GpuGroup.ADA_24, workers=(1, 5), dependencies=["torch"])

@api.post("/predict")
async def predict(data: list[float]):
    import torch
    return {"result": torch.tensor(data, device="cuda").sum().item()}

@api.get("/health")
async def health():
    return {"status": "ok"}
模式 3:外部镜像(客户端)

部署预构建的 Docker 镜像,并通过 HTTP 调用。

from runpod_flash import Endpoint, GpuGroup, PodTemplate

server = Endpoint(
    name="my-server",
    image="my-org/my-image:latest",
    gpu=GpuGroup.AMPERE_80,
    workers=1,
    env={"HF_TOKEN": "xxx"},
    template=PodTemplate(containerDiskInGb=100),
)

# LB-style
result = await server.post("/v1/completions", {"prompt": "hello"})
models = await server.get("/v1/models")

# QB-style
job = await server.run({"prompt": "hello"})        # optional: webhook="https://..." for completion callback
await job.wait()
print(job.output)

通过 ID 连接到现有端点(不进行配置):

ep = Endpoint(id="abc123")
job = await ep.runsync({"prompt": "hello"})  # runsync wraps this as {"input": {"prompt": "hello"}}
print(job.output)

如何确定模式

参数模式
仅 name=装饰器(你的代码)
设置了 image=客户端(部署镜像,然后通过 HTTP 调用)
设置了 id=客户端(连接到现有端点,不进行配置)

上表说明了如何根据参数选择模式。以下说明何时使用 image=:

何时使用 image=(自定义容器),而不是自己的代码

默认选择编写 Python 代码(装饰器/路由)——它可以运行任意代码,通过 dependencies=[...]/system_dependencies=[...] 安装依赖,且不需要 Dockerfile。即使是大型 HuggingFace 模型,也可以使用装饰器模式(权重会在运行时流式传输——请参阅 reference/patterns.md → Loading ML models)。只有在以下情况需要时,才使用 image=:

  • 预构建的推理服务——vLLM、TensorRT-LLM(image="vllm/vllm-openai:latest",或 runpod/worker-vllm、runpod/worker-comfy)
  • 无法通过 pip 安装的系统级依赖——特定版本的 CUDA/cuDNN、操作系统库
  • 预先打包在镜像中的模型——完全跳过运行时下载
  • 现有的 Runpod Serverless 工作进程——你已经有可用的镜像

权衡:image= 模式无法运行任意 Python 代码(所有逻辑都由镜像负责),且镜像必须实现 Runpod Serverless 处理程序。完整列表和示例: https://docs.runpod.io/flash/custom-docker-images

注意事项

  1. 只有函数体会被发送到 worker——这是最常见的错误。将导入语句以及函数所用的任何模块级常量/辅助函数都放到装饰后的函数体内。flash deploy 会导入整个模块,因此模块全局变量碰巧能正常使用;flash dev 只会发送函数体,因此模块级名称会引发 NameError。部署后能正常运行的处理函数,在 dev 模式下可能会出错——将所有内容移到函数内部即可修复。
  2. 忘记使用 await——所有装饰后的函数和客户端方法都需要使用 await。
  3. 缺少依赖项——必须在 dependencies=[] 中列出。
  4. gpu 和 cpu 互斥——每个 Endpoint 只能选一个。
  5. idle_timeout 的单位是秒——默认值为 60s,不是分钟。
  6. 负载上限为 10MB——传递 URL,而不是大型对象。将二进制数据(音频/图片/文件)以 base64 形式放在 JSON 中返回({"audio_b64": ...}),并在客户端解码;对于更大的输出,将其写入 NetworkVolume 或上传到存储空间,然后返回 URL。
  7. 客户端与装饰器的区别——image=/id= 属于客户端参数;否则属于装饰器参数。
  8. 自动切换 GPU 要求 workers >= 5——传入 GPU 类型列表(例如 gpu=[GpuGroup.ADA_24, GpuGroup.AMPERE_80]),并将 workers=5 或更高。只有当最大 worker 数至少为 5 时,平台才会根据供应情况自动切换 GPU 类型。
  9. runsync 超时时间为 60s——冷启动可能超过 60s。首次请求请使用 ep.runsync(data, timeout=120),或改用 ep.run() + job.wait()。
  10. 请求体结构(仅适用于原始/外部 HTTP 调用方)——请求结构必须与 Endpoint 类型匹配:
    • LB 路由(@api.post(...)):在顶层发送处理函数参数——{"data": {...}}。
    • QB Endpoint(裸 @Endpoint,通过 .../run 或 .../runsync 调用):worker 会调用 handler(**job_input),因此请求的 input 键必须与处理函数的参数名称匹配——def transcribe(input_data: dict) 需要 {"input": {"input_data": {...}}},而 def read(input: dict) 需要 {"input": {"input": {...}}}。不匹配会导致 got an unexpected keyword argument …。如果处理函数会忽略负载,请使用 **kwargs。
    • 切勿发送空的 input。 QB 请求中的 {"input": {}} 会被 worker SDK 拒绝,并报错 Job has missing field(s): id or input——始终至少包含一个键。
    • 背景: flash 客户端(ep.runsync(x)、api.post(...))会隐藏参数展开过程,因此只有原始 HTTP/外部调用方会遇到此问题(已通过 2026-07-10 的 worker 日志验证不匹配行为)。请参阅 Autonomous Dev Loop。
  11. 每个 worker 加载一次模型(而非每次调用都加载)——对于实际推理,请使用类形式的 @Endpoint,并在其 __init__ 中加载模型,使每个 worker 只加载一次(参见 reference/patterns.md → Loading ML models)。使用函数形式时,需兼顾第 #1 条:在函数体内将模型缓存到模块全局变量中,确保它在 flash dev 和 deploy 模式下都能正常工作:
    global _MODEL
    try: _MODEL
    except NameError: _MODEL = load_model()   # 每个 worker 只运行一次,后续调用会复用
    
  12. 原生 CUDA 库也要放进 dependencies=[]——例如,CTranslate2/faster-whisper 需要 nvidia-cublas-cu12 + nvidia-cudnn-cu12,否则会静默退回 CPU。请将它们与 Python 包一并添加。
  13. 401 身份验证失败不会明确提示——设置了 RUNPOD_API_KEY 环境变量时,它会覆盖 flash login 令牌,因此无效或过期的密钥会优先生效。该失败不会明确提示:配置日志会显示 GraphQL request failed: 401,但 flash dev 仍会打印正常的就绪信息(“failed endpoints deploy on-demand”),因此看起来一切正常。Endpoint 无法配置时:
    1. 检查配置日志中是否有 GraphQL request failed: 401。
    2. 独立验证当前密钥:curl -s -o /dev/null -w '%{http_code}' https://api.runpod.io/v2/serverless -H "Authorization: Bearer $RUNPOD_API_KEY"(200 = 正常,401 = 无效)。
    3. 修复方式:运行 unset RUNPOD_API_KEY,以回退到 flash login 令牌;或运行 export 设置有效密钥。
  14. system_dependencies= 会延长冷启动时间——apt 软件包(例如 ["ffmpeg", "espeak-ng"])会在首次使用前安装到 worker 上,因此首次调用会更慢(还要加上任何模型下载所需的时间);热调用不受影响。
  15. 使用 flash app delete <app> 拆除已部署的应用——对于已部署且正在提供服务的应用,flash undeploy list 可能会显示“no endpoints”;flash app delete(或 runpodctl serverless delete <id>)能可靠地将其删除。

资源

评论

支持 Markdown