本文详解如何利用 RAG 技术解决大模型“幻觉”问题,从零构建基于私有知识库的问答系统。涵盖文档分割、向量化存储、检索增强生成及提示词工程等核心环节,结合 LangChain、Ollama 等工具实现完整代码,并探讨了增量更新与混合检索等进阶优化方案。

一、理解 RAG 的核心价值

1.1 什么是 RAG?

RAG 是一种混合架构,它将用户的查询与知识库中的相关内容相结合,然后交给大语言模型生成回答。简单来说,就是"先检索,再生成"。

1.2 为什么需要 RAG?

大语言模型虽然强大,但存在两个固有缺陷:

问题 表现 RAG 的解决方案
知识过时 模型训练完成后无法获取新信息 知识库可随时更新
幻觉问题 模型可能编造不存在的答案 强制基于检索到的文档回答

1.3 RAG 的优势

  • 事实准确:回答基于真实文档,减少幻觉
  • 可更新:无需重新训练模型即可更新知识
  • 可追溯:可以标注答案来源
  • 成本低廉:相比微调模型,成本更低

二、系统架构设计


2.1 整体架构图

整体架构

整体架构

2.2 核心组件职责

组件 职责 技术选型
DocumentChunker 将文档分割为语义完整的片段 LangChain TextSplitters
EmbeddingStore 存储和检索向量表示 Chroma + Ollama Embeddings
KnowledgeBase 协调整个知识库的构建和管理 自定义类
RAGChat 处理用户提问,协调检索和生成 LangChain + Ollama

三、离线阶段:构建知识库


3.1 文本分割:DocumentChunker

文档分割是 RAG 的第一步,也是最关键的一步。分割的好坏直接影响检索效果。

为什么需要分割?
  • 大语言模型有上下文长度限制
  • 向量检索需要更小的语义单元
  • 合理的分割能提高检索精度
分割策略
// 项目配置
const chunkSize = 800;      // 每个 chunk 的字符数
const chunkOverlap = 100;   // 相邻 chunk 的重叠字符数

参数说明:

  • chunkSize:太小会丢失上下文,太大会降低检索精度,推荐 500-1000
  • chunkOverlap:确保边界信息的连续性,推荐 50-150
LangChain TextSplitters API

LangChain 提供了多种分割器,本项目使用两种:

// Markdown 文档专用分割器
const mdSplitter = new MarkdownTextSplitter({
    chunkSize: 800,
    chunkOverlap: 100
});

// 递归字符分割器(通用型)
const textSplitter = new RecursiveCharacterTextSplitter({
    chunkSize: 800,
    chunkOverlap: 100,
    // 按优先级递归尝试的分隔符
    separators: ["/n/n", "/n", "。", "!", "?", ";", ",", " ", ""]
});

递归分割的工作原理:

  1. 首先尝试用 "/n/n" 分割(段落级别)

  2. 如果结果仍然太大,尝试用 "/n" 分割(句子级别)

  3. 继续尝试标点符号,直到满足 chunkSize 要求

支持多文件处理
export class DocumentChunker {
    constructor(filepath: string | string[]) {
        // 支持单个文件或文件数组
    }

    async splitText(): Promise<string[]> {
        if (Array.isArray(this.filepath)) {
            // 并行处理多个文件
            const allChunks = awaitPromise.all(
                this.filepath.map(fp =>this.processFile(fp))
            );
            return allChunks.flat();
        }
        returnawaitthis.processFile(this.filepath);
    }
}

3.2 向量化与存储:EmbeddingStore

什么是向量?

向量是文本的数值表示,相似的文本在向量空间中距离更近。通过计算向量之间的相似度,可以找到与查询最相关的文档。

向量化流程

向量化流程

向量化流程

LangChain Embeddings API
import { OllamaEmbeddings } from "@langchain/ollama";

const embeddings = new OllamaEmbeddings({
    model: "qwen3-embedding:4b",
    baseUrl: "http://localhost:11434"
});

// 单个文本向量化
const vector = await embeddings.embedQuery("查询文本");

// 批量向量化
const vectors = await embeddings.embedDocuments(["文档1", "文档2"]);
Chroma 向量数据库

Chroma 是一个开源的向量数据库,专为 AI 应用设计:

import { Chroma } from "@langchain/community/vectorstores/chroma";

const vectorStore = new Chroma(embeddings, {
    collectionName: "my-knowledge-base",
    clientParams: { host: 'localhost', port: 8000 },
    collectionMetadata: {
        "hnsw:space": "cosine"  // 余弦相似度
    }
});

相似度算法选择:

算法 特点 适用场景
Cosine 关注方向,忽略长度 文本向量(推荐)
Euclidean 关注绝对距离 需要精确匹配
Dot Product 关注对齐程度 归一化后的向量

在使用Chroma API之前,需要安装 Chroma 客户端,比如使用 docker 安装:

# 拉取镜像
docker pull ghcr.io/chroma-core/chroma:latest

# 运行容器
docker run -d /
    --name chroma-server /
    -p 8000:8000 /
    -v chroma-data:/chroma/chroma/ /
    -e IS_PERSISTENT=TRUE /
    -e CHROMA_WORKERS=$(nproc) /
    ghcr.io/chroma-core/chroma:latest
文档去重机制
export class EmbeddingStore {
    private documentHashes = new Set<string>();

    async addDocumentsWithDeduplication(documents: string[]) {
        const uniqueDocs = documents.filter(doc => {
            const hash = this.calculateHash(doc);
            if (this.documentHashes.has(hash)) {
                return false;  // 已存在,跳过
            }
            this.documentHashes.add(hash);
            return true;
        });

        awaitthis.vectorStore.addDocuments(uniqueDocs);
    }
}

3.3 知识库管理:KnowledgeBase

KnowledgeBase 是整个系统的协调器,负责协调整个知识库的构建和更新。

export class KnowledgeBase {
    staticasync create(filepath: string | string[]): Promise<KnowledgeBase> {
        const kb = new KnowledgeBase(filepath);
        await kb.init();
        return kb;
    }

    privateasync init() {
        const chunks = await this.documentChunker.splitText();
        awaitthis.embeddingStore.setVectors(chunks);
    }
}

使用工厂方法的好处:

  • 确保异步初始化完成后再返回实例
  • 隐藏构造函数,强制使用正确的初始化方式
  • 便于后续扩展(如连接池、缓存等)

四、在线阶段:问答流程


4.1 检索相关上下文

当用户提问时,系统首先在向量数据库中检索最相关的文档片段。

检索上下文

检索上下文

VectorStore API 使用
// 相似度搜索(返回文档列表)
const docs = await vectorStore.similaritySearch(query, k);

// 相似度搜索(返回文档和分数)
const results = await vectorStore.similaritySearchWithScore(query, k);
// 格式: [[Document, score], ...]

// 按相似度阈值过滤
const filtered = results.filter(([_, score]) => score > 0.8);

4.2 提示词工程

提示词(Prompt)是控制模型输出的关键,好的提示词能显著提升回答质量。

基础提示词
请基于以下上下文回答问题。

上下文:{context}
问题:{question}
回答:
优化后的提示词
你是一个专业的问答助手,请基于提供的参考文档回答用户的问题。

【参考文档】
{context}

【用户问题】
{question}

【回答要求】
1. **只使用参考文档中的信息回答,不要编造内容**

2. **如果参考文档中没有相关信息,请明确说明"文档中未找到相关答案"**

3. **回答时要条理清晰,使用恰当的段落分隔**

4. **如果答案是列表形式,请使用项目符号**

回答:

优化要点:

  • 明确角色定位
  • 使用分隔符增强可读性
  • 列出具体要求,减少模型理解偏差
  • 处理无答案的情况
LangChain PromptTemplate API
import { PromptTemplate } from "@langchain/core/prompts";

const promptTemplate = PromptTemplate.fromTemplate(`
你是一个专业的问答助手,请基于提供的参考文档回答用户的问题。

【参考文档】
{context}

【用户问题】
{question}

【回答要求】
1. **只使用参考文档中的信息回答,不要编造内容**

2. **如果参考文档中没有相关信息,请明确说明"文档中未找到相关答案"**

3. **回答时要条理清晰,使用恰当的段落分隔**

4. **如果答案是列表形式,请使用项目符号**

回答:
`);

// 格式化提示词
const prompt = await promptTemplate.format({
    context: "检索到的文档内容...",
    question: "用户的问题"
});

4.3 生成回答

使用 LangChain 的链式调用机制,将检索、提示词构建和生成串联起来。

链式调用基础
import { StringOutputParser } from "@langchain/core/output_parsers";

// 创建链
const chain = llm
    .pipe(new StringOutputParser())  // 解析输出为字符串
    .pipe((text) => text.trim());    // 后处理

// 调用链
const result = await chain.invoke("用户输入");
完整的 RAG 链
export class RAGChat {
    async answer(question: string): Promise<void> {
        // 步骤1:检索相关上下文
        const contextList = await this.knowledgeBase.getEmbeddingStore()
            .retrieveContext(question);
        const context = contextList?.join("/n/n");

        // 步骤2:构建提示词
        const prompt = await this.promptTemplate.format({
            context,
            question,
        });

        // 步骤3:调用模型生成回答
        const chain = this.llm.pipe(new StringOutputParser());
        const answer = await chain.stream(prompt);

        // 步骤4:流式输出
        await answer.pipeTo(writable);
    }
}
async function main() {  try {    console.log("正在初始化 RAG 系统...");    const knowledgeBase = await KnowledgeBase.create(      path.resolve(__dirname, "../xxxx.md")    );    const ragChat = new RAGChat({      knowledgeBase    });    console.log("RAG 系统初始化完成!");    console.log("输入您的问题(输入 'exit' 或 'quit' 退出):/n");    const rl = readline.createInterface({      input: process.stdin,      output: process.stdout    });    const askQuestion = () => {      rl.question("> ", async (prompt) => {        const trimmedPrompt = prompt.trim();        if (!trimmedPrompt) {          askQuestion();          return;        }        if (trimmedPrompt === "exit" || trimmedPrompt === "quit") {          console.log("再见!");          rl.close();          return;        }        await ragChat.answer(trimmedPrompt);        console.log();        askQuestion();      });    };    askQuestion();  } catch (error) {    console.error("系统启动失败:", error instanceof Error ? error.message : String(error));    process.exit(1);  }}
使用 RunnableSequence

对于更复杂的场景,可以使用 RunnableSequence

import { RunnableSequence } from"@langchain/core/runnables";

const ragChain = RunnableSequence.from([
    {
        // 步骤1:检索上下文
        context: (input) => retriever.invoke(input.question),
        question: (input) => input.question
    },
    // 步骤2:格式化提示词
    (input) => promptTemplate.format(input),
    // 步骤3:调用模型
    llm,
    // 步骤4:解析输出
    new StringOutputParser()
]);

const response = await ragChain.invoke({ question: "用户问题" });

五、进阶功能:增量更新


生产环境中,知识库需要频繁更新而不需要重新处理所有文档。

5.1 文件变更检测

通过文件哈希值判断文件是否发生变化:

class KnowledgeBase {
    private fileHashes = new Map<string, string>();

    private calculateFileHash(filepath: string): string {
        const content = fs.readFileSync(filepath, 'utf-8');
        return crypto.createHash('md5').update(content).digest('hex');
    }

    private isFileChanged(filepath: string): boolean {
        const currentHash = this.calculateFileHash(filepath);
        const previousHash = this.fileHashes.get(filepath);

        if (previousHash !== currentHash) {
            this.fileHashes.set(filepath, currentHash);
            return true;
        }
        return false;
    }
}

5.2 增量更新流程

增量更新流程

增量更新流程

5.3 实现代码

export class KnowledgeBase {
    async update(filepath: string | string[]): Promise<void> {
        const filepaths = Array.isArray(filepath) ? filepath : [filepath];
        let updated = false;

        for (const fp of filepaths) {
            if (this.isFileChanged(fp)) {
                const chunks = await this.documentChunker.processFile(fp);
                awaitthis.embeddingStore.deleteDocumentsBySource(fp);
                awaitthis.embeddingStore.addDocumentsWithDeduplication(chunks, fp);
                updated = true;
            }
        }

        if (updated) {
            console.log('知识库更新完成');
        }
    }
}

六、常见问题与解决方案


Q1: 检索结果不相关怎么办?

可能原因:

  • chunkSize 设置不当
  • 嵌入模型不适合当前语言
  • 分割策略不合理

解决方案:

  1. 调整 chunkSize(推荐 500-1000)

  2. 尝试不同的嵌入模型

  3. 优化分割策略,增加 chunkOverlap

  4. 使用混合检索(关键词+向量)

Q2: 如何处理超长文档?

解决方案:

  • 使用章节级别分割
  • 添加目录索引
  • 实现分块检索策略

Q3: 模型回答不够准确?

解决方案:

  • 优化提示词模板
  • 增加 k 值获取更多上下文
  • 添加相似度阈值过滤
  • 使用更强的模型

Q4: 如何提升系统性能?

优化方向:

  • 批量向量化处理
  • 使用向量索引(如 HNSW)
  • 实现缓存机制
  • 并行处理多个文件

七、总结与展望


7.1 RAG 技术总结

RAG 技术通过"检索+生成"的方式,让大语言模型能够基于私有知识库回答问题,具有事实准确、可更新、可追溯等优势。

本项目从零开始构建了一个完整的 RAG 问答系统,涵盖了:

  • ✅ 文本分割与向量化
  • ✅ 向量存储与检索
  • ✅ 提示词工程
  • ✅ 链式调用机制
  • ✅ 增量更新功能

7.2 RAG 当前面临的挑战

尽管 RAG 技术已经取得了显著进展,但在实际应用中仍存在一些挑战:

挑战 具体表现
检索准确性 语义鸿沟问题,向量检索可能错过相关文档
上下文长度限制 模型上下文窗口有限,难以容纳大量检索内容
多轮对话能力弱 难以有效利用对话历史进行检索
推理能力有限 跨文档的复杂推理能力不足
延迟问题 检索+生成的链路延迟较高
知识更新成本 向量化存储和索引更新仍有开销

7.3 新兴技术与解决方案

针对上述挑战,研究界和工业界正在积极探索多种解决方案:

1. 混合检索(Hybrid Retrieval)

问题解决: 提高检索准确性

结合关键词检索(BM25)和向量检索的优势:

混合检索

混合检索

技术代表:

  • LangChain 的 BM25Retriever + VectorStoreRetriever
  • Elasticsearch 的 dense_vector + text 字段混合查询
2. 重排序(Reranking)

问题解决: 提升检索结果的相关性

在初步检索后,使用专门的排序模型对结果进行精排:

// 检索 Top-50 个候选
const candidates = await vectorStore.similaritySearch(query, 50);

// 使用重排序模型精排
const reranker = new CohereRerank();
const rankedResults = await reranker.compressDocuments(candidates, query);

// 取 Top-5
const topResults = rankedResults.slice(0, 5);

技术代表:

  • Cohere Rerank API
  • BGE-Reranker(开源)
  • ColBERT(Late Interaction)
3. 长上下文模型(Long Context LLMs)

问题解决: 突破上下文长度限制

新一代支持超长上下文的模型,可以直接处理更多检索内容:

模型 上下文长度 特点
GPT-4 Turbo 128K 支持长文档直接处理
Claude 3 200K 优秀的长文档理解能力
Qwen-Long 10M 超长上下文,适合海量检索
Gemini 1.5 1M 多模态长上下文
4. 智能体 RAG(Agentic RAG)

问题解决: 增强推理和多轮对话能力

将 RAG 与 Agent 结合,使用工具调用和思维链增强推理能力:

Agentic RAG

Agentic RAG

技术代表:

  • LangGraph(Agent 工作流)
  • AutoGPT、BabyAGI
  • ReAct 框架
5. 图谱 RAG(GraphRAG)

问题解决: 增强跨文档推理能力

将知识库构建为知识图谱,支持结构化查询和推理:

图谱 RAG

图谱 RAG

技术代表:

  • Microsoft GraphRAG
  • Neo4j + LLM
  • LlamaIndex Knowledge Graphs
6. 自适应检索(Adaptive RAG)

问题解决: 优化延迟和准确性

根据问题类型动态决定是否需要检索,以及检索多少内容:

// 判断是否需要检索
const needsRetrieval = await router.predict({
    query: userQuestion
});

if (needsRetrieval === "yes") {
    // 根据问题复杂度调整检索数量
    const k = determineRetrievalDepth(userQuestion);
    const context = await retrieve(userQuestion, k);
    return generateAnswer(context, userQuestion);
} else {
    // 直接使用模型内部知识
    return llm.invoke(userQuestion);
}

技术代表:

  • Self-RAG(带自我反思的 RAG)
  • Adaptive RAG(自适应检索)
  • Corrective RAG(纠错型 RAG)
7. 微调 RAG(Fine-tuned Embeddings)

问题解决: 提升领域特定检索效果

针对特定领域微调嵌入模型:

方案 特点 适用场景
BGE-M3 多语言、多功能 通用场景
E5 基于对比学习 问答系统
Jina Embeddings 开源高效 成本敏感场景
自定义微调 领域定制 垂直领域

7.5 总结

RAG 技术正在快速演进,从最初的"简单检索+生成"模式,发展到今天融合混合检索、重排序、智能体、知识图谱等多种技术的综合方案。

对于开发者而言,选择合适的 RAG 方案需要考虑:

  1. 应用场景:问答、对话、知识管理、代码辅助等

  2. 数据特性:文本类型、数据规模、更新频率

  3. 性能要求:延迟、准确性、成本

  4. 团队能力:技术栈、维护成本

希望本文能够帮助你理解 RAG 的核心概念,并在实际项目中应用这些技术。随着技术的不断发展,RAG 的应用场景将会越来越广泛,让我们一起探索更多可能性!

最后

对于正在迷茫择业、想转行提升,或是刚入门的程序员、编程小白来说,有一个问题几乎人人都在问:未来10年,什么领域的职业发展潜力最大?

答案只有一个:人工智能(尤其是大模型方向)

当下,人工智能行业正处于爆发式增长期,其中大模型相关岗位更是供不应求,薪资待遇直接拉满——字节跳动作为AI领域的头部玩家,给硕士毕业的优质AI人才(含大模型相关方向)开出的月基础工资高达5万—6万元;即便是非“人才计划”的普通应聘者,月基础工资也能稳定在4万元左右

再看阿里、腾讯两大互联网大厂,非“人才计划”的AI相关岗位应聘者,月基础工资也约有3万元,远超其他行业同资历岗位的薪资水平,对于程序员、小白来说,无疑是绝佳的转型和提升赛道。
图片
图片
对于想入局大模型、抢占未来10年行业红利的程序员和小白来说,现在正是最好的学习时机:行业缺口大、大厂需求旺、薪资天花板高,只要找准学习方向,稳步提升技能,就能轻松摆脱“低薪困境”,抓住AI时代的职业机遇。

如果你还不知道从何开始,我自己整理一套全网最全最细的大模型零基础教程,我也是一路自学走过来的,很清楚小白前期学习的痛楚,你要是没有方向还没有好的资源,根本学不到东西!

下面是我整理的大模型学习资源,希望能帮到你。

图片

👇👇扫码免费领取全部内容👇👇

在这里插入图片描述

最后

1、大模型学习路线

img

2、从0到进阶大模型学习视频教程

从入门到进阶这里都有,跟着老师学习事半功倍。

在这里插入图片描述

3、 入门必看大模型学习书籍&文档.pdf(书面上的技术书籍确实太多了,这些是我精选出来的,还有很多不在图里)

在这里插入图片描述

4、 AI大模型最新行业报告

2026最新行业报告,针对不同行业的现状、趋势、问题、机会等进行系统地调研和评估,以了解哪些行业更适合引入大模型的技术和应用,以及在哪些方面可以发挥大模型的优势。

img

5、面试试题/经验

img

【大厂 AI 岗位面经分享(107 道)】

img

【AI 大模型面试真题(102 道)】

img

【LLMs 面试真题(97 道)】

img

6、大模型项目实战&配套源码

img

适用人群

在这里插入图片描述

四阶段学习规划(共90天,可落地执行)
第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范
第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

  • 为什么要做 RAG
  • 搭建一个简单的 ChatPDF
  • 检索的基础概念
  • 什么是向量表示(Embeddings)
  • 向量数据库与向量检索
  • 基于向量检索的 RAG
  • 搭建 RAG 系统的扩展知识
  • 混合检索与 RAG-Fusion 简介
  • 向量模型本地部署
第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建
第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

  • 硬件选型

  • 带你了解全球大模型

  • 使用国产大模型服务

  • 搭建 OpenAI 代理

  • 热身:基于阿里云 PAI 部署 Stable Diffusion

  • 在本地计算机运行大模型

  • 大模型的私有化部署

  • 基于 vLLM 部署大模型

  • 案例:如何优雅地在阿里云私有部署开源大模型

  • 部署一套开源 LLM 项目

  • 内容安全

  • 互联网信息服务算法备案

  • 👇👇扫码免费领取全部内容👇👇

    在这里插入图片描述

3、这些资料真的有用吗?

这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理,现任上海殷泊信息科技CEO,其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证,服务航天科工、国家电网等1000+企业,以第一作者在IEEE Transactions发表论文50+篇,获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。

资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的技术人员,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。
在这里插入图片描述
在这里插入图片描述

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐