大语言模型(LLM)常因内部知识不足而引发幻觉问题,同时其上下文长度(Context Length)有限,难以容纳大量知识,这些问题一直备受诟病。

RAG 知识库的出现,在一定程度上解决了上述问题。基于检索增强生成(RAG,Retrieval Augmented Generation)的知识库方案,旨在将信息检索与大语言模型相结合,不仅有效缓解了大模型在推理过程中产生的幻觉问题,还通过仅提取与问题相关的知识,减少了大量无关信息输入上下文的情况,从而提升了回答的准确性和效率。

本文将会通过 LangChain 快速搭建一个简易的基于大语言模型(LLM)的检索增强生成(RAG)知识库,我们先了解相关原理,最终实现此方法。

框架与原理解析

我们将分步骤逐步搭建基于大语言模型的检索增强生成 RAG 知识库框架。

1. 知识文件嵌入与索引存储

所谓的检索增强,旨在为大语言模型提供特定专业领域或与问题相关的知识,以此增强大模型的在特定领域的能力。实际上,构建检索增强的过程类似于打造搜索引擎,用户需要通过输入问题查询(query)来获取相对精准的答案。

因此,构建 RAG 的首要步骤是提供一个支持增删查改的数据库,以便用户能够通过查询(query)语句高效获取所需信息。

在机器学习领域,主流的方法是将文档等不同类型的数据通过嵌入模型(Embedding Model)获得嵌入向量(Embedding Vector),并将其存入向量数据库

请看下图,这个流程展示了知识文件嵌入与存储流程。
图源来自@Catcolia
图源来自@Catcolia
  • 知识文件 (Documents):输入的原始文档,一般是特定领域的知识。

    • 这里所指的文档(Documents)可以指代任何形式的文件格式或多媒体等。例如:网站、文档、PDF、视频及音频文件等,即嵌入的知识可以是多模态的。
  • 分块器 (Chunker):由于大语言模型上下文大小的限制,我们有必要将文档分割成小块。

  • 分块知识 (Chunks):分割后的文档块。

  • 嵌入模型 (Embedding Model):使用一个机器学习模型(如 BERT、GPT 等)对每个分块知识进行嵌入,生成对应的嵌入向量(Embedding Vectors)。

  • 嵌入向量 (Embedding Vectors):每个分块知识对应的数值向量表示。

  • 向量数据库 (Vector Database):存储所有嵌入向量的数据库,用于后续的查询和检索。


不过对于初学者来说,这有点太抽象了
我们将使用一个具体的例子讲解,我们将大语言模型(LLM)作为一个天气查询小助手
图源来自@Catcolia
图源来自@Catcolia

我们的知识文件中包含明天所有城市的天气预报,我们的第一步是将天气预报数据存储到向量数据库

对于大量的知识文件,我们无法将其全部喂给大模型,因此有必要分块儿,我们需要一个叫做分块器(Chunker)的工具。理想的分块效果是将内容划分为若干个不同的部分(块),每个块既独立又相互关联

之后,我们将分好块的知识依次通过嵌入模型(Embedding Model)获得嵌入向量(Embedding Vector)
不过,这里的嵌入模型究竟是什么东西呢,以及我们为什么要获得嵌入向量

图源来自Bright AI@Shivika K Bisen
图源来自Bright AI@Shivika K Bisen

首先是向量空间(Embedding Space),向量空间被广泛用于表示数据的特征,复杂的原始数据(如文本、图像、音频等)会被映射到一个低维或固定维度的向量空间中,可以更方便地进行计算和分析。上图中最右侧的三维空间就是一个向量空间。

在上图中,三维空间能够提供一个三维嵌入,每一个数据被嵌入模型转化为一个三维空间中的一个点的坐标,例如第一个是 [0.6,0.3,0.1]。对于一个 1024 维的嵌入向量(Embedding),其会被转换为类似 [0.1,0.2,0.3,…] 的一个 1024 维向量。

嵌入模型(Embedding Model)可以将文本、图像、音频等多模态数据转换为向量空间中的一个点。训练好的嵌入模型理解各个数据之间的关联,也即相似的数据在向量空间中的距离更近,而不相似的数据距离更远,其能够捕捉数据之间的关联性和结构化信息。在实际应用中,我们经常接触的嵌入模型的维度通常是 1024 维,这个维度数量足够准确地表示一个数据的关联性。

在获得嵌入向量后,我们将嵌入向量存入向量数据库中,也即完成了复杂数据到嵌入向量作为索引存储的转换,以便后续数据的检索(召回)。

2. 查询语句嵌入

同样的,我们需要将用户输入,也即对查询语句进行嵌入(Embedding)以获得查询的嵌入向量,请看下图。

图源来自@Catcolia
图源来自@Catcolia

用户输入的语句是"北京的天气预报",我们需要通过嵌入模型将其转化为嵌入向量,该向量可视为对向量数据库中数据的索引。在后续步骤中,利用该索引进行检索(召回),从而提取与用户输入语句相关的分块知识的索引(分块的嵌入向量)。

3. 数据检索与输入合成

嵌入模型的核心能力在于挖掘数据之间的关联性。在之前的步骤中,知识文件已被转化为索引(即嵌入向量),并存储在向量数据库(或向量空间)中。同时,查询语句也被转化为嵌入向量。接下来,只需在向量数据库(或向量空间)中找出与查询语句关联性最强的数据,即可完成检索任务。

此外,还需要将用户原始输入与查询到的知识分块进行合成,最终将输入提供给 LLM 大语言模型。

图源来自@Catcolia
图源来自@Catcolia

首先,我们需要一种名为检索器(Retriever)的工具,它能够分析并找出两者之间的关联性。常用的算法包括相似度计算(Similarity)和最大边际相关性(MMR,Maximal Marginal Relevance)等。简而言之,检索器通常会根据某种排序规则,筛选出与查询最相关的数据索引。我们会在之后取出排名靠前的 k 组数据索引,也称为 top-k。

在通过检索器(Retriever)获取到 top-k 组数据后,这些数据仍然以嵌入向量(Embedding Vector)的形式存在,例如 [0.1, 0.2, 0.3, …] 这样的向量。因此,还需要将这些嵌入向量还原为原始的知识文档分块。例如,在上图中仅提取了排名最靠前的一组数据,其嵌入向量被转换回原始的知识文档分块,即"北京天气 南风 多云 15℃"。

接下来,将得到的文档分块与用户输入进行合成,这涉及到一个领域「提示词工程」(Prompt Engineering)。
「提示词工程」一词听起来很荒谬,甚至有点搞笑,像是那种售卖 AI 课程的讲师口中会频繁提到的词汇。然而,实际上,提示词工程涵盖了诸如提升模型能力、优化输出质量以及增强模型安全性等多个方面。大语言模型依赖于提示词所提供的上下文信息,提示词越清晰、越具体,其越能准确理解你的意图。通过设计高效提示词,能够引导模型完成预期任务的方法。

详细的提示词工程请参考这篇指南,这篇可比哪些卖课的信息密度高多了

我们将只实现一个简单的模版,让模型依据内容回答问题。

1
2
3
仅根据提供的上下文回答以下问题。
<context>{context}</context>
问题: {input}

这里的 {context} 和 {input} 是一种模版,请看上图中此处将由获取到的文档分块和用户输入替换。

替换好的内容如下
1
2
3
仅根据提供的上下文回答以下问题。
<context>北京天气 南风 多云 15℃</context>
问题: 北京的天气预报

4. 喂给大语言模型

是的,喂给 AI 就好了
完整的流程图如下
图源来自@Catcolia
图源来自@Catcolia

基于 Langchain 的实践

接下来,我们将使用 Langchain 复现上述方法,LangChain 是一个应用框架,旨在简化使用大型语言模型的应用程序。

你可以参考此处的中文教程了解更多 Langchain 有关内容,(不过广告有点多,有条件最好看官方英文版的)

我们将构建一个以网页数据为知识源的简易知识库,并结合 LLM 大语言模型。
考虑到部分学习者可能无法调用外网模型,这里 采用 deepseek-v3 模型和阿里系的 text-embedding-v3 嵌入模型 作为解决方案。

1. 环境准备

  1. 前往 deepseek 的官方平台充值并获取API秘钥,可以自定义仅选择充值1元。

    在此页面创建API Key,你会得到一个以 sk- 开头的秘钥,请保留备用。

  2. 开通阿里云百炼平台,详细教程请参考此处:

    同样的,你会得到一个以 sk- 开头的秘钥,请保留备用。

  3. 安装好python环境,此处忽略,然后使用pip安装下面的package。

    1
    pip install langchain langchain-community langchain-deepseek beautifulsoup4
请注意接下来的 Python 代码应合并为一个文件,或使用 Jupyter 进行单元运行。

2. 模型准备

1
2
3
4
5
6
7
8
9
10
from langchain_deepseek import ChatDeepSeek

llm = ChatDeepSeek(model="deepseek-chat", api_key="<你的Deepseek API Key>")

# stream 方法将会逐字输出模型内容
for chunk in llm.stream("你好"):
print(chunk.text(), end="")

# invoke 方法一次性输出模型内容
# llm.invoke("你好")

请在 api_key 中填入你的 deepseek 平台的秘钥。
你可以通过此代码测试 API 可用性,运行它将会流式输出大模型的回复。

1
2
3
4
5
6
7
8
9
10
11
12
13
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_community.embeddings import OpenAIEmbeddings

embeddings = DashScopeEmbeddings(
model="text-embedding-v3",
dashscope_api_key="<你的阿里云百炼 API Key>",
)

text = "Hello world!"
# 嵌入查询语句,获得嵌入向量
query_result = embeddings.embed_query(text)
print(f"嵌入模型的嵌入向量维度是 {len(query_result)}")
print(f"嵌入结果 {query_result}")

这里使用阿里云的 DashScope 平台,它和阿里云百炼是通用的,请在 dashscope_api_key 中填入阿里云百炼的秘钥
你可以通过此代码测试 API 可用性,不出意外的话,运行它将会获得和此处相同的嵌入向量。

3. 爬虫搭建

我们基于的数据爬取是基于 beautifulsoup4 的。不过,langchain 已经将 beautifulsoup 的方法包装好,我们只需使用 langchain 的 WebBaseLoader 方法即可。

下面的例子爬取了微信公众号上的新闻文章,请注意下方代码中添加 User-Agent 的位置,以防止环境异常被拦截。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import os
os.environ['USER_AGENT'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'

from langchain_community.document_loaders import WebBaseLoader
urls = [
"https://mp.weixin.qq.com/s/o2yVa6_aea0I-E_Dz_rDZA", # 早报 | 国家标准要求4层起设电梯;钉钉创始人陈航将回归掌舵;比亚迪辟谣在印度投资建厂;马斯克称火星也归美国
"https://mp.weixin.qq.com/s/KoCfAbv2k82qKhgdyMM0xA", # 小米汽车进入创立以来最严峻的信任危机
"https://mp.weixin.qq.com/s/AbUnWSl7Y1-C8qGJC5QsaQ", # 缅甸地震不止是7.9级,也可能是一次“超音速灾难”
"https://mp.weixin.qq.com/s/bt76B8Pp9NkRF9f15SAy6g", # 不怪朱啸虎“撤退”,具身智能其实已经不存在“天使轮”了
"https://mp.weixin.qq.com/s/da9JGOxejDL510sNfaVNsQ", # 阿里秘密研发新模型将发布,影响力指标成最重要考核
]

docs = []
for url in urls:
loader = WebBaseLoader(url, verify_ssl=True)
doc = loader.load()
docs.append(doc)

[print(doc) for doc in docs]

这里的 loader.load() 将会调用爬虫获取网页内容,调用此代码你将会得到类似下面的 Document 数据。

1
2
3
4
5
[Document(metadata={'source': 'https://mp.weixin.qq.com/s/o2yVa6_aea0I-E_Dz_rDZA', 'title': '', 'description': '缅甸强震已致该国2056人遇难'...
[Document(metadata={'source': 'https://mp.weixin.qq.com/s/KoCfAbv2k82qKhgdyMM0xA', 'title': '', 'description': '没有一片雪花是无辜的'...
[Document(metadata={'source': 'https://mp.weixin.qq.com/s/AbUnWSl7Y1-C8qGJC5QsaQ', 'title': '', 'description': '最苦的还是老百姓。'...
[Document(metadata={'source': 'https://mp.weixin.qq.com/s/bt76B8Pp9NkRF9f15SAy6g', 'title': '', 'description': '一天一个破纪录的天价融资,“天使轮”不存在了'...
[Document(metadata={'source': 'https://mp.weixin.qq.com/s/da9JGOxejDL510sNfaVNsQ', 'title': '', 'description': '虎嗅独家获悉,阿里即将在4月第二周发布新模型Qwen3'...

4. 分块与向量数据库

我们将使用 FAISS 作为向量数据库。
还记得我们之前的流程吗?在入库前需要对 Document 进行分块,这里使用最简易的文本递归分割器 RecursiveCharacterTextSplitter,其继承自基类 TextSplitter,你可以通过调整参数 chunk_size 来调整每个分块的大小。例如,下面设置的分块大小是 2000 字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 这里为简化,将所有 Document 合并为一个 dict,类似这样:[Document,Document,...]
documents = []
for doc in docs:
documents.extend(doc)

from langchain_community.vectorstores import FAISS
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 文本递归分割器,chunk_size 可设置分块大小
text_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)
documents = text_splitter.split_documents(documents)
print(f"Document总分块数量: {len(documents)}")

# 通过嵌入模型将 Document 索引存入向量数据库 FAISS
vectorDB = FAISS.from_documents(documents, embeddings)

5. 构建模型输入模版与检索器

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
from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_template(
"""
Answer the following question based only on the provided context.

<context>
Today is 2025.04.01.
{context}
</context>

Question: {input}
"""
)

from langchain.chains.combine_documents import create_stuff_documents_chain
# 这是在做什么?创建链 stuff_documents_chain
# 传入:它将会被检索器传递所需要的 Document
# 传出:这个链会将检索到的 Document 和用户输入(prompt)按照模板合并,最后传递给 LLM 链
document_chain = create_stuff_documents_chain(llm, prompt)

# 这是在做什么?为向量数据库创建一个检索器,其即将获取 top-k 个分块项,这里是10个。
retriever = vectorDB.as_retriever(search_kwargs={"k": 10})

# 这是在做什么?创建一个检索链 retrieval_chain
# 传入:用户输入的检索数据,如“给我总结下最近的国际新闻吧”
# 传出:其将检索到的 Document 分块传递给上一个链 stuff_documents_chain
retrieval_chain = create_retrieval_chain(retriever, document_chain)

6. 模型输出

1
2
3
4
5
6
7
8
# 通过调用检索链,依次传递数据执行,最终到达 LLM 链,完成模型输出
for response in retrieval_chain.stream(
{"input": "给我总结下最近的国际新闻吧"},
):
if "answer" in response:
print(response["answer"], end="")
else:
print(response)
最终的模型输出如下
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
{'input': '给我总结下最近的国际新闻吧'}
{'context': [Document(id='a26395f0-3d0a-47ef-a1fb-7f7cdaa1f589', metadata={'source': 'https://mp.weixin.qq.com/s/o2yVa6_aea0I-E_Dz_rDZA', 'title': '', 'description': '缅甸强震已致该国2056人遇难', 'language': 'No language found.'}, page_content='大家早上好!这里是今天的早报,每天早上,我都会在这里跟你聊聊昨夜今晨发生了哪些大事儿。本栏目由虎嗅出品。热点追踪【缅甸强震已致该国2056人遇难】据央视新闻,根据缅甸国家管理委员会新闻信息组公布的最新统计数据,截至当地时间3月31日12时,缅甸全国因28日强烈地震造成的遇难人数达到2056人,另有3900人受伤,270人失踪,目前救援行动正在展开。【外媒:马斯克称“火星也将归美国”】......

最近的国际新闻主要包括以下重要事件:

1. **缅甸强震灾难**
- 缅甸于3月28日发生强烈地震,截至3月31日已造成2056人遇难、3900人受伤、270人失踪。震级达7.7-7.9级,震源深度浅(10-30公里),破坏力极强,导致大面积房屋倒塌、基础设施损毁,救援面临高温和战乱地区协调困难等挑战。

2. **马斯克争议言论**
- 马斯克在3月30日的集会上宣称“火星也将归美国”,并强调对美国忠诚,引发国际关注。他此前还透露SpaceX计划2026年用“星舰”送机器人登陆火星,载人任务或于2029-2031年实施。

3. **伊朗扣押油轮事件**
- 伊朗伊斯兰革命卫队于3月31日扣押两艘涉嫌走私燃油的外国油轮,指控其在波斯湾走私超300万升柴油,25名船员被拘。

4. **俄乌冲突动态**
- 特朗普称对俄罗斯同意俄乌停火设“心理最后期限”,暗示若俄方拖延将采取行动,但未透露具体细节。

5. **白宫应对泄密事件**
- 白宫于3月31日宣布已采取措施防止类似“信号软件群聊泄密”事件重演,此前美高官通过加密软件讨论军事计划的信息遭泄露。

6. **国际科技与环保**
- 苹果与马斯克的SpaceX因卫星通信计划冲突,双方在消除手机信号盲区的技术上存在竞争。
- 缅甸地震被世卫列为最高级别(三级)紧急事件,多国展开援助,中国救援队已赴现场。

这些事件涉及自然灾害、地缘政治、科技竞争等多领域,凸显当前国际局势的复杂性与紧迫性。
再让它总结国内的新闻
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
{'input': '给我总结下最近的中国国内新闻吧'}
{'context': [Document(id='2e23d5cc-35a0-4fb6-8d23-6cf866ad4ce3', metadata={'source': 'https://mp.weixin.qq.com/s/o2yVa6_aea0I-E_Dz_rDZA', 'title': '', 'description': '缅甸强震已致该国2056人遇难', 'language': 'No language found.'}, page_content='早报 | 国家标准要求4层起设电梯;钉钉创始人陈航将回归掌舵;比亚迪辟谣在印度投资建厂;马斯克称火星也归美国\n......

根据提供的2025年4月1日新闻内容,以下是近期中国国内热点新闻的总结:

### **科技与商业动态**
1. **钉钉高层变动**
- 钉钉创始人陈航(无招)将回归阿里集团出任钉钉CEO,其创立的跨境出海公司“两氢一氧”拟被阿里收购投资人股份。

2. **抖音反舞弊通报**
- 抖音集团2024年共移送39名涉嫌违法犯罪的员工至司法机关,23家合作方因行贿被列入永不合作清单。

3. **苹果AI功能扩展**
- Apple Intelligence全球开放,新增支持简体中文等语言,覆盖文本创作、图像生成等功能,并首次登陆Vision Pro头显。

4. **小米汽车信任危机**
- 小米SU7在安徽高速智驾事故致3人死亡,引发对智驾安全性的质疑,事故原因仍在调查中。

5. **比亚迪辟谣印度建厂**
- 比亚迪否认在印度投资建厂的传闻,称相关信息不实。

### **社会与政策**
1. **电梯新国标**
- 国家标准要求4层及以上住宅需设置电梯,同时提高卧室隔音标准至65分贝以下。

2. **12306回应不文明行为**
- 针对高铁或飞机上乘客光脚踩座椅等问题,12306建议向工作人员求助劝阻或换座。

3. **湖南耒水铊污染处置**
- 耒水流域铊浓度异常事件已解决,水质恢复正常,供水安全达标。

### **其他热点**
- **人形机器人投资争议**
- 朱啸虎称退出人形机器人投资引行业辩论,新兴公司如星海图、松延动力回应称行业需包容创新。

- **阿里模型研发**
- 阿里计划4月发布新模型Qwen3,重点提升推理能力,并考核开发者社区影响力(衍生模型超10万、下载量破2亿)。

### **总结**
近期国内焦点集中在企业动态(钉钉、小米、抖音)、政策调整(电梯新规)及环境安全(铊污染)。同时,AI与机器人领域的技术竞争和投资争议持续发酵。

总结

没错,这里是运用上述代码让大模型帮我总结的。

本文详细介绍了如何利用 LangChain 框架构建基于大语言模型(LLM)的检索增强生成(RAG)知识库。通过代码实例与原理解析,系统性地演示了 RAG 如何缓解大模型的幻觉问题,提升特定领域回答的准确性。其核心价值在于通过外部知识增强与大模型的协同,优化信息检索与生成效率,为实际应用(如新闻分析、专业咨询)提供了可复用的技术方案。

The End.