在大语言模型(LLM)的落地实践中,检索增强生成(Retrieval-Augmented Generation, RAG)已成为提升模型回答准确性、时效性和可控性的关键技术。

本文将基于 LangChain.js(截至 2025 年 12 月的最新稳定版本)的最新标准,带你通过代码实战,逐步了解 RAG 的底层机制与工程实现。
什么是 RAG?

RAG 是一种结合信息检索 (Retrieval)与文本生成(Generation)的技术范式。其核心思想是:
- 在用户提问时,先从外部知识库中检索与问题最相关的文档片段;
- 将这些片段作为上下文,连同原始问题一起输入给大语言模型;
- 模型基于增强后的上下文生成更准确、有依据的回答。
相比纯参数化的大模型,RAG 具备以下优势:
- 动态更新知识:无需重新训练模型即可引入新数据;
- 减少幻觉(Hallucination):回答有据可依;
- 领域定制性强:可针对特定业务场景构建私有知识库。
为什么需要 RAG?

尽管当前主流 LLM(如 GPT-4、Claude、Qwen 等)具备强大的通用能力,但仍存在明显局限:
| 问题 | RAG 的解决方案 |
|---|---|
| 知识截止于训练数据 | 实时接入最新文档、数据库或网页 |
| 对私有/内部数据无感知 | 构建专属向量知识库 |
| 回答缺乏引用来源 | 可追溯答案出处 |
| 容易"一本正经地胡说八道" | 基于真实文档生成,降低幻觉 |
因此,RAG 成为企业级 AI 应用(如智能客服、知识助手、法律咨询等)的首选架构。
如何导入不同格式的数据源?

LangChain.js 提供了丰富的 Document Loaders,支持从多种格式加载原始文本。以下是常见数据源的加载方式(v0.3+ 语法):
1. 加载本地文本文件(.txt)
ts
import { TextLoader } from "@langchain/community/document_loaders/fs/text";
const loader = new TextLoader("./data/faq.txt");
const docs = await loader.load();
2. 加载 PDF 文件
ts
import { PDFLoader } from "@langchain/community/document_loaders/fs/pdf";
const loader = new PDFLoader("./data/manual.pdf", {
splitPages: true, // 按页分割
});
const docs = await loader.load();
💡 需安装
pdf-parse:npm install pdf-parse
3. 加载网页内容
ts
import { WebBaseLoader } from "@langchain/community/document_loaders/web/base";
const loader = new WebBaseLoader("https://example.com/article");
const docs = await loader.load();
4. 加载 CSV 或 JSON
ts
import { CSVLoader } from "@langchain/community/document_loaders/fs/csv";
// 或
import { JSONLoader } from "@langchain/community/document_loaders/fs/json";
const csvLoader = new CSVLoader("./data/products.csv", "description");
const jsonLoader = new JSONLoader("./data/faq.json", ".[].answer");
const csvDocs = await csvLoader.load();
const jsonDocs = await jsonLoader.load();
如何存储和索引数据?
RAG 的核心在于将文本转化为向量表示 ,以便进行语义相似度检索。LangChain.js 通过 Embeddings + VectorStore 实现这一过程。

步骤 1:切分文档(Chunking)
使用 RecursiveCharacterTextSplitter 是最常用的策略,它会优先按段落、句子分隔符切分,保持语义完整性。
ts
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 1000, // 每个块的大小(字符数)
chunkOverlap: 200, // 重叠部分,防止上下文在切分处丢失
});
const splitDocs = await splitter.splitDocuments(docs);
console.log(`分割后文档数量: ${splitDocs.length}`);
步骤 2:Embedding 与 向量存储 (VectorStore)
我们需要一个 Embedding 模型将文本转为向量,以及一个 VectorStore 来存储这些向量。
这里以 OpenAI 和 MemoryVectorStore (内存存储,适合测试) 为例。生产环境推荐使用 Chroma, Pinecone 或 Supabase。
ts
import { OpenAIEmbeddings } from "@langchain/openai";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
// 如果使用 Chroma: import { Chroma } from "@langchain/community/vectorstores/chroma";
// 初始化 Embedding 模型
const embeddings = new OpenAIEmbeddings({
model: "text-embedding-3-small", // 性价比极高的模型
apiKey: process.env.OPENAI_API_KEY,
});
// 创建向量库并存入文档
// 这一步会自动调用 embeddings.embedDocuments()
const vectorStore = await MemoryVectorStore.fromDocuments(
splitDocs,
embeddings
);
console.log("向量库构建完成!");
其他支持的 VectorStore:Pinecone、Supabase、Weaviate、FAISS(via
@langchain/community)
如何检索并生成答案?
这是 RAG 的灵魂所在。在 LangChain.js v0.3 中,我们使用 LCEL (LangChain Expression Language) 或高阶封装函数 createRetrievalChain 来实现。
步骤 1:创建检索器 (Retriever)
将向量库转换为检索器接口,并配置检索参数(如 k 表示取前几条相似数据)。
typescript
const retriever = vectorStore.asRetriever({
k: 3, // 检索最相关的 3 个片段
searchType: "similarity", // 或 "mmr" (最大边际相关性,用于增加结果多样性)
});
步骤 2:构建 RAG 链 (The RAG Chain)
我们需要两个组件:
- LLM: 负责推理。
- Prompt: 指导模型如何利用上下文。
- Combine Chain: 将检索到的文档列表拼接成字符串。
typescript
import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { createStuffDocumentsChain } from "langchain/chains/combine_documents";
import { createRetrievalChain } from "langchain/chains/retrieval";
// 1. 初始化 LLM
const llm = new ChatOpenAI({
model: "gpt-4o",
temperature: 0, // RAG 任务通常设为 0 以保证严谨性
});
// 2. 设计 Prompt
// {context} 会被检索到的文档内容填充
// {input} 是用户的提问
const prompt = ChatPromptTemplate.fromTemplate(`
作为一个专业的文档助手,请基于以下提供的上下文回答用户的问题。
如果上下文中没有答案,请诚实地说不知道,不要编造。
上下文:
{context}
用户问题:
{input}
`);
// 3. 创建 "Stuff" 链(即把所有文档一次性塞入 Prompt)
const combineDocsChain = await createStuffDocumentsChain({
llm,
prompt,
});
// 4. 创建最终的检索增强链
// 这个链会自动处理:拿到 input -> 传给 retriever -> 拿到 docs -> 传给 combineDocsChain
const ragChain = await createRetrievalChain({
retriever,
combineDocsChain,
});
步骤 3:运行与测试
typescript
const response = await ragChain.invoke({
input: "LangChain.js v0.3 有什么新特性?",
});
// 输出结果
console.log("参考文档来源:", response.context.map(d => d.metadata));
console.log("AI 回答:", response.answer);
总结
通过 LangChain.js,我们能够以模块化、声明式的方式快速搭建一个生产就绪的 RAG 系统。关键在于:
- 数据预处理:合理加载、清洗、切分;
- 向量索引:选择合适的 Embedding 与 VectorStore;
- 检索生成协同:设计 Prompt 与 Chain 逻辑,确保上下文有效利用。
RAG 不仅是技术方案,更是连接 LLM 与企业知识资产的桥梁。掌握它,你就掌握了构建可信、可控、可解释 AI 应用的核心能力。
📚 参考资源
- LangChain.js 官方文档
- RAG 论文:Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks
- GitHub 示例仓库:
langchain-ai/langchainjs/examples/rag