Python AI知识库源码实战:RAG检索增强生成与向量数据库全流程

发布时间:2026/10/11 17:00:03
Python AI知识库源码实战:RAG检索增强生成与向量数据库全流程 简介这份AI知识库系统Python源码面向希望学习或二次开发知识管理系统的开发者尤其适合具备Python基础、想了解数据库设计与模块化Web应用结构的中级学习者。源码包共22个文件以10个html模板、6个py脚本、4个pyc字节码、1个txt说明文档和1个db数据库文件为主压缩包约53KB涵盖前端页面、后端逻辑、配置与数据持久化等层次。其中数据库文件承担知识数据的存储与索引配置脚本管理连接与上传检索参数初始化脚本负责建表与预置分类入口脚本串联各模块启动系统模板文件则支撑注册、登录、文章管理与问答检索等交互界面。已有66人学习下载。通过阅读这套源码读者可以掌握知识库系统从数据库初始化到页面渲染的完整链路理解模块划分与配置管理思路并以此为基础扩展文件上传、语义检索等功能适合作为课程设计或小型项目的参考骨架。1. 从一份 Python AI 知识库源码说起它能替你省掉哪三周的重复劳动如果你正在做企业内部文档问答、客服知识检索或者想把一堆 PDF、Markdown、Word 变成一个能对话的私有知识库那你大概率已经翻过 LangChain 的文档、试过几个开源方案最后卡在「能跑起来但不知道怎么改」这一步。这份 Python AI 知识库系统源码解决的就是这个卡点它不是一段 demo 脚本而是一套带检索、向量化、对话链路的完整工程结构拿到手就能顺着模块往下改。适合谁适合已经会 Python 基础语法、装过 pip 包、但没时间从零搭 RAG 管线的后端或算法同学。我拿到这份源码的第一反应是——终于不用再自己拼 Chroma 和 FastAPI 的胶水代码了。下面按「它是什么 → 怎么跑 → 怎么改 → 坑在哪」的顺序拆一遍。2. 拆开源码看结构向量检索、文档切分、对话链各在哪一层2.1 目录结构与模块职责拿到一份源码我习惯先看目录树再动手装依赖。这份工程的结构大致是这样组织的入口层负责启动 API 服务核心层放检索和向量化逻辑数据层管文档加载和切分配置层集中管理模型参数和路径。常见做法是app/放路由和启动逻辑core/放 RAG 管线data/放原始文档和向量库持久化文件config/或根目录的.env管密钥和模型名。先别急着pip install用一条命令把结构看清楚# 查看项目目录层级排除缓存和虚拟环境 find . -maxdepth 3 -type f -name *.py | grep -v __pycache__ | sort这条命令帮你快速定位哪些文件是业务代码、哪些是工具脚本。逻辑说明-maxdepth 3限制层级避免翻到依赖包内部grep -v __pycache__过滤编译缓存。参数可以按需调整如果你的项目嵌套更深改成 4 或 5。2.2 向量化与检索链路的关键参数知识库系统的核心就两步把文档变成向量存起来查询时把问题变成向量去比对。这份源码里文档切分的 chunk_size 和 chunk_overlap 直接决定检索质量。chunk_size 太大检索到的段落包含太多无关信息模型回答会跑偏太小上下文断裂答案不完整。我一般会从 500 字符起步overlap 设成 chunk_size 的 10% 到 20%。# 文档切分配置示例参数需根据文档类型调整 from langchain.text_splitter import RecursiveCharacterTextSplitter splitter RecursiveCharacterTextSplitter( chunk_size500, # 每段最大字符数中文文档建议 300-600 chunk_overlap80, # 相邻段重叠字符数防止语义被切断 separators[\n\n, \n, 。, , , , ] # 中文优先按句号切 ) docs splitter.split_documents(raw_documents) print(f切分后段落数: {len(docs)})逻辑说明RecursiveCharacterTextSplitter会按 separators 列表顺序尝试切分先按段落、再按句子、最后按字符。参数说明chunk_size控制单段长度chunk_overlap保证跨段语义连续。中文文档一定要把中文标点加进 separators否则会按空格切效果很差——这是血泪经验。2.3 向量库选型与持久化源码里默认用的向量库可能是 Chroma 或 FAISS。Chroma 适合开发阶段自带持久化、API 简单FAISS 适合数据量大、追求检索速度的场景但需要自己管理索引文件。选哪个取决于你的文档规模几千段用 Chroma 足够几十万段以上考虑 FAISS 或 Milvus。# Chroma 持久化向量库初始化 from langchain.vectorstores import Chroma from langchain.embeddings import OpenAIEmbeddings embedding OpenAIEmbeddings(modeltext-embedding-ada-002) vectordb Chroma.from_documents( documentsdocs, embeddingembedding, persist_directory./chroma_db # 向量数据落盘路径 ) vectordb.persist() # 显式持久化避免重启后丢失逻辑说明from_documents会逐段调用 embedding 接口并写入向量库。参数说明persist_directory指定落盘目录下次启动时用Chroma(persist_directory...)直接加载不用重新向量化。注意 embedding 模型如果换了旧向量库不能复用必须重建。3. 把源码跑起来环境配置、依赖安装与首次问答验证3.1 Python 环境与依赖安装这份源码对 Python 版本有要求常见是 3.9 以上。如果你机器上有多个版本建议用虚拟环境隔离避免和系统包冲突。python安装教程网上很多但关键就一步确认python --version输出的是你想要的版本。# 创建虚拟环境并激活 python -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows # 安装依赖建议加国内镜像加速 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple逻辑说明虚拟环境把项目依赖和系统 Python 隔开删掉 venv 目录就等于卸载干净。参数说明-i指定 pip 源国内网络环境下能明显加快下载。如果 requirements.txt 里有版本冲突先看报错里哪个包不兼容再单独降级或升级那个包。3.2 配置文件与密钥管理源码通常用.env文件管理 API Key 和模型名。不要把这些硬编码在 Python 文件里一是泄露风险二是换模型时要改多处。常见做法是用python-dotenv加载。# .env 文件内容示例 OPENAI_API_KEYsk-xxxxxxxxxxxxxxxx OPENAI_BASE_URLhttps://api.openai.com/v1 MODEL_NAMEgpt-3.5-turbo EMBEDDING_MODELtext-embedding-ada-002 CHROMA_PERSIST_DIR./chroma_db# 加载配置的代码片段 import os from dotenv import load_dotenv load_dotenv() # 读取 .env 文件到环境变量 api_key os.getenv(OPENAI_API_KEY) model_name os.getenv(MODEL_NAME, gpt-3.5-turbo) # 第二个参数是默认值逻辑说明load_dotenv()把 .env 里的键值对注入os.environ后续代码用os.getenv读取。参数说明os.getenv的第二个参数是找不到时的默认值建议给关键配置都设上避免 None 导致启动报错。3.3 灌入文档并验证检索环境配好后第一步不是直接问问题而是先灌文档、再单独验证检索是否命中。很多人跳过这步结果问答效果差却不知道是检索问题还是生成问题。# 加载本地文档并灌入向量库 from langchain.document_loaders import DirectoryLoader, TextLoader loader DirectoryLoader(./docs, glob**/*.md, loader_clsTextLoader) raw_docs loader.load() print(f加载文档数: {len(raw_docs)}) # 切分后灌入 docs splitter.split_documents(raw_docs) vectordb Chroma.from_documents(docs, embedding, persist_directory./chroma_db) # 单独测试检索不经过大模型 query 系统的部署流程是什么 results vectordb.similarity_search(query, k3) for i, doc in enumerate(results): print(f--- 命中段落 {i1} ---) print(doc.page_content[:200])逻辑说明先加载、再切分、再向量化三步分开验证。参数说明k3表示返回最相似的 3 段调大能提高召回但会增加后续模型输入长度。如果检索结果和问题无关先检查切分粒度再检查 embedding 模型是否适合中文。4. 改造成自己的知识库换模型、换数据源、调检索策略4.1 替换 Embedding 与对话模型源码默认可能用 OpenAI 的接口但实际项目里经常要换成别的模型。换 embedding 模型时要注意向量维度变了旧向量库必须重建。换对话模型相对简单只要接口兼容 OpenAI 格式改MODEL_NAME和BASE_URL就行。# 替换为本地 embedding 模型的示例 from langchain.embeddings import HuggingFaceEmbeddings embedding HuggingFaceEmbeddings( model_nameBAAI/bge-small-zh-v1.5, # 中文效果较好的轻量模型 model_kwargs{device: cpu}, # 有 GPU 改成 cuda encode_kwargs{normalize_embeddings: True} # 归一化提升余弦相似度精度 )逻辑说明HuggingFaceEmbeddings 会在本地加载模型不依赖外部 API。参数说明device控制推理设备normalize_embeddings对余弦相似度检索很关键不开的话相似度计算会有偏差。换完 embedding 后必须删掉旧 chroma_db 目录重新灌数据。4.2 接入多种文档格式实际知识库不可能只有 Markdown。PDF、Word、Excel 都要能读。源码里如果只带了 TextLoader你需要自己补 PDF 和 Word 的 loader。# 多格式文档加载 from langchain.document_loaders import PyPDFLoader, Docx2txtLoader, CSVLoader def load_document(file_path): if file_path.endswith(.pdf): return PyPDFLoader(file_path).load() elif file_path.endswith(.docx): return Docx2txtLoader(file_path).load() elif file_path.endswith(.csv): return CSVLoader(file_path).load() else: return TextLoader(file_path).load()逻辑说明按扩展名分派到不同 loader统一返回 Document 列表。参数说明PyPDFLoader 对扫描版 PDF 无效需要 OCR 预处理CSVLoader 默认把每行当一段列多的话要指定source_column。4.3 检索策略调优相似度阈值与重排序默认的 similarity_search 只按向量距离返回 top-k但实际中有些问题检索回来的段落相似度很低硬塞给模型反而干扰回答。加一个相似度阈值过滤再配合重排序效果会稳很多。# 带阈值过滤的检索 results vectordb.similarity_search_with_score(query, k5) filtered [(doc, score) for doc, score in results if score 0.8] # 距离越小越相似 print(f过滤后剩余: {len(filtered)} 段) # 如果过滤后为空说明知识库里没有相关内容应直接告知用户 if not filtered: print(知识库中未找到相关内容请换个问法或补充文档)逻辑说明similarity_search_with_score返回文档和距离分数距离越小越相似。参数说明阈值 0.8 是经验值不同 embedding 模型的分数分布不同需要拿实际数据试。过滤后为空时不要让模型硬答否则会出现幻觉。5. 避坑与排查源码跑不通时先看这几处5.1 依赖版本冲突导致 import 报错现象pip install -r requirements.txt后运行报ImportError或AttributeError提示某个模块没有某个函数。原因LangChain 生态更新快不同版本 API 差异大requirements.txt 里如果没锁版本装到最新版就可能不兼容。解决先看报错涉及哪个包用pip show 包名看当前版本再对照源码里 import 的写法降级到匹配版本。常见做法是在 requirements.txt 里把关键包用锁死。5.2 向量库重建后检索结果为空现象换了 embedding 模型或改了切分参数重新灌数据后检索什么都查不到。原因旧向量库目录没删新数据写进去了但查询时加载的还是旧索引或者维度不匹配导致写入失败但没报错。解决每次换 embedding 模型或切分策略先rm -rf chroma_db再重新灌。灌完后用一条已知答案的问题验证检索命中。5.3 API 调用超时或返回 429现象灌数据时跑到一半报超时或RateLimitError。原因embedding 接口有并发限制文档量大时逐条调用会触发限流。解决加批处理和重试。常见做法是用embed_documents批量接口每批 100 段批间加time.sleep(1)并对 429 错误做指数退避重试。import time from tenacity import retry, stop_after_attempt, wait_exponential retry(stopstop_after_attempt(3), waitwait_exponential(multiplier1, max10)) def embed_batch(texts): return embedding.embed_documents(texts) # 分批处理 batch_size 100 for i in range(0, len(texts), batch_size): batch texts[i:ibatch_size] embed_batch(batch) time.sleep(1) # 批间间隔降低限流概率逻辑说明tenacity的 retry 装饰器在失败时自动重试wait_exponential让每次重试间隔翻倍。参数说明stop_after_attempt(3)最多重试 3 次multiplier1起始间隔 1 秒。批大小 100 是经验值接口限流严的话调到 50。5.4 中文文档切分后语义断裂现象检索回来的段落读起来前言不搭后语答案缺关键信息。原因切分器按空格或英文标点切中文句子被从中间截断。解决在 separators 里把中文标点放前面并适当增大 chunk_overlap。如果文档结构规整也可以按标题层级切分保证每段自带上下文。5.5 对话模型答非所问或编造内容现象检索明明命中了正确段落但模型回答里出现了文档中没有的信息。原因prompt 里没有约束模型「只根据给定上下文回答」或者上下文塞了太多无关段落干扰。解决在 prompt 模板里明确写「如果上下文中没有答案直接说不知道」并控制传入的段落数量一般 3 到 5 段足够。6. 进阶技巧用元数据过滤把检索精度再提一档源码跑通、问答能用之后下一步是让检索更准。纯向量检索有个天然短板它只看语义相似度不看文档来源、时间、类型。比如你问「最新的部署流程」它可能返回一篇半年前的旧文档因为语义上更匹配。解决办法是给每个文档块打元数据标签检索时先过滤再比对。# 灌数据时附加元数据 for doc in docs: doc.metadata[source] doc.metadata.get(source, unknown) doc.metadata[date] 2024-06 # 从文件名或内容中提取 doc.metadata[category] deployment # 按目录或标签分类 vectordb Chroma.from_documents(docs, embedding, persist_directory./chroma_db) # 检索时按元数据过滤 results vectordb.similarity_search( query, k5, filter{category: deployment} # 只在部署类文档中检索 )逻辑说明filter参数在向量比对前先做元数据筛选缩小检索范围。参数说明filter 的写法取决于向量库Chroma 支持这种字典语法FAISS 需要自己实现。元数据字段建议在灌数据阶段就统一好后期补很麻烦。再进一步是重排序。向量检索召回 top-20再用一个交叉编码器对这 20 段重新打分取前 3 段给模型。这样精度明显提升代价是多一次模型推理。# 用 CrossEncoder 做重排序 from sentence_transformers import CrossEncoder reranker CrossEncoder(BAAI/bge-reranker-base) pairs [(query, doc.page_content) for doc in results] scores reranker.predict(pairs) ranked sorted(zip(results, scores), keylambda x: x[1], reverseTrue)[:3]逻辑说明CrossEncoder 把问题和每段文档拼在一起打分比向量点积更准但更慢。参数说明bge-reranker-base是中文场景常用的轻量重排模型GPU 环境下延迟可以接受。如果知识库规模不大、查询频率不高这步可以省但如果用户对答案准确率要求高加上重排序是值得的。我自己的习惯是每次换 embedding 模型或调整切分参数后先拿 20 条已知答案的问题跑一遍检索命中率确认召回没问题再去看生成效果。从那以后我每次改 RAG 管线都强制走一遍这个验证流程省得后面排查时分不清是检索还是生成的锅。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询