从零搭建网页RAG检索系统,保姆级向量库落地教程

发布时间:2026/9/12 20:33:29

从零搭建网页RAG检索系统,保姆级向量库落地教程 文章目录前言一、整套链路先看懂一步都不能少二、前期依赖包一次性装好三、第一步Loader网页转标准Document3.1 Loader是所有文件的统一转换器3.2 用CSS选择器精准提取正文3.3 Document自带两大核心属性四、第二步递归切分长文档解决检索粗糙问题4.1 为什么不能直接用整篇文章4.2 递归切割器配置实操4.3 递归分隔符的底层逻辑4.4 chunkOverlap重叠参数到底有啥用五、第三步批量生成Embedding向量六、第四步存入向量数据库测试先用内存库七、第五步相似度检索拿匹配度分数7.1 检索代码实现7.2 分数怎么看懂八、第六步拼接上下文丢给大模型回答九、demo离线上生产还差十万八千里十、全文流程总结P.S. 挖到宝藏AI教程全程通俗易懂风趣幽默零基础轻松入门传送门https://blog.csdn.net/qq_34419312前言之前聊RAG的时候咱们举的例子全是提前整理好的文字片段看着特别完美像开了作弊挂。但线下写代码的时候根本不是这么回事我之前第一次搭demo直接把掘金文章复制粘贴成字符串丢进去写完沾沾自喜结果被同事吐槽线上谁有空手动复制网页你这项目上线得雇十个实习生天天扒文章是吧现实里的知识源五花八门网页、PDF、Word、Markdown堆一堆今天咱们拿网页当素材完整走一遍从链接到AI问答的整条流水线每一步都带可运行代码。一、整套链路先看懂一步都不能少随便丢一个网页URL系统内部要走完完整的处理链条顺序错一步都跑不通URL → 下载网页HTML → 过滤广告侧边栏只留正文 → 标准化成Document对象 → 切割成小块Chunk → 生成向量Embedding → 存入向量库 → 根据用户问题检索匹配片段 → 丢给大模型输出答案这条链路跟点外卖流程一模一样URL是下单地址Loader是骑手取餐切分Chunk是分装小餐盒向量库是外卖柜检索就是按你想吃的菜翻柜子最后大模型是给你上菜的服务员。少一个环节你都吃不上饭。二、前期依赖包一次性装好本次demo用LangChain.js做主体Cheerio解析网页通义千问兼容接口生成向量内存向量库做测试安装命令直接复制运行pnpm add \ langchain/community \ langchain/textsplitters \ langchain/classic \ langchain/openai \ cheerio \ dotenv所有包各司其职不用额外装爬虫框架开箱就能解析网页。三、第一步Loader网页转标准Document3.1 Loader是所有文件的统一转换器不同文件对应专属加载工具分工分得清清楚楚网页内容CheerioWebBaseLoaderPDF文件PDF LoaderWord文档Docx Loader表格CSVCSV LoaderLoader就是RAG系统的前台接待不管你是网页、PDF还是表格进来全统一换成叫Document的标准工牌后面的流程只认工牌不认原始文件不然每个格式单独写一套处理逻辑代码能堆成山。3.2 用CSS选择器精准提取正文网页里乱七八糟的导航、评论、广告全是噪音必须靠CSS选择器锁定正文区域示例代码import { CheerioWebBaseLoader } from langchain/community/document_loaders/web/cheerio; const sourceUrl 目标掘金文章链接; const cheerioLoader new CheerioWebBaseLoader( sourceUrl, { selector: .article-viewer :not(style), }, ); const documents await cheerioLoader.load();selector配置含义只读取文章容器内的内容自动过滤样式标签标题、列表、表格、代码块全部保留到pageContent里。这里踩坑提醒网站一改版DOM结构直接报废上次我写好的选择器平台更新页面后抓出来全是空文本排查半小时才发现容器class改名了等于白写。3.3 Document自带两大核心属性加载完成后得到Document数组两个核心字段pageContent清洗后的文章纯正文metadata存放网页地址、文章标题等溯源信息这一步完全不生成向量只做格式标准化别搞混前后步骤。四、第二步递归切分长文档解决检索粗糙问题4.1 为什么不能直接用整篇文章一整篇文章只生成一个向量会出现严重问题文章里面同时讲文件API、异步回调、Promise用户只问fs模块相关内容检索出来一大段无关文字AI回答精准度直接崩盘。好比你去图书馆找一本技术书整本书打包塞一个袋子里你想找某一页内容只能拎一整袋翻效率极低切成一页一页小纸条检索才能精准定位。4.2 递归切割器配置实操import { RecursiveCharacterTextSplitter } from langchain/textsplitters; const textSplitter new RecursiveCharacterTextSplitter({ chunkSize: 400, chunkOverlap: 80, separators: [ \n\n, \n, 。, , , , , , ], }); const splitDocuments await textSplitter.splitDocuments(documents);测试掘金文章直接从1个完整文档拆成30个独立Chunk数量随文章长度变动。4.3 递归分隔符的底层逻辑切割会按顺序逐级尝试拆分优先保留完整语义段落换行 → 单行换行 → 中文句号 → 感叹号/问号/分号 → 逗号 → 空格 → 字符兜底数组最后放空字符串就算遇到无标点代码块、纯英文内容也能强制控制文本长度。4.4 chunkOverlap重叠参数到底有啥用关键语句刚好卡在两个Chunk中间时单独读取任意一块都会丢失完整逻辑。示例前一段末尾讲主线程不适合同步IO后一段开头讲优先异步读取分开看完全看不懂因果。重叠就像电视剧两集片尾片头重复一小段剧情防止你断片看不懂前后关联。但重叠值不能拉满数值太大重复文本暴增向量存储、接口调用成本直接翻倍纯纯浪费钱。chunkSize和chunkOverlap没有万能固定值要根据文档类型、向量模型、线上检索效果反复调试。五、第三步批量生成Embedding向量咱们用通义千问兼容OpenAI接口生成文本向量配置代码如下import { OpenAIEmbeddings } from langchain/openai; const embeddings new OpenAIEmbeddings({ apiKey: process.env.DASHSCOPE_API_KEY, model: process.env.EMBEDDINGS_MODEL_NAME, batchSize: 10, configuration: { baseURL: process.env.DASHSCOPE_BASE_URL, }, });batchSize控制单次接口请求文本数量本次30个Chunk会自动分3批调用不用手动循环处理。批量参数别乱填服务商有接口限流一次塞50条直接返回429限流报错半夜调试接口卡在这里差点怀疑人生。六、第四步存入向量数据库测试先用内存库import { MemoryVectorStore } from langchain/classic/vectorstores/memory; const vectorStore await MemoryVectorStore.fromDocuments( splitDocuments, embeddings, );fromDocuments内部自动完成两件事读取每个Chunk文本、调用向量接口生成向量、统一保存文本、向量和元数据。内存向量库只适合学习和小demo程序一关数据直接清空线上项目敢用这个等于每天手动重建知识库运维能找你谈话。生产必须换持久化向量库。七、第五步相似度检索拿匹配度分数7.1 检索代码实现const question fs 模块有哪些常用 API; const scoredResults await vectorStore.similaritySearchWithScore(question, 3);方法会自动把用户问题转为向量和库内所有Chunk向量做比对返回Top3匹配内容对应分数。7.2 分数怎么看懂内存向量库默认计算余弦相似度数值区间0~1数字越大代表和问题关联性越强。示例返回结果0.6843、0.6454、0.6131分数越低越无关。换其他向量库要注意有的返回距离值数字越小越匹配上次我直接沿用余弦相似度判断逻辑检索结果全是无关内容查了半天才发现指标定义完全相反。八、第六步拼接上下文丢给大模型回答检索出来的片段不能直接丢给模型要格式化拼接进提示词限制AI只能根据检索内容作答const docs scoredResults.map(([doc]) doc); const context docs .map( (doc, index) [片段 ${index 1}]\n${doc.pageContent}, ) .join(\n\n-----\n\n); const prompt 你是一个文章阅读助手。请只根据给定文章片段回答问题 如果片段没有提供答案请明确说明信息不足。 文章片段 ${context} 问题${question} 回答 ; const response await model.invoke(prompt); console.log(response.content);格式化片段后模型能精准提取文章内readFileSync、readFile、node:fs/promises等API信息不会凭空编造内容。九、demo离线上生产还差十万八千里咱们跑通的示例只能用来学习上线必须补齐这些功能网页DOM改版自动适配、捕获抓取失败、空内容过滤重复文档去重、网页内容增量更新同步替换持久化向量数据库保证重启不丢数据相似度阈值过滤低匹配片段处理无答案场景元数据筛选、回答附带原文来源链接Chunk参数批量测试调优接入Rerank重排优化检索提示词注入防护不信任外部网页内容不能覆盖系统规则很多新手跑通demo就敢上线结果用户搜问题全是无关内容、网页抓取一堆广告、重启服务知识库清空线上bug堆一堆改起来比从头写还费劲。十、全文流程总结网页接入RAG不是丢个URL就能完事完整流水线一句话概括网页链接 → Cheerio加载器标准化文档 → 递归切割语义块 → 批量生成向量 → 存入向量库 → 相似度检索高匹配片段 → 拼接上下文交给大模型输出答案外部网页经过这套完整处理流程才能转化成支持语义检索的可用知识库少任意一环RAG效果都会大打折扣。P.S. 挖到宝藏AI教程全程通俗易懂风趣幽默零基础轻松入门传送门https://blog.csdn.net/qq_34419312
延伸阅读

更多相关文章

2026/8/31 6:56:42

Cargo 与容器构建:多阶段构建把镜像从 2GB 压缩到 50MB 的实操

Cargo 与容器构建:多阶段构建把镜像从 2GB 压缩到 50MB 的实操 一、2GB 镜像的成因 —— Rust 编译产物为什么这么大 很多人以为 Rust 编译出来的二进制应该很小,这其实是个误解。Debug 模式编译的 Rust 二进制确实可以很大,因为它包含了大量…

2026/9/10 23:04:32

从git 一个分支cherry-pick apk 到另外一个分支!

1.找到原分支的hash值 在原分支下面执行 git log --oneline b35b237c9f4 2.在新分支上执行 git cherry-pick b35b237c9f4 error: could not apply b35b237c9f4… 修复缺陷 hint: After resolving the conflicts, mark them with hint: “git add/rm ”, then run hint: “git c…

2026/9/12 20:31:02

大模型小白必看:Agent记忆系统实战指南(收藏版)

本文深入剖析了Agent记忆系统从理论架构到工程实践的转变。阐述了理想记忆系统与现实业务场景之间的工程取舍,如上下文窗口限制、算力成本和模型缺陷。以企业客服Agent为例,探讨了记忆摘要蒸馏的利弊和业务调整策略。同时,分析了记忆污染与漂…

2026/9/12 20:31:02

消费电子ESD整改实战:从C/D级故障根治到机电协同防护

1. 项目概述:这不是一次普通维修,而是一场EMC攻防实战“静电打到死机、RGB灯永久烧毁”——这句标题不是夸张修辞,而是我们实测时连续三次复现的故障现象。客户送来的那批量产耳机,刚出厂就批量出现ESD(静电放电&#…

2026/9/12 20:31:02

上门家政对老人的优势:让居家养老更安心、更体面

1. 引言 随着老龄化社会的到来,如何让父母安享晚年,成为许多子女心头最牵挂的事。老人往往对陌生的养老院心存抵触,更愿意留在熟悉的环境里生活。上门家政服务正是在这样的需求下应运而生——它把专业的照护、清洁与陪伴送进家门,…

2026/9/12 20:31:02

易如意网络验证1.71:软件注册码授权验证与机器码绑定实战解析

简介:易如意网络验证1.71是一套基于PHP的网络验证系统,主要面向PHP开发者、软件作者及网站站长,用于实现软件授权、用户认证、卡密管理与接口对接等典型场景。压缩包共196个文件,以104个PHP文件与29个HTML页面为主体,辅…

2026/9/12 2:05:33

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/12 3:55:12

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/12 10:09:03

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介:本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包,聚焦于长鼻浣熊优化算法(COA)的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题,作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码