【大模型12步学习路线 · 第12步 · ②代码篇】Qwen3-VL + ColQwen2.5 + Qdrant 多模态 RAG 全栈实战
【大模型12步学习路线 · 第12步 · ②代码篇】Qwen3-VL + ColQwen2.5 + Qdrant 多模态 RAG 全栈实战
系列定位:「大模型正确学习顺序」12 步系列第 12 步 · 多模态的 ②代码篇。
前置阅读:①原理篇 —— VLM 全景 + Multimodal RAG 三大架构。
本篇产出:Qwen3-VL-8B 视觉问答上手 + ColQwen2.5 + Qdrant 完整多模态 RAG pipeline + vLLM/SGLang 多模态部署 + LiteLLM Proxy 多模态路由 + 存储优化。
🚀 0. 环境准备
# 多模态推理引擎pipinstall-Uvllm# vLLM v0.7+ 原生支持 Qwen3-VL / Qwen2.5-VL# ColPali / ColQwen 系列pipinstall-Ucolpali-engine[interpretability]# 官方包pipinstall-Usentence-transformers byaldi# ColPali wrapper# 向量库pipinstallqdrant-client# PDF 处理pipinstallpdf2image PyMuPDF pillow🖼️ 1. Qwen3-VL-8B 5 分钟启动(本地视觉问答)
1.1 用 vLLM 启动 Qwen3-VL
vllm serve Qwen/Qwen3-VL-8B-Instruct\--host0.0.0.0--port8000\--max-model-len16384\--gpu-memory-utilization0.9\--limit-mm-per-prompt'{"image": 5}'\--enable-prefix-caching关键参数:
--limit-mm-per-prompt '{"image": 5}'—— 每个 prompt 最多 5 张图(防 token 爆炸);--enable-prefix-caching—— Veri-Copilot 必开;- 用 GPTQ-Int4 量化版能进一步减半内存:
vllm serve Qwen/Qwen3-VL-8B-Instruct-AWQ\--quantizationawq...
1.2 OpenAI 协议调用(传图)
importbase64fromopenaiimportOpenAI client=OpenAI(base_url="http://localhost:8000/v1",api_key="EMPTY")# 读图为 base64withopen("axi4_timing_diagram.png","rb")asf:img_b64=base64.b64encode(f.read()).decode()resp=client.chat.completions.create(model="Qwen/Qwen3-VL-8B-Instruct",messages=[{"role":"user","content":[{"type":"image_url","image_url":{"url":f"data:image/png;base64,{img_b64}"}},{"type":"text","text":"请描述这张时序图。AWVALID 拉高后,AWREADY 最多可以延迟几个时钟周期?"},],}],)print(resp.choices[0].message.content)实测:RTX 4090,Qwen3-VL-8B,一张时序图 + 简短问题 → ~2 秒返回回答。
🧬 2. ColQwen2.5 部署:Page-as-Image 多模态检索
2.1 加载 ColQwen2.5 模型
# embed_pages.pyimporttorchfromcolpali_engine.modelsimportColQwen2_5,ColQwen2_5_Processor device="cuda"iftorch.cuda.is_available()else"cpu"# 加载 ColQwen2.5(基于 Qwen2.5-VL)model=ColQwen2_5.from_pretrained("vidore/colqwen2.5-v0.2",torch_dtype=torch.bfloat16,device_map=device,).eval()processor=ColQwen2_5_Processor.from_pretrained("vidore/colqwen2.5-v0.2")2.2 PDF → 多 patch embeddings
# index_pdf.pyfrompdf2imageimportconvert_from_pathimporttorchdefindex_pdf(pdf_path:str,page_dpi:int=200):# === 1) PDF → 图像列表 ===images=convert_from_path(pdf_path,dpi=page_dpi)# PIL Imagesprint(f"PDF has{