Agent-study项目教程(04):数学建模知识库助手(RAG)
一、理论部分1. 为什么需要 RAG解决“知识过期”与“不可溯源”仅依赖大模型参数内的知识会遇到两个典型问题知识边界模型未必覆盖你的垂直领域材料例如一本专业书或内部文档。不可控与不可溯源模型可能“看似合理但实际编造”且难以追溯回答依据。RAGRetrieval-Augmented Generation检索增强生成的核心思想是在回答前先去你的私有知识库中检索相关内容把检索结果作为上下文Context提供给模型让模型“基于证据回答”从而提升准确性与可控性。2. RAG 的三段式流程Indexing → Retrieval → Generation一个最常见、也最容易工程落地的 RAG 系统可以拆成三步Indexing构建索引把文档转成文本 → 切分成片段chunk→ 计算向量embedding→ 写入向量数据库。Retrieval检索把用户问题向量化 → 在向量库中做相似度检索 → 返回 Top-K 相关片段。Generation生成把检索片段拼成上下文 → 与问题一起发给模型 → 生成最终回答并要求“不知道就说不知道”。本项目即严格按照上述流程实现并将 Indexing 与 Query 分离为两个脚本便于工程化部署与复用。3. 文本切分Chunking的关键参数chunk_size 与 chunk_overlapRAG 效果很大程度取决于切分策略。切分太大片段内容冗余相关性被稀释上下文拼接后更容易超出模型输入限制切分太小单个片段信息不足模型难以组织出完整答案检索返回片段需要更多拼接整体噪声可能增加因此通常采用chunk_size控制片段长度本项目为 500chunk_overlap片段重叠本项目为 100用于保留跨边界语义连续性4. Embedding 与向量数据库为什么要选“中文向量模型”RAG 的检索依赖 embedding 的质量。对于中文材料直接使用英文向量模型往往会造成相似度失真导致检索效果明显下降。本项目使用shibing624/text2vec-base-chinese作为中文 embedding 模型并将向量存入 ChromaDB本地持久化以获得稳定、可离线复现的中文检索能力。二、实战部分1. 项目目标实现一个“数学建模知识库问答助手”从本地 PDF 文档构建知识库向量索引支持在命令行中输入问题先检索 Top-5 相关片段再基于片段生成回答明确约束上下文中没有信息时必须如实说明不得编造2. 运行准备请确保本地已安装依赖并配置环境变量依赖安装示例pipinstall-rrequirements.txt环境变量示例DEEPSEEK_API_KEYDEEPSEEK_BASE_URL文档准备将待构建知识库的 PDF 文档放入项目约定的文件夹中例如按章节拆分后的 PDF。首次构建索引会下载中文 embedding 模型体积较大请确保网络环境可用。3. 主要代码核心实现本项目分为两部分构建索引Indexing与问答检索Query Generate。由于代码较长本文保留关键逻辑代码完整工程文件可在资料中获取。3.1 构建知识库读取 PDF → 切分 → 向量化 → 写入 ChromaDB核心流程包括使用 PyMuPDF 读取 PDF 文本使用RecursiveCharacterTextSplitter做中文友好切分使用 SentenceTransformer EmbeddingFunction 写入 ChromaDB关键代码如下示例importosimportloggingimportchromadbimportfitz# PyMuPDFfromlangchain_text_splittersimportRecursiveCharacterTextSplitterfromchromadb.utilsimportembedding_functionsfromhuggingface_hubimportsnapshot_download logging.getLogger(transformers.modeling_utils).setLevel(logging.ERROR)current_diros.path.dirname(os.path.abspath(__file__))pdf_folderos.path.join(current_dir,数学建模算法与应用)db_pathos.path.join(current_dir,chroma_db)defload_pdf_content(file_path):textdocfitz.open(file_path)forpageindoc:textpage.get_text()\ndoc.close()returntextdefsplit_text(text):splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap100,separators[\n\n,\n,。,,,, ,],)returnsplitter.split_text(text)defmain():chroma_clientchromadb.PersistentClient(pathdb_path)model_nameshibing624/text2vec-base-chineselocal_model_pathos.path.join(current_dir,model_cache,text2vec-base-chinese)ifnotos.path.exists(local_model_path):snapshot_download(repo_idmodel_name,local_dirlocal_model_path,local_dir_use_symlinksFalse,)emb_fnembedding_functions.SentenceTransformerEmbeddingFunction(model_namelocal_model_path)try:chroma_client.delete_collection(math_modeling_rag)except:passcollectionchroma_client.get_or_create_collection(namemath_modeling_rag,embedding_functionemb_fn,)pdf_files[fforfinos.listdir(pdf_folder)iff.lower().endswith(.pdf)]total_chunks0forpdf_fileinpdf_files:full_pathos.path.join(pdf_folder,pdf_file)contentload_pdf_content(full_path)chunkssplit_text(content)total_chunkslen(chunks)ids[f{pdf_file}_{i}foriinrange(len(chunks))]metadatas[{source:pdf_file}for_inchunks]collection.add(documentschunks,idsids,metadatasmetadatas)print(f所有处理完成共存入{total_chunks}个知识片段。)if__name____main__:main()3.2 问答助手Top-K 检索 → 拼接上下文 → 约束生成问答侧的关键点是两步从向量库检索n_results5个最相关片段将片段拼接为context并在 Prompt 中明确“无信息则不编造”关键代码如下示例importosimportchromadbfromdotenvimportload_dotenvfromopenaiimportOpenAIfromchromadb.utilsimportembedding_functionsfromhuggingface_hubimportsnapshot_download load_dotenv()clientOpenAI(api_keyos.getenv(DEEPSEEK_API_KEY),base_urlhttps://api.deepseek.com,)current_diros.path.dirname(os.path.abspath(__file__))db_pathos.path.join(current_dir,chroma_db)chroma_clientchromadb.PersistentClient(pathdb_path)local_model_pathos.path.join(current_dir,model_cache,text2vec-base-chinese)ifnotos.path.exists(local_model_path):snapshot_download(repo_idshibing624/text2vec-base-chinese,local_dirlocal_model_path,local_dir_use_symlinksFalse,)emb_fnembedding_functions.SentenceTransformerEmbeddingFunction(model_namelocal_model_path)collectionchroma_client.get_collection(namemath_modeling_rag,embedding_functionemb_fn,)defquery_rag(question:str):resultscollection.query(query_texts[question],n_results5,)documentsresults[documents][0]context\n\n.join(documents)promptf 你是一个专业的数学建模助手。请基于以下检索到的上下文 (Context) 回答用户的问题。 如果上下文中没有相关信息请诚实地说不知道不要编造。 上下文:{context}问题:{question}.strip()responseclient.chat.completions.create(modeldeepseek-chat,messages[{role:system,content:You are a helpful assistant.},{role:user,content:prompt},],streamTrue,)forchunkinresponse:ifchunk.choices[0].delta.content:print(chunk.choices[0].delta.content,end,flushTrue)print()4. 如何运行本项目分两步执行1构建知识库首次必做python stage_03_rag_and_memory/project_04_rag_agent/indexer.py2启动问答助手python stage_03_rag_and_memory/project_04_rag_agent/rag.py5. 运行结果示例构建知识库时的典型输出示例⚙️ 初始化向量数据库... 正在加载中文 Embedding 模型... 发现 30 个 PDF 文件。 正在读取: 第1章.pdf ... ✅ 读取成功共 123456 字符。 正在存入数据库: 第1章.pdf (320 片段)... ... 所有处理完成共存入 9800 个知识片段。 现在可以运行 rag.py 进行提问了。问答时的典型输出示例 数学建模知识库助手 (RAG) 已启动 输入 quit 或 exit 退出。 请输入你的问题: 什么是层次分析法AHP 正在检索知识库: 什么是层次分析法AHP ... 检索到 5 个相关片段 正在思考并生成回答... 模型基于检索片段输出的回答内容... 6. 项目总结RAG 的核心价值在于“先检索证据再基于证据生成”显著提升垂直领域问答的可靠性与可控性。影响效果的关键工程点包括文本切分策略chunk_size/overlap、中文 embedding 模型选择、Top-K 检索数量与 Prompt 约束。将 Indexing 与 Query 分离能够更贴近真实工程索引可离线构建与增量更新问答服务则保持轻量与稳定运行。

相关新闻

网盘下载慢到怀疑人生?这款开源脚本让九大网盘的直链下载一步到位

网盘下载慢到怀疑人生?这款开源脚本让九大网盘的直链下载一步到位

网盘下载慢到怀疑人生?这款开源脚本让九大网盘的直链下载一步到位 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动…

2026/10/26 12:24:51 阅读更多 →
东北高寒环境专网通信:DMR 公专融合项目实战与故障排坑

东北高寒环境专网通信:DMR 公专融合项目实战与故障排坑

现象:距离基站 1‑2km 通信良好,远端巡护点断续、噪声大;冬天比夏天问题严重很多。 根因:天线积雪覆冰增大链路损耗;低温设备频漂;馈线老化泄漏;冬季电力线路带来额外电磁干扰。 整改方案&#…

2026/10/25 21:51:32 阅读更多 →
第二十章 感知组合结构与认知对象理论

第二十章 感知组合结构与认知对象理论

第二十章 感知组合结构与认知对象理论📅 2026年08月14日👤 东塬一老翁📂 第二卷:感知元素理论(Perceptual Elements Theory)第二十章 感知组合结构与认知对象理论Cognitive Object Theory Based on Perce…

2026/10/24 3:30:12 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/26 12:00:21 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/25 22:36:10 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/26 4:52:12 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/26 12:00:21 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/26 5:00:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/26 3:16:46 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 12:00:19 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/25 13:21:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 8:34:37 阅读更多 →