RAGRetrieval Augmented Generation检索增强生成这个技术方向我最近花了不少时间研究。简单说就是让大模型在回答问题前先查资料这样回答就不会胡编乱造了。这篇文章记录了我从零搭建一个智能知识库的完整过程代码和踩坑经验都在这。什么是 RAG为什么前端人该关注大模型有个老毛病不知道的事情会编。你问它一个公司内部的政策它根本没见过你的内部文档但会编一个看起来合理的答案。RAG 的思路很简单回答之前先从你的私有资料库里检索相关信息把这些信息和问题一起交给大模型。这样模型回答的依据是真实数据不是训练记忆。前端工程师做 RAG 有几个优势前端天然做用户界面知识库的交互体验需要前端信息架构是前端的强项RAG 本质就是把信息组织好、检索准不需要训练模型用现成的 Embedding API 向量库就能跑起来项目目标能用的智能知识库需要这几件事上传 PDF/Markdown 文档作为知识来源自动将文档切块、向量化、存入数据库用户提问时先检索相关文档片段再生成回答回答附带引用来源方便核实技术选型试了几种方案这是目前觉得适合前端开发者的组合组件选择理由运行时Node.js TypeScript前端友好EmbeddingOpenAI text-embedding-3-small便宜、快、效果好向量库Chroma本地/ Pinecone云端Chroma 零配置本地跑框架LangChain.js生态成熟文档全前端Next.js Tailwind快速出界面文档解析pdf-parse marked处理 PDF 和 Markdown环境准备1 2 3 4 5 mkdir rag-knowledge-base cd rag-knowledge-base npm init -y npm install langchain langchain/openai langchain/chroma npm install pdf-parse marked npm install -D typescript types/node配置 TypeScript1 2 3 4 5 6 7 8 9 10 { compilerOptions : { target : ES2020 , module : ESNext , moduleResolution : node , outDir : ./dist , rootDir : ./src , esModuleInterop : true } }文档处理知识库的第一步是把文档变成可以检索的小片段。流程读取文件 → 切块 → 向量化。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import fs from fs ; import pdfParse from pdf-parse ; import { RecursiveCharacterTextSplitter } from langchain/text_splitter ; // 读取文件支持 PDF 和 Markdown async function readFile ( filePath: string ): Promise string { if (filePath. endsWith ( .pdf )) { const dataBuffer fs. readFileSync (filePath); const result await pdfParse (dataBuffer); return result. text ; } return fs. readFileSync (filePath, utf-8 ); } // 切块 async function chunkText ( text: string ) { const splitter new RecursiveCharacterTextSplitter ({ chunkSize : 500 , chunkOverlap : 50 , }); return await splitter. splitText (text); } // 测试 const text await readFile ( ./docs/my-document.pdf ); const chunks await chunkText (text); console . log ( 文档被切分为 ${chunks.length} 个片段 );切块这一步很关键。块太大检索不准块太小上下文不够。500 字符是我试下来比较好的默认值你可以根据实际文档类型调整。向量存储切好的片段通过 Embedding 变成向量存入向量数据库。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import { Chroma } from langchain/chroma ; import { OpenAIEmbeddings } from langchain/openai ; import { Document } from langchain/core/documents ; const embeddings new OpenAIEmbeddings ({ modelName : text-embedding-3-small , apiKey : process. env . OPENAI_API_KEY , }); // 将切块转为 Document 对象 function chunksToDocuments ( chunks: string[], sourceFile: string ) { return chunks. map ( (chunk, i) new Document ({ pageContent : chunk, metadata : { source : sourceFile, chunkIndex : i }, }) ); } // 存入 Chroma async function storeDocuments ( documents: Document[], collectionName: string ) { const vectorStore new Chroma (embeddings, { collectionName, url : http://localhost:8000 , }); await vectorStore. addDocuments (documents); console . log ( 已存储 ${documents.length} 个文档到 ${collectionName} ); } // 完整流程 const chunks await chunkText ( await readFile ( ./docs/product-guide.pdf )); const docs chunksToDocuments (chunks, product-guide.pdf ); await storeDocuments (docs, my-knowledge-base );启动 Chroma 本地服务1 2 pip install chromadb chroma run --path ./chroma-data检索 生成回答知识库建好了接下来做核心的检索和回答功能。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 import { ChatOpenAI } from langchain/openai ; import { ChatPromptTemplate } from langchain/core/prompts ; import { StringOutputParser } from langchain/core/output_parsers ; import { Chroma } from langchain/chroma ; const llm new ChatOpenAI ({ modelName : gpt-4o , temperature : 0.3 , }); // 连接已有的知识库 const vectorStore new Chroma (embeddings, { collectionName : my-knowledge-base , url : http://localhost:8000 , }); // RAG 提示词模板 const RAG_PROMPT ChatPromptTemplate . fromMessages ([ [ system , 你是一个知识库助手根据检索到的文档片段回答问题。 如果文档中有相关信息请基于文档内容回答并在末尾标注引用来源。 如果文档中没有相关信息请如实告知用户 知识库中没有找到相关信息 。 不要编造答案。 ], [ human , 检索到的文档 {context} 用户问题{question} ], ]); // 完整的 RAG 查询流程 async function queryKnowledge ( question: string ) { // 1. 检索相关文档 const results await vectorStore. similaritySearch (question, 3 ); if (results. length 0 ) { return { answer : 知识库中没有找到相关内容 , sources : [] }; } // 2. 组装上下文 const context results. map ( (doc, i) [文档${i 1}] ${doc.pageContent}\n来源: ${doc.metadata.source} ). join ( \n\n ); // 3. 生成回答 const chain RAG_PROMPT . pipe (llm). pipe ( new StringOutputParser ()); const answer await chain. invoke ({ context, question }); // 4. 返回回答 引用来源 return { answer, sources : results. map ( doc doc. metadata . source ), }; } // 测试 const result await queryKnowledge ( 产品的退款政策是什么 ); console . log ( 回答: , result. answer ); console . log ( 来源: , result. sources );前端界面前端开发者最关心的还是界面。用 Next.js 做一个简单的知识库问答界面1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 // app/page.tsx use client ; import { useState } from react ; interface Message { role : user | assistant ; content : string ; sources?: string []; } export default function Home () { const [messages, setMessages] useState Message []([]); const [input, setInput] useState ( ); const [loading, setLoading] useState ( false ); const sendMessage async () { if (!input. trim ()) return ; const userMessage : Message { role : user , content : input }; setMessages ( prev [...prev, userMessage]); setInput ( ); setLoading ( true ); const res await fetch ( /api/query , { method : POST , headers : { Content-Type : application/json }, body : JSON . stringify ({ question : input }), }); const data await res. json (); const assistantMessage : Message { role : assistant , content : data. answer , sources : data. sources , }; setMessages ( prev [...prev, assistantMessage]); setLoading ( false ); }; return ( div className min-h-screen bg-gray-50 flex flex-col header className bg-white shadow p-4 h1 className text-xl font-bold 智能知识库/h1 /header main className flex-1 overflow-y-auto p-4 space-y-4 {messages. map ( (msg, i) ( div key{i} className{ max-w-2xl p-4 rounded-lg ${ msg. role user ? bg-blue-100 ml-auto : bg-white border } } p className whitespace-pre-wrap {msg. content }/p {msg. sources msg. sources . length 0 ( div className mt-2 text-xs text-gray-500 来源: {msg. sources . join ( , )} /div )} /div ))} {loading ( div className max-w-2xl p-4 rounded-lg bg-white border p className text-gray-400 正在检索知识库.../p /div )} /main footer className bg-white border-t p-4 div className max-w-2xl mx-auto flex gap-2 input value{input} onChange{ (e) setInput (e. target . value )} onKeyDown{ (e) e. key Enter sendMessage ()} placeholder 输入你的问题... className flex-1 border rounded-lg px-4 py-2 / button onClick{sendMessage} disabled{loading} className bg-blue-600 text-white px-6 py-2 rounded-lg disabled:opacity-50 提问 /button /div /footer /div ); }API 路由1 2 3 4 5 6 7 8 9 // app/api/query/route.ts import { NextResponse } from next/server ; import { queryKnowledge } from /lib/rag ; export async function POST ( request: Request ) { const { question } await request. json (); const result await queryKnowledge (question); return NextResponse . json (result); }批量导入文档实际使用中不可能一条条录入。写一个批量导入脚本1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import glob from glob ; import { RecursiveCharacterTextSplitter } from langchain/text_splitter ; import { Chroma } from langchain/chroma ; import { OpenAIEmbeddings } from langchain/openai ; import { Document } from langchain/core/documents ; import fs from fs ; import pdfParse from pdf-parse ; async function importAllDocuments () { const files glob. sync ( ./docs/**/*.{pdf,md} ); console . log ( 找到 ${files.length} 个文档 ); const allDocuments : Document [] []; for ( const file of files) { let text : string ; if (file. endsWith ( .pdf )) { const dataBuffer fs. readFileSync (file); const result await pdfParse (dataBuffer); text result. text ; } else { text fs. readFileSync (file, utf-8 ); } const splitter new RecursiveCharacterTextSplitter ({ chunkSize : 500 , chunkOverlap : 50 , }); const chunks await splitter. splitText (text); const docs chunks. map ( (chunk, i) new Document ({ pageContent : chunk, metadata : { source : file, chunkIndex : i }, }) ); allDocuments. push (...docs); console . log ( 处理完成: ${file} → ${chunks.length} 个片段 ); } const embeddings new OpenAIEmbeddings ({ modelName : text-embedding-3-small , }); const vectorStore new Chroma (embeddings, { collectionName : my-knowledge-base , url : http://localhost:8000 , }); await vectorStore. addDocuments (allDocuments); console . log ( 全部导入完成共 ${allDocuments.length} 个文档片段 ); } importAllDocuments();踩坑记录1. 中文检索效果不好一开始用 text-embedding-ada-002中文文档的检索准确率只有 60% 左右。换成 text-embedding-3-small 后提升到 85%。如果你的知识库以中文为主建议直接用 3-small。2. 切块大小影响很大块太小200 字符检索出的内容缺乏上下文块太大1000 字符又会混入不相关信息。500 字符是我试下来比较合适的值具体看你的文档类型。技术文档可以偏大一些FAQ 类偏小。3. 回答引用的来源不对有时候回答引用的文档和实际内容对不上。原因是 metadata 没有正确传递。确保每个 Document 对象都有 source 字段检索结果按源文件过滤。4. Chroma 本地存储的坑Chroma 默认数据存在内存里重启就没了。启动时加上--path ./chroma-data参数才能持久化。进阶优化方向方向说明难度混合检索关键词检索 向量检索结合⭐⭐重排序用 Cross-Encoder 对检索结果重新排序⭐⭐⭐多路召回多个知识库并行检索合并结果⭐⭐⭐流式输出SSE 实现打字机效果⭐⭐问答评估自动化评估回答准确率和忠实度⭐⭐⭐RAG 的入门门槛不高但要做好需要反复调参。文档切块、检索策略、提示词设计这三个环节最值得花时间优化。说真的这两年看着身边一个个搞Java、C、前端、数据、架构的开始卷大模型挺唏嘘的。大家最开始都是写接口、搞Spring Boot、连数据库、配Redis稳稳当当过日子。结果GPT、DeepSeek火了之后整条线上的人都开始有点慌了大家都在想“我是不是要学大模型不然这饭碗还能保多久”我先给出最直接的答案一定要把现有的技术和大模型结合起来而不是抛弃你们现有技术掌握AI能力的Java工程师比纯Java岗要吃香的多。即使现在裁员、降薪、团队解散的比比皆是……但后续的趋势一定是AI应用落地大模型方向才是实现职业升级、提升薪资待遇的绝佳机遇这绝非空谈。数据说话2025年的最后一个月脉脉高聘发布了《2025年度人才迁徙报告》披露了2025年前10个月的招聘市场现状。AI领域的人才需求呈现出极为迫切的“井喷”态势2025年前10个月新发AI岗位量同比增长543%9月单月同比增幅超11倍。同时在薪资方面AI领域也显著领先。其中月薪排名前20的高薪岗位平均月薪均超过6万元而这些席位大部分被AI研发岗占据。与此相对应市场为AI人才支付了显著的溢价算法工程师中专攻AIGC方向的岗位平均薪资较普通算法工程师高出近18%产品经理岗位中AI方向的产品经理薪资也领先约20%。当你意识到“技术AI”是个人突围的最佳路径时整个就业市场的数据也印证了同一个事实AI大模型正成为高薪机会的最大源头。最后我在一线科技企业深耕十二载见证过太多因技术卡位而跃迁的案例。那些率先拥抱 AI 的同事早已在效率与薪资上形成代际优势我意识到有很多经验和知识值得分享给大家也可以通过我们的能力和经验解答大家在大模型的学习中的很多困惑。我整理出这套 AI 大模型突围资料包【允许白嫖】✅从入门到精通的全套视频教程✅AI大模型学习路线图0基础到项目实战仅需90天✅大模型书籍与技术文档PDF✅各大厂大模型面试题目详解✅640套AI大模型报告合集✅大模型入门实战训练这份完整版的大模型 AI 学习和面试资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】①从入门到精通的全套视频教程包含提示词工程、RAG、Agent等技术点② AI大模型学习路线图0基础到项目实战仅需90天全过程AI大模型学习路线③学习电子书籍和技术文档市面上的大模型书籍确实太多了这些是我精选出来的④各大厂大模型面试题目详解⑤640套AI大模型报告合集⑥大模型入门实战训练获取方式有需要的小伙伴可以保存图片到wx扫描二v码免费领取【保证100%免费】