PDF图片转写与RAG检索增强:从解析到问答的完整流程

发布时间:2026/10/19 16:48:10
PDF图片转写与RAG检索增强:从解析到问答的完整流程
1. 为什么PDF里的图片会成为RAG的盲区1.1 RAG的基础链路默认忽略图片RAG检索增强生成的核心逻辑其实不复杂大模型记不住你本地的几十份甚至几百份PDF文档所以先把文档切成文本块转成向量存进索引库用户提问时先检索出最相关的几个文本块再把它们拼进上下文让大模型作答。这个过程能不能答对前提只有一个——检索端必须覆盖到用户想知道的内容。如果答案是某段正文那一切顺畅可如果答案藏在一张图里而文档解析阶段根本没把图片当回事那后面的嵌入、检索、生成做得再好也是白搭。我在做某知识库项目初期就犯过这个错误。当时导出的PDF里文本量很大我理所当然认为图片属于锦上添花最多后面补个OCR就行。结果开头测试就翻车文档里有一张带箭头指向的部署架构图用户问整个链路里哪一步负责数据清洗系统完全答不上来。明明图里的箭头和标注写得很清楚但因为检索空间里压根没有这张图的语义信息大模型只能靠猜测蒙一个答案。这种问题不是模型能力不够是管道设计漏掉了一整类信息载体。图片在RAG链路里的特殊性在于它既是高频信息载体又是最容易被解析阶段丢弃的对象。技术类PDF里的架构图、流程图、数据图表、界面截图往往浓缩了正文里最关键的结论。如果把图片直接跳过等于把一个信息宝库锁在门外检索再多文本也是片面检索。所以对PDF图片的处理从来不是可选项而是决定知识库问答质量的核心环节。1.2 图片被忽略之后的真实代价这里举一个典型场景某份材料里有张季度营收柱状图图上每个柱子都标注了具体数字旁边还有一个文字段落描述整体趋势。用户提问哪个季度增长最明显如果只做文本检索系统大概率会召回描述趋势的那句话但拿不到具体季度和数值。如果图里还有异常点标注那丢失的信息就更致命了。生成阶段的大模型面对不完整的上下文只能给出含糊回答用户一追问具体数字系统就说不出话了。图片被忽略会导致三个层面的问题检索缺失图片内容没有进入索引检索空间天然存在盲区任何基于向量的相似度匹配都找不到这部分信息。语义缺失即使把图片文件本身存进数据库大模型也读不懂像素无法把图片内容转换成可引用的知识点。结构缺失就算用OCR抽出图片里的文字如果丢掉了视觉布局、箭头方向、层级关系检索能召回片言只语但生成答案时依然连不起来。这三个问题层层递进也是我在后续实践中反复踩过的地方。要解决它们靠的不是某一个魔法模型而是把图片纳入一条完整的、有顺序的处理链路。1.3 处理图片的正确姿势语义化转写我最终确定的思路是不把图片直接塞给多模态模型而是把图片转写成高质量的语义文本再走回常规文本RAG管道。这样做有几个现实好处兼容性最强。已有的文本切块、向量化、检索逻辑全部可以复用不需要为图片单独建一套多模态检索基础设施可调试性最好。图片转成文本后你可以直接看检索命中的内容是什么一条条检查不会像端到端多模态系统那样难定位问题成本更可控。文本向量化的资源消耗远低于直接做多模态向量化也更容易水平扩展。但这套方案真正的难点在于转写质量的保障和步骤顺序的安排。转写不能是简单一句话这是一张流程图那样信息密度太低等于把图片降级成了噪声文本步骤顺序更不能乱比如先OCR再定位会导致图片描述无法准确关联到它的上下文段落。所以接下来我会按照一条完整可复现的流程把每个环节拆开细讲。2. 图片处理完整流程拆解2.1 总体步骤顺序与核心决策点我建议的标准化处理顺序是PDF解析与图片定位记录页码、坐标、尺寸、唯一ID图片去重、过滤、预处理去噪并筛查低质量内容图片分类决策判断走OCR、视觉模型描述还是两者结合生成结构化描述文本并保存带元数据的中间结果上下文拼接把图片描述挂靠到邻近正文段落切块、向量化、写入索引检索召回与生成增强最后带回引用信息。这个顺序不是随意定的每一步的输出都是下一步的输入。尤其是第1步的坐标记录很多人容易忽略。没有坐标后面就无法把图片描述准确放回它所在的上下文位置也无法在问答时给出见图3、第5页右上角这类精确引用。所以我整条流程里一直强调图片ID和坐标元数据要像身份证一样全程携带从解析阶段一路带到检索阶段。为了更直观我把各阶段的关键产物整理成一个速查表阶段输入关键操作产物PDF解析PDF文件遍历页面图片对象记录xref与坐标图片文件元数据图片预处理原始图片过滤小图、去重、转底色、合并碎块干净图片集内容理解干净图片OCR/视觉模型分类处理文字或结构化描述上下文对齐描述原文档按坐标匹配邻近文本图片文本块切块索引图片文本块切块、向量化、写入向量库可检索索引检索生成用户问题混合检索、拼装提示词、调用生成带引用的答案这里最关键的决策点在第3步的图片分类。分类方向错了后续处理全歪。比如把文字截图丢给视觉模型做泛泛描述容易漏掉细节把流程图丢给纯OCR又会丢失箭头和层级关系。所以分类必须有一套标准化依据。2.2 PDF解析图片发现、去重与坐标记录PDF解析阶段的目标不只是把图存到硬盘上而是要搞清楚三件事图在哪些页面出现过、图在页面上的具体区域、图本身是位图还是矢量图。先说位图。PDF内部的图片对象可以通过解析库的图片列表接口拿到每个图片对象有一个唯一的xref引用号。但要注意同一个xref可能在多页反复出现比如公司Logo、页眉装饰图它们在每一页都有相同的引用号。如果你见一次存一次索引里会出现大量重复图片块。我的习惯是按文件内容哈希去重把同一张图对应的物理文件只保存一份但把出现位置全部记录到元数据里。再说坐标。每个图片对象在页面上的显示区域一般可以通过解析库的矩形查询接口拿到。这里要区分同一个xref可能在一页上被渲染多次也可能被裁剪成多个可见区域所以要用返回的矩形列表逐一登记。坐标系的原点在页面左上角单位是点1点约等于0.3528毫米。记得把矩形坐标存成[x0, y0, x1, y1]四元组后面做上下文匹配和局部渲染都需要它。最后是矢量图。很多PDF图表其实不是位图而是由线条、曲线和色块组成的矢量对象。如果只用图片列表扫描这类内容不会被发现。正确做法是按坐标区域渲染页面把指定区域输出成位图再交给下游的OCR或视觉模型处理。这也是为什么坐标记录如此重要——没有坐标你连把哪块区域渲染出来都不知道。2.3 图片预处理清洗、合并与质量把关预处理阶段看起来不起眼但恰恰是决定下游效果的分水岭。我通常会做四件事过滤过小图片。宽或高小于100像素的装饰性元素比如小箭头、分割线、圆点图标直接跳过。这些内容信息量极低进入索引只会污染检索结果。透明背景转白底。很多PDF里的图片是PNG透明底OCR和视觉模型处理时容易把透明区域识别成黑块或噪声。统一填充成白色背景会稳定很多。碎块合并。有些出版工具会把一张完整的表或图拆成多个图片对象插入页面。判断方法很朴素如果两个图片矩形的水平范围接近、垂直方向紧邻且宽度差不多就很有可能原本是一张图。这类碎块最好先合并成一个矩形区域再整体渲染和识别。旋转和清晰度修正。扫描件常见的歪斜可以通过角度检测和旋转校正分辨率太低的图不要强行放大放大只会增加噪声不如在元数据里标记低清晰度让下游处理时降低期望。这些预处理步骤都不复杂但如果你跳过它们后面OCR会多出一堆神秘字符视觉模型也会把装饰性图标描述成有意义的内容最终污染整个索引。我在图形处理上吃过不少亏现在每次跑管道前都会先加一层过滤规则。2.4 内容理解OCR与视觉模型的分工图片分类之后的处理策略我总结成一张决策表图片特征首选方案补充方案文字截图、代码截图OCR视觉模型整理排版表格截图OCR提取单元格内容视觉模型整理为Markdown表格柱状图、折线图、饼图视觉模型描述趋势与数值OCR补充坐标轴标签架构图、流程图、拓扑图视觉模型提取节点与关系OCR核对节点文字装饰性图标、Logo直接忽略不进入索引OCR的核心价值在于字准。纯文字截图、代码块、表格里的数值用OCR比视觉模型更可靠因为视觉模型在生成表格时偶尔会凭空补一行数据。不过OCR也有局限它只能输出文字序列不理解文字之间的视觉关系。股价曲线里上升这个信息OCR是抓不到的。视觉模型VLM的价值在于懂关系。它能把图中的箭头方向、层级结构、空间布局、数据趋势描述出来。但VLM最大的风险是幻觉——它可能在描述里编造图里根本不存在的节点或数字。所以我的建议是对于信息密集的复杂图先跑OCR拿到文字标签再把OCR结果和原图一起喂给视觉模型让它结合文字和视觉布局做结构化描述。这样既能拿到准确文字又能保住结构关系幻觉概率也会低很多。2.5 文本化表达结构化描述与上下文拼接视觉模型输出的原始描述不能直接丢进索引。我会要求模型按模板输出结构化描述比如包含图片类型、主要元素、元素关系、图内文字、关键数据结论。这么做不是为了炫技而是为了让后面的检索阶段能更精准地命中。实际操作中图片文本块我建议拼成这样一个格式【图片:p3_x12 页码:3 区域:左上角】 图片类型: 流程图 内容说明: 这是一个四步数据管道... 图内文字: 采集 - 清洗 - 训练 - 发布 关键关系: 采集与清洗呈顺序依赖关系这样拼接之后检索时不管是问数据管道分几步还是直接问清洗在哪个环节后都能从不同措辞命中同一图片块。提示词也要多花心思我会在生成描述时明确要求请用简洁客观的语言描述这张图片。包括图片类型主要元素元素之间的关联图中出现的所有文字如果包含数据图表请给出最高值、最低值、异常点等关键信息。不要编造图中不存在的内容。上下文拼接也很关键。图片不是孤立存在的它通常紧跟着一段正文说明。我会用图片的坐标矩形从页面文本里找出距离它最近的段落把这段文字作为邻近上下文加进图片块。这样图文信息就形成了互补检索时既能靠图内文字命中也能靠正文描述上下文命中。2.6 切块向量化与混合检索图片块的文本特征和普通文本不太一样它信息密度高、关键词集中、结构性强。所以切块参数我一般会放宽一点单块允许到500到1000字重叠部分保持50到100字。太长会稀释向量语义太短又会把关系描述切断。向量化阶段普通中文文本嵌入模型就够用了关键是把图片类型和页码这些元数据拼进文本里。为什么因为用户提问时经常会说图2、架构图、流程图这类词如果你只在文本里存描述检索不到这些标签把元数据拼进去相当于给图片块加了一层可检索的定位锚点。不过单靠向量检索在图片场景有个短板。图片描述经常由短词和专有名词组成比如Kafka、Nginx、模型训练向量相似度对这类精确词不够友好有时候会被同义改写带偏。所以我更推荐向量检索加全文关键词检索的混合方案。向量负责语义相似关键词负责精确匹配两边召回后合并排序效果会比单路检索稳定很多。2.7 生成增强与溯源引用检索到图片块之后生成环节的增强方式是原文回填。图片块本身就是文本把它直接拼进提示词模型就能基于图片的语义内容作答。更关键的是图片块里携带了页码、图片ID、坐标信息生成阶段可以要求模型在回答末尾标注信息来源比如根据第3页图2的描述。溯源看起来是个小功能但对知识库系统来说价值极大。用户能核实答案的真伪管理员能检查哪张图的转写质量有问题后续优化也能精准定位到具体图片而不是大海捞针。这也是我把图片处理称为工程而不是调模型的原因——每一环都要可回查、可追溯。3. 实操代码从PDF到可问答的图片知识3.1 环境准备与依赖安装实操环节我用Python生态里最常用的几个库来演示。先安装依赖pip install pymupdf paddleocr paddlepaddlePyMuPDF负责PDF解析和图片提取PaddleOCR负责图片文字识别。视觉模型部分你可以选择任何支持图片加文字输入的开源模型部署成本一般都在可控范围。如果本机资源有限也可以重点先用OCR把文字类图片处理掉视觉模型覆盖最关键的几张复杂图效果提升依然显著。向量检索我用FAISS做示例它是目前上手最快的相似度索引库。切块工具可以用通用的文本切分器也可以自己写一个简单的按分隔符切割函数。3.2 图片提取与去重图片提取的核心逻辑是遍历所有页面拿到每个图片对象保存图片文件同时记录坐标和引用信息。代码里我会额外加一个MD5哈希缓存自动过滤重复图片。import fitz import hashlib import os def extract_pdf_images(pdf_path, out_dir): os.makedirs(out_dir, exist_okTrue) doc fitz.open(pdf_path) file_cache {} records [] for page_no in range(len(doc)): page doc[page_no] for img in page.get_images(fullTrue): xref img[0] pix fitz.Pixmap(doc, xref) # PDF中部分图片是CMYK或多通道格式统一转成RGB if pix.n - pix.alpha 4: pix fitz.Pixmap(fitz.csRGB, pix) raw pix.tobytes(png) digest hashlib.md5(raw).hexdigest() # 同一张图只保存一次但每次出现都记录 if digest not in file_cache: fname os.path.join(out_dir, fimg_{digest[:8]}.png) pix.save(fname) file_cache[digest] fname for rect in page.get_image_rects(xref): records.append({ image_id: fp{page_no1}_x{xref}, file: file_cache[digest], page: page_no 1, bbox: [rect.x0, rect.y0, rect.x1, rect.y1], }) doc.close() return records注意一个细节page.get_images(fullTrue)返回的元组里第一个元素就是xref但同一张图可能在页面多处渲染所以要用get_image_rects拿矩形列表逐一遍历。这样每一条渲染记录都能保留独立的页码和坐标。如果遇到矢量图这段代码的get_images是找不到对象的。解决办法是直接用坐标区域渲染页面page doc[page_no - 1] rect fitz.Rect(bbox) pix page.get_pixmap(cliprect, dpi200) pix.save(region_render.png)dpi200是我常用的渲染参数太低看不清细节太高文件太大200是比较均衡的档位。3.3 OCR文字提取实现OCR阶段我推荐直接用带方向分类的中文OCR库对扫描歪斜的图片有自动矫正能力。from paddleocr import PaddleOCR import json ocr PaddleOCR(use_angle_clsTrue, langch) def ocr_image_to_lines(image_path): result ocr.ocr(image_path, clsTrue) lines [] if not result: return lines for page_res in result: if not page_res: continue for box in page_res: coords box[0] text_and_score box[1] text text_and_score[0] score text_and_score[1] if score and score 0.6: lines.append({ text: text, bbox: coords, score: float(score) }) return lines置信度阈值0.6是个经验值。阈值太高会漏掉模糊文字太低会涌入大量错误字符。不同文档扫描质量差异很大我一般先用一小批图测试再决定调到0.5还是0.65。OCR输出的结果不要直接拼成一长串最好保留每一行文字和对应坐标。后面和视觉模型描述合并时这些坐标能帮你判断文字在图中的位置关系也可以用来校验视觉模型是否漏读了标签。3.4 视觉模型描述生成视觉模型部分我假设你已经有一个本地部署好的模型服务代码里用HTTP接口调用的方式演示。读图转base64再连同提示词一起提交import base64 import requests VLM_ENDPOINT http://127.0.0.1:8000/vlm # 换成你的本地服务入口 def vlm_describe(image_path, prompt): with open(image_path, rb) as f: image_b64 base64.b64encode(f.read()).decode(utf-8) payload { image_base64: image_b64, prompt: prompt, } resp requests.post(VLM_ENDPOINT, jsonpayload, timeout180) resp.raise_for_status() return resp.json()[text]这里有两个忠告。第一提示词一定要写清楚不要编造图中不存在的内容。第二对包含大量文字的复杂图把OCR结果作为额外提示文本一起传入可以有效减少模型幻觉。比如这样组织提示词prompt 请结合OCR识别文本描述这张图片的结构。 要求 1. 图片类型例如流程图、柱状图、架构图 2. 说明主要元素及其位置关系 3. 图中如果存在箭头说明从哪个元素指向哪个元素 4. 不要编造OCR文本中没有的内容 OCR识别文本 {ocr_text} .format(ocr_textocr_text)3.5 图片上下文拼接与索引构建拿到OCR文本和视觉模型描述后下一步是把它们拼成标准文本块。我用一个函数来组装def build_image_text_block(record, vlm_desc, ocr_text, nearby_text): return ( f【图片:{record[image_id]} 页码:{record[page]} 区域:{record[bbox]}】\n f图片说明:{vlm_desc}\n f图内文字:{ocr_text}\n f上下文:{nearby_text} )nearby_text怎么取我在第2章提过用图片坐标从页面文本里找到最近的段落。简单实现是直接采集页面中所有文本块取垂直中心点与图片中心点最近的文本块def get_nearby_text(page, bbox): blocks page.get_text(blocks) img_cy (bbox[1] bbox[3]) / 2 best_block None best_dist float(inf) for b in blocks: x0, y0, x1, y1, text, *_ b block_cy (y0 y1) / 2 dist abs(block_cy - img_cy) if dist best_dist: best_dist dist best_block text.strip() return best_block[:300]拼接完成后我把所有文本块重新切分再做向量化import numpy as np def get_embedding(text): # 这里接入你选用的文本向量模型返回一个列表 return [] splitter RecursiveCharacterTextSplitter( chunk_size800, chunk_overlap100, separators[\n\n, \n, 。, , , , ] ) final_chunks [] for block in all_image_blocks: final_chunks.extend(splitter.split_text(block)) embedding_matrix np.array([get_embedding(c) for c in final_chunks]) embedding_matrix embedding_matrix.astype(float32) # 归一化方便直接使用内积计算余弦相似度 embedding_matrix / np.linalg.norm(embedding_matrix, axis1, keepdimsTrue)最后用FAISS建索引import faiss dim embedding_matrix.shape[1] index faiss.IndexFlatIP(dim) index.add(embedding_matrix)3.6 检索问答链路实现查询阶段的核心逻辑是把用户问题向量化在向量库中召回TopK再拼接到提示词里交给生成模型。def search(question, top_k5): q np.array([get_embedding(question)], dtypefloat32) q / np.linalg.norm(q) scores, ids index.search(q, top_k) return ids[0], scores[0] def answer(question, llm_generate): ids, scores search(question) context \n\n.join(final_chunks[i] for i in ids) prompt f 请基于以下资料回答问题。回答中如果引用了图片内容请注明图片编号和页码。 资料内容 {context} 问题{question} return llm_generate(prompt)这里有个实用细节如果启用了关键词召回可以把向量召回的TopK和关键词召回的TopK做合并再用RRF倒数排名融合排序。RRF实现非常简单就是对同一文档在多个结果列表中的名次取倒数求和排名越靠前权重越大。混合召回能显著提升图片块的命中率尤其是用户问题里带专有名词的时候。4. 高频问题与避坑技巧实录4.1 表格图片被OCR拆碎怎么办表格类图片是OCR翻车重灾区。OCR按读序输出多行多列表格一旦有合并单元格输出就会彻底乱掉表头和数值对应关系全丢。我一开始遇到这种问题傻乎乎地在输出结果后补正则去抓看起来像数字的内容结果越补越乱。后来改成双轨方案表格图片先跑OCR拿到每个单元格的原始文字然后让视觉模型结合OCR结果把整张表转成Markdown格式。提示词可以这么写请把这张图片中的表格完整转换为Markdown表格保留所有行和列不要遗漏单元格不要改动数据。对于纯OCR输出我的经验是不要强求它复原表格结构只把它当作文字食材。结构整理交给视觉模型更合适因为它看得见行列位置关系能从视觉上判断某一列属于哪个表头。4.2 重复图片和页眉页脚污染索引PDF里最常见的重复图片就是页眉Logo、页脚图标、背景水印。如果不做去重几千页PDF能索引出几百份一模一样的Logo图片块。用户问这个Logo是什么时还好怕的是这些重复块在检索时频繁命中把真正有用的图片块挤出了TopK。处理办法在代码里已经体现了按图片字节内容的MD5哈希去重同一内容只保存一份。但这还不够页眉Logo在每页都会出现虽然文件只有一份但记录里会有几百条出现位置。我建议在进入索引前加一道过滤如果同一图片ID在文档中出现次数超过阈值比如10次大概率是装饰性元素直接在索引构建阶段剔除。水印文字也要留意。有些PDF加了斜向水印文字OCR会把水印混进正文。处理办法是让OCR忽略整页统一背景或者在水印文字出现频次过高时降低对应文本的权重。4.3 视觉模型描述出现幻觉数据视觉模型幻觉是图片转写里最隐蔽的问题。它不像OCR那样有明显的识别错误而是会一本正经地编造出图里不存在的节点、数字或流程分支。比如一张三步流程图模型可能描述出第四步数据验证因为它在别处见过相似模板。降低幻觉的办法我总结为三条提示词硬约束明确写只描述图片中可见的内容不确定的信息用【不确定】标注交叉验证图片里出现数字时让OCR先抽取文字再让视觉模型只描述关系不改数字人工抽检随机抽取10%的图片块由人来核对描述和原图是否一致。别小看这个笨办法它能让你快速发现哪些提示词设计有问题。如果视觉模型输出的描述里混进了OCR文本里没有的实体词我基本会视为幻觉删除该实体再向比或者要求模型重新生成一次。4.4 图片块太长挤占上下文窗口图片描述动辄几百字如果一页里有多张图生成的文本块拼接起来很容易超过生成模型的上下文限制。检索时TopK如果是5可能一半都是图片块正文内容反而被挤掉了。我的处理思路是分级压缩如果同一页出现多个图片块先做一个图片清单页式的聚合块每张图只用一两句话概括然后完整链路里只把检索命中的那一两张图的详细描述放进去。另外TopK在图片场景不要设太大我一般设为3到5召回内容够用且不容易爆上下文。如果实在要保存长描述也可以把描述分成摘要和细节两个字段。检索时用摘要做匹配生成时把对应的细节块一并带入。这样既能保住关联性又不会每个命中块都带着冗长细节。4.5 扫描版PDF别当普通PDF处理扫描版PDF里每一页本质上就是一张大图如果用提取页面内嵌图片的逻辑去处理你会发现整页图片能提取出来但拆成十几个小碎片OCR结果惨不忍睹。处理方法完全不同遇到扫描版PDF应该走整页OCR路线。先把整页渲染成清晰位图然后对整页做OCR输出带坐标的完整文本。得到文本后再走正常切块、向量化流程。判断标准很直接如果页面上最大的图片矩形覆盖面积超过整页面积的80%就当作扫描页处理。page_pix page.get_pixmap(dpi200) # 对整页做OCR扫描版PDF一定要在预处理阶段就识别出来否则后面所有针对内嵌图片的处理都会变成无用功。4.6 图片召回率上不去的补救方法如果图片块建好了索引但检索时总是召不回问题多半出在措辞不一致上。图片描述里写圆柱形容器用户问的是存储引擎两者语义相关但不完全一致向量模型可能算不出高相似度。补救方法有三个在图片文本块里加类型前缀。比如【图表柱状图|收入趋势】这种明确的标签词检索时命中率极高给描述补同义词。把模型训练补成模型训练Model Training把存储引擎补成存储引擎数据库/仓库不要过度膨胀但关键术语的同义词扩展很有用混合检索兜底。向量召回和关键词召回合并后图片块的精确词能以关键词方式补进来即使向量相似度不够高也有一席之地。4.7 常见问题速查表现象可能原因解决方向表格图片OCR乱序表格结构复杂OCR读序不保留行列关系视觉模型转Markdown同一图片反复命中页眉水印未去重按哈希去重过滤高频装饰图描述里出现不存在的数字视觉模型幻觉提示词硬约束OCR交叉校验上下文长度超限图片块过多过长压缩为摘要块缩小TopK扫描PDF图片支离破碎把扫描页当内嵌图处理整页OCR方案图片召不回描述和提问措辞不一致加类型前缀、同义词、混合检索5. 实战心得与个人建议整套流程落地之后我最大的体会是处理PDF图片的难点不在于模型选型而在于流程里那些一不留神就漏掉的元数据工程。图片ID、页码、坐标、出现频次、文字置信度、描述来源这些字段如果记录得不完整后续排查问题时就会被卡在这条内容到底是OCR还是视觉模型生成的这种问题上进退两难。我现在每次跑图片管道都会把中间产物完整存下来提取出的图片文件、OCR的JSON输出、视觉模型的原始描述、最终拼接形成的文本块。这些中间产物既是检查质量的抓手也是调试问题时的关键线索。你别嫌多这一步麻烦等你在线上知识库里发现某个答案明显错误时能快速定位到具体环节这个价值远大于存储那点开销。另一个心得是要给图片块设立质量阈值。OCR置信度过低、视觉模型描述过短、图片尺寸过小这些情况都直接标记为低质量块不进入正式索引最多放在调试集里。宁缺毋滥图片块的质量污染对RAG问答的伤害比缺失还严重因为它会让系统给出信心满满的错误答案。最后分享一个我一直在用的回归测试法。每次改完图片处理链路我没空把整个知识库重新问一遍就固定准备三到五个必问题专门覆盖图片场景比如图3里的流程分几步这张架构图里哪两个模块之间有调用关系图表里哪个数据点最低。跑完这几个问题再对比一下答案和引用是否准确基本就能判断这次改动是变好了还是改坏了。这个习惯帮我防住了好几次看似升级、实则退化的改版。