企业知识库多向量入库架构: Milvus 与 VLM 分文件路由的工程实现

📅 2026/8/7 15:26:11
企业知识库多向量入库架构: Milvus 与 VLM 分文件路由的工程实现
企业知识库多向量入库架构: Milvus 与 VLM 分文件路由的工程实现在企业知识库的选型评估中多模态文件的向量化入库一直是个工程难点。纯文本可以用 BERT 系列模型直接转向量但 PDF 扫描件、设计图纸、产品图片这些非结构化数据各自的最优向量提取路径完全不同。本文结合实际工程经验梳理一种基于 Milvus 与 VLMVision-Language Model分文件路由的多向量入库架构供参考。一、为什么需要分文件路由传统方案里所有文件类型共用一套 embedding 模型。这在面对企业知识库常见的混合数据类型时会出现明显的效果分化Office 文档Word/Excel/PPT以文字为核心内容用文本 embedding 模型如 text2vec-base效果最好PDF 扫描件或图片关键信息是视觉布局和图表用 OCR 文本 embedding 的链路更稳产品设计图纸CAD、Visio、Sketch依赖视觉结构理解VLM 能提取语义但开销较大纯代码文件JSON、XML、源码用代码专用 embedding 模型如 codegeex比通用模型精度更高。如果统一用一个大模型处理所有类型要么牺牲精度要么成本失控。分文件路由的本质是为每种文件类型选最合适的解析和 embedding 链路。二、整体架构设计整个入库链路分为四层文件接入层、内容解析层、向量路由层、存储检索层。文件接入层负责接收原始文件支持 S3、NFS、WebDAV 等协议并通过巴别鸟智巢 AI 做格式识别和预分类。内容解析层根据文件 MIME 类型调度不同的解析器文本解析器textract、python-docx、OCR 解析器paddleocr、tesseract、视觉解析器VLM 如 Qwen-VL、InternVL。向量路由层根据解析结果选择对应的 embedding 模型将内容转为高维向量。存储检索层统一写入 Milvus支持多 collection 跨向量空间检索。这里最关键的设计在第三层——向量路由。它决定了每份文件最终落入哪个向量子空间也决定了后续检索时的召回策略。三、Milvus 分 collection 设计Milvus 本身的 collection 是隔离的不同 collection 里的向量不做跨 collection 检索。一种常见的工程实践是按文件主类型建 collectionbabellbird_text存储纯文本类文件Word、Markdown、TXT、代码的向量维度 768使用 text2vec-base-chinese 模型。babielbird_image存储图片、设计稿的向量维度 1024使用 CLIP-ViT-L/14 模型。babielbird_doc存储 PDF、扫描件、混合文档维度 1024使用 Qwen-VL-Chat 的 vision encoder 输出。每条记录除了向量本身还要冗余存储原始文件路径、文件类型、所属知识库 ID、解析状态字段。检索时根据用户 query 的模态类型先确定目标 collection再在对应空间内做 ANN近似最近邻检索最后合并跨模态结果排序。Milvus 的建 collection 示例Python pymilvusfrompymilvusimportconnections,Collection,CollectionSchema,FieldSchema,DataType connections.connect(aliasdefault,hostmilvus-node-01,port19530)fields[FieldSchema(nameid,dtypeDataType.VARCHAR,max_length64,is_primaryTrue),FieldSchema(namefile_path,dtypeDataType.VARCHAR,max_length512),FieldSchema(namefile_type,dtypeDataType.VARCHAR,max_length32),FieldSchema(namekb_id,dtypeDataType.VARCHAR,max_length64),FieldSchema(nameembedding,dtypeDataType.FLOAT_VECTOR,dim1024),]schemaCollectionSchema(fieldsfields,descriptionbabielbird_doc collection for mixed documents)collectionCollection(namebabielbird_doc,schemaschema)collection.create_index(field_nameembedding,index_params{index_type:IVF_FLAT,metric_type:IP,params:{nlist:128}})四、VLM 分文件路由的实现VLM 在这条链路里的角色是做视觉语义理解输出可用于 embedding 的文本描述或直接输出向量。工程实现中常用的策略是先用 VLM 对图像/文档做结构化描述再用 text embedding 模型向量化描述文本。一个典型的路由判断逻辑Pythondefroute_file(file_path:str,mime_type:str)-str:text_routable{application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document,text/plain,text/markdown,application/json}image_routable{image/jpeg,image/png,image/webp,image/svgxml}vlm_routable{image/vnd.dwg,application/acad,image/tiff}ifmime_typeintext_routable:returntext_pipelineelifmime_typeinimage_routable:returnclip_pipelineelifmime_typeinvlm_routable:returnvlm_pipelineelse:returnfallback_text以 CAD 图纸DWG为例VLM 路由链路的工作流是文件 → dwg2svg 中间转换 → Qwen-VL-Plus 视觉编码 → SVG 结构化描述文本 → text2vec 向量化 → 写入 babielbird_doc collection。VLM 的调用成本比纯文本 embedding 高 10-20 倍所以必须严格控制触发条件。只在文件属于 vlm_routable 类型且文件体积超过 2MB 时才走 VLM 链路小于 2MB 的图纸直接走 CLIP embedding避免不必要的开销。五、多向量联合检索入库是多 collection 的检索也要做跨模态聚合。工程上一般分两阶段第一阶段根据 query 类型确定检索的 collection 集合。如果用户输入的是文字在 babielbird_text babielbird_doc 两个 collection 并发检索如果输入的是图片直接在 babielbird_image 检索。第二阶段将多路召回结果合并排序。合并时需要对不同向量空间的得分做归一化min-max 或 z-score因为不同 embedding 模型的打分分布差异很大直接比较没有意义。归一化后再按加权求分排序输出。frompymilvusimportconnections,Collectiondefmulti_collection_search(query_emb,query_type,top_k20):collections_to_search[babielbird_text,babielbird_doc]ifquery_typeimage:collections_to_search[babielbird_image]results[]forcol_nameincollections_to_search:colCollection(namecol_name)col.load()search_params{metric_type:IP,params:{nprobe:16}}rescol.search(data[query_emb],anns_fieldembedding,paramsearch_params,limittop_k,output_fields[file_path,file_type,kb_id])results.extend(res[0])# 归一化 合并排序scores[r.scoreforrinresults]ifscores:min_s,max_smin(scores),max(scores)forrinresults:r.norm_score(r.score-min_s)/(max_s-min_s1e-9)returnsorted(results,keylambdax:x.norm_score,reverseTrue)[:top_k]六、工程踩坑记录向量维度不一致的问题不同 collection 的向量维度必须和写入时的模型输出维度严格一致。Milvus 建表后维度就固定了如果模型中途换了版本导致输出维度变化需要新建 collection 并做存量数据迁移。Milvus 混合检索的限制Milvus 原生不支持跨 collection 的联合检索必须在应用层做结果聚合。本方案的第二阶段归一化合并就是这个工程约束的产物。VLM 解析慢导致入库队列堆积VLM 单张图纸处理耗时在 GPU 上约 2-4 秒CPU 上 15-30 秒。上线初期遇到过入库队列堆积报警后续加了 minio 的分级队列VLM 任务单独排队单独限流避免拖垮整体入库速度。文件类型的 MIME 判断不准有些 CAD 文件上传后扩展名是 .dwg 但 MIME 识别成了 application/octet-stream。解决方式是在文件接入层加一个魔数magic bytes检测层不完全依赖扩展名。总结一下分文件路由的本质是根据数据类型选最优解析链路而不是用一个模型处理所有输入。Milvus 分 collection 隔离不同向量空间应用层做跨模态聚合检索。VLM 只在必要时触发避免把 VLM 当成万能视觉理解引擎。这套架构在文件类型丰富的企业知识库场景里召回精度和计算成本之间有较好的平衡。