1. 批量生成虚拟女友,卡点从来不是模型而是流程
如果你已经能用 Stable Diffusion 稳定出一张好看的虚拟女友图,下一步大概率会想:能不能一次跑几十张,把表情、服装、场景都换一遍?这个需求听起来简单,真正动手时会发现三个卡点:一是提示词每次都要手动改,改到后面自己都乱了;二是 API Key 和接口地址散落在不同工具里,换台机器就得重新配;三是批量任务跑起来之后,出图一致性没法验证,同一组参数两次结果差很多。
这篇内容就是围绕这三个卡点展开的。我会用 TaoToken 作为统一的 API 通道,把 Stable Diffusion 的接入配置、提示词模板设计、批量生成脚本编排串成一条可复制的流程。适合已经装好 SD WebUI 或准备用 API 方式调用的朋友,也适合想把 AI 绘画接进自己工作流的人。核心检索词就三个:Stable Diffusion、AI 绘画、批量生成。读完你能拿到一份 config.toml / settings.json 配置骨架、一张批量生成参数表,以及用固定种子加提示词矩阵验证出图一致性的具体动作。
先说清楚一件事:批量生成不是把同一句提示词复制 60 遍。真正有效的批量,是让变量可控。比如表情是一个变量,服装是一个变量,场景是一个变量,每次只动一个维度,其余维度锁死。这样你才能判断到底是哪个词在影响出图。下面从接入配置开始,一步步来。
2. TaoToken 前置:统一 Key 与 API 通道
2.1 为什么需要统一通道
Stable Diffusion 本身是本地跑的,但很多辅助环节需要调模型接口,比如提示词扩写、批量任务调度、出图后的质量筛选。如果每个环节都单独配一套 Key 和地址,维护成本会很高。TaoToken 的作用就是把这些调用收敛到一个 API 通道上,你只需要维护一份 Key,换工具时改配置就行。
官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基础地址是 https://taotoken.net/api ,注意 API 地址后面不加 UTM 参数。这两个地址建议先记下来,后面配置文件里会用到。
2.2 拿 Key 和确认模型入口
进入控制台后,在 API Keys 页面创建一个新 Key。创建时建议按用途命名,比如 sd-batch-prod,这样后面如果要做多环境区分,不会混。Key 只显示一次,复制后先存到本地环境变量里,不要直接写进代码仓库。
模型对话入口在 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite ,你可以在这里确认当前可用的模型列表。如果你后面要做长期编码或者 Agent 类的批量任务,可以看 Coding Plan 页面 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,它更适合持续性的任务编排。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,配置字段有疑问时以文档为准。
注意:Key 不要写进前端代码或公开的 notebook 里。批量脚本建议用环境变量读取,下面配置骨架里会体现这一点。
3. 可复制配置:config.toml 与 settings.json 骨架
3.1 config.toml 配置骨架
如果你用的是支持 TOML 的工具链,可以直接用下面这份骨架。重点是把 base_url 指向 TaoToken 的 API 地址,api_key 从环境变量读,模型名按你实际用的填。
# config.toml [api] base_url = "https://taotoken.net/api" api_key = "${TAOTOKEN_API_KEY}" timeout = 120 max_retries = 3 [generation] model = "your-model-name" default_steps = 28 default_cfg_scale = 7.0 default_sampler = "DPM++ 2M Karras" default_width = 512 default_height = 768 [batch] seed_mode = "fixed" output_dir = "./outputs/virtual_girl" prompt_file = "./prompts/matrix.csv" concurrency = 1这里 concurrency 先设成 1,因为本地显卡跑图本身就是串行的,设太高反而会爆显存。等流程跑通之后,如果你用的是远程推理服务,再考虑调高。
3.2 settings.json 配置骨架
如果你用的是 JSON 配置的工具,下面这份可以直接改。字段含义和上面 TOML 一一对应,注意 JSON 里不能写注释,我把说明放在表格里。
{ "api": { "base_url": "https://taotoken.net/api", "api_key_env": "TAOTOKEN_API_KEY", "timeout": 120 }, "generation": { "model": "your-model-name", "steps": 28, "cfg_scale": 7.0, "sampler": "DPM++ 2M Karras", "width": 512, "height": 768 }, "batch": { "seed_mode": "fixed", "output_dir": "./outputs/virtual_girl", "prompt_file": "./prompts/matrix.csv", "concurrency": 1 } }| 字段 | 作用 | 建议值 |
|---|---|---|
| base_url | API 基础地址 | https://taotoken.net/api |
| api_key_env | 环境变量名 | TAOTOKEN_API_KEY |
| seed_mode | 种子模式 | fixed 用于一致性验证 |
| concurrency | 并发数 | 本地显卡填 1 |
| steps | 采样步数 | 20 到 30 之间 |
| cfg_scale | 提示词引导强度 | 6 到 8 之间 |
配置写完之后,先在终端里导出环境变量,再跑一次最小请求确认通道是通的。
export TAOTOKEN_API_KEY="你的Key"4. 提示词模板设计与批量生成脚本编排
4.1 提示词矩阵怎么设计
批量生成的核心是把提示词拆成固定部分和变量部分。固定部分包括画质词、人物基础描述、镜头和构图;变量部分就是你要批量替换的维度,比如表情、服装、场景。下面这张表是我实际用过的矩阵结构,你可以直接照着建 CSV。
| 列名 | 类型 | 示例 | 说明 |
|---|---|---|---|
| id | 固定 | 001 | 任务编号 |
| expression | 变量 | smile | 表情词 |
| outfit | 变量 | black jacket | 服装词 |
| scene | 变量 | streets | 场景词 |
| seed | 固定 | 123456 | 固定种子 |
| weight | 固定 | 0.66 | LoRA 权重 |
表情词可以从这些里挑:smile、blink、surprise、cute、shyness、happiness、calmness、confidence、worry、boredom。不要一次全上,先选 5 到 8 个跑通,再扩。服装和场景同理,每次只动一个维度。
4.2 提示词拼接脚本
下面这段 Python 脚本读取 CSV,把固定模板和变量拼成完整提示词,然后逐条调用生成接口。注意 seed 是固定的,这样同一行参数两次跑出来的图应该高度接近,方便你验证一致性。
import csv import os import requests API_BASE = "https://taotoken.net/api" API_KEY = os.environ["TAOTOKEN_API_KEY"] TEMPLATE = ( "best quality, ultra high res, (photorealistic:1.4), 1girl, " "loose and oversized black jacket, white sports bra, " "(green yoga pants:1), (Kpop idol), (aegyo sal:1), " "(light brown short ponytail:1.2), looking at viewer, full body, " "{scene}, outdoors, (({expression}))" ) def build_prompt(row): return TEMPLATE.format( scene=row["scene"], expression=row["expression"] ) def generate(prompt, seed): payload = { "prompt": prompt, "seed": int(seed), "steps": 28, "cfg_scale": 7.0, "width": 512, "height": 768 } headers = {"Authorization": f"Bearer {API_KEY}"} resp = requests.post( f"{API_BASE}/v1/images/generations", json=payload, headers=headers, timeout=120 ) resp.raise_for_status() return resp.json() with open("./prompts/matrix.csv", newline="", encoding="utf-8") as f: reader = csv.DictReader(f) for row in reader: prompt = build_prompt(row) result = generate(prompt, row["seed"]) print(row["id"], row["expression"], "done")这段脚本跑起来之后,你会看到每个表情对应一张图,文件名建议用 id 加 expression 命名,方便后面比对。
4.3 固定种子与提示词矩阵验证一致性
一致性验证的做法是:同一行参数跑两次,比较两张图的差异。如果差异很小,说明种子和参数锁得住;如果差异很大,检查是不是采样器或步数被改了。下面这个对比表可以帮你记录。
| 任务 id | 表情 | 第一次种子 | 第二次种子 | 差异程度 | 结论 |
|---|---|---|---|---|---|
| 001 | smile | 123456 | 123456 | 低 | 一致 |
| 002 | worry | 123456 | 123456 | 低 | 一致 |
| 003 | boredom | 123456 | 654321 | 高 | 种子变了 |
只要种子不变,同一组提示词和参数应该稳定复现。如果你发现种子没变但结果差很多,优先检查 cfg_scale 和 sampler 有没有被默认值覆盖。
5. 验证请求与成功结果
5.1 最小请求验证
在跑批量之前,先用一条最小请求确认通道是通的。下面这段 curl 可以直接复制,把 Key 换成你自己的。
curl -X POST "https://taotoken.net/api/v1/images/generations" \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "best quality, 1girl, smile, streets, outdoors", "seed": 123456, "steps": 28, "cfg_scale": 7.0, "width": 512, "height": 768 }'如果返回里带有图片地址或 base64 数据,说明通道正常。如果返回 401,检查 Key 有没有导出成功;如果返回 404,检查 base_url 后面有没有多写路径。
5.2 批量跑通后的结果检查
批量跑完之后,建议按表情分组看一遍。重点看三件事:表情词有没有生效、人物基础特征有没有跑偏、场景词有没有被忽略。如果表情词权重不够,可以把 ((smile)) 再加一层括号,变成 (((smile))),权重会再乘 1.1。如果场景词被忽略,把它往前挪,放在提示词靠前的位置。
实测下来,固定种子加固定参数的情况下,同一行任务两次出图的构图和人物特征基本一致,表情差异也能稳定体现。这就说明你的批量流程是可控的,后面扩到 30 张、60 张只是时间问题。
6. 本篇常见错排查
6.1 报错 401 或 403
优先检查环境变量有没有生效。在终端里执行 echo $TAOTOKEN_API_KEY,如果输出为空,说明导出没成功。另一个常见原因是 Key 复制时带了空格,建议重新复制一次。如果确认 Key 没问题,检查请求头里的 Authorization 格式是不是 Bearer 加空格加 Key。
6.2 出图全部一样,表情没变化
这种情况通常是提示词拼接时变量没替换进去。检查 CSV 里的列名和脚本里的 row["expression"] 是否一致,大小写也要对。另一个原因是表情词权重太低,被画质词盖住了,把表情词加括号提权,或者往前挪。
6.3 批量跑到一半中断
本地显卡跑图时,显存占用会累积。如果跑到一半中断,先把 concurrency 降到 1,然后在每张图之间加一个短等待。如果你用的是远程服务,检查 timeout 是不是设得太短,120 秒一般够用,复杂参数可以调到 180。
6.4 种子固定但结果不一致
检查采样器和步数有没有被工具默认值覆盖。有些工具在批量模式下会忽略你传入的 sampler,改用默认值。解决办法是在配置文件里显式写死 sampler 和 steps,不要依赖默认。
6.5 图片保存路径找不到
output_dir 建议用绝对路径,相对路径在不同工作目录下会跑到别的地方。跑之前先手动创建目录,或者脚本里加一行 os.makedirs(output_dir, exist_ok=True)。
7. 接入与排障入口
如果你在配置 TaoToken 通道时遇到问题,先去 API Keys 页面确认 Key 状态,地址是 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。配置字段不确定的,对照接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 逐项核对。想先验证模型对话是否正常,可以用模型对话入口 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 发一条测试消息。如果你打算把批量生成做成长期任务,或者接进 Agent 工作流,Coding Plan 页面 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 里有更适合持续调用的方案说明。
最后补一个实用技巧:批量生成时,先把表情维度跑通,再加服装,最后加场景。每次只加一个变量,出问题容易定位。我试过一次性把三个维度全打开,结果排查了半天才发现是场景词权重太低被忽略了。慢一点,反而快。