基于多模态嵌入的 AI 搜索与 RAG 应用实现
企业数据常以多模态形式存在,传统文本嵌入无法有效处理图像。通过引入多模态嵌入模型,可直接对文字与图像生成统一向量,存入单一向量空间。文章展示了利用 LlamaIndex、Cohere 多模态嵌入模型及 Qdrant 向量库构建 RAG 应用的实例。该方法支持文本到图像、图像到图像的混合检索,简化了索引流程并降低了成本,提升了跨模态检索精度与响应质量,适用于企业智能搜索等场景。

企业数据常以多模态形式存在,传统文本嵌入无法有效处理图像。通过引入多模态嵌入模型,可直接对文字与图像生成统一向量,存入单一向量空间。文章展示了利用 LlamaIndex、Cohere 多模态嵌入模型及 Qdrant 向量库构建 RAG 应用的实例。该方法支持文本到图像、图像到图像的混合检索,简化了索引流程并降低了成本,提升了跨模态检索精度与响应质量,适用于企业智能搜索等场景。

在企业应用中,大量的数据以复杂的多模形态而存在,所以构建一个企业级的 AI 搜索或者 RAG(检索增强生成)应用时,多模态数据特别是图像数据的索引与检索就是一个无法回避也是较复杂的问题,而借助嵌入向量的语义检索是常见方法。本文将探讨在广为所知的文本嵌入基础上,如何借助更强大的多模态嵌入,更简洁的组合多形态的企业信息,实现跨模态的检索应用。
当前有一些针对 RAG 应用中多模态内容的处理方法,即:组合使用文本嵌入模型与多模态视觉大模型(VLM)。借助视觉大模型将图片做'文本化',生成图片的描述、摘要甚至关联的上下文,再借助文本嵌入模型实现这些信息的语义检索。大致的处理流程如下:
[图示:文档解析工具与视觉大模型将图片提取并理解成文本]
这里的解决方案本质上仍然是文本到文本的语义检索,其问题是:
索引过程较为繁琐,性能较差,成本较高
由于需要借助 VLM 实现多模态内容的理解与'文本化',如识别图片文字、生成内容摘要、甚至生成图片相关的上下文等,导致索引过程性能较低,且 VLM 的使用成本一般较高。
容易产生语义损失与偏离,检索精度不足
尽管多模态视觉大模型得到了长足的进步,但在将图片做'文本化'的过程中,仍可能存在一定的语义损失与偏离(受到图片质量、类型、甚至提示词的影响),导致后续的检索精度降低。
无法支持文本到图像、图像到图像的混合检索
这种方案在检索阶段是一种文本到文本的语义检索,而非直接将输入文本与图像连接(当然你可以借助元数据关联出原始图像),所以更无法支持图像到图像的检索。但在实际企业应用中往往存在这样的应用场景:
这些场景在现有的方案中无法得到有效的支持。
文本嵌入已经被普遍应用于大量的 AI 应用中,但它们的问题是无法处理图像数据。一种可行的解决方案是借助于逐渐成熟的多模态嵌入模型(Multimodal Embedding Model),能够直接对文字与图像生成嵌入,并在单一的向量库/向量空间中保存生成的嵌入向量数据:
[图示:多模态嵌入模型统一处理文本与图像]
这里的主要收益包括:
**更简单且直接的将多模态内容中的信息向量化,有更高的性能与更低的成本。**这有助于提取企业内部保存在图像中的大量信息的价值,可用来快速准确的检索多模态资产,如分析图表、产品图片、设计文档等,对于构建企业智能搜索或者 RAG 应用有重要意义。
在单一向量空间保存多种模态的嵌入,你无需在不同的库中保存不同模态的数据,简化了集成的复杂性。而在检索时,也无需考虑特定的模态,直接考虑数据背后的语义即可。
在 RAG 应用中,对知识库中图片信息的处理流程更简洁,有助于提高后续语义检索的精度与相关度。通过提供更相关的上下文(包括检索出的文本或图片内容)给 LLM,可以提高响应质量。
**支持更强大的混合模态搜索,而不再局限在文本到文本的搜索,更可以实现文本到图像或图像到图像的检索。**现在你可以更方便的允许客户使用产品特征或照片作为输入,以获得产品的全面信息。
现在,我们将尝试创建一个实际用例:**借助于多模态的嵌入模型,实现一个基于多模态知识的 RAG 应用。**总体流程如下:
[图示:多模态 RAG 应用总体流程]
用例将要展示的步骤包括:
**1. 解析输入文档并借助多模态嵌入模型做嵌入与索引。**核心方法与工具:
2. 进行多模态的检索测试:
3. 将检索到的文本与图像交给 VLM 生成最终响应。
这里借助更面向 RAG 应用的LlamaIndex框架来实现代码。
我们用一个简单的 word 文档做测试,其中包含了若干产品介绍信息,混合了文字与图片(由于 Cohere 的测试 API-Key 存在每分钟的 API 调用限制,因此测试时文档中的图片不宜太多):
[图示:测试用的 Word 文档示例]
这是关键的阶段,借助 Cohere 的 embed-multilingual-v3.0 这个强大的多模态嵌入模型,以及 LlamaIndex 中的多模态相关组件,可以很轻松的完成索引过程,简单描述代码的处理过程为:
借助 Llama_parse 提取原始文档中的文本与图片到临时目录 使用 LlamaIndex 组件加载临时目录中的文本与图片文件 加载后的 Document 对象用来嵌入与创建索引。在此过程中,框架会自动对文本做一定的分割后,并借助多模态嵌入模型统一生成文本与图像的嵌入,并存储到向量库。
核心代码如下:
# ...省略 import,以及相关的 API_KEY 设置...
# 定义文件路径
FILE_NAME = "xiaomi_products.docx"
IMAGES_DOWNLOAD_PATH = "parsed_data"
# 解析文档并提取文本和图像节点,llamaparse 的用法可参考官方文档
def parse_doc():
# 初始化 LlamaParse 解析器,设置输出格式为 markdown
parser = LlamaParse(
api_key=LLAMA_CLOUD_API_KEY,
language='ch_sim',
result_type="markdown",
)
# 解析文档并提取 JSON 数据
json_objs = parser.get_json_result(FILE_NAME)
json_list = json_objs[0]["pages"]
# 文本节点
text_nodes = [TextNode(text=page["text"], metadata={"page": page["page"]}) for page in json_list]
# 文本节点保存成 txt 文件
texts = [node.text for node in text_nodes]
all_text = "\n\n".join(texts)
# 如果目录不存在则创建
os.makedirs(IMAGES_DOWNLOAD_PATH, exist_ok=True)
with open(f"{IMAGES_DOWNLOAD_PATH}/extracted_texts.txt", "w", encoding="utf-8") as file:
file.write(all_text)
# 图像节点保存成图片文件
parser.get_images(json_objs, download_path=IMAGES_DOWNLOAD_PATH)
parse_doc()
# 在设置中配置嵌入模型,注意这里使用多模态的嵌入模型
Settings.embed_model = CohereEmbedding(api_key=COHERE_API_KEY,model_name="embed-multilingual-v3.0")
# 从临时目录加载文档,包括图片和文本文件
documents = SimpleDirectoryReader("parsed_data/",
required_exts=[".jpg", ".png", ".txt"],
exclude_hidden=).load_data()
client = qdrant_client.QdrantClient(path=)
vector_store = QdrantVectorStore(client=client, collection_name=)
storage_context = StorageContext.from_defaults(vector_store=vector_store, image_store=vector_store)
index = MultiModalVectorStoreIndex.from_documents(
documents,
storage_context=storage_context,
transformations=[TokenTextSplitter(separator=,chunk_size=)],
image_embed_model=Settings.embed_model,
)
()
成功完成这里的步骤后(注意 install 与 import 必要的库,以及有效的 API_key,并确保相关库都为最新版本),可以在指定的 parsed_data 目录下看到处理过的文本与图片,这些都已经被成功嵌入与索引:
[图示:处理后的文本与图片列表]
现在可以创建一个检索器来测试多模态的检索能力,这里重点测试文本到图片,以及图片到图片的测试。使用如下代码:
from llama_index.core.response.notebook_utils import display_source_node
from llama_index.core.schema import ImageNode
import matplotlib.pyplot as plt
from PIL import Image
# 一个辅助函数:显示检索到的图片信息
def display_images(file_list, grid_rows=2, grid_cols=3, limit=9):
plt.figure(figsize=(16, 9))
count = 0
for idx, file_path in enumerate(file_list):
if os.path.isfile(file_path) and count < limit:
img = Image.open(file_path)
plt.subplot(grid_rows, grid_cols, count + 1)
plt.imshow(img)
plt.axis('off')
count += 1
plt.tight_layout()
plt.show()
# 创建检索器,并进行检索
retriever_engine = index.as_retriever(similarity_top_k=3, image_similarity_top_k=2)
query = "一款可折叠屏幕的手机"
retrieval_results = retriever_engine.retrieve(query)
# 由于检索到的结果可能混合了文本与图片,这里进行分离与显示
retrieved_image = []
for res_node in retrieval_results:
if isinstance(res_node.node, ImageNode):
retrieved_image.append(res_node.node.metadata["file_path"])
else:
display_source_node(res_node, source_length=500)
display_images(retrieved_image)
我们查看以上代码检索的输出结果:
[图示:文本查询返回的图片与文本结果]
可以看到,检索到的图片与文本的确都是与输入信息相关,并进行了正确的排名。现在我们把输入修改成如下:
query = '一款白色的设备,有多个天线'
现在输出的检索结果如下:
[图示:白色设备查询结果]
然后,我们把输入信息修改成图片,来测试多模态嵌入模型的图像到图像的语义匹配与检索的能力,只需要修改上面代码中的两行代码即可:
query_image = 'router.png'
retrieval_results = retriever_engine.image_to_image_retrieve(query_image)
这里的 query_image 为自己准备的输入图片,以下展示检索的效果,上图为输入图片,下图为检索结果的输出:
[图示:图像到图像检索效果]
以上的检索测试表明:使用多模态嵌入模型创建的索引可以在文本到文本、文本到图像和图像到图像任务中提供了较好的检索体验。其最大区别是:
在单一向量空间实现了多种模态内容的嵌入
混合模态检索能力,从文本到图像,从图像到图像
现在我们创建一个 RAG 查询引擎,用来把检索到的文本与图片发送给 VLM,以生成最终响应结果。借助于 LlamaIndex 的 as_query_engine 可以快速的从向量索引创建查询引擎。使用如下代码:
import logging
from llama_index.core.schema import NodeWithScore, ImageNode, MetadataMode
from llama_index.core.prompts import PromptTemplate
from llama_index.multi_modal_llms.dashscope import (
DashScopeMultiModal,
DashScopeMultiModalModels,
)
# 定义带有明确指示的模板
qa_tmpl_str = (
"以下是上下文信息:\n"
"---------------------\n"
"{context_str}\n"
"---------------------\n"
"请仅基于提供的上下文和输入的图片 (不要使用先验知识) 回答问题。"
"请按以下格式回答:\n"
"Result: [基于上下文的回答]\n"
"---------------------\n"
"我的问题:{query_str}\n"
)
qa_tmpl = PromptTemplate(qa_tmpl_str)
# 使用多模态模型,以支持可能检索到的相关图片
multimodal_llm = OpenAIMultiModal(model="gpt-4o-mini", temperature=0.0, max_tokens=1024)
# 创建查询引擎,输入:多模态模型、检索的参数、提示模板;剩下的交给框架
query_engine = index.as_query_engine(
llm=multimodal_llm,
text_qa_template=qa_tmpl,
similarity_top_k=5,
image_similarity_top_k=2
)
result = query_engine.query("介绍小米的高性能游戏笔记本")
# 输出结果,打印出本地查询检索到的第一个图片
print(result)
display_images([result.metadata["image_nodes"][0].metadata["file_path"]])
输出如下,这里我们用代码显示了本次查询所引用的图片,这个图片由查询引擎从上面已经创建好的多模态向量库中检索得到:
[图示:RAG 生成结果及引用图片]
显然,借助于多模态嵌入模型,我们已经成功的将文本与图像嵌入在单一空间存放,并进行跨模态的统一检索,最后将检索出的文本与图片输入给多模态的 LLM 进行理解与输出。
[图示:多模态 RAG 完整链路总结]
以上演示了借助于强大的多模态嵌入模型(用的是 cohere 的 embed-multilingual-v3.0 模型),可以对企业数据中的文本与图像进行统一的嵌入表示、存放与检索,大大降低了构建复杂知识环境下的 RAG 应用的复杂性。
此外,在企业 AI 搜索、个性化推荐、图像内容审核等其他涉及多模态数据检索任务的场景下也具有较大的应用潜力,我们也期待看到更强大的多模态嵌入模型的出现。
在实际落地过程中,除了技术选型外,还需关注以下几点以确保系统稳定运行:
通过上述实践,企业可以更高效地挖掘非结构化数据价值,提升智能化服务水平。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online