认识RAG原理
RAG(Retrieval-Augmented Generation)(本地知识库)是一种结合信息检索和大语言模型(LLM)的技术,目的是在解决传统生成模型的局限性。
- 传统大语言模型(如 GPT-4、Llama 3)依赖训练时的数据,无法动态获取最新信息,有了RAG在生成答案前,先从外部知识库(如数据库、文档、网页)检索最新信息,确保答案的时效性
- LLM 可能会生成看似合理但实际错误的答案(即“幻觉”),基于检索到的可信数据生成答案可以减少编造信息的风险
- 通用 LLM 可能缺乏特定行业(如医疗、法律)或企业内部数据(如公司文档)的知识。RAG 允许接入自定义知识库(如企业文档、科研论文),提供更精准的回答。
RAG 的核心价值在于让 LLM 的生成能力与外部知识库的动态检索相结合,既保留了 LLM 的语言理解能力,又弥补了其在时效性、准确性和专业性上的不足。对于需要实时数据、私有知识或可解释性的应用,RAG 是目前最有效的解决方案之一
RAG的工作原理
RAG 流程分为两个不同的阶段:索引(创建RAG)和检索(搜索RAG),LangChain4j 为这两个阶段提供了工具。索引阶段指的是把提前准备好的数据给LLM建立RAG知识库,这些数据可以是公司的内部数据,某在线文档,或者用户上传的文档等。以下是索引阶段的简化图
- Document : 我们准备用来建立知识库的数据
- TextSplitter : 文本切割器,用于把一段大文本按照某种规则切成多个小段,以方便创建向量,因为每个模型处理的文本都是有长度限制的。
- Segments : 代表文本切割后的每个分段
- EmbeddingModel : 向量模型,创建RAG索引的过程需要通过 向量模型 为文本创建向量并存储到向量数据库中。向量是数学中的一个定义,这里的意思是文本向量化:将单词、句子或文档转换为数值向量(如 [0.2, -0.7, 0.5, …])
- EmbeddingStore :向量存储,需要准备向量数据库用于存储文本转换后的向量
检索阶段通常发生在线,当用户提交需要使用索引文档来回答的问题时,LLM根据用户的提问去RAG中进行搜索。以下是检索阶段的简化图
用户的提问会被EmbeddingModel向量模型转化为向量去向量数据库中进行查找,检索到的相关数据会通过LanguageModel对话模型处理后响应给用户。
Docker安装Pgvector
1. 安装DockerDesk
首先需要下载docker-desktop:https://www.docker.com/products/docker-desktop/,根据引导安装好DockerDesktop,可以参考《Ollama+WebUI+DeepSeek部署自己的本地大模型》docker-desktop安装部分。
2. 安装Pgvector
通过终端执行docker命令创建pgvecor容器
docker run --name pgvector -v c:/data:/var/lib/postgresql/data -e POSTGRES_PASSWORD=123456 -p 5433:5432 -d ankane/pgvector
- POSTGRES_PASSWORD : 密码
- -p 5433:5432 :端口是5433
使用navcat新建连接选择:postgressql ,数据库和用户名默认写postgres
选中数据 - 编辑数据库 - 扩展 - 找到vector - 移动到后边代表已安装该插件
PS:也可以通过CREATE EXTENSION vector;
来创建插件
执行下面SQL测试向量数据库
-- 创建测试向量表
CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));
-- 插入向量数据
INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
效果如下
Windows安装Pgvector
1.安装PgSql
首先需要先安装PGSql ,下载路径 : https://www.enterprisedb.com/downloads/postgres-postgresql-downloads , 安装参考文档:https://www.enterprisedb.com/docs/supported-open-source/postgresql/installing/windows/,
2.开启Pgector
开启Pgector 需要有C++环境,所以先在电脑上安装 Visual Studio 下载路径:https://learn.microsoft.com/en-us/visualstudio/releases/2022/system-requirements ,下载执行安装,选择使用c++桌面开发
确保安装了Visual Studio中的C++支持,并运行:
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
注意:具体路径将根据 Visual Studio 版本而有所不同,然后使用nmake来构建:
set "PGROOT=C:\Program Files\PostgreSQL\16"
cd %TEMP%
git clone --branch v0.8.0 https://github.com/pgvector/pgvector.git
cd pgvector
nmake /F Makefile.win
nmake /F Makefile.win install
其他注意事项
-
缺少标头 :如果编译失败Cannot open include file: ‘postgres.h’: No such file or directory,请确保PGROOT正确。
-
不匹配的架构 :如果编译失败error C2196: case value ‘4’ already used,请确保vcvars64.bat已调用。然后运行nmake /F Makefile.win clean并重新运行安装说明。
-
缺少符号 :如果unresolved external symbol float_to_shortest_decimal_bufn与 Postgres 17.0-17.2 链接失败,请升级到 Postgres 17.3+。
-
权限 :如果安装失败Access is denied,请以管理员身份重新运行安装说明。
项目集成Vector
1.配置向量存储
要使用RAG必须先引入依赖langchain4j-easy-rag,langchain4j-pgvector
,然后执行SQL创建表:CREATE TABLE langchain4j (id bigserial PRIMARY KEY, embedding vector(3));
然后在项目的配置中加入以下配置
pgvector:
database: postgres
host: 127.0.0.1
port : 5433
user: postgres
password: 123456
table: langchain4j
然后我们还需要一个配置类把上面配置读取到SpringBoot项目中
@Configuration
@ConfigurationProperties(prefix = "pgvector")
@Data
public class PgConfig {
//主机
private String host;
//端口
private int port;
//数据库
private String database;
//账号
private String user;
//密码
private String password;
//向量表
private String table;
}
另外要注意:如果要创建RAG知识库,就需要使用支持向量的模型,这里使用ollama.embedding配置的模型名使用的是all-minilm,如果没有该模型可以使用ollama run all-minilm 去安装
langchain4j:
# community:
# dashscope: #通义千问
# chat-model:
# api-key: sk-xxxx #https://bailian.console.aliyun.com/?apiKey=1#/api-key
# model-name: qwen-max-latest
ollama:
chat-model:
base-url: http://127.0.0.1:11434
model-name: llama3.1 #qwen2:7b
embedding-model: #配置向量数据库
base-url: http://127.0.0.1:11434
model-name: all-minilm
2.创建 EmbeddingStore
EmbeddingStore 表示嵌入的存储,也称为向量数据库。它提供了基本的向量CRUD方法,langchain4j默认提供了 InMemoryEmbeddingStore 基于内存以及 PgVectorEmbeddingStore 基于PGVector的向量存储方式。我们直接使用基于向量数据库的,配置如下
/**
* 嵌入模型配置
*/
@Configuration
@RequiredArgsConstructor
public class EmbeddingStoreConfig {
final PgConfig pgConfig;
//创建向量存储
@Bean
public EmbeddingStore<TextSegment> initEmbeddingStore() {
//基于 PgVector的向量存储 - 基于yml配置读取
return PgVectorEmbeddingStore.builder()
.table(pgConfig.getTable())
//.dropTableFirst(true) 每次重启都要重新创建
.createTable(true) //自动创建表
.host(pgConfig.getHost())
.port(pgConfig.getPort())
.user(pgConfig.getUser())
.password(pgConfig.getPassword())
.dimension(384) //all-minilm模型的向量维度(简单理解就是内容长度如[111,222 ... 333])
.database(pgConfig.getDatabase())
.build();
}
}
- TextSegment :文本段,如文档或聊天对话的段(块/片段/片段)。这可能是一个句子、一个段落或任何其他具有含义的离散文本单元。此类封装一段文本及其关联的元数据。
- dimension :向量维度(简单理解就是内容长度如[111,222 … 333]),该值需要和向量模型支持的维度匹配,一般在各大大模型平台中的向量模型都有说明。
3.RAG创建知识库
接下来我们就需要把准备好的知识库数据投喂给大模型了,可以是你公司的私有数据,或者你的个人文章,或者是一片作文,一个段故事,格式是txt,PDF等。Langchain4j默认集成了Apache Tika 库支持多种文档类型导入 ,我们通过FileSystemDocumentLoader.loadDocuments 去导入,然后通过EmbeddingStoreIngestor去构建RAG知识库,如下
//向量存储
private final EmbeddingStore<TextSegment> embeddingStore;
//向量模型
private final EmbeddingModel embeddingModel;
/**
* 加载文档,创建RAG知识库
*/
@RequestMapping("/rag/load")
public void ragLoad() {
List<Document> documents = FileSystemDocumentLoader.loadDocuments("C:\\Users\\Administrator\\Desktop\\rag");
EmbeddingStoreIngestor.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
//文档切割 - 按照什么样的规则把文档分段
.documentSplitter(new DocumentByLineSplitter(100,10))
.build().ingest(documents);
}
-
FileSystemDocumentLoader.loadDocuments 加载的是一个目录,我这里创建了一个rag目录,里面随便放了一个txt文档
-
DocumentByLineSplitter 实现了 DocumentSplitter 接口,是 LangChain4j 中用于处理文档分割的核心组件,它负责将大文档分割成适合处理的较小片段(chunks),它按照文档中的换行符(\n)将文档分割成多个文本片段(TextSegment),每个片段对应原始文档中的一行内容。具体可以去看一下DocumentSplitter 的几种实现分别对应了不同的切割规则。DocumentByLineSplitter 的2个重要参数
maxSegmentSizeInChars :现在每段的最大字符,如果不加限制可能会超过大模型支持的最大的token数量
maxOverlapSizeInChars :文本重叠数,为了不让大模型丢失上下文,在分段的时候一般会把第一段的结尾包含一部分在第二段的开始,这样大模型在处理问题的时候就会更具人性化。
测试执行 - 观察 langchain4j向量表中的数据 - 有东西说明已经创建好了向量数据库
4.让智能体具备RAG搜索功能
接下来给智能体指定 contentRetriever内容检索能力,通过EmbeddingStoreContentRetriever.from(embeddingStore))
指定 EmbeddingStore,让他可以去向量库中去检索,如下:
/**
* 创建智能体
* @param chatModel :大模型
*/
@Bean
public ChatAssistant chatAssistant(ChatLanguageModel chatModel, SearchApiWebSearchEngine webSearchEngine, EmbeddingStore<TextSegment> embeddingStore){
return AiServices.builder(ChatAssistant.class)
//指定内容检索器
.contentRetriever(EmbeddingStoreContentRetriever.from(embeddingStore))
//指定对话记忆 - 记忆10次对话
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
//自定义存储方式
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.builder().chatMemoryStore(new PersistentChatMemoryStore()).maxMessages(10).build())
//指定模型
.chatLanguageModel(chatModel)
//function call调用tools
.tools(new WeatherTool(),
//web搜索引擎
new WebSearchTool(webSearchEngine))
.build();
}
5.测试对话
创建一个controller接口测试对话,观察大模型的回答是否按照知识库中的数据来回答
总结
本篇文章介绍了RAG的优势和必要性,通过搭建PGVector本地向量数据库,使用Langchain4j创建RAG知识库的全过程。如果文章对你有帮助请一定三连哦,你的鼓励是我最大的动力!!!