Skip to main content

Q16: 在 LangChain 中,如何实现多模态(文本+图像)的问答系统?

在 LangChain 中,实现多模态(文本+图像)问答系统,核心思路是借助视觉语言模型(Vision Language Model, VLM) 的理解能力,并结合检索增强生成(RAG) 来引入外部知识。总的来说,有“简单直接”和“功能强大”两种主要的实现路径,具体的取舍可以参考下面的表格:

对比维度✅ 基础方法:直接输入🚀 高级方法:多模态 RAG
核心原理将图像(URL或Base64)直接放入模型提示中,让模型看图解答。为图像生成摘要或向量,建立知识库;检索相关图像后交给模型回答。
适用场景单张或少量的图像问答,即时分析。拥有大量或格式复杂(含图表、扫描件)的文档知识库,需要处理海量信息。
优势实现非常简单,低延迟,能处理长上下文。性能强大,不受模型上下文窗口限制,能处理海量复杂文档。
挑战受限于模型的上下文窗口大小,不适合处理大量图像的文档。架构相对复杂,有一定实现成本,需要处理图像的存取与检索。

✅ 基础方法:将图像直接输入模型

如果你的目标只是让模型理解一张或几张图像,最直接的方法就是将图像信息嵌入到提示(Prompt)中,发送给具备视觉能力的模型。

1. 准备工作:加载图像 LangChain 本身不提供图像加载器,你可以使用 PIL(Pillow)等通用工具先加载图像。对于 PDF 文档,你可以借助 pdf2image 等工具将其中的页面转为图像。

2. 构建提示:封装“文本+图像” 在 LangChain 中,这是通过在 HumanMessagecontent 字段中传递一个包含“文本”和“图像”内容的列表来实现的。这个列表在 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 GeminiNVIDIA's VLMOllama(通过特定集成)等,基本都遵循此模式调用。

🚀 高级方法:构建多模态 RAG 系统

当知识库包含大量文档(如成百上千页的 PDF、大量图表等),无法一次性全塞给模型时,多模态 RAG 是更优解。它的目标是将所有文档中的图像信息也纳入索引,实现高效检索。

架构概览

一个完整的多模态 RAG 流程,可以看作标准 RAG 的“升级版”,通常包含以下核心环节:

  • 📄 文档解析与预处理:从文档(如 PDF、PPT)中提取出其中的图像,可能还需要为图像生成摘要。
  • 🔍 向量化与索引构建:分别为图像摘要、图像本身(通过多模态嵌入模型)和文本块创建向量表示,并存入向量数据库。
  • 🔄 检索与生成:根据用户问题检索相关的文本块或图像;最后将这些检索到的上下文(文本+图像)一起输入到多模态模型中,生成最终答案。

⚙️ 分步实现

第一步:解析文档与图像处理 核心任务是从原始文档中分离出图像,并生成供检索和生成的素材。

  • 提取图像:使用库如 unstructuredpypdf,将 PDF 中的图像提取并保存。
  • 生成图像摘要:对于提取出的每张图像,调用一个多模态模型(如 GPT-4V),让它为图像生成一段详尽的文本描述。

第二步:向量化与存储 核心是将所有信息(文本块、图像摘要、图像本身)存入向量数据库,以便后续检索。

  • 文本与摘要向量化:使用文本嵌入模型(如 text-embedding-3-small)为文本块和图像摘要生成向量。
  • 图像向量化:使用多模态嵌入模型(如 CLIPAmazon 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)

# 检索结果中,就包含了相关的图像摘要或文本块。

第三步:检索与生成回答 当用户提问时,系统执行以下操作:

  1. 检索相关上下文:将用户的问题向量化,去向量数据库中检索。最佳实践是同时进行多种检索
    • 文本检索:在文本块库中搜索,找到包含相关信息的段落。
    • 多模态检索:使用多模态向量库,直接搜索相关图像。
  2. 组合与生成:将检索到的文本块、以及检索到的图像(通过 URL 或 Base64)组合起来,构建成符合 VLM 输入格式的 Prompt。
  3. 调用 VLM:将包含“原始问题”和“相关文本+图像”的多模态提示,发送给 VLM,让它生成最终答案。

💡 关键问题与最佳实践

在实际项目中选择方案时,可以参考下面的建议:

  • 关于图像“看懂”方式:有两种主流方法。一种是提取图像后,让 LLM 生成摘要再检索(准确率高但成本高);另一种是直接使用多模态嵌入模型(如CLIP)为图像生成向量,实现直接的“图-文”检索(效率高,但对模型能力要求也高)。
  • 关于模型选择:根据成本、延迟和效果综合决定。
    • 闭源商业模型:推荐 OpenAI GPT-4oGoogle Gemini
    • 开源/本地部署模型:推荐 NVIDIA NIM 微服务Meta Llama 3.2 Vision 等。
    • 中文场景方案:可选用 Qwen-VLDeepSeek-VL
  • 关于向量数据库:普通场景用 ChromaFAISS即可;如需要专业的、为多模态优化的数据库,可以考虑 WeaviateMilvus

多模态问答系统的核心在于整合图像与文本的检索与生成能力,你可以根据实际场景的复杂度和资源情况,灵活选用。