第四章.干货干货!!!Langchain4j开发智能体-搭建本地RAG知识库

认识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知识库的全过程。如果文章对你有帮助请一定三连哦,你的鼓励是我最大的动力!!!

### 如何在本地创建和管理 LangChain4j 知识库 #### 创建知识库 为了使大模型能够基于私有化的本地知识进行回答,在本地建立知识库是一个重要的步骤。这涉及到将本地知识切片后做 Embedding,再存储到向量数据库中[^1]。 对于LangChain4j而言,实现这一过程的方法之一是通过RAG(Retrieval-Augmented Generation),即检索增强型生成技术来达成。此方法允许定制化特殊场景下的模型应用,比如学校官网AI或个人博客AI等案例,确保这些应用程序仅针对特定领域内的查询提供精准的回答[^2]。 具体操作上,首先需准备要嵌入的知识文件,并将其分割成适合embedding model处理的小片段。接着利用相应的API对这些小片段实施向量化处理,最后将得到的向量数据存入预先设置好的向量数据库内[^4]。 ```java // 假设已经完成了环境配置以及必要的依赖导入 List<Document> documents = loadDocumentsFromSource(); // 加载原始文档集合 List<String> chunks = splitIntoChunks(documents); // 将文档拆分成更小的部分以便于后续处理 VectorStore vectorStore = new VectorDB(); // 初始化一个用于储存向量表示形式的对象实例 for (String chunk : chunks){ float[] embedding = generateEmbedding(chunk); // 使用预训练的语言模型为每个文本块生成对应的向量表达 vectorStore.add(embedding); // 把新产生的向量加入到矢量数据库里去 } ``` #### 查询与响应机制 一旦建立了这样的知识库,下一步就是设计如何有效地从中提取有用信息以回应用户的请求。这里的关键在于定义好合适的检索逻辑——当接收到一个新的询问时,系统会先尝试从已有的知识库里找到最接近的内容作为上下文背景,然后再交给大型语言模型来进行具体的应答创作[^3]。 ```python def get_knowledge_based_answer(query, knowledge_base_path): # 实例化llm_model_ins对象并创建LocalDocQA类的新实体 qa_system = LocalDocQA(llm_model_ins()) # 执行初始化配置动作 qa_system.init_cfg() # 设置待查问句及关联的知识源位置参数 answer_info = qa_system.get_knowledge_based_answer( query=query, kb_root_dir=knowledge_base_path ) return { "answer": answer_info['result'], "source_docs": answer_info['source_documents'] } ``` 上述代码展示了如何构建这样一个问答系统的框架结构,其中包含了加载所需资源、执行初始化工作流、指定查询条件以及最终获取答案的过程描述。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨家巨子@俏如来

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值