LangChain4j+RAG
教程地址:黑马程序员LangChain4j从入门到实战项目全套视频课程,涵盖LangChain4j+ollama+RAG,Java传统项目AI智能化升级_哔哩哔哩_bilibili
1. 大模型部署方式
- 自己部署
- 云服务器部署
- 本地机器部署
- 他人部署
- 阿里云百炼
- 百度智能云
- 硅基流动
- 火山引擎
2. 大模型部署
2.1 Ollama部署本地大模型
2.1.1 Linux下载Ollama
curl -fsSL https://ollama.com/install.sh | sh
检查Ollama是否安装成功:
ollama --version
2.1.2 Ollama部署大模型
通过ollama安装qwen3(0.6b参数)的大模型
该命令如果本地没有qwen,就会先下载,再进去。如果下载好了qwen,就直接进去
ollama run qwen3:0.6b
退去聊天框
/bye
2.1.3 Ollama的进程与默认监听端口号
查看Ollama运行进程
查看Ollama默认监听的端口号
2.1.4 通过http请求,访问ollama部署的qwen3
ollama默认的端口号是11434
2.2 阿里云百炼部署大模型
3. 大模型调用
3.1 常见参数
3.2 响应数据
4. LangChain4j
官网:https://docs.langchain4j.dev/
4.1 会话功能
4.1.1 引入langchain4j-open-ai依赖
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.18</version>
</dependency>
</dependencies>
4.1.2 SDK调用大模型
import dev.langchain4j.model.openai.OpenAiChatModel;
public class Main {
public static void main(String[] args) {
OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") //百炼平台的url
.apiKey(System.getenv("API_KEY"))
.modelName("qwen-plus")
.logRequests(true)
.logResponses(true)
.build();
String result = model.chat("你是谁?");
System.out.println(result);
}
}
4.1.3 小结
4.1.4 Spring整合LangChain4j
本项目环境:JDK17+Maven3.8.8
(1)构建SpringBoot项目
注意,点击Next之后,还有勾选web依赖,因为要返回给前端。
(2)application.yml
langchain4j:
open-ai:
chat-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 # 阿里云百炼平台的baseurl
api-key: ${API_KEY} # 本地环境变量要配置export API_KEY=xxxxxxxxxxxx
model-name: qwen-plus # 调用大模型的名称
log-requests: true # 日志
log-responses: true
logging:
level:
dev.langchain4j: debug
(3) controller层
package com.gtc.consultant.controller;
import dev.langchain4j.model.openai.OpenAiChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ChatController {
@Autowired
private OpenAiChatModel model;
@RequestMapping("/chat")
public String chat(String message){
String result = model.chat(message);
return result;
}
}
(4)启动类
package com.gtc.consultant;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConsultantApplication {
public static void main(String[] args) {
SpringApplication.run(ConsultantApplication.class, args);
}
}
4.1.5 AIServices工具类
引入依赖:
<!--langchain4j的起步依赖-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>1.0.1-beta6</version>
</dependency>
<!--AiServices相关的依赖-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.0.1-beta6</version>
</dependency>
(1)application.yml
langchain4j:
open-ai:
chat-model: # 在ioc容器中自动注入openAiChatModel
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 # 阿里云百炼平台的baseurl
api-key: ${API_KEY} # 本地环境变量要配置export API_KEY=xxxxxxxxxxxx
model-name: qwen-plus # 调用大模型的名称
log-requests: true # 日志
log-responses: true
logging:
level:
dev.langchain4j: debug
(2)controller层
package com.gtc.consultant.controller;
import com.gtc.consultant.service.ConsultantService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ChatController {
@Autowired
private ConsultantService consultantService;
@RequestMapping("/chat")
public String chat(String message) {
String result = consultantService.chat(message);
return result;
}
}
(3)service层
package com.gtc.consultant.service;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,// 手动装配
chatModel = "openAiChatModel" //使用名为 "openAiChatModel" 的 Bean 来作为底层的大模型。
)
public interface ConsultantService {
// 用于聊天的方法
public String chat(String message);
}
4.1. 6 流式调用
(1)引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--langchain4j的起步依赖-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>1.0.1-beta6</version>
</dependency>
<!--AiServices相关的依赖-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.0.1-beta6</version>
</dependency>
<!--引入流式调用的相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
<version>1.0.1-beta6</version>
</dependency>
</dependencies>
(2)application.yml配置
langchain4j:
open-ai:
chat-model: # 在ioc容器中自动注入openAiChatModel
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 # 阿里云百炼平台的baseurl
api-key: ${API_KEY} # 本地环境变量要配置export API_KEY=xxxxxxxxxxxx
model-name: qwen-plus # 调用大模型的名称
log-requests: true # 日志
log-responses: true
streaming-chat-model: # 在ioc容器中自动注入openAiStreamingChatModel
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 # 阿里云百炼平台的baseurl
api-key: ${API_KEY} # 本地环境变量要配置export API_KEY=xxxxxxxxxxxx
model-name: qwen-plus # 调用大模型的名称
log-requests: true # 日志
log-responses: true
logging:
level:
dev.langchain4j: debug
(3)controller层
package com.gtc.consultant.controller;
import com.gtc.consultant.service.ConsultantService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RestController
public class ChatController {
@Autowired
private ConsultantService consultantService;
@RequestMapping(value = "/chat", produces = "text/html;charset=utf-8")
public Flux<String> chat(String message) {
Flux<String> result = consultantService.chat(message);
return result;
}
}
(4)service层
package com.gtc.consultant.service;
import dev.langchain4j.service.spring.AiService;
import dev.langchain4j.service.spring.AiServiceWiringMode;
import reactor.core.publisher.Flux;
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,// 手动装配
chatModel = "openAiChatModel", //使用名为 "openAiChatModel" 的 Bean 来作为底层的大模型。
streamingChatModel = "openAiStreamingChatModel"
)
public interface ConsultantService {
// 用于聊天的方法
public Flux<String> chat(String message);
}
4.1.7 消息注解
4.1.8 会话记忆
(1)会话记忆的基本使用
1. 将ChatMemory类的bean对象交给ioc容器管理
@Configuration
public class CommonConfig {
@Autowired
private OpenAiChatModel openAiChatModel;
// 构建会话记忆对象
@Bean
public ChatMemory chatMemory(){
MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
.maxMessages(20)
.build();
return memory;
}
}
2. controller层
@RestController
public class ChatController {
@Autowired
private ConsultantService consultantService;
@RequestMapping(value = "/chat", produces = "text/html;charset=utf-8")
public Flux<String> chat(String message) {
Flux<String> result = consultantService.chat(message);
return result;
}
}
3. service层
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,// 手动装配
chatModel = "openAiChatModel", //使用名为 "openAiChatModel" 的 Bean 来作为底层的大模型。
streamingChatModel = "openAiStreamingChatModel",
chatMemory = "chatMemory" // 配置会话记忆对象(从ioc容器中获取chatMemory的bean)
)
public interface ConsultantService {
// 用于聊天的方法
@SystemMessage(fromResource = "system.txt")
public Flux<String> chat(String message);
}
(2)会话记忆的隔离
为了让新对话不记住前面的对话,需要采用会话记忆的隔离。每个会话都有一个唯一的memoryId。
1. 配置bean对象交给ioc容器管理
@Configuration
public class CommonConfig {
// 构建ChatMemoryProvider对象
@Bean
public ChatMemoryProvider chatMemoryProvider(){
ChatMemoryProvider chatMemoryProvider = new ChatMemoryProvider(){
/**
* 如果有memoryId对应的对象,就使用,没有就创建
* @param memoryId
* @return
*/
@Override
public ChatMemory get(Object memoryId) {
return MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(20)
.build();
}
};
return chatMemoryProvider;
}
}
2. controller层
@RestController
public class ChatController {
@Autowired
private ConsultantService consultantService;
/**
* 前端向后端传递,不仅要传递消息,还要传递会话的memoryId
* @param memoryId
* @param message
* @return
*/
@RequestMapping(value = "/chat", produces = "text/html;charset=utf-8")
public Flux<String> chat(String memoryId, String message) {
Flux<String> result = consultantService.chat(memoryId, message);
return result;
}
}
3. service层
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,// 手动装配
chatModel = "openAiChatModel", //使用名为 "openAiChatModel" 的 Bean 来作为底层的大模型。
streamingChatModel = "openAiStreamingChatModel",
chatMemoryProvider = "chatMemoryProvider" // 配置会话记忆提供者对象
)
public interface ConsultantService {
// 用于聊天的方法
@SystemMessage(fromResource = "system.txt")
public Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
}
(3)会话记忆的持久化
后端重启之后,之前记忆的会话就不存在了。为什么会消失?因为消息是存储在集合中。也就是服务器的内存中。重启肯定就挂了。
实现思路:
1. 准备redis环境
docker run --name redis -d -p 6379:6379 redis
2. 引入redis起步依赖
<!-- 引入redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
3. 配置redis连接信息
spring:
data:
redis:
host: 192.168.31.20
port: 6379
password: 123456
4. 提供ChatMemoryStore实现类
@Repository
public class RedisChatMemoryStore implements ChatMemoryStore {
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public List<ChatMessage> getMessages(Object memoryId) {
// 获取会话消息
String json = redisTemplate.opsForValue().get(memoryId);
// 把json字符串转换成List<ChatMessage>
List<ChatMessage> list = ChatMessageDeserializer.messagesFromJson(json);
return list;
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> list) {
// 更新会话消息
// 1. 把list转换成json数据
String json = ChatMessageSerializer.messagesToJson(list);
// 2. 把json数据存储到redis中
redisTemplate.opsForValue().set(memoryId.toString(), json, Duration.ofDays(1));
}
@Override
public void deleteMessages(Object memoryId) {
redisTemplate.delete(memoryId.toString());
}
}
5. 配置ChatMemoryStore
@Configuration
public class CommonConfig {
@Autowired
private ChatMemoryStore redisChatMemoryStore;
@Bean
public ChatMemoryProvider chatMemoryProvider(){
ChatMemoryProvider chatMemoryProvider = new ChatMemoryProvider(){
/**
* 如果有memoryId对应的对象,就使用,没有就创建
* @param memoryId
* @return
*/
@Override
public ChatMemory get(Object memoryId) {
return MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(20)
.chatMemoryStore(redisChatMemoryStore)
.build();
}
};
return chatMemoryProvider;
}
}
5. RAG知识库
5.1 原理
RAG:Retrieval Augmented Generation, 检索增强生成。通过检索外部知识库的方式增强大模型的生成能力。
我们需要关注两个问题:
- 如何搭建知识库?
- 如何从知识库检索片段?
知识库就是向量数据库,目前市面上主要包括:
- Milvus
- Chroma
- Pinecone
- RedisSearch(Redis)
- pgvector(PostgreSQL)
存储知识库例子:
5.2 快速入门
核心操作包括:构建向量数据库+从向量数据库中检索
5.2.1 存储-构建向量数据库操作对象
(1)引入rag依赖
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-easy-rag</artifactId>
<version>1.0.1-beta6</version>
</dependency>
(2)将知识库导入项目
(3)构建向量数据库操作对象
这个bean对象放在config文件,以方便加载到ioc容器
// 构建向量数据库操作对象
@Bean
public EmbeddingStore embeddingStore(){
// 1. 加载文档进内存
List<Document> documents = ClassPathDocumentLoader.loadDocuments("content");
// 2. 构建向量数据库操作对象
InMemoryEmbeddingStore store = new InMemoryEmbeddingStore();
// 3. 构建一个EmbeddingStoreIngestor对象, 完成文本向量切割,向量化,存储
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingStore(store)
.build();
ingestor.ingest(documents);
return store;
}
5.2.2 检索-构建向量数据库检索对象
// 构建向量数据库检索对象
@Bean
public ContentRetriever contentRetriever(EmbeddingStore store){
return EmbeddingStoreContentRetriever.builder()
.embeddingStore(store)
.minScore(0.5) // 余弦相似度大于等于0.5
.maxResults(3) // 最多查3个片段
.build();
}
启动项目:
实际向大模型发送的请求:
- system:你是一个AI志愿填报助手。。。
- user:西北大学2024年最高分数线是什么?你可以使用以下知识: xxxxxx
相当于通过RAG,先把知识库加载进内存,再检索与问题最相关的知识,将这些知识一并作为user的提问,喂给大模型。
5.3 RAG核心API
5.3.1 文档加载器
- FileSystemDocumentLoader: 根据本地磁盘绝对路径加载
- ClassPathDocumentLoader: 相对于类路径加载
- UrlDocumentLoader: 根据url路径加载
5.3.2 文档解析器
演示使用pdf的文档解析器
(1)准备pdf格式的数据
(2)引入pdf解析器依赖
<!--pdf解析器依赖-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
<version>1.0.1-beta6</version>
</dependency>
5.3.3 文档分割器
// 构建向量数据库操作对象
@Bean
public EmbeddingStore store(){
// 1. 加载文档进内存
List<Document> documents = ClassPathDocumentLoader.loadDocuments("content", new ApachePdfBoxDocumentParser());
// 2. 构建向量数据库操作对象
InMemoryEmbeddingStore store = new InMemoryEmbeddingStore();
// 自定义文本分割器(500长度,100重复字符)
DocumentSplitter ds = DocumentSplitters.recursive(500,100);
// 3. 构建一个EmbeddingStoreIngestor对象, 完成文本向量切割,向量化,存储
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.documentSplitter(ds)
.embeddingStore(store)
.build();
ingestor.ingest(documents);
return store;
}
5.3.4 向量模型
用于把文档分割后的片段向量化或者查询时把用户输入的内容向量化。
默认的向量模型:
自定义向量模型:
(1)application.yml配置
(2)配置embeddingModel
5.3.5 向量数据库
默认的向量化存储在内存,每一次向量化都要调用api,需要花钱。因此将向量化数据存储在本地redis-search中。
(1)安装redis-search
docker run --name redis-vector -d -p 6379:6379 redislabs/redisearch
(2)引入依赖
<!--引入langchain4j对于redis向量数据库的支持-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-redis-spring-boot-starter</artifactId>
<version>1.0.1-beta6</version>
</dependency>
(3)配置向量数据库信息
(4)注入RedisEmbeddingStore并使用
6. Tools工具(Function Calling)
更多推荐
所有评论(0)