起因
事情是这样的。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 不就行了?
curl -sL "https://api.github.com/repos/lllyasviel/Fooocus/tarball/main" | tar xzGitHub 直连不通但 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/fooocusimage_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 Clientclient = 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,搞定
最后
整个流程走下来,有几个有意思的点:
- 国内网络下 pull 开源项目的技巧——git clone 不通不妨试试 tar 包
- PyTorch 的体量——5.8G 的 venv 里,框架本身只占不到四分之一,剩下全是 CUDA 的二进制库
- AI 的插件体系——不算复杂,一个 ABC + 一个 register 函数就能接自定义后端
- AI 自己调自己的生图后端——这件事本身就挺 meta 的
以后生图就不花 API 钱了,让 3060 慢慢算。可能慢点,但便宜啊
后记:本来还想写个 DXVK 跑 AliceInCradle 的番外篇的,字数够了算了。别问怎么知道的。
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时
