听说大模型总“胡言乱语”?用 RAG 堵住它的嘴!

不知道你在调戏各种 AI 大模型的时候,有没有遇到过以下经典翻车现场:

:"请问我们公司昨天新办的报销流程是什么?" AI:(一本正经地胡说八道)"根据规定,您需要先骑上一只尖叫鸡,然后提交一份由火星办事处盖章的纸质申请......"

这种现象在人工智能领域有个专门的名字,叫"幻觉"(Hallucination)。

今天我们就来扒一扒,为什么聪明的大模型会变成"糊涂蛋"?而我们程序员又是如何用一项叫做 RAG 的技术,在不花大钱"微调"(Fine-tune)模型的情况下,让 AI 乖乖听话、有据可依的。

1. 大模型的"打工人痛点":为什么它会胡说八道?

要理解大模型为什么会产生幻觉,我们得先明白它是怎么被塞满知识的。

核心症结:数据集的局限性

大模型(LLM)所有能回答出来的知识,完全取决于它在出厂训练时吃进去的数据集。这就导致了两个致命的知识盲区:

  1. 时效性差:如果模型是 2025 年底训练完成的,你问它 2026 年最新发生的科技新闻,它绝对一问三不知。
  2. 私密性孤岛:你企业内部的私有文档、你个人的秘密笔记,公网上的大模型是绝对接触不到的。

致命性格:宁可毒死你,也不愿意"交白卷"

如果是一个诚实的打工人,不知道往往会说"对不起,我没学过"。但大模型不是。它本质上是一个"概率超级Next-Token预测机",它的天职就是根据你上一句话,猜出下一句话最可能是什么。

当你问它它不知道的事情时,它为了完成"接话"的使命,就会开始根据已有的字词概率生搬硬套,胡乱回答。这就是幻觉

2. 拯救大模型的两条路:微调 vs RAG

既然大模型有知识盲区,我们怎么给它"补课"呢?行业里通常有两种做法。

方案 A:微调(Fine-tuning)

简单来说,就是把你的私有文档打碎成训练格式,把大模型送回工厂"重新深造"。

  • 缺点:成本高得吓人!不仅需要昂贵的显卡(GPU)算力,而且每次你的私有文档一更新(比如公司昨天改了报销制度),你就得重新训练一次。这谁顶得住?

方案 B:给它一本"开卷考试"的参考书(RAG)

既然重回学校太贵,那我们直接在它考试(回答问题)的时候,把小抄......哦不,把参考答案塞到它手里不就行了?

当用户提出一个问题时,我们先去内部的"知识库"里把相关的文章查出来,然后把这些文章和用户的问题一起打包成一个超长的提示词(Prompt)喂给大模型:

"请结合以下参考资料,回答用户的问题。如果资料里没写,就老实说不知道。 【参考资料:公司2026年最新报销流程.pdf】 用户问题:怎么报销?"

大模型有了底气,看着参考资料作答,幻觉自然就消失了。这种技术,就叫做 RAG

3. 拆解 RAG:硬核概念的白话文翻译

RAG 是三个英文单词的缩写:Retrieval-Augmented Generation ,翻译过来叫 检索增强生成

我们把它拆成三步来理解:

scss 复制代码
[用户提问] ──> 1. Retrieval (检索相关文档) ──> 2. Augmented (塞入Prompt增强) ──> 3. Generation (大模型生成回答)
  • Retrieval(检索) :去你的企业知识库或者个人文档里,把和用户问题相关的文档片段(可以是一个自然段、一页 PDF 或者一个章节)给找出来
  • Augmented(增强) :把找出来的这堆文档片段,死缠烂打地拼接进原始的 Prompt 里面。这时候的 Prompt 变得非常丰满,这就叫增强
  • Generation(生成) :大模型阅读了这些背景知识后,吐出最终的、靠谱的回答

4. 检索的演进:从"死板匹配"到"灵魂共鸣"

RAG 的核心瓶颈在于第一步:你凭什么能把最相关的文档片段准确地查出来?

传统做法:关键词搜索(Lexical Search)

早期的搜索像老学究,玩的是文本硬匹配。比如你搜"西红柿",它能帮你找到含有"西红柿"的文档。但如果你搜"番茄",它可能就懵圈了,因为它觉得这两个词的长相完全不一样。这种文本匹配在复杂的语义面前,可以说是"不太行"。

现代做法:向量(Vector)语义查询

为了让计算机理解"番茄"和"西红柿"是同一种东西,科学家引入了多维向量

什么叫向量?你可以把它想象成给每个词语或者句子打上各式各样的"属性标签标签"。 为了方便理解,我们假设世界上只有两个属性指标: "食用性" (0表示不能吃,1表示极好吃)和"硬度"(0表示液体,1表示极硬)。 那么,我们可以用一个包含两个数字的数学列表(也就是二维向量)来表达它们的特征:

  • 水果[0.9, 0.3](能吃,偏软)
  • 苹果[0.9, 0.5](能吃,比一般水果硬点)
  • 香蕉[0.4, 0.1](能吃,非常软)
  • 石头[0.1, 0.9](不能吃,硬邦邦)

在由这两个坐标轴组成的数学空间里,"水果"、"苹果"和"香蕉"因为属性接近,它们对应的点离得非常近。如果从原点向它们分别画一条线,这些线之间的夹角就会非常小。通过计算夹角的余弦值(余弦相似度),计算机就能一秒看出:"哦!苹果和水果相关性很大,而石头和水果完全不搭边!"

在实际应用中,我们会用成百上千个维度(比如几百上千个数字组成的超长列表)来表达极其复杂的丰富语义。不管是文本、图片、PDF 还是语音,都能被抹平转换成这一串串数字向量,实现真正的"语义搜索"。

而负责把大白话和各种文档转换成这种高维向量的专用模型,就叫做嵌入模型(Embedding Model) 。它通常比生成模型(Generation Model)要便宜得多。

5. RAG 的落地实现:向量数据库

既然文档变成了向量,我们普通的 MySQL 数据库可就犯难了。MySQL 擅长找 id = 1 或者 name = '张三' 的数据,你要是让它在几百万条几百维的数字列表里找出"哪个向量和当前问题的向量夹角最小",它会直接cpu烧干。

于是,向量数据库(Vector Database)应运而生。它专门用来做两件事:

  1. 高效存储海量的多维向量数据(持久化存储)。
  2. 提供极快的"相似度检索"算法,能在电光石火间找出语义最接近的文本块。

6. 代码实战:搭建你的第一个 RAG 脚手架

概念听够了,我们来点真的。我们将使用大名鼎鼎的 AI 编排框架 LangChain 逐步搭建一个 RAG 基础工程。

步骤一:环境配置与依赖引入

首先,我们需要引入环境变量,并拉取 LangChain 中专门对接 OpenAI 模型的工具。同时,我们引入 Document 对象,它是 LangChain 内部用来封装每一段文本块的基础数据结构。

JavaScript

javascript 复制代码
import 'dotenv/config'
import { ChatOpenAI, OpenAIEmbeddings } from 'langchain/openai'
// Document 是 LangChain 中表示文档片段的核心类,可以把 txt、js、pdf 切成有一定大小的段落
import { Document } from 'langchain/core/documents'

步骤二:初始化模型实例

接下来,我们实例化两辆核心马车:一辆是用来生成最终回答的 ChatOpenAI 聊天模型,另一辆是负责把文本变成数学向量的 OpenAIEmbeddings 嵌入模型。

为了保证回答的严谨性,我们将聊天模型的 temperature(随机性)设置为 0,让它老老实实根据资料回答,绝不瞎发挥。

JavaScript

arduino 复制代码
// 1. 初始化聊天生成模型(Generation)
const model = new ChatOpenAI({
  temperature: 0, // 设置为0,尽可能让其严谨,不胡乱发挥
  model: process.env.MODEL_NAME,
  apiKey: process.env.OPENAI_API_KEY,
  configuration: {
    baseURL: process.env.OPENAI_API_BASE, // 这里的配置基址确保能正确连接到 API 服务
  }
})

// 2. 初始化嵌入模型(Embedding),用于将文本向量化
const embeddings = new OpenAIEmbeddings({
  apiKey: process.env.OPENAI_API_KEY,
  model: process.env.OPENAI_EMBEDDINGS_MODEL,
  configuration: {
    baseURL: process.env.OPENAI_BASE_URL,
  }
})

步骤三:模拟知识库构建与向量化

有了工具,我们手写两个文档片段来模拟我们的私有"知识库"。一个是关于公司最新报销流程的,另一个是毫不相关的冷知识。我们尝试使用 embeddings 将它们转化成多维数字向量。

JavaScript

ini 复制代码
// 3. 准备知识库里的文档片段(已经过切分处理)
const doc1 = new Document({ pageContent: "2026年新规定:公司差旅报销必须在行程结束后3个工作日内提交,且需附带电子行程单。" });
const doc2 = new Document({ pageContent: "世界冷知识:大熊猫每天花12个小时吃竹子。" });

// 4. 将这些文本转为多维向量(以 doc1 为例)
const vectorSample = await embeddings.embedQuery(doc1.pageContent);
console.log("文本成功向量化!前5个维度的数字为:", vectorSample.slice(0, 5));
// 输出看起来会是这样:[ 0.01234, -0.05678, 0.09101, -0.0023, 0.0456 ]

步骤四:检索与最终生成(构建 RAG 闭环)

现在,用户提问了:"差旅报销要在几天内提交?"

完整的 RAG 逻辑如下:在没有向量数据库的简化场景下,我们通过代码模拟这个检索、拼接并交给大模型回答的闭环:

JavaScript

javascript 复制代码
// 5. 用户提问
const userQuery = "差旅报销要在几天内提交?";

// 6. 【检索阶段 (Retrieval)】:
// 在真实场景中,我们会将 userQuery 向量化后去向量数据库做相似度查询。
// 这里我们肉眼可见 doc1 与问题最相关,直接将其作为检索出来的背景背景材料。
const retrievedContext = doc1.pageContent;

// 7. 【增强阶段 (Augmented)】:拼装带背景知识的超强 Prompt
const augmentedPrompt = `
你是一个诚实的助手。请严格根据以下给出的背景知识回答用户的问题。如果背景知识中没有提到,请回答"不知道"。

背景知识:
${retrievedContext}

用户问题:${userQuery}
`;

// 8. 【生成阶段 (Generation)】:让大模型根据小抄作答
const response = await model.invoke(augmentedPrompt);

console.log("=== AI的终审回答 ===");
console.log(response.content);
// 输出:2026年新规定指出,公司差旅报销必须在行程结束后3个工作日内提交。

7. 总结:RAG 真正落地需要突破的难关

虽然上面的代码跑通了,但在真实的工程落地中,还有几个骨头极难啃的技术突破点

  1. 文档怎么切分(Chunking) :一个 100 页的 PDF,你不能整本塞进去(大模型吃不下,而且很贵)。你得把它切成一个个片段。但怎么切才能保证语义不被打断?按字数硬切?还是按自然段落、章节、页码切?这是个技术活。
  2. 检索的精准度(Retrieval Quality) :怎么保证向量数据库挑出来的文档片段真的完美命中了用户的意图,而不是找了一堆干扰项?
  3. 多模态融合:如果你的文档里有复杂的架构图、表格、流程图,怎么把它们也顺利地向量化并让大模型看懂?

不过别慌,万丈高楼平地起。理解了"向量化""检索-增强-生成"的底层逻辑,你已经超越了绝大多数只会给大模型发简单提示词的普通玩家了。接下来的文章里,我们将深入探讨如何高效切分文档以及向量数据库的持久化实战,敬请期待!

相关推荐
Dawson Zhu几秒前
【AI架构前沿】MEMO:解耦推理与记忆,破解大模型“知识更新“与“灾难性遗忘“的两难困境
人工智能·架构·aigc·agi
江湖有缘4 分钟前
跨平台AI终端Wave:智能SSH与文件管理
运维·人工智能·ssh
IT_陈寒10 分钟前
Python装饰器把我坑惨了,原来这样用才不掉链子
前端·人工智能·后端
吃旺旺雪饼的小男孩11 分钟前
自动驾驶图像分割开源数据集指南(2026)
人工智能·开源·自动驾驶
A133455513 分钟前
视频特效字幕怎么翻译?保姆级AI字幕与外挂字幕教程
人工智能·音视频
飞哥数智坊14 分钟前
我给 DeepSeek 看了两次截图,才发现 Vision 真正的价值
人工智能·ai编程·deepseek
飞哥数智坊25 分钟前
AI提升了人效,但组织却接不住释放的生产力
人工智能
飞哥数智坊34 分钟前
什么才叫真正的端到端?
人工智能
武科大许志伟1 小时前
从并行进化到分布式进化计算读 A Survey on Distributed Evolutionary Computation
人工智能·分布式·演化计算
长谷深风1111 小时前
好的 Tool Schema,不是字段越全越好
java·大数据·人工智能·ai agent·agent工作流·智能体设计·ai产品设计