写作与公文
为指定 LoRA 在 Hugging Face…
当用户要求为某个 LoRA 创建、生成、交付或发布 Space、demo、Gradio app 或 playground 时,用此流程产出可浏览器访问的私有 ZeroGPU Space。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
为指定 LoRA 在 Hugging F特定
解决思路
- Phase 1:确认需要 Hub 上的 LoRA repo,例如 username/my-lora。
- 先尝试不带 token 读取该 repo:成功说明是 public,继续;若 401/403 说明 private/gated,需要认证会话。不要立刻要 token,先检查用户是否已经认证。
- 用 `get_token()` 读取 HF_TOKEN 环境变量或 CLI 缓存登录;用 `HfApi().whoami(token=cached_token)` 验证;若有效缓存 token 且能读 repo,直接使用,无需提示。若没有有效缓存 token 或不能读该私有 repo,一次性询问用户要 token,并说明需要 write scope 以便读 private/gated LoRA 和发布 Space,创建地址为 https://huggingface.co/settings/tokens。该 token 复用于最终发布。
- 读取 repo 内容:用 `HfApi().list_repo_files(repo_id)` 列出文件,查找 `.safetensors`、`README.md`、示例图片/视频、多个 checkpoint。
- 用 `ModelCard.load(repo_id)` 加载模型卡,读取 `data` 结构化字段和 `text` 正文。
- 若有多个 `.safetensors`,按顺序选择:README 推荐文件优先,其次 `pytorch_lora_weights.safetensors`,再次最新训练 checkpoint,否则询问用户。
- 从模型卡确定:base model(`base_model` 字段或 README 文本);task(`pipeline_tag` 或从 base model/README 推断,五类为 `text-to-image`、`image-to-image`、`text-to-video`、`image-to-video`、`video-to-video`);trigger words(trigger word、instance prompt、activation word 或示例 prompt 中);推荐推理配方(step count、guidance scale、true CFG scale、LoRA scale、resolution;信任 Python snippet 的参数,但加载方式优先用 `pipe.load_lora_weights(...)` 而非 snippet 的加载方法);示例 prompts 和示例媒体;sub-task/具体用途。
- 无法推断时,一次性批量询问用户,问题格式要容易回答:task 分类给五个编号选项;sub-task 给一行描述示例,如 relight portraits、apply manga style、extend videos to wider aspect ratios。不要问已能从 base model 或 README 自信推断的内容。
- 若模型卡完全无有用信息,明确说明并询问用户:(1) base model,(2) 这个 LoRA 做什么,(3) 推荐 step count 和 guidance scale(若知道)。
- Phase 2:决定加载哪个 reference 文件和哪个 pipeline class,这两个问题不同。先加载 base model family 的 reference 文件:`references/base-models/qwen-image.md`(Qwen-Image 和 Qwen-Image-Edit 家族,text-to-image 和 image-to-image);`references/base-models/ltx.md`(LTX 家族,text-to-video、image-to-video、video-to-video,包括 IC-LoRAs);`references/base-models/krea-2.md`(Krea 2,text-to-image,RAW 训练、Turbo 蒸馏 checkpoint 推理/LoRA)。若 base model 不在这些文件,告知暂无一等支持,询问按最接近模型类比继续还是停止,不要静默猜。
- 强制验证 pipeline class 与 base model 自己的卡一致:用 `ModelCard.load(base_model_id)` 读 `base_card.text`,找 diffusers 推理片段,它导入的 pipeline class 是 source of truth。示例:`Qwen-Image-Edit` 用 `QwenImageEditPipeline`,`Qwen-Image-Edit-2509` 和 `Qwen-Image-Edit-2511` 用 `QwenImageEditPlusPipeline`,class 和默认参数不同且接收图像列表;LTX-Video 用 `LTXPipeline`/`LTXImageToVideoPipeline`/`LTXConditionPipeline`,LTX-2 用不同模块路径的 `LTX2Pipeline`,LTX-2.3 有时需要 diffusers 外的 native pipeline。若 base model 卡无 diffusers 片段,才回退 reference 文件表格,并告知用户你在回退。
- 选择 diffusers 还是 native pipeline:默认在 base model 有 diffusers pipeline class 时用 `diffusers`(Qwen-Image、Qwen-Image-Edit 和多数 LTX 如此)。某些 LTX 变体(尤其 LTX-2.3 搭配某些 IC-LoRAs)需要 native pipeline,LTX reference 会说明。diffusers 提供标准 `load_lora_weights`/`set_adapters` 语义;native 路径需要 LoRA 专用胶水代码。
- Phase 3:不要套模板,从 LoRA 的 task 和输入推理 UI。读 `references/tasks.md` 获取各 task 基线 UI 模式(T2I、I2I、T2V、I2V、V2V 的标准输入/输出)。
- 读 `references/adapting-to-the-lora.md`,思考这个特定 LoRA 需要什么:同一 task 可需要不同 UI,例如 pose-control LTX LoRA 需要视频输入和姿态提取预览;outpaint LTX LoRA 需要 aspect-ratio picker 和黑边预览;relighting Flux LoRA 需要图像和画笔画布指示加光位置。
- 写 UI 前自检:用一句话描述用户 10 秒内如何使用这个 Space。若这句话不能把此 LoRA 与同 task 其他 LoRA 区分开,UI 还不够贴合。通过示例:上传视频、选目标宽高比、点击 Generate,模型填充空白边缘;画彩色笔触表示想加光的位置、选光照风格、点击 Generate,模型重打光;上传人物运动视频和另一角色图像,模型生成该角色做动作的视频。失败示例:输入 prompt 点击生成(泛化 T2I);上传图像和指令(泛化 edit,需说明哪种 edit)。
- 注意 Gradio 组件新鲜度:考虑更新组件是否更合适,例如 `gr.ImageSlider` 用于 edit LoRA 前后对比,`gr.BrowserState` 用于持久偏好,`@gr.render` 用于随输入变化的 UI。不确定组件是否存在或签名时,web-fetch 当前 Gradio 文档 https://www.gradio.app/docs,不要猜。
- 当内置和 Hub 自定义组件不足以表达 LoRA 的自然输入形状(点集、笔触、轨迹、带元数据多区域标注、3D 旋转 gizmo、时间轴 scrubber 等用户在媒体上操作的东西)时,进入 creative mode:用 `gr.HTML` 降级到自定义 HTML/JS。读 `references/creative-mode.md` 了解 Gradio primitives(`gr.HTML`、`head=` 注入、`elem_id` 寻址、两种 JS↔Python 状态同步方法)、定义 JSON wire format 的纪律和陷阱。不要只为酷而用 creative mode;也不要跳过 Hub 自定义组件这一级,例如 `gradio_image_annotation`。
- 为媒体输入 Space 准备 `gr.Examples`:当模型自己的 repo 没有合适示例媒体时,从共享输入池按模态拉取,以便 HF dataset viewer 渲染缩略图:图像用 `linoyts/repo-to-space-example-inputs`,视频用 `linoyts/repo-to-space-example-videos`。两者都是 CC0,带 `categories` 和自然语言 `caption` 元数据,各自 README 有相同 filter/rank 配方。选 2–3 个符合 task 的,预处理成模型期望形状,把副本烘焙进 Space。设 `cache_examples=True, cache_mode="lazy"`,让首次点击缓存且不在构建时运行 examples。
- Phase 4:写文件前具体告诉用户即将写哪些文件:`app.py`(Gradio demo 和推理代码)、`requirements.txt`(Python 依赖)、`README.md`(Space 配置,包括 ZeroGPU hardware 设置)。然后展示三者供审阅后再发布。不要只说“三个文件”而不命名。
- 三个文件紧耦合:`requirements.txt` 由 `app.py` import 决定,`README.md` YAML frontmatter 设置 SDK 版本、hardware、Space 标题,必须匹配。把它们一起写,然后在单条批量消息里展示三者请求批准,再发布。
- 读 `references/zerogpu-and-publishing.md` 了解 ZeroGPU 规则。非显然规则:模型在 module level 放到 `cuda`,不要 lazy-load 到 GPU function 内;ZeroGPU 的 CUDA 模拟让这样可行,且 module-level 比 deferred 快很多。运行推理的函数用 `@spaces.GPU(duration=...)` 装饰,duration 按 task 选,图像短、视频长。不要用 `torch.compile`,它与 ZeroGPU 进程模型不兼容。
- 编写 `app.py`:从 Phase 1–3 的决定组合,不要粘贴模板,每个 section 都应因需要而存在。包括 imports:`gradio as gr`、`torch`、`spaces`、pipeline class、预处理需要的库。包括 constants:`LORA_REPO`、`BASE_MODEL`、推荐 step count、guidance、LoRA scale、trigger word。包括 module-level 模型加载:pipeline `from_pretrained`、`.to("cuda")`、`load_lora_weights`。若 LoRA repo 私有,传 `token=os.environ["HF_TOKEN"]`。包括预处理函数(如有):姿态提取、padding、mask building 等;CPU 代码可在 module level,GPU 代码必须在 `@spaces.GPU` 函数内。包括推理函数:用 `@spaces.GPU(duration=...)` 装饰,验证输入,应用 trigger word,构建 pipeline kwargs,返回输出。包括 Gradio Blocks:连接 Phase 3 的 UI 到推理函数。
- `app.py` 常见正确点:返回实际使用的 seed 和结果,以便复现;在推理函数上用 `gr.Progress(track_tqdm=True)` 展示 diffusers 内部进度条;验证输入,缺必需输入时 `raise gr.Error("Please upload an image first.")`,不要让 pipeline 报 cryptic error;`gr.Examples` 用 `cache_examples=True, cache_mode="lazy"`,普通 `cache_examples=True` 会在构建时运行 examples 并在 ZeroGPU 失败;当 `gr.Examples` 有 `fn=`,点击一行只按位置传 `inputs=` 的值,因此所有不在 `inputs` 里的 `fn` 参数必须有默认值,否则点击时 `TypeError: missing N required positional arguments`,修复方式:给额外参数默认值(保留 `inputs=[prompt]`),或列出每个输入并提供完整示例行,或去掉 `fn`/`outputs` 让点击只填充字段。
- 编写 `requirements.txt`:不要固定最小列表碰运气;按顺序从实际需要推导:(1) `app.py` 中每个顶层非 stdlib import,如 `import cv2` 要 `opencv-python`,`from controlnet_aux import OpenposeDetector` 要 `controlnet-aux`,机械地走一遍 imports,注意排除运行时内置项;(2) base-model reference 的 Required dependencies 小节列出的非显然 extras,如 Qwen-Image 的 `torchvision`(Qwen 2.5-VL 文本编码器)、LTX 的 `imageio[ffmpeg]`(视频导出),全部包含;(3) LoRA 自己模型卡明确提到要安装的依赖,若有 `pip install` 块就提取;(4) diffusers/ML stack:`diffusers`、`transformers`、`accelerate`、`peft`、`safetensors`,默认不 pin;若 base-model reference 说模型需要,把 `diffusers` 切到 `git+https://github.com/huggingface/diffusers`(近期发布常需要,例如 Qwen-Image-Edit-2511)。
- `requirements.txt` 中不要列:`gradio`,它由 `README.md` YAML frontmatter 的 `sdk_version:` 控制,列了最好被忽略、最坏与 SDK 版本冲突;`torch`、`spaces`、`huggingface_hub`,它们由 Space runtime 提供,除非要特定版本 pin(少见且通常表示别处有问题)。这四个在 ZeroGPU 容器预装,列出来是与运行时管理版本冲突。
- 其他依赖不确定时倾向 include 而非 skip:Space 用不到的包只让 build 稍慢;缺少必需包导致启动崩溃,更难诊断,成本不对称。
- 两个依赖不要反射式添加,因为它们在 ZeroGPU 常造成更多问题:`xformers` 仅在 `app.py` 实际使用时加入;它常与 torch 版本 pin 冲突,ZeroGPU runtime 带 torch 2.8+,Blackwell 上 FA3 dispatch 误判硬件(FA3 kernel 仅 Hopper `sm_90a`,dispatcher 却按 `device_capability >= (9, 0)` 也匹配 Blackwell),在 kernel launch 时崩 `CUDA invalid argument`;若 Space 用 xformers attention 遇到此问题,在 module load 时禁用 FA3 dispatch:`try: from xformers.ops.fmha import _set_use_fa3 _set_use_fa3(False) except Exception: pass`。`flash-attn` 需要 build step,常安装失败,也有 torch 2.8+ 对齐注意事项,仅在 `app.py` 实际使用时加入。
- 其他版本只在有理由时 pin,例如已知不兼容,或匹配模型卡配方。
- 编写 `README.md`:Spaces 由顶部 YAML frontmatter 配置,frontmatter 选择 ZeroGPU。模板字段包括 `title`、`emoji`、`colorFrom`、`colorTo`、`sdk: gradio`、`sdk_version: <current Gradio version>`、`app_file: app.py`、`pinned: false`、`hardware: zero-a10g`、`short_description: <one short line for the Space tile, ~60 chars max>`、`models:` 下 base model repo 和 lora repo。正文写标题和带 LoRA/base model 链接的简短描述。
- `README.md` 关键字段:`sdk: gradio` 是 ZeroGPU 必需;`sdk_version` 匹配你写代码所针对的 Gradio 版本,用 `pip index versions gradio` 或 https://www.gradio.app 查当前版本,不要猜;`hardware: zero-a10g` 是 ZeroGPU 的 legacy 字符串,实际硬件是 NVIDIA RTX Pro 6000 Blackwell,但标识符是 `zero-a10g`,ZeroGPU 对 PRO、Team、Enterprise 账户开放,若用户未订阅 Space 会回退 CPU,怀疑未订阅时提一下;`models:` 列出 base 和 LoRA repo 以启用 Hub 缓存和发现;`short_description` 显示在 Space tile,保持短(约 60 字符或更少),Hub YAML validator 会因过长值在 `https://huggingface.co/api/validate-yaml` 返回 400,表现为 `create_repo` 或 `upload_file` 中的 `HfHubHTTPError`,服务器端精确限制未文档化且可能变化,目标可见 tile 长度范围而不要顶到上限;若遇 400,修复通常就是缩短该字段,一句话描述足够,更长内容放 YAML 下方 README 正文。
- 单批审批顺序:先连续写 `app.py`、`requirements.txt`、`README.md`,文件之间不要穿插 prose,不要说“现在写下一个”,不要边写边描述;然后单条消息请求三者一起批准,例如"Here's the Space — `app.py` (N lines), `requirements.txt`, and `README.md`. Review and confirm to publish, or tell me what to change.";用户一次回应覆盖三个文件的所有更改。避免写完 `app.py` 就讲结构/设计再写其他;避免问“ready for the next one?”或“want me to continue with requirements?”;避免展示一个文件并说准备好再给下一个;不要把三个文件任一视为可选或后续。若用户在看到第一个文件后打断反馈,可以回应,但下次产码仍一起产剩余文件,不要一次一个。
- Phase 5:用 Phase 1 的认证会话发布。默认 private,让用户先审查再公开。创建前确认目标用户名:"I'll publish to `{username}/{space_name}` — confirm?"
- 发布代码:用 `HfApi(token=hf_token)`,`username = api.whoami()["name"]`,`repo_id = f"{username}/{space_name}"`;调用 `api.create_repo(repo_id=repo_id, repo_type="space", space_sdk="gradio", space_hardware=SpaceHardware.ZERO_A10G, private=True, exist_ok=True)`;然后对 `app.py`、`requirements.txt`、`README.md` 循环 `api.upload_file(path_or_fileobj=path, path_in_repo=path, repo_id=repo_id, repo_type="space")`。
- 若 LoRA repo 本身 private/gated,Space runtime 下载 LoRA 需要 token。调用 `api.add_space_secret(repo_id=repo_id, key="HF_TOKEN", value=HF_TOKEN)`,并在 `app.py` 用 `token=os.environ["HF_TOKEN"]` 加载 LoRA。
- 上传后先跑 smoke-test 再分享。通过后分享 Space URL `https://huggingface.co/spaces/{repo_id}`,告知用户 Space 是 private,需登录查看。build 需几分钟,失败日志在 `https://huggingface.co/spaces/{repo_id}/logs/container`。
- 发布时失败(build 开始前):`HfHubHTTPError: 400 Bad Request` 来自 `https://huggingface.co/api/validate-yaml`,发生在 `create_repo` 或 `upload_file`,说明 README YAML 服务端验证失败,最常见是 `short_description` 太长,有时是 stray field 或 malformed value;修复:缩短 `short_description` 到约 60 字符并重试;若仍不行,检查字段名 typo 或非法值(如 `colorFrom`/`colorTo` 不支持的颜色、非法 `hardware` 字符串)。403 on `create_repo` 且 `space_hardware="zero-a10g"`:用户不在 PRO/Team/Enterprise,不能在创建时请求 ZeroGPU;修复:重试 `create_repo` 不带 `space_hardware`,在 README YAML 保留 `hardware: zero-a10g`,Space 会以 CPU 创建,之后可升级 PRO(自动转 ZeroGPU)或申请 community GPU grant(在 Space 硬件设置请求)。401/403 on `upload_file`:token 没有 write scope,重新向用户要 write-scoped token。
- 常见 build 失败(build 开始后):`load_lora_weights` 的 LoRA `weight_name` 不匹配,用 `list_repo_files` 查实际文件名;base model 是 gated 且 token 未设为 Space secret;ZeroGPU 未分配(用户不是 PRO),Space 回退 CPU 不可用;diffusers 版本不认识 pipeline class,在 `requirements.txt` pin 到 git diffusers;module load 时缺依赖,见 `requirements.txt` 推导规则,最常见是 Qwen-Image 文本编码器的 `torchvision` 这类传递依赖。若 build 失败,提出读日志并修复。
- Phase 6:声明 Space 完成并把 URL 给用户前,端到端跑一次。多个失败模式(错误 `weight_name`、错误 pipeline class、缺传递依赖、gated-base-model token 问题)会 build 绿但首次推理失败。`gradio` Python 包自带 CLI:`gradio info` 返回 endpoint signature,`gradio predict` 跑真实推理;二者随 Space 已需要的 `gradio` pip 依赖一起提供。
- Step 1 等待 build:`create_repo` 立即返回,但容器镜像仍在 build。轮询 `HfApi().get_space_runtime(repo_id).stage` 直到 `RUNNING`;若 `BUILD_ERROR`、`RUNTIME_ERROR`、`CONFIG_ERROR` 则 raise,日志 URL `https://huggingface.co/spaces/{repo_id}/logs/container`,每 15 秒 sleep。若 build 失败,抓容器日志、读 traceback、提出修复。不要在 Space 未运行时跑 `gradio info`,会挂起或 503。
- Step 2 验证 endpoint signature:`gradio info {repo_id} --token {hf_token}` 返回暴露的 endpoints 和参数类型。确认:(a) endpoint 存在(默认 `/predict`,Blocks Spaces 常有来自 Python 函数名的自定义名),(b) 参数顺序与 `app.py` 声明一致,(c) 文件类型参数显示 `"type": "filepath"`。若不对,用户 UI 可能仍看似正确但 API 调用失败,修复并重传。
- Step 3 跑一次真实推理:选最轻可行输入,LoRA 卡最简单示例或某个 `gr.Examples` 条目。private Spaces 传 `--token`。文件输入的 payload 用 `{"path": "...", "meta": {"_type": "gradio.FileData"}}`。示例:text-to-image 用 `gradio predict {repo_id} /predict '{"prompt": "...", "aspect_ratio": "1:1", ...}' --token $HF_TOKEN`;image-to-image 用 `gradio predict {repo_id} /predict '{"input_image": {"path": "/tmp/sample.jpg", "meta": {"_type": "gradio.FileData"}}, "prompt": "..."}' --token $HF_TOKEN`。若没有本地 I2I 样本图,从 LoRA repo 用 `hf_hub_download(repo_id, filename="example.png")` 拉取,或从 base model card 拉取。
- creative-mode Space 的 caveat:`gradio info` 和 `gradio predict` 只测 Python endpoint,不能测 `gr.HTML` 自定义 JS 是否工作。若 Space 用 creative mode(见 `references/creative-mode.md`),API smoke-test 通过后,**在浏览器打开 Space URL 验证一次交互**再分享。服务端绿但 JS 坏是这类最常见失败模式。
- Step 4 解释结果:成功且输出合理则完成,分享 URL;`HTTPError 503` / "Space is sleeping" 说明 Space 在步骤 1 和 3 之间休眠,唤醒 `api.restart_space(repo_id)` 后重试;推理错误提到 `weight_name`/`safetensors` 说明 `app.py` 的 LoRA 文件名与实际 repo 不符,重新检查 `list_repo_files`、修 `weight_name=`、重传 `app.py`;推理错误提到 missing pipeline class 或 attribute 说明 diffusers 版本太旧,把 `requirements.txt` 切到 `git+https://github.com/huggingface/diffusers` 并重传;module load 时 `ImportError` 说明缺依赖,加入 `requirements.txt` 并重传,runtime 日志 `/logs/run` 会指名缺的包;OOM 则降低默认分辨率或 step count,或选更小 base variant;Timeout/hangs 则增大 `@spaces.GPU(duration=...)` 并重传。
- smoke-test 的目的是把“用户发现并反馈”转成“你在分享前发现并修复”。不要因为 build 变绿就跳过;green-build-broken-inference 是非平凡 pipeline 的 Spaces 最常见失败模式。
- 避免:泛化的“所有 LoRA 一个 demo”模板;在 GPU function 内 lazy-load 模型;`torch.compile`;在 ZeroGPU 上 `cache_examples=True` 不带 `cache_mode="lazy"`;`gr.Examples(fn=…)` 的 `inputs` 未覆盖推理函数必需参数;把 LoRA 权重上传进 Space repo(应在 runtime 从 LoRA 自己的 Hub repo 拉取);最后才要 HF token 然后发现 LoRA 一直是 private;暴露每个 diffusers 旋钮(只选对该 LoRA 重要的 1–3 个控件);Space 发布后聊天回复长 preamble(URL 是交付物,收尾简短)。
适用边界 · 注意事项
- 当 LoRA 的 base model 不属于 Qwen-Image、LTX、Krea 2 等已支持家族,且用户不愿意按最接近模型类比迁移时,不适用。
- 当用户没有 Hugging Face 写权限 token,且无法/不愿处理私有或 gated LoRA、或不能使用 Hugging Face Spaces 时,不适用。
- 当目标不是发布 Hugging Face ZeroGPU Space(例如只要本地脚本、其他云平台、或无法使用 ZeroGPU/PRO)时,不适用。