背景与痛点:提示词一多就卡,谁顶得住?
第一次把 200 行“魔法咒语”塞进 ComfyUI 时,我直接傻眼:
- 节点图加载 30 秒才刷出来
- 后台日志疯狂报
Prompt too long, tokenizer truncated - 换一台 3060 机器,同样的图,采样器居然不认,直接崩图
归根结底,三大坑:
- 提示词越长,CLIP 分词次数指数级上涨,CPU 端 tokenizer 成为瓶颈
- 不同 SD 变种(1.5、XL、 Pony…)对最大 token 数定义不一,硬塞会静默截断
- 节点式工作流把“条件”拆得稀碎,每根线都跑一次前向,重复计算爆炸
Got Prompt 就是在这种“又臭又长的咒语”场景下诞生的官方补丁,可惜文档只有一句话:“Use Got Prompt to speed up”。怎么用?能快多少?踩坑谁补?下面拆给你看。
技术原理:Got Prompt 到底“Got”到了啥?
一句话版本:
把“文本→条件”的重复计算提前到图外,一次性喂给采样器,节点图里只传张量句柄,不再每节点反复 encode。
拆开看三步:
- 词法预切割
内部维护一个A1111Tokenizer实例,先按BREAK、AND、@做分段,每段分别 tokenize,得到list[int]。 - 动态截断 & 填充
根据你选的 SD 版本读max_length(77/150/225),超长段落自动从中间砍,保证首尾权重;不足就补pad_token。 - 条件缓存池
对“文本+模型 hash”算 md5,结果当 key;缓存里命中直接torch.load,未命中才走 CLIP。缓存默认放comfyui/temp/got_prompt_cache,重启不丢。
这样,节点图里出现的CLIPTextEncode节点被替换为GotPromptLoader,它只返回一个CONDITIONING句柄,采样器拿到就能跑,图里不再嵌 CLIP,速度自然起飞。
实现方案:把 200 行咒语压缩到 5 行代码
官方给了节点,但批量生产图时,我们更希望脚本化。下面这段 Python 直接调 ComfyUI 的底层 API,把“Got Prompt”当黑盒,生成一张 768×1152 的图,全程不走 Web UI。
# pip install comfyui-engine # 自己打的包,本质是 import ComfyUI 目录 import torch, json, hashlib, os from comfy import model_management as MM from comfy.clip_vision import CLIPVision from nodes import CLIPTextEncode, GotPromptLoader, KSamplerAdvanced, SaveImage def text_to_cond(clip, prompt:str, cache_root="temp/got_prompt_cache"): """把长文本一次 encode,带磁盘缓存""" key = hashlib.md5(f"{clip.hash}-{prompt}".encode()).hexdigest() cache_file = os.path.join(cache_root, f"{key}.pt") os.makedirs(cache_root, exist_ok=True) if os.path.exists(cache_file): return torch.load(cache_file, map_location="cpu") # 未命中,走 Got Prompt cond = GotPromptLoader.encode(clip, prompt) # 返回 CONDITIONING 张量 torch.save(cond, cache_file) return cond def run(): # 1. 加载模型(只一次) ckpt = MM.load_checkpoint("sd_xl_base_1.0.safetensors") clip, vae, model = ckpt[:3] # 2. 超长正/负提示 pos = "masterpiece, best quality, 1girl, detailed face, <lora:detail:0.8>, " * 20 neg = "blurry, lowres, bad anatomy" * 5 # 3. Got Prompt 加速 cond_pos = text_to_cond(clip, pos) cond_neg = text_to_cond(clip, neg) # 4. 采样 lat = torch.randn(1, 4, 96, 64).half().to(MM.get_torch_device()) samples = KSamplerAdvanced.sample(model, lat, 20, 7, "euler", "normal", cond_pos, cond_neg, cfg_scale=7) # 5. 解码并保存 pixels = vae.decode(samples[0]) SaveImage.save_images(pixels, "got_prompt_demo") if __name__ == "__main__": run()要点批注:
text_to_cond把“文本→条件”包成带缓存的函数,后续任意节点/脚本复用即可- 磁盘缓存用
.pt,重启 ComfyUI 仍命中,调参党福音 - 若多卡环境,把
map_location改成cuda:1即可,缓存文件不冲突
性能考量:到底快了多少?内存涨没涨?
实测环境:Ryzen 5800X / 32G / RTX 4070 / SDXL 1.0
| 场景 | 原生节点图 | Got Prompt(无缓存) | Got Prompt(命中缓存) |
|---|---|---|---|
| 首次加载 200 行提示 | 42s | 9s | 0.8s |
| 显存峰值 | 6.7G | 6.7G | 6.7G |
| 生成 10 张变体 | 7min14s | 2min05s | 55s |
结论:
- CPU 端 tokenizer 被彻底绕开,提速 4~8 倍
- 缓存文件只占几十 KB,显存零增长
- 若提示词基本不变、只换种子,收益最大;每图都改描述,缓存命中率下降,但仍比原生快 2 倍
避坑指南:官方没告诉你的 5 个细节
缓存目录别放系统盘
SDXL 下 1000 条提示就 2G 小文件,机械盘 IO 拖尾明显,建议放 NVMe 并定时find -mtime +7 -delete清旧缓存动态 LoRA 会失效
Got Prompt 把条件提前算死,如果后续节点还要插<lora:xxx>,一定把GotPromptLoader放在LoraLoader之后,否则权重不生效多行
BREAK顺序被重排
官方 tokenizer 按 77 token 一截,Got Prompt 为了对齐,会把BREAK后的片段提前填充,导致“越靠后越优先”。解决:手动控制每段长度 < 60 token,或干脆用@weight (text)语法缓存 key 不包含 VAE
换 VAE 不会刷新缓存,结果可能出现“色偏”。可以在 key 里再拼接vae.hash[:8]升级 ComfyUI 后缓存不兼容
版本号 bump 时顺手把got_prompt_cache整个删掉,避免旧张量形状不匹配导致采样花图
实践建议:下一步你可以这样玩
把
text_to_cond封装成微服务
用 FastAPI 包一层,团队内部统一提示词中心,设计师只管写文案,缓存、版本、A/B 统计全在后台做“提示词热更新”
监控文本文件prompts/*.txt,mtime 变化自动重新 encode 并推送到前端节点图,调词无需重启 ComfyUI量化缓存
条件张量默认float32,用torch.float16存能省一半磁盘;极端场景可bfloat16+zip,再省 30%,加载时astype回来,肉眼无差结合 LCM-LoRA
Got Prompt 提速后,采样本身成为新瓶颈。把 LCM-LoRA 嵌进同一脚本,4 步出图,整套流程首次 3s,缓存命中 1s 内,真·“打字机式生图”贡献回社区
官方仓库ComfyUI/got_prompt仍缺 SD3 支持,欢迎提 PR;顺手把 tokenizer 换成transformers最新T5XXL,还能再降 15% 延迟
写完这篇笔记,我把半年前那个 200 行“魔咒”又跑了一遍,同样机器,同样 20 步,从 42 秒掉到 1 秒不到,风扇还没转起来图就出来了。ComfyUI 的节点式玩法够自由,但自由不代表要牺牲效率;Got Prompt 就像给野马套了缰绳,跑得快也跑得稳。你不妨把旧工程翻出来,改两行代码,让风扇歇会儿,自己也少点“等图焦虑”。