1421 字
4 分钟
给 AI 安个本地生图
2026-05-07
2026-05-09

起因#

事情是这样的。AI 助手(咱一直在用的)虽然能生图,但走的都是云 API——OpenAI 或者 xAI 的 Grok,按张收费。我这新鲜的、刚到的 RTX 3060 在机箱里闲着也是闲着,不如让它干点正事

于是跟 AI 聊着聊着就决定:本地搭个 SDXL 生图后端,让 AI 自己调用,省 API token。

选 Fooocus 是因为它在 SDXL 生态里算是开箱即用体验最好的,Gradio 前端 + 一键启动,不用搓代码就能用。而且它底层用的 ldm_patched(ComfyUI 那套),有完整的显存控制

拉 代 码#

第一关就是 GitHub。国内网络,git clone 直接走 HTTPS 超时到天荒地老,换各种 ghproxy 镜像?代理?当时起不来,只能换方法了也是各种 reset by server,

最后发现 GitHub 的 API 倒是能通——api.github.com 返回 200——那直接下 tarball 不就行了?

lllyasviel
/
Fooocus
Waiting for api.github.com...
00K
0K
0K
Waiting...
curl -sL "https://api.github.com/repos/lllyasviel/Fooocus/tarball/main" | tar xz

GitHub 直连不通但 HTTP API 能通,这事儿本身就挺玄学的。可能是 git smart protocol 和普通 HTTP 走了不同的路由?懒得深究,能下就行

虚拟环境,一个老生常谈的话题#

Fooocus 的 requirements_versions.txt 里写了 Python 3.10。Arch 的系统 Python 已经是 3.12 了,还好系统里装了 python310,建 venv:

python3.10 -m venv venv

然后装依赖。PyTorch + CUDA 全家桶,又是从国外源拉。清华 PyPI 镜像 pypi.tuna.tsinghua.edu.cn 救了一命

这个装完一看——好家伙,一个 venv 占了 5.8G。拆开看:PyTorch 本体 1.2G,CUDA 工具链(cublas、cudnn、cusolver…)2.7G,其他依赖 1.9G

pip 版的 PyTorch 是自包含的,不管系统有没有 CUDA 都自己带一份。好处是去哪都能跑,坏处是 SSD 肉疼

显存,一个不那么老生常谈的话题#

3060 有 12G VRAM,但这不是能全用的——一个 SDXL 模型裸跑就要 6-7G。而且我还要同时跑游戏(Terraria 啊 AliceInCradle 啊)和 Ollama 的小模型、偶尔还要上点压力

所以得压

Fooocus 底层基于 ldm_patched(ComfyUI 的执行引擎),提供了几个有用的参数:

--always-low-vram # 模型按需加载,不用的部分卸出显存
--all-in-fp16 # 半精度,权重直接减半
--vae-in-cpu # VAE 解码器放 CPU
--attention-split # 分块注意力计算

这四行组合拳理论上能把 SDXL 压在 3.5-4.5G 左右。实测跑起来再看吧,12G 物理显存有大把余量,超了也不要紧——CUDA OOM 只会崩掉吃最多的那个进程,不会死机

插件才是正经活#

Fooocus 本身只是一个 Gradio Web 应用。要让 AI 能调用它,需要写一个 image_gen 插件

AI 的插件体系还挺干净的。做 image_gen 提供商只需要继承 ImageGenProvider 这个抽象基类,实现一个 generate() 方法:

class FooocusImageGenProvider(ImageGenProvider):
@property
def name(self): return "fooocus"
def generate(self, prompt, aspect_ratio, **kwargs):
# 1. 检查 Fooocus 是否在跑
# 2. 调用 gradio_client 给它发任务
# 3. 把生成的图片拷到缓存目录
# 4. 返回路径

注册也很简单:

def register(ctx):
ctx.register_image_gen_provider(FooocusImageGenProvider())

放到 ~/.hermes/plugins/image_gen/fooocus/ 里,在 config.yaml 里启用:

plugins:
enabled:
- image_gen/fooocus
image_gen:
provider: fooocus

一次 /reset,AI 就能用本地生图代替云 API 了

关于手动启停的哲学问题

最初的版本写了自动启动——检测到 Fooocus 没跑就自动执行 run.sh 拉起来。结果用户说:“不行,显存我要自己控制。”

确实,让 AI 自己决定什么时候启动、什么时候停一个吃 GPU 的服务,听起来有点毛骨悚然。于是改成了纯手动——你不跑 fooocus.sh,生图就会礼貌地告诉你”服务没在跑,手动起一下”

对,我写这段的时候想起来那个关于”AI 能不能决定自己开服务”的问题。暂时还是让人来做这个决定吧

gradio_client 的存在#

AI 和 Fooocus 之间的通信走的是 Gradio 的 API。Fooocus 启动后是一个 Gradio Web 应用,有 /api/predict/ 端点可以用

最开始我写了一个 HTTP 调用,但要解析 Gradio 的 fn_index,还得猜生成函数的参数顺序——太脆了

后来发现 gradio_client 这个库——Gradio 官方出的 Python 客户端——能直接按函数名调用:

from gradio_client import Client
client = Client("http://127.0.0.1:7865")
result = client.predict(prompt, negative_prompt, ..., api_name="/generate")

省了猜 index 的破事,而且它在 Fooocus 的 requirements_versions.txt 里已经作为 Gradio 的依赖装好了。现成的

从 Fooocus 到 ComfyUI#

Fooocus 的 Gradio API 用了一段时间,发现 gradio_client 调起来还是不太顺手——参数顺序、默认值、返回格式都得靠猜,稍微调个采样器或 CFG 就要翻前端源码。而且 Fooocus 的定制空间有限,想换模型改参数都受它前端限制

后来试了 ComfyUI。虽然多了个拖节点的界面,但它的 REST API 比 Gradio 干净太多——直接 POST 一个 prompt JSON 过去就行,参数完全可控,想改什么改什么。而且 ComfyUI 的 ldm_patched 后端跟 Fooocus 同源,显存控制那套参数照搬就能用

切换成本很低:插件里把调用从 gradio_client 换成 ComfyUI 的 /prompt 端点,config 端口从 7865 改成 8188,搞定

comfyanonymous
/
ComfyUI
Waiting for api.github.com...
00K
0K
0K
Waiting...

最后#

整个流程走下来,有几个有意思的点:

  1. 国内网络下 pull 开源项目的技巧——git clone 不通不妨试试 tar 包
  2. PyTorch 的体量——5.8G 的 venv 里,框架本身只占不到四分之一,剩下全是 CUDA 的二进制库
  3. AI 的插件体系——不算复杂,一个 ABC + 一个 register 函数就能接自定义后端
  4. AI 自己调自己的生图后端——这件事本身就挺 meta 的

以后生图就不花 API 钱了,让 3060 慢慢算。可能慢点,但便宜啊


后记:本来还想写个 DXVK 跑 AliceInCradle 的番外篇的,字数够了算了。别问怎么知道的。

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

给 AI 安个本地生图
https://text.lilystar.cn/posts/ai-picture/
作者
Lily
发布于
2026-05-07
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录