ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI智能体项目实战记录(07):RAG项目实战之文档内容向量化入库

AI智能体项目实战记录(07):RAG项目实战之文档内容向量化入库

1. 引言

在上一篇实战记录中,我们已经完成了上传文档的解析工作,将 PDF、Word、TXT 等格式的文档内容提取为纯文本。然而,仅仅解析出文本还不够——要让 AI 智能体能够"读懂"并检索这些内容,还需要将文本转换为向量并存入向量数据库。

本篇是 RAG(检索增强生成)项目实战的第七篇,核心任务是:将解析后的文档内容进行切割、向量化,并写入 Milvus 向量数据库,为后续的语义检索和问答环节打好数据基础。

2. 整体流程概览

文档从上传到入库,整体流程如下:

上传文档

文档解析

文本切割

向量化 Embedding

写入 Milvus

可供语义检索

本篇聚焦 C、D、E 三个环节:文本切割、向量化、入库。

3. 环境配置

3.1 .env 文件新增参数

在项目根目录的.env文件中,新增以下配置:

# 文本切割长度配置 CHUNK_SIZE=500 CHUNK_OVERLAP=50 # 本地模型驱动(cpu:cpu,gpu:cuda,互联网:remote) DEVICE="cpu" # 向量模型地址(可以从前面第4篇提到的国内模型官网上面下载一个向量模型放到指定的文件夹下) EMBEDDING_MODEL_PATH="D:/AI_Model/modelscope/AI-ModelScope/bge-base-zh-v1.5" # 向量数据库配置 MILVUS_URL="http://192.168.4.77:19530" MILVUS_USER="root" MILVUS_PASSWORD="******" # 向量库集合索引 MILVUS_COLLECTION_WEBSITE="ai_demo_website" MILVUS_COLLECTION_DOC="ai_demo_doc"

说明:以上配置中,数据库地址、用户名、密码等敏感信息已做脱敏处理,实际部署时请替换为真实值。

3.2 settings.py 新增参数

在settings.py中,将上述环境变量映射为配置字段:

# 文本切割长度配置chunk_size:intchunk_overlap:int# 模型驱动device:str# 向量模型embedding_model_path:str# 知识向量库milvus_url:strmilvus_user:strmilvus_password:str# 向量库索引milvus_collection_website:strmilvus_collection_doc:str

4. 文档解析后切割(这个操作实际在上一篇的内容已有)

文档解析得到完整文本后,需要根据配置的chunk_size进行切割。切割的目的是将长文本拆分为适合向量化的片段,避免单条文本过长导致向量化效果变差。

# 小于文本字数时无需切割iflen(doc_str)<setting.chunk_size:splits=[doc_str]else:# 创建文本切割器text_splitter=RecursiveCharacterTextSplitter(chunk_size=setting.chunk_size,chunk_overlap=setting.chunk_overlap)splits=text_splitter.split_text(doc_str)

4.1 切割参数说明

  • chunk_size(500):每个文本块的最大字符数。过大会导致向量化精度下降,过小则会丢失上下文语义。
  • chunk_overlap(50):相邻文本块之间的重叠字符数。重叠部分可以保留跨块的上下文信息,避免语义断裂。

4.2 为什么使用 RecursiveCharacterTextSplitter

RecursiveCharacterTextSplitter是 LangChain 提供的递归式文本切割器,它会优先按照段落、句子、标点等自然边界进行切割,尽量保持语义完整性,而不是简单粗暴地按固定长度硬切。

5. 文档切割后入库(这个操作实际在上一篇的内容已有)

文本切割完成后,将每个文本块向量化并写入 Milvus:

# 确保文档集合存在且 schema 正确(doc_str 为文本字段、vector 为向量字段)milvus_service.ensure_doc_collection(setting.milvus_collection_doc)# 写入向量库milvus_service.batch_save_update(collection_name=setting.milvus_collection_doc,document_list=[{'id':str(uuid4()),'name':file.filename,'doc_str':split}forsplitinsplits],embedding_column_name='doc_str',save=True)

5.1 入库逻辑说明

  • ensure_doc_collection:确保目标集合存在,且 schema 正确(doc_str为文本字段、vector为向量字段)。
  • batch_save_update:批量写入向量库。每个文本块生成一个 UUID 作为主键,并携带文件名和文本内容。
  • embedding_column_name=‘doc_str’:指定对doc_str字段进行向量化。
  • save=True:表示执行插入操作;若为False则执行 upsert(更新或插入)。

6. 用于操作 Milvus 的 Service

下面是与 Milvus 交互的核心 Service 层代码,封装了集合管理、数据写入、查询、删除等常用操作。

#!/usr/bin/env python# -*- coding: utf-8 -*-# @File : milvus_service.py# @Author: hqg# @Date : 2024/9/6# @Desc : 用于操作milvus的servicefromtypingimportList,Dict,UnionfrompymilvusimportMilvusClient,CollectionSchema,FieldSchema,DataTypefromloguruimportloggerfromapp.configimportsettingfromapp.service.systemimportembedding_service logger.info('连接Milvus...')milvus_client=MilvusClient(uri=setting.milvus_url,user=setting.milvus_user,password=setting.milvus_password)logger.info('Milvus连接成功')defbatch_save_update(collection_name:str,document_list:List[Dict],embedding_column_name:str='text',save:bool=True):text_list=[doc[embedding_column_name]fordocindocument_list]embedding_list=embedding_service.embedding_text(text_list)foriinrange(len(text_list)):document_list[i]['vector']=embedding_list[i]ifsaveisTrue:milvus_client.insert(collection_name=collection_name,data=document_list)else:milvus_client.upsert(collection_name=collection_name,data=document_list)defdelete_by_filter(collection_name:str,ids:Union[list,str,int]=None,filter:str="")->Dict:returnmilvus_client.delete(collection_name=collection_name,filter=filter,ids=ids)defbuild_filter_by_dict(filter_dict:Dict)->str:""" 将字典条件转换为字符串条件 :param filter_dict: 字典条件 :return: 字符串条件 """filter_parts=[]forkey,valueinfilter_dict.items():ifvalueisNone:continue# if value is str, add double quotesifisinstance(value,str):filter_parts.append(f'{key}== "{value}"')# if value is list, use inelifisinstance(value,list):in_str=', '.join([f'"{v}"'forvinvalue])filter_parts.append(f'{key}in [{in_str}]')else:raiseValueError(f"Unsupported filter value type:{type(value)}")filter_parts=["("+part+")"forpartinfilter_parts]return" and ".join(filter_parts)defquery(collection_name:str,filter:str=None,limit=20,output_fields:List[str]=["text"])->List[Dict]:returnmilvus_client.query(collection_name=collection_name,filter=filter,limit=limit,output_fields=output_fields)defsearch(collection_name:str,embedding:List[float],limit:int,filter:str=None,output_fields:List[str]=["vector"])->List[Dict]:res=milvus_client.search(collection_name=collection_name,data=[embedding],limit=limit,filter=filter,output_fields=output_fields)return[eforeinres[0]]defcheck_collection(collection_name:str):""" 检查集合是否存在 :param collection_name: 集合名称 :return: """returnmilvus_client.has_collection(collection_name)defcreate_collection(collection_name:str,schema:CollectionSchema,primary_field_name:str="id",id_type:str="string",vector_field_name:str="vector",properties:Dict=None):""" 创建集合 :param collection_name: 集合名称 :param schema: 集合结构 :param primary_field_name: 主键名字 :param id_type: id类型 :param vector_field_name: 向量字段名 :param properties: 集合属性 """# 创建集合的具体实现pass

6.1 核心方法说明

方法功能说明
batch_save_update批量向量化并写入/更新数据,是入库的核心方法
delete_by_filter按条件或 ID 删除数据
build_filter_by_dict将字典条件转换为 Milvus 过滤表达式字符串
query按条件查询数据
search向量相似度检索,返回最相似的 Top-K 结果
check_collection检查集合是否存在
create_collection创建集合

入库后可以看到:

7. 小结

本篇完成了 RAG 项目中"文档向量化入库"这一关键环节:

  1. 配置层:在.env和settings.py中新增了文本切割、模型驱动、向量模型、Milvus 连接等配置。
  2. 切割层:使用RecursiveCharacterTextSplitter对解析后的长文本进行智能切割,兼顾语义完整性与向量化效果。
  3. 入库层:通过milvus_service.batch_save_update将切割后的文本块批量向量化并写入 Milvus。
  4. Service 层:封装了 Milvus 的增删查改与向量检索能力,供上层业务调用。

至此,文档数据已经以向量的形式存储在 Milvus 中。下一篇实战记录,我们将基于这些向量数据,实现语义检索与 RAG 问答,让 AI 智能体真正"读懂"文档内容。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进