从0开始做基于 RAG 架构的多源非结构化数据自动化 ETL 与知识库构建系统(代码部分)
目录第一步文本切块chunker.py第二步虚拟环境第三步chunker.py测试运行第四步Git同步第五步多线程自动化管道src/pipeline.py第六步配置智谱大模型接口第七步填入PDF文献⚠️ 只有一个小小的“避坑点”第八步:Pipeline.py测试运行第九步Git同步下一步知识检索与大模型智能问答Retrieval Generation接下来我们要开始一行一行地编写chunker.py里面的核心清洗与切块逻辑了。第一步文本切块chunker.py完整代码如下# 语义级文本切块算法 import re from typing import List, Dict from loguru import logger # 工业级日志库比普通的 print 高级很多 class SemanticChunker: def __init__(self, chunk_size: int 500, chunk_overlap: int 100): 初始化语义切块器 :param chunk_size: 每个文本块的最大字符数控制模型的上下文窗口负载 :param chunk_overlap: 相邻文本块的重叠字符数核心防止切缝处的语义断层 self.chunk_size chunk_size self.chunk_overlap chunk_overlap def split_text(self, text: str, metadata_base: Dict) - List[Dict]: 核心方法对原始文本进行清洗、按语义边界切分并注入元数据Metadata logger.info(f开始对文件 {metadata_base.get(source, 未知)} 进行智能化语义切块...) # 1. 基础清洗ETL第一步利用正则表达式去除异常的不可见字符、控制字符以及连续的空行 text re.sub(re.compile(r[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff]), , text) text re.sub(r\n, \n, text).strip() # 2. 语义边界切分核心难点抛弃硬切按照中文的标点符号。或换行符进行切分保留完整的句子边界 sentences re.split(r(?[。\n]), text) chunks [] current_chunk for sentence in sentences: if not sentence.strip(): continue # 动态滑窗逻辑如果当前累加的句子长度没超过限制就继续往里装 if len(current_chunk) len(sentence) self.chunk_size: current_chunk sentence else: # 超过限制了说明当前块已经饱和立刻归档 if current_chunk: chunks.append(self._create_chunk_dict(current_chunk, metadata_base, len(chunks))) # 【高能踩坑点】处理重叠度Overlap # 新的一块不能直接从新句子开始而是要向前回溯保留一部分老文本chunk_overlap长度 # 这样可以确保前后两个 Chunk 之间的语义在数学向量空间上具有连续性 if len(current_chunk) self.chunk_overlap: current_chunk current_chunk[-self.chunk_overlap:] sentence else: current_chunk sentence # 别忘了收尾把最后剩下的一点尾巴文本装进最后一个 Chunk 归档 if current_chunk: chunks.append(self._create_chunk_dict(current_chunk, metadata_base, len(chunks))) logger.success(f切块完成共生成 {len(chunks)} 个高聚合、带元数据的数据块。) return chunks def _create_chunk_dict(self, content: str, base_meta: Dict, index: int) - Dict: 辅助方法为每一个切出来的文本块注入多维度的元数据Metadata标签 meta base_meta.copy() meta[chunk_id] index # 文本块的序号 meta[content_length] len(content) # 文本块的字符长度 return { page_content: content, metadata: meta } # # 本地局部测试确保这个组件能单独跑通典型的软件工程单元测试思维面试加分项 # if __name__ __main__: # 模拟一段行业原始语料 test_text 人工智能是核心生产力。大模型需要吃进高质量的语料燃料所以AI数据工程师的岗位在当前极其重要这就是我们开发自动化ETL系统的初衷。希望这个项目能帮你拿到满意的Offer。 # 实例化切块器故意把最大长度设小方便看切块效果 chunker SemanticChunker(chunk_size35, chunk_overlap12) # 模拟一个上游传入的基础元数据比如文件名和行业分类 mock_metadata {source: interview_tips.txt, category: AI_Tech} # 跑一下切块流程 results chunker.split_text(test_text, mock_metadata) # 打印出来看看成果 print(\n--- 单元测试查看切块结果 ---) for index, item in enumerate(results): print(f【Chunk {index}】内容 - {item[page_content]}) print(f 元数据 - {item[metadata]}\n)第二步虚拟环境在运行测试之前先在 Git Bash 终端里执行三行命令1.创建虚拟环境做好隔离 python -m venv .venv 2.激活虚拟环境 source .venv/Scripts/activate # 激活成功后会发现命令行开头多了一个括号 (.venv) 3.安装包 pip install -r requirements.txt安装包的过程比较长耐心等待2-5mins左右。中间需要等很久下载完成之后还有解压安装配置过程小电脑在背后默默工作哟~第三步chunker.py测试运行在终端里确保在rag-data-pipeline的根目录下做简单的单元测试python src/chunker.py结果如下第四步Git同步把这行具有里程碑意义的代码存入 Git 账本# 1. 检查当前状态你会看到 src/chunker.py 变成了红色 git status # 2. 把修改并测试通过的 chunker.py 添加到暂存区 git add src/chunker.py # 3. 签字画押feat 标签代表这是一个开发成功的新功能 git commit -m feat: implement semantic chunker with sentence boundary and overlap retention第五步多线程自动化管道src/pipeline.py作用是调用刚才写好的chunker.py批量、多线程地去把某个文件夹下的海量 PDF 文献读进来然后自动调用本地免费的 Embedding 模型变成向量一键灌入向量数据库Chroma里。pipeline.py完整代码如下import os from concurrent.futures import ThreadPoolExecutor from loguru import logger from langchain_community.vectorstores import FAISS from langchain_zhipu import ZhipuAIEmbeddings from pypdf import PdfReader # 优雅复用你的高级语义切块器 from chunker import SemanticChunker class AutoDataPipeline: def __init__(self, input_dir: str, db_dir: str): 自动化高性能数据资产管道初始化 :param input_dir: 存放待处理原始 PDF 文献的本地目录 :param db_dir: 向量数据库最终在本地持久化导出的资产目录 self.input_dir input_dir self.db_dir db_dir # 1. 实例化高级切块器组件单片上限500字重叠80字保证语义连续 self.chunker SemanticChunker(chunk_size500, chunk_overlap80) # 2. 建立云端安全网关连接完全解耦不消耗本地CPU/GPU算力 logger.info( 正在连接云端免费高维 Embedding 模型网关...) self.embeddings ZhipuAIEmbeddings( api_key替换 ) logger.success(✅ 云端模型网关握手成功) def process_single_file(self, file_name: str): 核心ETL单文件闭环从PDF中压榨文本 - 智能化切块 - 自动流控落库 if not file_name.endswith(.pdf): return file_path os.path.join(self.input_dir, file_name) logger.warning(f [流水线启动] 正在纯净并行处理文件: {file_name}) try: # ----------------------------------------------------------------- # STEP 1: Extraction (数据抽取) # 使用纯 Python 编写的 PdfReader 逐页读取文本100% 避开本地任何重量级模型库 # ----------------------------------------------------------------- reader PdfReader(file_path) text_list [] for page in reader.pages: page_text page.extract_text() if page_text: text_list.append(page_text) full_text .join(text_list) # 严格边界拦截如果是纯扫描件图片提取不出文本直接安全熔断防止污染上游 if not full_text.strip(): logger.error(f❌ 文件 {file_name} 提取内容为空可能是纯扫描件图片已拦截。) return # ----------------------------------------------------------------- # STEP 2: Transformation (数据清洗与语义切块) # 自动灌入结构化元数据Metadata方便未来在大模型检索时进行精确溯源 # ----------------------------------------------------------------- base_metadata {source: file_name, data_type: unstructured_report} chunks self.chunker.split_text(full_text, base_metadata) # ----------------------------------------------------------------- # STEP 3: Loading (工业级流控向量沉淀) # ----------------------------------------------------------------- # 【核心防御性机制】物理过滤一切空字符串或纯空格块防止触发云端参数有误报错 clean_chunks [c for c in chunks if c[page_content] and c[page_content].strip()] texts [c[page_content] for c in clean_chunks] metadatas [c[metadata] for c in clean_chunks] if not texts: logger.warning(f⚠️ 文件 {file_name} 经过纯净清洗后未检测到合法文本跳过落库。) return logger.info(f 正在将 {file_name} 的 {len(texts)} 个精纯向量节点批量沉淀至本地库...) # 【★ 终极破案手写高并发窗口滑动机制 ★】 # 旧版集成库在 from_texts 内部存在不透传参数的 Bug。我们直接在最前端手写分批 # 强行每次最多只打包 64 条数据送往智谱网关完美兼容并对齐云端的物理吞吐硬限制。 db None CHUNK_LIMIT 64 for i in range(0, len(texts), CHUNK_LIMIT): batch_texts texts[i:i CHUNK_LIMIT] batch_metadatas metadatas[i:i CHUNK_LIMIT] logger.info(f 正在发送当前网络分批: 正在写入第 {i} 到 {i len(batch_texts)} 个高维向量节点...) if db is None: # 第一批次在内存中直接拉起 FAISS 基础矩阵地基 db FAISS.from_texts(textsbatch_texts, embeddingself.embeddings, metadatasbatch_metadatas) else: # 后续批次增量追加在内存中动态拼接矩阵无任何硬盘 I/O 锁死风险 db.add_texts(textsbatch_texts, metadatasbatch_metadatas) # ----------------------------------------------------------------- # STEP 4: Serialization (原子化资产持久化) # 整个文件所有切块在内存里完美转化完毕后一次性原子落盘在 D 盘生成精纯资产 # ----------------------------------------------------------------- if db: db.save_local(self.db_dir) logger.success(f [处理成功] 知识资产已完美录入本地 FAISS 向量库: {file_name}) except Exception as e: logger.error(f❌ [处理失败] 文件 {file_name} 在流水线中发生异常: {str(e)}) def get_file_md5(self, file_path: str) - str: 【新增物理审计】计算文件的唯一MD5指纹防止同名不同内容或者改名重复执行 import hashlib hasher hashlib.md5() with open(file_path, rb) as f: # 每次读取 4KB防止大文件吃爆内存 for chunk in iter(lambda: f.read(4096), b): hasher.update(chunk) return hasher.hexdigest() def run_pipeline(self, max_workers: int 4): 高性能并发总控引擎引入工业级断点续传与智能去重审计 if not os.path.exists(self.input_dir): os.makedirs(self.input_dir) logger.warning(f输入目录 {self.input_dir} 不存在已自动创建。) return # 1. 初始化/读取成功落库的历史文献 log_file_path os.path.join(self.db_dir, processed_files.txt) processed_hashes set() if os.path.exists(log_file_path): with open(log_file_path, r, encodingutf-8) as lf: processed_hashes set(line.strip() for line in lf if line.strip()) raw_files [f for f in os.listdir(self.input_dir) if f.endswith(.pdf)] if not raw_files: logger.error(f 发现待处理的 PDF 文件数量为 0。请先往 {self.input_dir} 文件夹中放置 PDF 文献) return # 2. 【核心去重漏斗】遍历文件计算指纹剔除已经处理过的文献 files_to_process [] for file_name in raw_files: file_path os.path.join(self.input_dir, file_name) file_hash self.get_file_md5(file_path) if file_hash in processed_hashes: # 瞬间跳过控制台亮起优雅的白色日志 logger.info(f⏭️ [智能跳过] 检测到文献 {file_name} 历史已成功落库无需重复计算。) else: # 登记进入本次动工的“生死簿” files_to_process.append((file_name, file_hash)) if not files_to_process: logger.success(✨ [完美对齐] 目录内所有文献均已在本地向量库中无任何新任务需要执行) return logger.info(f 自动化并行数据管道触发待冲锋新任务: {len(files_to_process)} 个分配线程数: {max_workers}) # 3. 剥离出纯文件名列表扔给线程池并行动工 pure_file_names [item[0] for item in files_to_process] with ThreadPoolExecutor(max_workersmax_workers) as executor: executor.map(self.process_single_file, pure_file_names) # 4. 【全量大捷后追加账本】将本次成功动工的指纹追加写入物理账本固化成果 # 注意为了简化逻辑默认本次多线程运行全部成功。工业上会严格配合 try-catch 成功后才写入 os.makedirs(self.db_dir, exist_okTrue) with open(log_file_path, a, encodingutf-8) as lf: for _, file_hash in files_to_process: lf.write(f{file_hash}\n) logger.success( [大获全胜] 管道全线畅通新版增量向量资产追加完毕) if __name__ __main__: # 配置统一输入输出目录 INPUT_DIRECTORY ./data/input VECTOR_DB_DIRECTORY ./data/vector_db pipeline AutoDataPipeline(input_dirINPUT_DIRECTORY, db_dirVECTOR_DB_DIRECTORY) pipeline.run_pipeline(max_workers2)第六步配置智谱大模型接口智谱AI开放平台1. 在终端安装智谱 AI 的免费开源官方桥接件 pip install langchain-community 2. 找到下面的代码行替换成自己的 self.embeddings ZhipuAIEmbeddings( zhipuai_api_key替换 )第七步填入PDF文献打开rag-data-pipeline文件夹。创建一个data文件夹点进去再建一个名为input的子文件夹。从你的电脑里随便找一两篇普通的 PDF 格式文件比如你以前的大学课件、论文、说明书或者任何 PDF 报告都行把它们复制并粘贴到data/input/文件夹里面。⚠️ 只有一个小小的“避坑点”千万不要找那种“纯图片扫描版”的 PDF就是那种里面的文字用鼠标完全没办法选中、像一张张照片拼起来的 PDF。因为我们目前使用的是轻量级的文本提取器它只能读取 PDF 里的“原生文本”。如果是纯图片它会识别出空内容。第八步:Pipeline.py测试运行python src/pipeline.py大获全胜第一次测试用一个文件做测试即可没问题之后再多加入几个pdf文献比如三个文件一起测试多线程并发。代码中加入来筛选和清洗避免文件重复解析录入浪费资源。再额外加入另一个文件测试是否会被准确跳过。可以观察到之前的三个已经被跳过了非常成功再次运行可以发现全部跳过。第九步Git同步# 1. 检查当前状态你会看到 src/chunker.py 变成了红色 git status # 2. 把修改并测试通过的 chunker.py 添加到暂存区 git add src/pipeline.py # 3. 签字画押feat 标签代表这是一个开发成功的新功能 git commit -m feat: implement semantic pipeline with sentence boundary and overlap retention下一篇知识检索与大模型智能问答部分Retrieval Generation

相关新闻

从0开始做基于 RAG 架构的多源非结构化数据自动化 ETL 与知识库构建系统(知识检索与大模型智能问答部分)

从0开始做基于 RAG 架构的多源非结构化数据自动化 ETL 与知识库构建系统(知识检索与大模型智能问答部分)

第一步:新建一个总控脚本 src/app.py完整代码如下:import os import sys from loguru import logger from langchain_community.vectorstores import FAISS from langchain_zhipu import ZhipuAIEmbeddings, ChatZhipuAI from langchain_core.prompts im…

2026/7/19 17:19:36阅读更多 →
智能刷题 Coach 的反馈闭环:做题、评估与弱点定位的自动化流程

智能刷题 Coach 的反馈闭环:做题、评估与弱点定位的自动化流程

智能刷题 Coach 的反馈闭环:做题、评估与弱点定位的自动化流程 一、刷了 500 道题,动态规划还是做不好,问题出在哪 很多刷题者经历过这样的场景:LeetCode 上刷了几个月,题量上去了,但某类问题&#xff08…

2026/7/19 17:17:35阅读更多 →
mlx-community/gemma-4-e2b-it-mxfp8模型架构解析: vision_config与text_config如何协同工作?

mlx-community/gemma-4-e2b-it-mxfp8模型架构解析: vision_config与text_config如何协同工作?

mlx-community/gemma-4-e2b-it-mxfp8模型架构解析: vision_config与text_config如何协同工作? 【免费下载链接】gemma-4-e2b-it-mxfp8 项目地址: https://ai.gitcode.com/hf_mirrors/mlx-community/gemma-4-e2b-it-mxfp8 mlx-community/gemma-4-…

2026/7/19 17:17:35阅读更多 →
ngx_output_chain_get_buf

ngx_output_chain_get_buf

1 定义 ngx_output_chain_get_buf 函数 定义在 src/core/ngx_output_chain.cstatic ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) {size_t size;ngx_buf_t *b, *in;ngx_uint_t recycled;in ctx->in->buf;size ctx->buf…

2026/7/20 0:15:05阅读更多 →
互联网大厂常见Java面试题及答案汇总(2026持续更新)

互联网大厂常见Java面试题及答案汇总(2026持续更新)

金九银十即将来袭,又是一个跳槽的好季节,准备跳槽的同学都摩拳擦掌准备大面好几场,今天为大家准备了互联网面试必备的 1 到 5 年 Java 面试者都需要掌握的面试题,分别 JVM,并发编程,MySQL,Tomca…

2026/7/20 0:15:05阅读更多 →
python数据可视化技巧的100个练习 -- 31. 类别数据的点图

python数据可视化技巧的100个练习 -- 31. 类别数据的点图

重要性★★★☆☆ 难度★★☆☆☆ 你是一家零售公司的数据分析师。你的经理要求你可视化最近产品发布的客户满意度评级分布。评级是分类的,范围从“非常不满意”到“非常满意”。创建一个点图以显示每个评级类别的频率。使用 Python 进行数据处理和可视化。在代码中生成输入…

2026/7/20 0:13:05阅读更多 →
智能体走进物理世界,千里科技携舱驾协同成果亮相WAIC 2026

智能体走进物理世界,千里科技携舱驾协同成果亮相WAIC 2026

在2026世界人工智能大会(WAIC 2026)举办期间,千里科技董事长、阶跃星辰董事长印奇作为特邀嘉宾出席大会开幕式并在大会主论坛(上午场)发表主题演讲《当智能体进入物理世界》。在印奇看来,"智能体"…

2026/7/20 0:13:05阅读更多 →
商汤大装置发布“技术-生态-商业”闭环布局,共启“国产AI基础设施规模化商用元年”

商汤大装置发布“技术-生态-商业”闭环布局,共启“国产AI基础设施规模化商用元年”

7月18日,在WAIC 2026商汤科技 “基座大模型架构创新与生态合作论坛”上,商汤科技联合创始人、大装置事业群总裁杨帆发表《智变共生——加速AI基础设施持续升级》主题演讲,系统呈现了商汤大装置国产AI基础设施“技术-生态-商业”闭环布局&…

2026/7/20 0:13:05阅读更多 →
2026郑州美发学校避坑指南:拆解5种教学方式,谁在“流水线”谁在“真传技”?

2026郑州美发学校避坑指南:拆解5种教学方式,谁在“流水线”谁在“真传技”?

2026年想在郑州学美发,很多零基础学员最先搜索的问题就是:郑州美发学校哪家好?这个问题没有一个只看学校名字就能得出的答案。因为不同学校的课程方向、学习周期、教学方式和适合人群并不一样。有的更适合零基础,有的偏向发型师进修,还有的只做某一项短期技术培训。对于完全没…

2026/7/20 0:11:05阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/20 0:50:54阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/20 0:50:54阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/20 0:50:54阅读更多 →
2026 WAIC:努比亚二代“豆包手机”NaviX Ultra亮相,智能体验全面升级!

2026 WAIC:努比亚二代“豆包手机”NaviX Ultra亮相,智能体验全面升级!

7月18日智东西消息,在2026 WAIC期间,努比亚联合字节豆包打造的二代“豆包手机”努比亚NaviX Ultra首次亮相,相比一代有诸多升级。智能体手机理念中兴通讯终端事业部总裁、努比亚总裁倪飞表示,智能体手机要从人操作手机变为手机帮人…

2026/7/20 0:01:04阅读更多 →
努比亚NaviX Ultra亮相WAIC,智能体手机能否让用户生活更简单?

努比亚NaviX Ultra亮相WAIC,智能体手机能否让用户生活更简单?

努比亚NaviX Ultra:外观与功能双升级在2026 WAIC期间,首次亮相的努比亚NaviX Ultra吸引了众多目光。它是努比亚联合字节豆包打造的二代“豆包手机”,与一代努比亚M153相比,外观设计变化较大。其机身背部搭载横向排布的大尺寸影像模…

2026/7/20 0:01:04阅读更多 →
C# 将逗号分割的字符串转换为long,并添加到List<long>

C# 将逗号分割的字符串转换为long,并添加到List<long>

目录 方法1:使用Split和Convert.ToInt64 方法2:使用LINQ的Select和ToList 方法3:使用TryParse进行异常安全转换(推荐) 如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天…

2026/7/20 0:01:04阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/19 22:50:49阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/19 14:50:26阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/19 18:50:36阅读更多 →