使用GPT-4o视觉模态优化检索增强生成
技术背景
在现实世界的文档(如报告、手册、学术论文)中,信息往往以图像、图表和表格等形式呈现,这些视觉元素对于理解内容至关重要。传统RAG系统仅处理文本,导致视觉信息丢失,回答不完整或不准确。例如,世界银行年度报告中的财务数据图表、工程图纸等,仅靠文本描述难以准确传达。因此,需要一种方法将视觉内容纳入RAG流程。本教程通过利用GPT-4o的视觉模态,将页面图像直接作为上下文,弥补了文本提取的不足。但需注意,视觉模态资源密集,延迟和成本较高,应仅在文本方法效果不佳时使用。
核心原理
核心原理是双通道检索增强:文本通道和视觉通道。首先,将PDF文档解析为页面,并利用GPT-4o视觉模态从页面图像中提取文本和视觉描述,生成包含标记的页面文本。然后,为每页文本生成嵌入向量,并上传至Pinecone向量数据库,同时存储元数据(如页码、图像路径、视觉标记)。在查询时,将用户问题嵌入,通过余弦相似度检索最相关的页面。如果页面标记为包含视觉内容,则可以选择将页面图像作为上下文传递给GPT-4o,否则仅使用文本。这样,模型能够同时利用文本和视觉信息,提高回答的准确性。
架构分析
系统架构分为四个主要组件:1) 文档处理模块:负责下载PDF、分页、转换为图像,并调用GPT-4o视觉模态提取文本和视觉描述,生成DataFrame。2) 嵌入生成模块:使用OpenAI的text-embedding-3-large模型为每页文本生成3072维嵌入,并添加视觉标记。3) 向量存储模块:使用Pinecone作为向量数据库,存储嵌入和元数据,支持高效的相似性搜索。4) 查询响应模块:接收用户问题,生成嵌入,查询Pinecone获取相关页面,根据视觉标记决定是否包含图像,最后调用GPT-4o生成回答。设计决策包括:使用Pinecone serverless索引,维度与嵌入模型匹配,度量选择余弦相似度;元数据设计支持过滤和图像路径存储;视觉标记用于动态选择上下文类型。
完整实战教程
使用GPT-4o视觉模态优化检索增强生成
在实现检索增强生成(RAG)时,处理包含大量图像、图形和表格的文档会带来独特的挑战。传统的RAG模型在文本数据上表现出色,但当视觉元素在传达信息中起关键作用时,往往效果不佳。在本教程中,我们通过利用视觉模态来提取和解释视觉内容,从而弥合这一差距,确保生成的响应尽可能信息丰富且准确。
我们的方法是将文档解析为图像,并利用元数据标记来识别包含图像、图形和表格的页面。当语义搜索检索到这样的页面时,我们将页面图像传递给视觉模型,而不是仅依赖文本。这种方法增强了模型理解并回答与视觉数据相关的用户查询的能力。
在本教程中,我们将探索并演示以下关键概念:
##### 1. 使用Pinecone设置向量存储:
- 学习如何初始化和配置Pinecone以高效存储向量嵌入。
##### 2. 解析PDF并提取视觉信息:
- 发现将PDF页面转换为图像的技术。
- 使用GPT-4o视觉模态从包含图像、图形或表格的页面中提取文本信息。
##### 3. 生成嵌入:
- 利用嵌入模型创建文本数据的向量表示。
- 标记具有视觉内容的页面,以便在向量存储中设置元数据标志,并检索图像以通过视觉模态传递给GPT-4o。
##### 4. 将嵌入上传到Pinecone:
- 将这些嵌入上传到Pinecone进行存储和检索。
##### 5. 对相关页面执行语义搜索:
- 对页面文本实现语义搜索,以找到最匹配用户查询的页面。
- 将匹配的页面文本作为上下文提供给GPT-4o,以回答用户的查询。
##### 6. 处理具有视觉内容的页面(可选步骤):
- 学习如何使用GPT-4o视觉模态传递图像,以提供额外上下文进行问答。
- 理解此过程如何提高涉及视觉数据的响应的准确性。
通过本教程,您将深入理解如何实现能够处理并解释具有复杂视觉元素的文档的RAG系统。这些知识将使您能够构建提供更丰富、更准确信息的AI解决方案,提升用户满意度和参与度。
我们将使用世界银行报告 - 一个更好的银行,为了更美好的世界:2024年年度报告 来说明这些概念,因为该文档混合了图像、表格和图形数据。
请记住,使用视觉模态是资源密集型的,会导致延迟和成本增加。建议仅在纯文本提取方法在评估基准上表现不佳的情况下使用视觉模态。有了这个背景,让我们开始吧。
步骤 1:使用 Pinecone 设置向量存储
在本节中,我们将使用 Pinecone 设置一个向量存储,以高效地存储和管理我们的嵌入。Pinecone 是一个针对高维向量数据优化的向量数据库,对于语义搜索和相似性匹配等任务至关重要。
先决条件
- 按照此处的说明注册 Pinecone 并获取 API 密钥:Pinecone 数据库快速入门
- 使用
pip install "pinecone[grpc]"安装 Pinecone SDK。gRPC(gRPC 远程过程调用)是一个高性能、开源的通用 RPC 框架,使用 HTTP/2 进行传输,以 Protocol Buffers(protobuf)作为接口定义语言,并支持分布式系统中的客户端-服务器通信。它旨在使服务间通信更高效,适用于微服务架构。
安全存储 API 密钥
- 出于安全目的,将 API 密钥存储在项目目录中的 .env 文件中,如下所示:
- 安装
pip install python-dotenv以从 .env 文件读取 API 密钥。
PINECONE_API_KEY=your-api-key-here。
创建 Pinecone 索引
我们将使用 create_index 函数在 Pinecone 上初始化我们的嵌入数据库。有两个关键参数需要考虑:
- 维度:此参数必须与所选模型生成的嵌入维度匹配。例如,OpenAI 的 text-embedding-ada-002 模型生成 1536 维的嵌入,而 text-embedding-3-large 模型生成 3072 维的嵌入。我们将使用 text-embedding-3-large 模型,因此将维度设置为 3072。
- 度量:距离度量决定了向量之间相似度的计算方式。Pinecone 支持多种度量,包括余弦、点积和欧几里得。对于本教程,我们将使用余弦相似度度量。您可以在 Pinecone 距离度量文档 中了解更多关于距离度量的信息。
import os
import time
# Import the Pinecone library
from pinecone.grpc import PineconeGRPC as Pinecone
from pinecone import ServerlessSpec
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv("PINECONE_API_KEY")
# Initialize a Pinecone client with your API key
pc = Pinecone(api_key)
# Create a serverless index
index_name = "my-test-index"
if not pc.has_index(index_name):
pc.create_index(
name=index_name,
dimension=3072,
metric="cosine",
spec=ServerlessSpec(
cloud='aws',
region='us-east-1'
)
)
# Wait for the index to be ready
while not pc.describe_index(index_name).status['ready']:
time.sleep(1)
导航到 Pinecone 上的索引列表,你应该能够在索引列表中看到 my-test-index。
第2步:解析PDF并提取视觉信息:
在本节中,我们将解析PDF文档——世界银行报告《为更美好世界打造更好的银行:2024年年度报告》,并提取文本和视觉信息,例如描述图像、图形和表格。该过程包括三个主要步骤:
- 将PDF解析为单独的页面: 我们将PDF拆分为单独的页面,以便于处理。
- 将PDF页面转换为图像: 这使视觉GPT-4o能够将页面作为图像进行分析。
- 处理图像和表格: 向GPT-4o提供指令,以提取文本,并描述文档中的图像、图形或表格。
先决条件
在继续之前,请确保您已安装以下软件包。同时确保您的OpenAI API密钥已设置为环境变量。您可能还需要安装Poppler以进行PDF渲染。
pip install PyPDF2 pdf2image pytesseract pandas tqdm
步骤分解:
1. 下载并分块PDF:
chunk_document函数从提供的URL下载PDF,并使用PyPDF2将其拆分为单独的页面。- 每个页面作为单独的PDF字节流存储在列表中。
2. 将PDF页面转换为图像:
convert_page_to_image函数接受单个页面的PDF字节,并使用pdf2image将其转换为图像。- 图像保存在本地的'images'目录中,以供进一步处理。
3. 使用GPT-4o视觉模态提取文本:
extract_text_from_image函数使用GPT-4o视觉能力从页面图像中提取文本。- 这种方法甚至可以从扫描文档中提取文本信息。
- 请注意,此模态资源密集,因此具有更高的延迟和相关成本。
4. 处理整个文档:
process_document函数协调每个页面的处理。- 它使用进度条(tqdm)显示处理状态。
- 从每个页面提取的信息被收集到列表中,然后转换为Pandas DataFrame。
import base64
import requests
import os
import pandas as pd
from PyPDF2 import PdfReader, PdfWriter
from pdf2image import convert_from_bytes
from io import BytesIO
from openai import OpenAI
from tqdm import tqdm
# Link to the document we will use as the example
document_to_parse = "https://documents1.worldbank.org/curated/en/099101824180532047/pdf/BOSIB13bdde89d07f1b3711dd8e86adb477.pdf"
# OpenAI client
oai_client = OpenAI()
# Chunk the PDF document into single page chunks
def chunk_document(document_url):
# Download the PDF document
response = requests.get(document_url)
pdf_data = response.content
# Read the PDF data using PyPDF2
pdf_reader = PdfReader(BytesIO(pdf_data))
page_chunks = []
for page_number, page in enumerate(pdf_reader.pages, start=1):
pdf_writer = PdfWriter()
pdf_writer.add_page(page)
pdf_bytes_io = BytesIO()
pdf_writer.write(pdf_bytes_io)
pdf_bytes_io.seek(0)
pdf_bytes = pdf_bytes_io.read()
page_chunk = {
'pageNumber': page_number,
'pdfBytes': pdf_bytes
}
page_chunks.append(page_chunk)
return page_chunks
# Function to encode the image
def encode_image(local_image_path):
with open(local_image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
# Function to convert page to image
def convert_page_to_image(pdf_bytes, page_number):
# Convert the PDF page to an image
images = convert_from_bytes(pdf_bytes)
image = images[0] # There should be only one page
# Define the directory to save images (relative to your script)
images_dir = 'images' # Use relative path here
# Ensure the directory exists
os.makedirs(images_dir, exist_ok=True)
# Save the image to the images directory
image_file_name = f"page_{page_number}.png"
image_file_path = os.path.join(images_dir, image_file_name)
image.save(image_file_path, 'PNG')
# Return the relative image path
return image_file_path
# Pass the image to the LLM for interpretation
def get_vision_response(prompt, image_path):
# Getting the base64 string
base64_image = encode_image(image_path)
response = oai_client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
},
},
],
}
],
)
return response
# Process document function that brings it all together
def process_document(document_url):
try:
# Update document status to 'Processing'
print("Document processing started")
# Get per-page chunks
page_chunks = chunk_document(document_url)
total_pages = len(page_chunks)
# Prepare a list to collect page data
page_data_list = []
# Add progress bar here
for page_chunk in tqdm(page_chunks, total=total_pages, desc='Processing Pages'):
page_number = page_chunk['pageNumber']
pdf_bytes = page_chunk['pdfBytes']
# Convert page to image
image_path = convert_page_to_image(pdf_bytes, page_number)
# Prepare question for vision API
system_prompt = (
"The user will provide you an image of a document file. Perform the following actions: "
"1. Transcribe the text on the page. **TRANSCRIPTION OF THE TEXT:**"
"2. If there is a chart, describe the image and include the text **DESCRIPTION OF THE IMAGE OR CHART**"
"3. If there is a table, transcribe the table and include the text **TRANSCRIPTION OF THE TABLE**"
)
# Get vision API response
vision_response = get_vision_response(system_prompt, image_path)
# Extract text from vision response
text = vision_response.choices[0].message.content
# Collect page data
page_data = {
'PageNumber': page_number,
'ImagePath': image_path,
'PageText': text
}
page_data_list.append(page_data)
# Create DataFrame from page data
pdf_df = pd.DataFrame(page_data_list)
print("Document processing completed.")
print("DataFrame created with page data.")
# Return the DataFrame
return pdf_df
except Exception as err:
print(f"Error processing document: {err}")
# Update document status to 'Error'
df = process_document(document_to_parse)
让我们检查一下DataFrame,以确保页面已被正确处理。为简洁起见,我们将仅检索并显示前五行。此外,您应该能够在'images'目录中看到生成的页面图像。
from IPython.display import display, HTML
# Convert the DataFrame to an HTML table and display top 5 rows
display(HTML(df.head().to_html()))
让我们看一个示例页面,比如第21页,其中包含嵌入的图形和文本。我们可以观察到,视觉模态有效地提取并描述了视觉信息。例如,该页面上的饼图被准确描述为:
“图6:中东和北非地区IBRD和IDA按部门贷款 - 2024财年占总额46亿美元的比例”是一个圆形图表,类似于饼图,展示了不同部门之间资金的百分比分配。这些部门包括:
# Filter and print rows where pageNumber is 21
filtered_rows = df[df['PageNumber'] == 21]
for text in filtered_rows.PageText:
print(text)
第3步:生成嵌入
在本节中,我们重点将文档每一页提取的文本内容转换为向量嵌入。这些嵌入捕获文本的语义含义,从而实现高效的相似性搜索和各种自然语言处理(NLP)任务。我们还识别包含视觉元素(如图像、图形或表格)的页面,并标记它们以便特殊处理。
步骤分解:
1. 为视觉内容添加标记
为了处理包含视觉信息的页面,在第2步中,我们使用视觉模态从图表、表格和图像中提取内容。通过在提示中包含特定指令,我们确保模型在描述视觉内容时添加诸如DESCRIPTION OF THE IMAGE OR CHART或TRANSCRIPTION OF THE TABLE之类的标记。在此步骤中,如果检测到此类标记,我们将Visual_Input_Processed标志设置为'Y';否则,它保持为'N'。
虽然视觉模态能有效捕获大多数视觉信息,但某些细节——尤其是在工程图纸等复杂视觉中——可能会在转换中丢失。在第6步中,我们将使用此标志来确定何时将页面图像传递给GPT-4 Vision作为额外上下文。这是一个可选增强,可以显著提高RAG解决方案的有效性。
2. 使用OpenAI的嵌入模型生成嵌入
我们使用OpenAI的嵌入模型text-embedding-3-large来生成高维嵌入,以表示每一页的语义内容。
注意:确保您使用的嵌入模型的维度与Pinecone向量存储的配置一致至关重要。在我们的案例中,我们将Pinecone数据库设置为3072维,以匹配text-embedding-3-large的默认维度。
# Add a column to flag pages with visual content
df['Visual_Input_Processed'] = df['PageText'].apply(
lambda x: 'Y' if 'DESCRIPTION OF THE IMAGE OR CHART' in x or 'TRANSCRIPTION OF THE TABLE' in x else 'N'
)
# Function to get embeddings
def get_embedding(text_input):
response = oai_client.embeddings.create(
input=text_input,
model="text-embedding-3-large"
)
return response.data[0].embedding
# Generate embeddings with a progress bar
embeddings = []
for text in tqdm(df['PageText'], desc='Generating Embeddings'):
embedding = get_embedding(text)
embeddings.append(embedding)
# Add the embeddings to the DataFrame
df['Embeddings'] = embeddings
我们可以验证我们的逻辑是否正确标记了需要视觉输入的页面。例如,我们之前检查过的第21页,其Visual_Input_Needed标志被设置为“Y”。
# Display the flag for page 21
filtered_rows = df[df['PageNumber'] == 21]
print(filtered_rows.Visual_Input_Processed)
第4步:将嵌入向量上传到 Pinecone:
在本节中,我们将为文档的每一页生成的嵌入向量上传到 Pinecone。除了嵌入向量,我们还会包含描述每一页的相关元数据标签,例如页码、文本内容、图像路径以及该页是否包含图形。
步骤分解:
1. 创建元数据字段:
元数据增强了我们执行更精细搜索的能力,可以找到与向量关联的文本或图像,并支持在向量数据库中进行过滤。
* pageId:将 document_id 和 pageNumber 组合起来,为每一页创建唯一标识符。我们将使用它作为嵌入向量的唯一标识符。
* pageNumber:文档中的数字页码。
* text:从页面中提取的文本内容。
* ImagePath:与页面关联的图像文件路径。
* GraphicIncluded:一个布尔值或标志,指示页面是否包含可能需要视觉处理的图形元素。
2. 上传嵌入向量:
我们将使用 Pinecone API 中的 upsert_vector 函数来“upsert”以下值:
* 唯一标识符
* 嵌入向量
* 如上定义的元数据
注意:“Upsert”是“update”和“insert”两个词的组合。在数据库操作中,upsert 是一种原子操作,如果记录存在则更新,如果不存在则插入新记录。当您希望确保数据库拥有最新数据,而无需分别执行插入或更新检查时,这尤其有用。
# reload the index from Pinecone
index = pc.Index(index_name)
# Create a document ID prefix
document_id = 'WB_Report'
# Define the async function correctly
def upsert_vector(identifier, embedding, metadata):
try:
index.upsert([
{
'id': identifier,
'values': embedding,
'metadata': metadata
}
])
except Exception as e:
print(f"Error upserting vector with ID {identifier}: {e}")
raise
for idx, row in tqdm(df.iterrows(), total=df.shape[0], desc='Uploading to Pinecone'):
pageNumber = row['PageNumber']
# Create meta-data tags to be added to Pinecone
metadata = {
'pageId': f"{document_id}-{pageNumber}",
'pageNumber': pageNumber,
'text': row['PageText'],
'ImagePath': row['ImagePath'],
'GraphicIncluded': row['Visual_Input_Processed']
}
upsert_vector(metadata['pageId'], row['Embeddings'], metadata)
导航到 Pinecone 上的索引列表,你应该能够查看已插入数据库的向量及其元数据。
第5步:执行语义搜索以查找相关页面:
在本节中,我们实现语义搜索,以查找文档中与用户问题最相关的页面。此方法使用存储在Pinecone向量数据库中的嵌入,根据页面内容与用户查询的语义相似性来检索页面。通过这样做,我们可以有效地搜索文本内容,并将其作为上下文提供给GPT-4o来回答用户的问题。
步骤分解:
1. 为用户问题生成嵌入
* 我们使用OpenAI的嵌入模型为用户问题生成高维向量表示。
* 该向量捕获问题的语义含义,使我们能够针对存储的嵌入执行高效的相似性搜索。
* 嵌入对于确保搜索查询与文档内容在语义上对齐至关重要,即使确切词语不匹配也是如此。
2. 查询Pinecone索引以获取相关页面
* 使用生成的嵌入,我们查询Pinecone索引以查找最相关的页面。
* Pinecone通过使用余弦相似度将问题的嵌入与向量数据库中存储的嵌入进行比较来执行相似性搜索。如果您还记得,我们在第1步创建Pinecone数据库时将此设置为metric参数。
* 我们指定要检索的顶部匹配数量,通常基于覆盖范围和相关性之间的平衡。例如,检索前3-5个页面通常足以提供全面的答案,而不会用太多上下文淹没模型。
3. 编译匹配页面的元数据以提供上下文
* 一旦识别出相关的嵌入,我们收集其关联的元数据,包括提取的文本和页码。
* 此元数据对于构建提供给GPT-4o的上下文至关重要。
* 我们还将编译的信息格式化为JSON,以便LLM易于解释。
4. 使用GPT-4o模型生成答案
* 最后,我们将编译的上下文传递给GPT-4o。
* 模型使用上下文生成信息丰富、连贯且与上下文相关的答案,以回答用户的问题。
* 检索到的上下文帮助LLM更准确地回答问题,因为它可以访问文档中的相关信息。
import json
# Function to get response to a user's question
def get_response_to_question(user_question, pc_index):
# Get embedding of the question to find the relevant page with the information
question_embedding = get_embedding(user_question)
# get response vector embeddings
response = pc_index.query(
vector=question_embedding,
top_k=2,
include_values=True,
include_metadata=True
)
# Collect the metadata from the matches
context_metadata = [match['metadata'] for match in response['matches']]
# Convert the list of metadata dictionaries to prompt a JSON string
context_json = json.dumps(context_metadata, indent=3)
prompt = f"""You are a helpful assistant. Use the following context and images to answer the question. In the answer, include the reference to the document, and page number you found the information on between <source></source> tags. If you don't find the information, you can say "I couldn't find the information"
question: {user_question}
<SOURCES>
{context_json}
</SOURCES>
"""
# Call completions end point with the prompt
completion = oai_client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": prompt}
]
)
return completion.choices[0].message.content
现在,让我们提出一个需要从图表中获取信息的问题。在这种情况下,相关细节位于饼图中。
question = "What percentage was allocated to social protections in Western and Central Africa?"
answer = get_response_to_question(question, index)
print(answer)
让我们通过提出一个需要解释表格中信息的问题来增加挑战性。在我们的第2步中,我们使用GPT-4o视觉模态提取了这些信息。
question = "What was the increase in access to electricity between 2000 and 2012 in Western and Central Africa?"
answer = get_response_to_question(question, index)
print(answer)
这种方法效果不错。然而,在某些情况下,信息可能嵌入在图像或图形中,当转换为文本时会丢失保真度,例如复杂的工程图纸。
通过使用 GPT-4o 的视觉模态,我们可以将页面的图像直接作为上下文传递给模型。在下一节中,我们将探讨如何使用图像输入来提高模型响应的准确性。
第6步:处理包含视觉内容的页面(可选步骤):
当元数据表明存在图像、图形或表格时,我们可以将图像作为上下文传递给GPT-4o,而不是提取的文本。这种方法在视觉信息的文本描述不足以传达上下文的情况下很有用。对于复杂的图形,如工程图纸或复杂图表,可能就是这种情况。
步骤分解:
此步骤与第5步的区别在于,我们添加了额外的逻辑来识别嵌入何时设置了Visual_Input_Processed标志。在这种情况下,我们不传递文本作为上下文,而是使用GPT-4o的视觉模态将页面图像作为上下文传递。
注意:这种方法确实会增加延迟和成本,因为处理图像输入更加耗费资源和昂贵。因此,只有在仅使用文本模态(如上述第5步所述)无法达到预期结果时,才应使用此方法。
import base64
import json
def get_response_to_question_with_images(user_question, pc_index):
# Get embedding of the question to find the relevant page with the information
question_embedding = get_embedding(user_question)
# Get response vector embeddings
response = pc_index.query(
vector=question_embedding,
top_k=3,
include_values=True,
include_metadata=True
)
# Collect the metadata from the matches
context_metadata = [match['metadata'] for match in response['matches']]
# Build the message content
message_content = []
# Add the initial prompt
initial_prompt = f"""You are a helpful assistant. Use the text and images provided by the user to answer the question. You must include the reference to the page number or title of the section you the answer where you found the information. If you don't find the information, you can say "I couldn't find the information"
question: {user_question}
"""
message_content.append({"role": "system", "content": initial_prompt})
context_messages = []
# Process each metadata item to include text or images based on 'Visual_Input_Processed'
for metadata in context_metadata:
visual_flag = metadata.get('GraphicIncluded')
page_number = metadata.get('pageNumber')
page_text = metadata.get('text')
message =""
if visual_flag =='Y':
# Include the image
print(f"Adding page number {page_number} as an image to context")
image_path = metadata.get('ImagePath', None)
try:
base64_image = encode_image(image_path)
image_type = 'jpeg'
# Prepare the messages for the API call
context_messages.append({
"type": "image_url",
"image_url": {
"url": f"data:image/{image_type};base64,{base64_image}"
},
})
except Exception as e:
print(f"Error encoding image at {image_path}: {e}")
else:
# Include the text
print(f"Adding page number {page_number} as text to context")
context_messages.append({
"type": "text",
"text": f"Page {page_number} - {page_text}",
})
# Prepare the messages for the API call
messages = {
"role": "user",
"content": context_messages
}
message_content.append(messages)
completion = oai_client.chat.completions.create(
model="gpt-4o",
messages=message_content
)
return completion.choices[0].message.content
让我们来检验一下在第5步中我们针对纯文本语义搜索提出的相同问题。我们注意到,GPT-4o模型能够识别出包含回答该问题相关信息的图表。
question = "What percentage was allocated to social protections in Western and Central Africa?"
answer = get_response_to_question_with_images(question, index)
print(answer)
现在让我们提出一个可能无法仅通过文本模态回答的问题,例如在文档中找到相关图像并描述该图像。
question = "Can you find the image associated with digital improvements and describe what you see in the images?"
answer = get_response_to_question_with_images(question, index)
print(answer)
结论
在本篇指南中,我们踏上了一场增强检索增强生成(RAG)系统的旅程,旨在处理富含图像、图形和表格的文档。传统的RAG模型虽然擅长处理文本数据,但往往忽略了通过视觉元素传达的丰富信息。通过集成视觉模型并利用元数据标记,我们弥合了这一差距,使AI能够有效地解释和利用视觉内容。
我们首先使用Pinecone设置了一个向量存储,为向量嵌入的高效存储和检索奠定了基础。使用GPT-4o视觉模态解析PDF并提取视觉信息,使我们能够将文档页面转换为相关文本。通过生成嵌入并标记包含视觉内容的页面,我们在向量存储中创建了一个强大的元数据过滤系统。
将这些嵌入上传到Pinecone,促进了与我们的RAG处理工作流的无缝集成。通过语义搜索,我们检索与用户查询匹配的相关页面,确保同时考虑文本和视觉信息。通过将包含视觉内容的页面传递给视觉模型来处理,提高了响应的准确性和深度,特别是对于依赖图像或表格的查询。
以世界银行的《建设更美好的银行:2024年年度报告》作为我们的指导示例,我们展示了这些技术如何协同处理并解释复杂文档。这种方法不仅丰富了提供给用户的信息,而且通过提供更全面和准确的响应,显著提高了用户满意度和参与度。
通过遵循本指南中概述的概念,您现在已具备构建能够处理并解释具有复杂视觉元素文档的RAG系统的能力。这一进步为AI应用在各个领域中开辟了新的可能性,尤其是在视觉数据发挥关键作用的领域。
常见问题
常见错误及排查:1) Pinecone索引未就绪:创建索引后需等待状态变为ready,否则查询会失败。2) 维度不匹配:确保嵌入模型维度与Pinecone索引维度一致,否则上传或查询会报错。3) 图像路径错误:在步骤6中,如果图像路径不正确,会导致编码失败,需检查路径是否存在。4) API密钥泄露:确保.env文件不被提交到版本控制。5) 视觉模态超时或限流:处理大量页面时可能遇到OpenAI限流,可增加重试机制或降低并发。6) 文本提取不完整:对于复杂图表,视觉模态可能描述不准确,可调整提示词或结合OCR。生产环境优化:使用异步处理提高吞吐量;对图像进行缓存;根据评估结果决定是否启用视觉模态;使用Pinecone的命名空间隔离不同文档。
企业应用扩展
本教程的方法可扩展至其他场景:1) 多模态RAG:结合CLIP等模型实现图像与文本的统一嵌入,实现跨模态检索。2) 动态视觉触发:基于查询类型或置信度动态决定是否使用图像,以平衡成本和准确性。3) 文档布局分析:使用LayoutLM等模型识别页面中的视觉元素,更精确地标记。4) 增量更新:支持新文档的增量索引,保持向量库最新。5) 评估体系:建立RAG评估基准,对比文本与视觉模态的效果,指导优化。6) 成本控制:使用模型蒸馏或缓存技术降低视觉调用成本。
总结
本教程面向有编程基础的开发者,深入讲解如何构建一个能够处理包含图像、图表和表格的文档的RAG系统。传统RAG仅处理文本,而本教程通过将PDF页面转换为图像,利用GPT-4o视觉模态提取视觉信息,并标记包含视觉内容的页面。在检索时,根据标记决定是否将页面图像作为上下文传递给视觉模型,从而提升回答的准确性。教程涵盖Pinecone向量数据库设置、PDF解析、嵌入生成、上传、语义搜索及可选图像增强步骤,并提供了完整代码和最佳实践。
- --
内容来源与验证
- 内容等级:PREMIUM_A
- 质量等级:S_CANDIDATE
- 难度:中级
- 验证等级:V1
- 原文作者:msingh-openai
- 原文日期:2024-11-12
- 来源许可:MIT
- 来源版本:
6d88448e281d4226504a4e327407f4d4aaa39bc7 - 查看原文
站内还有更多完整实战教程
加入会员,解锁全部教程、完整代码与持续更新内容。
加入会员