向量检索增强生成(RAG,Retrieval‑Augmented Generation),是弥补大语言模型固有缺陷的关键技术。它可接入私有文档、内部笔记等外部数据源,有效缓解训练数据滞后、知识固化、回答幻觉等问题,输出更为精准可信的内容。Naive RAG 即朴素 RAG,是 RAG 体系中最基础原始的实现方式,也是各类进阶 RAG 技术的底层基石。该方案架构极简、落地门槛低,舍弃复杂优化手段,只保留检索加生成的核心能力。很适合新手学习实践,同时该方式也多用于搭建轻量化知识库问答服务,适配各类简单问答场景。
当前主流 RAG 存在三种典型实现范式,分别为 Naive‑RAG、Advanced‑RAG、Agentic‑RAG。本章将以 Naive‑RAG 为例,介绍其功能实现逻辑,以及调用大模型完成 RAG 检索的完整流程。Naive‑RAG 在处理检索结果时,通常直接复用检索得到的文档片段,不会对召回内容做额外加工与二次处理。
完整流程为:用户输入问题后,直接执行语义相似度检索,通过向量相似度打分筛选出匹配度最高的文档块;随后将检索获取的上下文片段传入 LCEL 执行链,与提示词进行拼接,完成向量检索推理,最终交由大模型生成回答。
该方案仅依靠基础语义相似度完成召回,不具备查询改写、结果重排序、文本块优化等高级能力。但其实现逻辑简洁、开发效率高、调试难度低,是入门学习 RAG 技术的首选方案。
环境依赖安装 1、项目运行需依赖文档解析、文本分割、向量数据库、网络请求等核心库,为保证安装速度和稳定性,统一使用清华PyPI镜像源批量安装所有依赖,避免后续开发过程中反复补装库文件。
CMD> pip install -i https://pypi.tuna.tsinghua.edu.cn/simple langchain_text_splitters langchain_chroma chromadb pypdf requests bs4 CMD> CMD> pip list Package Version ---------------------------------------- ----------- beautifulsoup4 4.15.0 bs4 0.0.2 chromadb 1.5.9 langchain-chroma 1.1.0 langchain-text-splitters 1.1.2 pypdf 6.16.1 requests 2.34.2
2、大模型知识库检索分为对话大模型和Embedding向量模型两类,二者作用完全不同。对话模型输出自然语言文本(供人阅读),向量模型输出浮点型向量数组(供机器计算相似度),是实现RAG检索生成的核心组件。
本次选用 Qwen3-Embedding-0.6B-GGUF 轻量向量模型,模型存放于阿里魔搭社区,可直接访问链接下载对应文件:
下载完成后,将模型文件直接放入llama.cpp根目录,与后续启动脚本同级,避免因路径错误导致模型加载失败。
3、为避免对话模型和向量模型端口冲突、服务相互干扰,本次采用双端口分离部署方案。11433端口承载对话大模型服务,11434端口承载Embedding向量模型服务,两个服务独立运行、各司其职。
对话大模型服务启动,用于实现自然语言问答、对话交互,加载通用指令微调大模型,上下文窗口设置为4096,适配常规问答场景。
CMD> llama-server.exe -m qwen2.5-1.5b-instruct-q4_k_m.gguf --host 127.0.0.1 --port 11433 -c 4096 init: llama threadpool init, n_threads = 12 load_model: initializing, n_slots = 4, n_ctx_slot = 4096, kv_unified = 'true' llama_server: model loaded llama_server: listening on http://127.0.0.1:11433
向量Embedding模型服务启动,核心增加 --embeddings 参数,强制模型以向量编码模式启动,不输出文本,仅输出向量数据。
CMD> llama-server.exe -m Qwen3-Embedding-0.6B-Q8_0.gguf --host 127.0.0.1 --port 11434 -c 4096 --embeddings -b 512 -ub 512 init: llama threadpool init, n_threads = 12 load_model: initializing, n_slots = 4, n_ctx_slot = 4096, kv_unified = 'true' llama_server: model loaded llama_server: listening on http://127.0.0.1:11434
文本向量维度测试 Llama.cpp 内置 OpenAI 兼容接口标准,无需部署 OpenAI 服务,本地 GGUF 向量模型即可直接被 langchain_openai.OpenAIEmbeddings 调用,大幅降低本地RAG开发适配成本。
本段代码核心目的:验证向量模型服务可用性、向量维度合法性、文本向量化一致性,是RAG项目前置必测环节。核心区分两个核心向量化方法:
embed_query:面向用户提问,单条短句向量化,向量特征适配「检索匹配」场景;
embed_documents:面向知识库切片,批量长文本向量化,向量特征适配「入库存储」场景。
from langchain_openai import OpenAIEmbeddingsembeddings = OpenAIEmbeddings( model="Qwen3-Embedding-0.6B-Q8_0.gguf" , base_url="http://127.0.0.1:11434/v1" , api_key="dummy" ) text = "人工智能是什么" query_vector = embeddings.embed_query(text) print (f"向量长度:{len (query_vector)} " )print (f"前5个向量:{query_vector[:5 ]} " )texts = ["大模型" , "RAG检索增强生成" , "向量数据库" ] doc_vectors = embeddings.embed_documents(texts) print (f"文档向量数量:{len (doc_vectors)} " )print (f"文档向量前5个:{doc_vectors[0 ][:5 ]} " )print (f"文档向量前5个:{doc_vectors[1 ][:5 ]} " )print (f"文档向量前5个:{doc_vectors[2 ][:5 ]} " )
模型固定输出1024维浮点向量,所有文本的语义信息都会被压缩为统一维度的数值数组。语义相似度越高的文本,向量数值重合度越高、空间距离越近,这是语义检索的底层原理。
CMD> python main.py 向量长度:1024 前5个向量:[-0.021272549405694008, -0.04013322293758392, -0.016011258587241173, -0.1134452372789383, 0.014976831153035164] 文档向量数量:3 文档向量前5个:[0.012190932407975197, -0.04904358834028244, -0.011189550161361694, -0.04492426663637161, -0.02737090364098549] 文档向量前5个:[-0.021237701177597046, -0.0865737572312355, -0.018793350085616112, 0.08651088923215866, 0.02789725735783577] 文档向量前5个:[0.04903004691004753, -0.06314395368099213, -0.010090955533087254, -0.09537919610738754, 0.024128597229719162]
向量数据库存储与语义检索测试 Chroma 是轻量级嵌入式向量数据库,无需独立部署服务、无需额外数据库环境,开箱即用,极其适合本地轻量化RAG项目。核心特性为本地磁盘持久化,通过 persist_directory 参数指定存储目录,向量数据、原始文本、元数据会永久保存,重启项目无需重复向量化。
本段代码实现完整的「文本入库-向量存储-语义召回」流程,不依赖关键词匹配,仅通过向量空间距离计算相似度,支持模糊语义匹配。同时直观暴露 Naive RAG 原生短板:无重排序、无查询优化,单纯相似度检索容易出现匹配偏差。
from langchain_openai import OpenAIEmbeddingsfrom langchain_chroma import Chromaembeddings = OpenAIEmbeddings( model="qwen3-embedding-local.gguf" , base_url="http://127.0.0.1:11434/v1" , api_key="dummy" ) texts = [ "llama.cpp用来本地运行GGUF大模型,一款轻量级、高性能的本地大模型推理框架,主打低资源消耗,支持CPU、GPU混合推理。" , "RAG检索增强生成是解决大模型知识滞后、幻觉问题的核心技术,通过检索外部知识库,让大模型基于真实私有数据生成答案。" , "RAG技术核心流程分为文档加载、文本切片、向量嵌入存储、相似度检索、大模型生成回答五个核心步骤。" ] db = Chroma.from_texts( texts=texts, embedding=embeddings, persist_directory="./my_chroma_db" ) res = db.similarity_search("llamacpp能干什么?" ,k=2 ) print ("相似度检索结果:" )for idx, d in enumerate (res, 1 ): print (f"\n检索结果{idx} :{d.page_content} " )
本次检索结果看似不准确,是Naive RAG 典型缺陷:简短口语化问句与正式文档文本向量空间匹配度偏低,单纯向量相似度无法精准匹配业务语义。这也是进阶RAG需要引入重排序、查询改写、上下文优化的核心原因。
运行后项目目录自动生成 my_chroma_db 文件夹,即为持久化向量库,删除文件夹即可重置知识库数据。
CMD> python main.py 相似度检索结果: 检索结果1:RAG检索增强生成是解决大模型知识滞后、幻觉问题的核心技术,通过检索外部知识库,让大模型基于真实私有数据生成答案。 检索结果2:RAG技术核心流程分为文档加载、文本切片、向量嵌入存储、相似度检索、大模型生成回答五个核心步骤。
调用LCEL链测试 LCEL(LangChain Expression Language)是LangChain官方链式编程语法,用于极简、标准化组装AI业务流程,替代传统函数嵌套写法,结构清晰、易于调试、支持流式输出。
本段代码实现最简Naive RAG完整链路,覆盖全部核心环节:文档切片、向量库持久化、语义检索、Prompt约束、大模型生成、结果解析。同时引入向量距离分数可视化,分数越小语义相似度越高,可直观调试检索质量。
import osfrom langchain_openai import OpenAIEmbeddings, ChatOpenAIfrom langchain_chroma import Chromafrom langchain_text_splitters import RecursiveCharacterTextSplitterfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.runnables import RunnablePassthroughfrom langchain_core.output_parsers import StrOutputParserCHUNK_SIZE = 300 CHUNK_OVERLAP = 50 CHROMA_PERSIST_DIR = "./my_chroma_database" llm = ChatOpenAI( model="qwen2.5-1.5b-instruct-q4_k_m.gguf" , base_url="http://127.0.0.1:11433/v1" , api_key="dummy" , temperature=0.7 , max_tokens=512 , ) embeddings = OpenAIEmbeddings( model="qwen3-embedding-local.gguf" , base_url="http://127.0.0.1:11434/v1" , api_key="dummy" ) def build_vector_store (text_list: list [str ] ) -> Chroma: splitter = RecursiveCharacterTextSplitter( chunk_size=CHUNK_SIZE, chunk_overlap=CHUNK_OVERLAP, separators=["\n\n" , "\n" , "。" , "," , " " ] ) all_chunks = [] for text in text_list: chunks = splitter.split_text(text) all_chunks.extend(chunks) db = Chroma.from_texts( texts=all_chunks, embedding=embeddings, persist_directory=CHROMA_PERSIST_DIR ) print (f"[*] 向量库构建完成,共 {len (all_chunks)} 个文本块,保存到 {CHROMA_PERSIST_DIR} " ) return db def load_vector_store () -> Chroma: return Chroma( persist_directory=CHROMA_PERSIST_DIR, embedding_function=embeddings ) def format_docs (docs ): return "\n---\n" .join(doc.page_content for doc in docs) if __name__ == "__main__" : raw_texts = [ "llama.cpp用来本地运行GGUF大模型,支持CPU和GPU加速。" , "RAG检索增强生成用于知识库问答,先检索文档片段,再交给大模型生成答案。" , "Chroma是轻量级嵌入式向量数据库,可以本地持久化存储向量,不需要额外部署服务。" , "RecursiveCharacterTextSplitter用于把长文档切分成适合向量化的小块。" ] if os.path.exists(CHROMA_PERSIST_DIR): print ("[+] 检测到本地向量库,直接加载..." ) vector_db = load_vector_store() else : print ("[*] 本地向量库不存在,开始构建..." ) vector_db = build_vector_store(raw_texts) RETRIEVE_TOP_K = 4 retriever = vector_db.as_retriever(search_kwargs={"k" : RETRIEVE_TOP_K}) prompt = ChatPromptTemplate.from_messages([ ("system" , """你是知识库问答助手,请严格依据提供的上下文回答用户问题。 如果上下文中没有相关信息,直接回答“知识库中未找到相关内容”,不要编造信息。 参考上下文: {context}""" ), ("human" , "{question}" ) ]) rag_chain = ( {"context" : retriever | format_docs, "question" : RunnablePassthrough()} | prompt | llm | StrOutputParser() ) user_question = "llama.cpp有什么作用?" docs_score = vector_db.similarity_search_with_score(user_question, k=4 ) print ("\n[检索结果 (距离分数 越小越相似)]" ) for doc, score in docs_score: print (f"[分数:{score:.4 f} ] {doc.page_content} " ) answer = rag_chain.invoke(user_question) retrieved_docs = retriever.invoke(user_question) context_text = format_docs(retrieved_docs) print ("\n[检索到的上下文]" ) print (context_text) print ("\n[最终NaiveRAG回答]" ) print (answer)
本次运行充分体现 Naive RAG 的容错能力:虽然第一条检索结果匹配错误,但 Top4 召回集合中包含正确文档,大模型通过整合全部上下文,过滤无效信息、精准输出答案。
核心参数解读:temperature=0.7 平衡回答随机性与准确性,数值越低回答越严谨、越高越灵活;chunk_overlap 文本重叠量,用于避免切片截断丢失上下文信息。
CMD> python main.py [+] 检测到本地向量库,直接加载... [检索结果 (距离分数 越小越相似)] [分数:1.1428] RecursiveCharacterTextSplitter用于把长文档切分成适合向量化的小块。 [分数:1.1689] Chroma是轻量级嵌入式向量数据库,可以本地持久化存储向量,不需要额外部署服务。 [分数:1.2348] llama.cpp用来本地运行GGUF大模型,支持CPU和GPU加速。 [分数:1.2493] RAG检索增强生成用于知识库问答,先检索文档片段,再交给大模型生成答案。 [检索到的上下文] RecursiveCharacterTextSplitter用于把长文档切分成适合向量化的小块。 --- Chroma是轻量级嵌入式向量数据库,可以本地持久化存储向量,不需要额外部署服务。 --- llama.cpp用来本地运行GGUF大模型,支持CPU和GPU加速。 --- RAG检索增强生成用于知识库问答,先检索文档片段,再交给大模型生成答案。 [最终NaiveRAG回答] llama.cpp用于本地运行GGUF大模型,支持CPU和GPU加速。
调用LCEL增量测试 原生Chroma数据库存在重复添加文档生成冗余数据的问题,容易导致知识库内容重复、检索结果冗余,影响问答精度。因此本节在基础Naive RAG的基础上完成工程化升级,新增三项核心实用能力。
主要包含增量入库与覆盖入库双模式、MMR多样性检索、文档溯源元数据绑定三大能力,同时通过UUID唯一标识解决文档重复问题。MMR多样性检索能够优化基础相似度检索的缺陷,避免召回内容单一、重复,在保障语义匹配度的同时提升检索多样性;为每一个文本切片绑定文档来源元数据,可实现内容快速溯源、权限管控与文档迭代更新,是轻量化RAG项目的核心优化方案。
import osimport uuidfrom langchain_openai import OpenAIEmbeddings, ChatOpenAIfrom langchain_chroma import Chromafrom langchain_text_splitters import RecursiveCharacterTextSplitterfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.runnables import RunnablePassthroughfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.documents import DocumentCHUNK_SIZE = 300 CHUNK_OVERLAP = 50 CHROMA_PERSIST_DIR = "./my_chroma_database" RETRIEVE_TOP_K = 4 llm = ChatOpenAI( model="qwen2.5-1.5b-instruct-q4_k_m.gguf" , base_url="http://127.0.0.1:11433/v1" , api_key="dummy" , temperature=0.3 , max_tokens=800 , ) embeddings = OpenAIEmbeddings( model="qwen3-embedding-local.gguf" , base_url="http://127.0.0.1:11434/v1" , api_key="dummy" ) text_splitter = RecursiveCharacterTextSplitter( chunk_size=CHUNK_SIZE, chunk_overlap=CHUNK_OVERLAP, separators=["\n\n" , "\n" , "。" , "," , " " ] ) prompt = ChatPromptTemplate.from_messages([ ("system" , """你是知识库问答助手,请严格依据提供的上下文回答用户问题。 如果上下文中没有相关信息,直接回答“知识库中未找到相关内容”,不要编造信息。 参考上下文: {context}""" ), ("human" , "{question}" ) ]) def format_docs (docs ): return "\n---\n" .join( f"[来源:{doc.metadata.get('source' ,'未知' )} ]\n{doc.page_content} " for doc in docs ) def build_rag_chain (vector_db: Chroma ): retriever = vector_db.as_retriever( search_type="mmr" , search_kwargs={ "k" : RETRIEVE_TOP_K, "fetch_k" : 10 , "lambda_mult" :0.3 } ) rag_chain = ( {"context" : retriever | format_docs, "question" : RunnablePassthrough()} | prompt | llm | StrOutputParser() ) return rag_chain def add_documents_safe (db, docs ): ids = [str (uuid.uuid4()) for _ in docs] db.add_documents(docs, ids=ids) print (f"[+] 本次追加 {len (docs)} 个文本块,当前总数量:{db._collection.count()} " ) def get_vector_store (documents, incremental: bool = True ): """ :param documents: List[Document] 待入库文档 :param incremental: True=增量追加;False=覆盖重建(删除旧库) :return: Chroma db对象 """ if not incremental: if os.path.exists(CHROMA_PERSIST_DIR): import shutil shutil.rmtree(CHROMA_PERSIST_DIR) print ("[*] 删除旧向量库,开启覆盖重建模式" ) split_docs = text_splitter.split_documents(documents) if os.path.exists(CHROMA_PERSIST_DIR): print ("[+] 向量库已存在,增量追加新文档" ) db = Chroma(persist_directory=CHROMA_PERSIST_DIR, embedding_function=embeddings) add_documents_safe(db, split_docs) else : print ("[*] 新建向量库" ) db = Chroma.from_documents( documents=split_docs, embedding=embeddings, persist_directory=CHROMA_PERSIST_DIR ) print (f"[+] 存入 {len (split_docs)} 个文本块" ) return db if __name__ == "__main__" : batch = [ Document(page_content="llama.cpp用来本地运行GGUF大模型,支持CPU和GPU加速。" , metadata={"source" :"note1.txt" }), Document(page_content="RAG检索增强生成用于知识库问答。" , metadata={"source" :"note1.txt" }), Document(page_content="Chroma是轻量级向量数据库。" , metadata={"source" :"note2.txt" }), Document(page_content="RecursiveCharacterTextSplitter用于文档切分。" , metadata={"source" :"note2.txt" }), ] db = get_vector_store(batch, incremental=True ) print (f"\n向量库总文档数:{db._collection.count()} " ) docs_with_score = db.similarity_search_with_score("llama.cpp则作用是啥?" , k=10 ) print ("\n[全部检索结果(分数越小越相似)]" ) for doc, score in docs_with_score: print (f"score={score:.4 f} | source={doc.metadata['source' ]} | {doc.page_content} " ) chain = build_rag_chain(db) ans = chain.invoke("llama.cpp则作用是啥?" ) print (f"\n[最终NaiveRAG回答]: {ans} " )
MMR检索策略有效平衡相似度与多样性,lambda_mult=0.3 优先保证语义匹配精准度,同时规避结果同质化。输出结果自带文档来源,可快速定位知识库素材出处,适合后续知识库迭代优化。
CMD> python main.py [*] 新建向量库 [+] 存入 4 个文本块 向量库总文档数:4 [全部检索结果(分数越小越相似)] score=1.0284 | source =note1.txt | RAG检索增强生成用于知识库问答。 score=1.0645 | source =note1.txt | llama.cpp用来本地运行GGUF大模型,支持CPU和GPU加速。 score=1.1095 | source =note2.txt | Chroma是轻量级向量数据库。 score=1.1582 | source =note2.txt | RecursiveCharacterTextSplitter用于文档切分。 [最终NaiveRAG回答]: llama.cpp用来本地运行GGUF大模型,支持CPU和GPU加速。
增量PDF读取测试 原生LangChain PDF加载器依赖冗余第三方库,本案例手写轻量化PDF解析工具,仅依赖 pypdf,简洁高效、无多余依赖。支持读取本地PDF可编辑文本,自动按页封装Document对象,记录页码与文件来源元数据。
适配增量/覆盖入库模式,可直接将PDF文档批量向量化入库,实现本地PDF知识库问答。注意:仅支持可复制文本的PDF,扫描图片型PDF无法提取文本。
import osfrom pypdf import PdfReaderfrom langchain_core.documents import DocumentCHUNK_SIZE = 300 CHUNK_OVERLAP = 50 CHROMA_PERSIST_DIR = "./my_chroma_database" RETRIEVE_TOP_K = 4 def text_splitter (): pass def get_vector_store (documents, incremental: bool = True ): pass def build_rag_chain (vector_db ): pass def my_pdf_loader (pdf_path ): reader = PdfReader(pdf_path) docs = [] for page_idx, page in enumerate (reader.pages): text = page.extract_text() or "" docs.append(Document( page_content=text, metadata={"source" : pdf_path, "page" : page_idx} )) return docs if __name__ == "__main__" : pdf_file_path = "./test.pdf" if not os.path.exists(pdf_file_path): raise FileNotFoundError(f"PDF文件不存在:{pdf_file_path} " ) pdf_docs = my_pdf_loader(pdf_file_path) print (f"[*] PDF读取完成,共 {len (pdf_docs)} 页" ) db = get_vector_store(pdf_docs, incremental=False ) print (f"\n向量库总文档数:{db._collection.count()} " ) test_query = "概括一下文章内容" docs_with_score = db.similarity_search_with_score(test_query, k=10 ) chain = build_rag_chain(db) ans = chain.invoke(test_query) print (f"\n[最终NaiveRAG回答]: {ans} " )
PDF每页文本经过切片拆分,2页PDF最终生成8个文本块,保证切片长度均匀、适配向量模型输入。大模型基于全部PDF语义信息完成概括问答,实现私有PDF文档智能解读能力。
CMD> python main.py [*] PDF读取完成,共 2 页 [*] 删除旧向量库,开启覆盖重建模式 [*] 新建向量库 [+] 存入 8 个文本块 向量库总文档数:8 [最终NaiveRAG回答]: RAG是一种结合知识库检索与大模型生成的技术。它的工作流程包括文档加载、文本切分、向量化、存入向量数据库、检索、组装Prompt和输出答案。RAG的主要工作流程 包括文档加载、文本切分、向量化、存入向量数据库、检索、组装Prompt和输出答案。RAG的切分块大小不合适会导致噪声多或丢失上下文。RAG的主要工作流程包括文档加载、文 本切分、向量化、存入向量数据库、检索、组装Prompt和输出答案。
增量文本读取测试 针对本地TXT知识库场景,封装全自动文件夹批量加载工具。解决中文编码乱码问题,自动兼容 utf-8/gbk/gb2312 三大主流编码,无需手动适配。支持单层文件夹批量读取,可快速将大量笔记、文档批量入库构建私有知识库。
import osfrom langchain_core.documents import DocumentCHUNK_SIZE = 300 CHUNK_OVERLAP = 50 CHROMA_PERSIST_DIR = "./my_chroma_database" RETRIEVE_TOP_K = 4 def text_splitter (): pass def get_vector_store (documents, incremental: bool = True ): pass def build_rag_chain (vector_db ): pass def load_txt_file (file_path: str ) -> list [Document]: """读取单个txt文件,自动尝试utf‑8、gbk编码""" if not os.path.exists(file_path): raise FileNotFoundError(f"文件不存在:{file_path} " ) text = "" for enc in ("utf‑8" , "gbk" , "gb2312" ): try : with open (file_path, "r" , encoding=enc) as f: text = f.read() break except UnicodeDecodeError: continue else : raise RuntimeError(f"{file_path} 编码无法识别,尝试utf‑8/gbk均失败" ) return [Document(page_content=text, metadata={"source" : file_path})] def load_any_file (file_path: str ) -> list [Document]: """通用加载器,仅支持txt""" ext = os.path.splitext(file_path)[1 ].lower() if ext != ".txt" : raise ValueError(f"暂不支持文件类型 {ext} ,仅支持txt" ) return load_txt_file(file_path) class DirectoryLoader : """批量加载文件夹下全部txt文档""" def __init__ (self, directory: str , recursive: bool = False ): self.directory = directory self.recursive = recursive self.support_suffix = {".txt" } def load (self ) -> list [Document]: all_docs = [] if not os.path.isdir(self.directory): raise NotADirectoryError(f"目录不存在:{self.directory} " ) for root, _, files in os.walk(self.directory): for filename in files: ext = os.path.splitext(filename)[1 ].lower() if ext not in self.support_suffix: continue full_path = os.path.join(root, filename) try : print (f"\n[*] 正在加载:{full_path} " ) docs = load_any_file(full_path) all_docs.extend(docs) print (f"[+] {filename} 读取成功" ) except Exception as e: print (f"[!] 跳过 {filename} ,失败:{str (e)} " ) if not self.recursive: break return all_docs if __name__ == "__main__" : doc_dir = "./txt_docs" loader = DirectoryLoader(directory=doc_dir, recursive=False ) all_docs = loader.load() if not all_docs: print ("\n[!] 文件夹没有读取到任何有效txt文档,程序退出" ) else : db = get_vector_store(all_docs, incremental=False ) print (f"\n[+] 向量库总文档数:{db._collection.count()} " ) chain = build_rag_chain(db) test_query = "llama.cpp的作用是什么?" ans = chain.invoke(test_query) print (f"[最终NaiveRAG回答]: {ans} \n" )
批量读取文件夹内所有TXT文档,自动切片、入库、构建向量库,全程自动化。适合批量导入笔记、技术文档、学习资料,快速搭建专属文本知识库。
CMD> python main.py [*] 正在加载:./txt_docs\111.txt [+] 111.txt 读取成功 [*] 正在加载:./txt_docs\222.txt [+] 222.txt 读取成功 [*] 新建向量库 [+] 存入 8 个文本块 [+] 向量库总文档数:8 [最终NaiveRAG回答]: llama.cpp是GGUF格式模型的本地推理库,主要用于在CPU/GPU上本地运行大模型。它支持GGUF量化模型,例如q4_k_m量化版本,可以降低显存占用,适合个人电脑本地部 署。llama.cpp可以启动OpenAI兼容接口,LangChain可以直接调用该接口,不需要特殊适配。
增量网页读取测试 本模块实现无依赖轻量化网页爬虫,不依赖LangChain社区爬虫组件,仅通过 requests+bs4 完成网页抓取与清洗。自动过滤脚本、样式、空行等无效噪声,提纯网页核心文本,适配网页知识库搭建场景。支持批量URL抓取,可快速将技术博客、文档网站内容入库问答。
import osimport requestsfrom bs4 import BeautifulSoupfrom langchain_core.documents import DocumentCHUNK_SIZE = 300 CHUNK_OVERLAP = 50 CHROMA_PERSIST_DIR = "./my_chroma_database" RETRIEVE_TOP_K = 4 def text_splitter (): pass def get_vector_store (documents, incremental: bool = True ): pass def build_rag_chain (vector_db ): pass def load_web_urls (url_list: list [str ], timeout: int = 10 ) -> list [Document]: """ 手写网页抓取,仅网页来源,无langchain_community依赖 :param url_list: url列表 :param timeout: 请求超时秒数 :return: List[Document] """ headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" } web_docs = [] for url in url_list: try : print (f"\n[*] 正在抓取网页: {url} " ) resp = requests.get(url, headers=headers, timeout=timeout) resp.raise_for_status() soup = BeautifulSoup(resp.text, "html.parser" ) for bad_tag in soup(["script" , "style" , "noscript" ]): bad_tag.decompose() raw_text = soup.get_text(separator="\n" ) lines = [line.strip() for line in raw_text.splitlines() if line.strip()] clean_text = "\n" .join(lines) doc = Document( page_content=clean_text, metadata={"source" : url} ) web_docs.append(doc) print (f"[+] {url} 抓取成功,文本长度:{len (clean_text)} " ) except requests.exceptions.RequestException as e: print (f"[!] 请求异常 {url} : {str (e)} " ) except Exception as e: print (f"[!] 解析失败 {url} : {str (e)} " ) return web_docs if __name__ == "__main__" : all_docs = [] url_list = [ "https://www.lyshark.com" ] web_docs = load_web_urls(url_list) all_docs.extend(web_docs) if not all_docs: print ("\n[!] 没有加载到任何文档,程序退出" ) else : db = get_vector_store(all_docs, incremental=False ) print (f"\n[+] 向量库总文档数:{db._collection.count()} " ) chain = build_rag_chain(db) test_query = "请概括网页内容" ans = chain.invoke(test_query) print (f"[最终NaiveRAG回答]: {ans} \n" )
网页原始文本经过降噪清洗、切片拆分,长文本切割为32个适配向量化的文本块,成功构建网页知识库。可实现对任意公开技术网页的内容总结、问答、检索,适合学习资料快速沉淀。
CMD> python main.py [*] 正在抓取网页: https://www.lyshark.com [+] https://www.lyshark.com 抓取成功,文本长度:7706 [*] 删除旧向量库,开启覆盖重建模式 [*] 新建向量库 [+] 存入 32 个文本块 [+] 向量库总文档数:32 [最终NaiveRAG回答]: 一个致力于信息安全知识分享的专业平台,平台高度关注前沿攻防技术研究。 CMP扫描。