图片来源网络,侵权联系删。

在这里插入图片描述

1. 引言

在Web开发中,我们熟悉“数据 → 处理 → 展示”的经典流程:从前端表单收集用户输入,后端查询数据库,再将结果渲染成页面。而如今,当企业希望用自然语言查询内部文档(如产品手册、技术规范、HR政策),这套逻辑依然成立——只是“数据库”换成了向量数据库,“SQL查询”换成了语义搜索

这就是 RAG(Retrieval-Augmented Generation) 的核心思想:

先从海量文档中检索出与问题最相关的片段,再将这些片段作为上下文喂给大模型,生成精准回答。

对于Web开发者而言,RAG 并非全新范式,而是你熟悉的 “搜索 + 渲染”模式的AI升级版。本文将从Web工程视角出发,详解 LangChain 中 RAG 的完整链路,并通过一个 Node.js + React + Pinecone 的企业知识库项目,带你从零实现可落地的RAG应用。


2. RAG核心组件解析(Web类比)

在这里插入图片描述

RAG 组件 Web 类比 作用
文档加载器(Document Loaders) 文件上传解析器(如 multer + pdf-parse) 将PDF/Word/网页等转为纯文本
文本分割器(Text Splitters) 分页器(Pagination) 将长文档切分为小块,适配模型上下文
嵌入模型(Embedding Model) 搜索引擎的倒排索引构建器 将文本转为高维向量(语义指纹)
向量数据库(Vector DB) Elasticsearch / MySQL全文索引 存储向量并支持相似度搜索
检索器(Retriever) 搜索API(/api/search?q=…) 根据问题向量召回相关文档
LLM + Prompt 模板引擎(Handlebars/EJS) 将检索结果+问题组合成最终回答

整个流程如同构建一个“智能搜索引擎”:

用户提问 → 语义搜索 → 召回相关段落 → 注入提示词 → 生成答案

3. 文档处理:从原始文件到结构化文本

在这里插入图片描述

3.1 文档加载(Document Loading)

LangChain 提供多种加载器,覆盖常见格式:

// 加载本地PDF
import { PDFLoader } from "@langchain/community/document_loaders/fs/pdf";
const loader = new PDFLoader("./docs/product_manual.pdf");
const docs = await loader.load();

// 加载网页
import { PuppeteerWebBaseLoader } from "@langchain/community/document_loaders/web/puppeteer";
const webLoader = new PuppeteerWebBaseLoader("https://example.com/kb");
const webDocs = await webLoader.load();

💡 Web类比:这就像你用 pdf-parsecheerio 解析文件内容。

3.2 文本分割(Document Transformation)

大模型有上下文长度限制(如GPT-4o最多128K),需将长文档切块:

import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";

const splitter = new RecursiveCharacterTextSplitter({
  chunkSize: 1000,    // 每块约1000字符
  chunkOverlap: 200   // 相邻块重叠200字符,防断句
});

const splitDocs = await splitter.splitDocuments(docs);
// 输出: [Document(pageContent="...", metadata={source: "manual.pdf", ...}), ...]

关键点metadata 字段保留来源信息(文件名、URL、章节),便于溯源。


4. 向量化与存储:构建语义索引

在这里插入图片描述

4.1 嵌入模型(Embedding Model)

将文本转为向量。推荐使用开源且高效的 OpenAI EmbeddingsHuggingFace Sentence Transformers

import { OpenAIEmbeddings } from "@langchain/openai";

const embeddings = new OpenAIEmbeddings({
  apiKey: process.env.OPENAI_API_KEY,
  modelName: "text-embedding-3-small" // 成本低、性能好
});

4.2 向量数据库选型

数据库 Web部署友好度 适用场景
Pinecone ⭐⭐⭐⭐(全托管) 快速上线、无需运维
Chroma ⭐⭐⭐(嵌入式) 本地开发、轻量级
Weaviate ⭐⭐(需Docker) 需要混合搜索(关键词+向量)
PostgreSQL + pgvector ⭐⭐⭐⭐ 已有PostgreSQL、希望统一存储

本文以 Pinecone 为例(免费 tier 足够演示)。

4.3 构建向量索引

import { Pinecone } from "@pinecone-database/pinecone";
import { PineconeStore } from "@langchain/pinecone";

// 初始化Pinecone
const pc = new Pinecone({ apiKey: process.env.PINECONE_API_KEY });
const index = pc.Index("company-kb");

// 创建向量存储
const vectorStore = await PineconeStore.fromDocuments(
  splitDocs,           // 切分后的文档
  embeddings,          // 嵌入模型
  { pineconeIndex: index }
);

🔧 注意:首次运行会自动计算所有文档的向量并存入Pinecone。


5. 检索与生成:RAG链的核心逻辑

在这里插入图片描述

5.1 创建检索器(Retriever)

// 从向量库创建检索器,返回最相关的4个片段
const retriever = vectorStore.asRetriever({
  k: 4,
  searchType: "similarity"
});

5.2 构建RAG链(LCEL风格)

import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
import { createStuffDocumentsChain } from "langchain/chains/combine_documents";
import { createRetrievalChain } from "langchain/chains/retrieval";

const llm = new ChatOpenAI({ model: "gpt-4o" });

// 定义提示词模板
const prompt = ChatPromptTemplate.fromTemplate(`
你是一个企业知识库助手,请基于以下上下文回答问题。
如果不知道答案,请说“根据现有资料无法回答”。

上下文:
{context}

问题:{input}
`);

// 组合文档链
const combineDocsChain = createStuffDocumentsChain({
  llm,
  prompt,
});

// 创建完整RAG链
const ragChain = createRetrievalChain({
  retriever,
  combineDocsChain,
});

5.3 调用RAG链

const response = await ragChain.invoke({
  input: "我们的产品退货政策是什么?"
});

console.log(response.answer);
// 输出: "根据公司政策,商品在签收后7天内可无理由退货..."
console.log(response.context); // 返回检索到的原始文档片段

6. 应用实战:企业知识库问答系统

在这里插入图片描述

6.1 项目架构

enterprise-rag/
├── backend/
│   ├── ingestion/          # 文档预处理
│   │   └── ingest.js       # 加载+切分+存向量库
│   ├── chains/
│   │   └── ragChain.js     # RAG链定义
│   └── routes/
│       └── ask.js          # /api/ask 接口
└── frontend/               # React搜索界面

6.2 后端API(Express)

// backend/routes/ask.js
import { ragChain } from "../chains/ragChain.js";

router.post("/ask", async (req, res) => {
  try {
    const { question } = req.body;
    const result = await ragChain.invoke({ input: question });
    
    // 返回答案 + 溯源(用于前端展示来源)
    res.json({
      answer: result.answer,
      sources: result.context.map(doc => ({
        content: doc.pageContent,
        source: doc.metadata.source
      }))
    });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

6.3 前端界面(React)

// 展示答案和来源
function Answer({ answer, sources }) {
  return (
    <div>
      <div className="answer">{answer}</div>
      <div className="sources">
        <h4>参考来源:</h4>
        {sources.map((src, i) => (
          <div key={i} className="source-card">
            <p>{src.content.substring(0, 100)}...</p>
            <small>来自: {src.source}</small>
          </div>
        ))}
      </div>
    </div>
  );
}

6.4 效果演示

用户问:“如何申请年假?”
系统回答:“员工需提前3天在HR系统提交申请…”
并附上《员工手册_v2.pdf》第12页的原文片段 —— 可解释、可溯源


7. 优化与生产建议

7.1 提升检索精度

  • 使用 HyDE(假设性文档嵌入):先让LLM生成假设答案,再用该答案去检索
  • 混合搜索:结合关键词(BM25) + 向量搜索(如Weaviate)
  • 元数据过滤:只检索特定部门/产品的文档(retriever.getRelevantDocuments(query, { filter: { department: "IT" } })

7.2 降低成本

  • 使用 text-embedding-3-small 而非 large
  • 缓存高频问题的答案(Redis)
  • 限制上下文长度,避免Token浪费

7.3 安全与权限

  • metadata 中记录文档权限级别
  • 检索时传入用户角色,过滤无权访问的文档
  • 敏感内容脱敏后再存入向量库

8. 总结与学习路径

RAG 不是魔法,而是一套可工程化的信息检索增强方案。作为Web开发者,你已具备构建它的全部能力:

  • 文件处理 → 用过 multer / pdf-parse
  • 搜索系统 → 熟悉 Elasticsearch / SQL LIKE
  • API设计 → 知道如何封装 /ask 接口

下一步

  1. 动手实践

    • 用公司内部文档(如Confluence导出PDF)搭建知识库
    • 尝试不同向量数据库(Chroma本地跑,Pinecone上云)
  2. 深入优化

    • 实现多轮RAG(追问时保留上下文)
    • 加入评分机制:让用户对答案点赞/点踩,反馈优化检索
  3. 推荐资源


结语:未来的内部工具,不再是复杂的表单和菜单,而是一个“懂你”的对话入口。作为Web开发者,你站在构建这一未来的最前线——用RAG,把知识变成服务。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐