textgen 多模态(视觉)模型实战指南:从 mmproj 加载到视觉 API 的完整流程
本文基于 textgen 官方文档 [docs/Multimodal Tutorial.md](https://gitcode.com/GitHub_Trending/te/textgen/blob/79b46b80ec7ec98141c570dbc26f867fdfc39ead/docs/Multimodal Tutorial.md?utm_source=gitcode_repo_files) 整理并扩充,系统讲解如何在 textgen 中启用视觉理解能力:以 llama.cpp 加载「GGUF 模型 + mmproj 视觉投影文件」为主线,覆盖 ExLlamaV3 原生多模态加载方式,并给出可直接使用的 OpenAI 兼容视觉 API 调用示例。读完本文,你可以独立完成一个本地多模态模型的下载、加载、对话测试,以及通过 /v1/chat/completions 接口向模型传入图片。
一、textgen 中的两条多模态技术路线
textgen 支持两种让本地 LLM「看懂图片」的方式,二者对文件的要求不同:
| 路线 | 模型格式 | 额外文件要求 | 底层实现 |
|---|---|---|---|
| llama.cpp | GGUF | 需要配套的 mmproj-*.gguf 视觉投影文件 |
启动 llama-server 时附加 --mmproj 参数 |
| ExLlamaV3(非 HF 版) | EXL3 | 不需要任何额外文件 | 模型配置内置 vision_config,原生加载视觉组件 |
两条路线在代码中的入口可以清楚看到:
- llama.cpp 路线:modules/llama_cpp_server.py 中,当用户设置了 mmproj 时,会在启动 llama-server 的命令后追加
--mmproj <path>参数(见cmd += ["--mmproj", str(path)],位于第 479–489 行附近),由 llama.cpp 后端完成图片 embedding; - ExLlamaV3 路线:modules/exllamav3.py 在加载模型时检查
config.config_dict中是否包含vision_config字段,若有则通过Model.from_config(config, component="vision")单独加载视觉组件(第 185–199 行附近)。
两条路线最终都会把图片转换为嵌入/占位符注入生成流程,这一点在 modules/image_utils.py 和两个 loader 的 _process_images_for_generation 方法中实现。
二、快速上手:llama.cpp(GGUF + mmproj)方式
这是官方教程给出的标准流程,共 5 步。
1. 找到一个带视觉能力的高精度多模态模型
带视觉能力的 GGUF 模型通常会与一个 mmproj 文件一起上传到 Hugging Face。mmproj(multimodal projector)是把视觉编码器输出投影到语言模型词向量空间的连接层,必须与语言模型版本严格配套,混用不同模型家族的 mmproj 会得到无意义输出。
官方文档示例使用的是 unsloth/gemma-3-4b-it-GGUF 这个仓库,其中同时包含:
- 语言模型文件:
gemma-3-4b-it-Q4_K_S.gguf - 视觉投影文件:
mmproj-F16.gguf
2. 下载语言模型到 user_data/models
将示例仓库中的 gemma-3-4b-it-Q4_K_S.gguf 下载到 textgen/user_data/models 目录。textgen 启动时会扫描该目录列出所有可用模型(目录中的 占位文件 即提示模型应放在这里)。
3. 下载配套的 mmproj 文件到 user_data/mmproj
将 mmproj-F16.gguf 下载到 textgen/user_data/mmproj 目录,并重命名为 mmproj-gemma-3-4b-it-F16.gguf,便于识别对应关系。这个命名规范不是随意的:从源码看,modules/utils.py 中的 get_available_mmproj() 函数会列出 user_data/mmproj/ 下的全部文件,以及主模型目录中所有以 mmproj- 开头、以 .gguf 或 .bin 结尾的文件(is_mmproj_file 判断逻辑见第 207–209 行),这些信息直接构成 Model 页面上 "Multimodal (vision)" 下拉框的候选项。
4. 加载模型
- 启动 Web UI(可通过 server.py 或
cmd_linux.sh/start_linux.sh等脚本启动); - 进入 Model 标签页;
- 在 Model 下拉框中选择 GGUF 语言模型;
- 展开 "Multimodal (vision)" 折叠面板,在下拉菜单中选择上一步下载的 mmproj 文件;
- 点击 Load 加载。
该下拉框在代码中的定义位于 modules/ui_model_menu.py 第 96–99 行,其提示文字也说明了扫描范围:"Lists files placed in user_data/mmproj//, plus any mmproj-*.gguf files found in your main models folder"。
此外还有两个实用细节,来自 modules/models_settings.py 第 242–253 行的自动检测逻辑:
- mmproj 自动探测:当你使用 llama.cpp loader 且尚未为该模型保存过 mmproj 设置时,系统会调用
find_sibling_mmproj()检查模型所在目录中是否存在恰好一个mmproj-*文件,若存在会自动填充到state['mmproj']。也就是说,把语言模型和 mmproj 放在同一目录时可能无需手动选择; - 命令行方式:也可以不经过 UI,直接通过启动参数指定。modules/shared.py 第 99 行定义了
--mmproj参数("Path to the mmproj file for vision models"),例如python server.py --model path/to/model.gguf --mmproj mmproj-gemma-3-4b-it-F16.gguf。mmproj 路径解析支持三种写法:绝对/相对路径、user_data/mmproj/下的裸文件名、或主模型目录中的文件名(见 modules/llama_cpp_server.py 第 479–489 行)。
更多 llama.cpp loader 参数(gpu_layers、ctx_size、cache_type 等)可参考 [docs/04 - Model Tab.md](https://gitcode.com/GitHub_Trending/te/textgen/blob/79b46b80ec7ec98141c570dbc26f867fdfc39ead/docs/04 - Model Tab.md?utm_source=gitcode_repo_files)。
5. 发送带图片的消息
在 Chat 页点击输入框旁的 📎 图标选择本地图片作为附件,然后正常发送消息即可,模型会基于图片内容回复。从源码结构看,这条路径的数据流是:
- 前端把图片编码为 base64 的
image_attachments随消息提交,modules/chat.py 第 1213–1224 行将其收集到state['image_attachments']; - llama.cpp 后端在 modules/llama_cpp_server.py 的
_process_images_for_generation中把附件转成 PIL 图像,再通过convert_pil_to_base64打包进发给 llama-server 的multimodal_data字段(第 182–197 行); - 该文件中还有一处与上下文长度相关的细节:
IMAGE_TOKEN_COST_ESTIMATE = 600,即每张图按约 600 个 token 估算成本并计入last_prompt_token_count,用于提示/截断逻辑。因此图片数量过多时可能更快触及ctx_size上限。
三、使用 ExLlamaV3 加载多模态模型
多模态同样支持 ExLlamaV3 loader(文档中特指非 HF 的 ExLlamaV3,而非 ExLlamav3_HF)。这种方式最大的便利是:无需任何额外的 mmproj 文件,直接加载一个多模态 EXL3 模型并发送图片即可。
官方文档给出的可用模型示例包括 turboderp/gemma-3-27b-it-exl3 和 turboderp/Mistral-Small-3.1-24B-Instruct-2503-exl3(Hugging Face 同名仓库)。
从 modules/exllamav3.py 的实现看,其工作机制是:
- 加载阶段:若模型配置含
vision_config,先于主模型加载视觉组件(注释明确说明"Load vision and draft before the main model so autosplit"顺序),并缓存到self.vision_model; - 生成阶段:
_process_images_for_generation(第 256 行起)按优先级收集三类图片来源——WebUI 的image_attachments、OpenAI API 的raw_images、或消息列表中的image_url内容——调用vision_model.get_image_embeddings()生成图像嵌入,并以ie.text_alias作为占位符替换提示词中的图像标记,最终把embeddings传入生成请求。
也就是说,ExLlamaV3 路线的图片理解在本地进程内完成,而 llama.cpp 路线是把图片传给独立的 llama-server 进程处理。
四、多模态 API 示例(llama.cpp 与 ExLlamaV3 通用)
textgen 内置 OpenAI 兼容 API(默认端口 5000),视觉请求同样通过标准接口发送。完整示例见 [docs/12 - OpenAI API.md](https://gitcode.com/GitHub_Trending/te/textgen/blob/79b46b80ec7ec98141c570dbc26f867fdfc39ead/docs/12 - OpenAI API.md?utm_source=gitcode_repo_files) 的 "Multimodal/vision" 小节,这里摘录其核心用法。
方式一:/v1/chat/completions(官方推荐)
curl http://127.0.0.1:5000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "Please describe what you see in this image."},
{"type": "image_url", "image_url": {"url": "https://example.com/cat.png"}}
]
}
],
"temperature": 0.6,
"top_p": 0.95,
"top_k": 20
}'
content 是一个数组,按顺序混合 text 与 image_url 两种类型的内容块,与 OpenAI 的多模态消息格式一致。
方式二:/v1/completions
同样支持 messages 格式的混合内容数组,且支持一张消息中传多张图片(多个 image_url 块)。
Base64 图片格式
不想引用外部 URL 时,把 image_url 的 url 值替换为 Data URL 格式即可:
data:image/FORMAT;base64,BASE64_STRING
其中 FORMAT 是图片格式(png、jpeg、gif 等),BASE64_STRING 是图片的 base64 编码。这一解析逻辑正是 modules/image_utils.py 中 process_message_content() 与 decode_base64_image() 实现的:data:image/ 前缀走 base64 解码,http 前缀则通过 safe_get 拉取远程图片(超时 10 秒),其他格式会记录警告并跳过。
五、实践要点小结
- mmproj 必须与语言模型配套:不同模型家族、不同量化版本的 mmproj 不要混用,建议重命名时带上模型标识(如
mmproj-gemma-3-4b-it-F16.gguf); - 两个扫描目录:
user_data/mmproj/和主模型目录下的mmproj-*.gguf文件都会进入下拉框候选,同一模型目录中存在恰好一个 mmproj 时还会被自动选中; - 上下文预算:llama.cpp 路线下每张图按约 600 token 估算,多图对话要留意
ctx_size是否足够; - loader 选择:有 EXL3 多模态模型且希望零额外文件时选 ExLlamaV3;只有 GGUF 资源时走 llama.cpp + mmproj 路线;
- API 入口统一:无论哪种 loader,视觉请求都通过
/v1/chat/completions(推荐)或/v1/completions以image_url内容块发送,兼容标准 OpenAI 客户端。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00