Q16: 在 LangChain 中,如何实现多模态(文本+图像)的问答系统?
在 LangChain 中,实现多模态(文本+图像)问答系统,核心思路是借助视觉语言模型(Vision Language Model, VLM) 的理解能力,并结合检索增强生成(RAG) 来引入外部知识。总的来说,有“简单直接”和“功能强大”两种主要的实现路径,具体的取舍可以参考下面的表格:
| 对比维度 | ✅ 基础方法:直接输入 | 🚀 高级方法:多模态 RAG |
|---|---|---|
| 核心原理 | 将图像(URL或Base64)直接放入模型提示中,让模型看图解答。 | 为图像生成摘要或向量,建立知识库;检索相关图像后交给模型回答。 |
| 适用场景 | 单张或少量的图像问答,即时分析。 | 拥有大量或格式复杂(含图表、扫描件)的文档知识库,需要处理海量信息。 |
| 优势 | 实现非常简单,低延迟,能处理长上下文。 | 性能强大,不受模型上下文窗口限制,能处理海量复杂文档。 |
| 挑战 | 受限于模型的上下文窗口大小,不适合处理大量图像的文档。 | 架构相对复杂,有一定实现成本,需要处理图像的存取与检索。 |
✅ 基础方法:将图像直接输入模型
如果你的目标只是让模型理解一张或几张图像,最直接的方法就是将图像信息嵌入到提示(Prompt)中,发送给具备视觉能力的模型。
1. 准备工作:加载图像
LangChain 本身不提供图像加载器,你可以使用 PIL(Pillow)等通用工具先加载图像。对于 PDF 文档,你可以借助 pdf2image 等工具将其中的页面转为图像。
2. 构建提示:封装“文本+图像”
在 LangChain 中,这是通过在 HumanMessage 的 content 字段中传递一个包含“文本”和“图像”内容的列表来实现的。这个列表在 LangChain v1 中被标准化为 content_blocks,支持 text 类型块和 image_url 类型块。
下面是使用 OpenAI GPT-4V(或 GPT-4o)的一个代码示例:
import base64
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
# 1. 加载图像并转为 Base64
with open("example_chart.png", "rb") as image_file:
image_base64 = base64.b64encode(image_file.read()).decode("utf-8")
# 2. 创建支持多模态的模型实例
model = ChatOpenAI(model="gpt-4o", max_tokens=1024)
# 3. 构建包含文本和图像的消息内容
message = HumanMessage(
content=[
{"type": "text", "text": "这张图表展示了什么趋势?请用中文简述。\n数据如图。"},
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{image_base64}"
}
},
]
)
# 4. 调用模型并获得回复
response = model.invoke([message])
print(response.content)
这种“文本+图像”的
content结构是 LangChain 的标准,主流的多模态模型如 Google's Gemini、NVIDIA's VLM、Ollama(通过特定集成)等,基本都遵循此模式调用。
🚀 高级方法:构建多模态 RAG 系统
当知识库包含大量文档(如成百上千页的 PDF、大量图表等),无法一次性全塞给模型时,多模态 RAG 是更优解。它的目标是将所有文档中的图像信息也纳入索引,实现高效检索。
架构概览
一个完整的多模态 RAG 流程,可以看作标准 RAG 的“升级版”,通常包含以下核心环节:
- 📄 文档解析与预处理:从文档(如 PDF、PPT)中提取出其中的图像,可能还需要为图像生成摘要。
- 🔍 向量化与索引构建:分别为图像摘要、图像本身(通过多模态嵌入模型)和文本块创建向量表示,并存入向量数据库。
- 🔄 检索与生成:根据用户问题检索相关的文本块或图像;最后将这些检索到的上下文(文本+图像)一起输入到多模态模型中,生成最终答案。
⚙️ 分步实现
第一步:解析文档与图像处理 核心任务是从原始文档中分离出图像,并生成供检索和生成的素材。
- 提取图像:使用库如
unstructured或pypdf,将 PDF 中的图像提取并保存。 - 生成图像摘要:对于提取出的每张图像,调用一个多模态模型(如 GPT-4V),让它为图像生成一段详尽的文本描述。
第二步:向量化与存储 核心是将所有信息(文本块、图像摘要、图像本身)存入向量数据库,以便后续检索。
- 文本与摘要向量化:使用文本嵌入模型(如
text-embedding-3-small)为文本块和图像摘要生成向量。 - 图像向量化:使用多模态嵌入模型(如
CLIP、Amazon Titan Multimodal Embeddings等),它能将图像和文本映射到同一个向量空间,实现“以文搜图”。 - 存储:将生成的向量和对应的原始内容(文本、图像摘要、图像存储路径)存入向量数据库(如 Chroma, FAISS, Pinecone 等)。
为了更直观地理解,可以看下这张示例代码,它展示了多模态 RAG 检索的核心逻辑:
from langchain_chroma import Chroma
from langchain_core.documents import Document
from your_multimodal_embeddings import get_multimodal_embedding
# 假设我们有文本块和图像摘要
docs = [Document(page_content="一段文本..."), Document(page_content="一张饼图的摘要...")]
# 使用文本嵌入模型
vectorstore = Chroma.from_documents(docs, text_embedding_model)
# 检索时,可以用文本或图像作为查询
query = "去年营收最高的季度是?"
# 1. 将查询向量化
query_embedding = text_embedding_model.embed_query(query)
# 2. 在向量库中搜索相关内容
related_docs = vectorstore.similarity_search_by_vector(query_embedding)
# 检索结果中,就包含了相关的图像摘要或文本块。
第三步:检索与生成回答 当用户提问时,系统执行以下操作:
- 检索相关上下文:将用户的问题向量化,去向量数据库中检索。最佳实践是同时进行多种检索:
- 文本检索:在文本块库中搜索,找到包含相关信息的段落。
- 多模态检索:使用多模态向量库,直接搜索相关图像。
- 组合与生成:将检索到的文本块、以及检索到的图像(通过 URL 或 Base64)组合起来,构建成符合 VLM 输入格式的 Prompt。
- 调用 VLM:将包含“原始问题”和“相关文本+图像”的多模态提示,发送给 VLM,让它生成最终答案。
💡 关键问题与最佳实践
在实际项目中选择方案时,可以参考下面的建议:
- 关于图像“看懂”方式:有两种主流方法。一种是提取图像后,让 LLM 生成摘要再检索(准确率高但成本高);另一种是直接使用多模态嵌入模型(如CLIP)为图像生成向量,实现直接的“图-文”检索(效率高,但对模型能力要求也高)。
- 关于模型选择:根据成本、延迟和效果综合决定。
- 闭源商业模型:推荐 OpenAI GPT-4o或 Google Gemini。
- 开源/本地部署模型:推荐 NVIDIA NIM 微服务、Meta Llama 3.2 Vision 等。
- 中文场景方案:可选用 Qwen-VL或 DeepSeek-VL。
- 关于向量数据库:普通场景用 Chroma 或 FAISS即可;如需要专业的、为多模态优化的数据库,可以考虑 Weaviate 或 Milvus。
多模态问答系统的核心在于整合图像与文本的检索与生成能力,你可以根据实际场景的复杂度和资源情况,灵活选用。