Spring+LangChain4j小智医疗项目
这里写目录标题
- LangChain4j入门
- 配置
- 测试
- Ollama
- 阿里云百炼平台
- AIService
- 聊天记忆
- 隔离聊天
- MongoDB
- 持久化存储
- Prompt
- *创建小智医疗助手
- Function Calling(Tools)
- 实战小智医疗智能体
- RAG
- Token分词器
- 向量存储
- 流式输出
- 总结
LangChain4j入门
LangChain4j 是一个用于构建基于大型语言模型(LLM)应用的 Java 框架,它简化了与 OpenAI、Hugging Face 等 LLM 服务的集成,并提供了工具链来构建复杂的 LLM 应用。
配置
dev.langchain4j langchain4j-open-ai-spring-boot-starter 1.0.0-beta3
在yml配置api_key,base_ur,model_name必需项
一般将APIKEY保存在系统环境变量中,用System.getenv()获取
测试
@Autowired private OpenAiChatModel openAiChatModel; @Test public void testChat() { String question = "java的特性"; String ans = openAiChatModel.chat(question); System.out.println(ans); }
Ollama
Ollama是一个允许开发者在本地计算环境中运行模型的工具。
dev.langchain4j langchain4j-ollama 1.0.0-beta3
阿里云百炼平台
在线集成了阿里的通义系列大模型和第三方大模型,涵盖文本、
图像、音视频等不同模态。
依赖
dev.langchain4j langchain4j-community-dashscope-spring-boot-starter
在官网申请API-Key
langchain4j: community: dashscope: chat-model: api-key: sk-66xxxxxxx model-name: qwen-max
AIService
dev.langchain4j langchain4j-spring-boot-starter
AIService用于格式化输入,解析输出,记忆聊天等功能。
- 创建接口
package com.atguigu.java.ai.langchain4j.assistant; public interface Assistant { String chat(String userMessage); }
- 创建类测试
@Autowired private QwenChatModel qwenChatModel; @Test public void testChat() { //创建AIService Assistant assistant = AiServices.create(Assistant.class, qwenChatModel); //调用service的接口 String answer = assistant.chat("Hello"); System.out.println(answer); }
更方便的方式是使用@AIService注解,然后通过@Autowired使用
package com.atguigu.java.ai.langchain4j.assistant; @AiService(wiringMode = EXPLICIT, chatModel = "qwenChatModel") public interface Assistant { String chat(String userMessage); }
聊天记忆
我们来测试每次聊天是否有记忆
@Autowired private Assistant assistant; @Test public void testAssistant() { String question1 = "我是赵铁柱"; String question2 = "我是谁?"; String ans1 = assistant.chat(question1); String ans2 = assistant.chat(question2); System.out.println(ans1); System.out.println(ans2); }
目前是没记忆的,需要使用chatMemory
- 注解
@AiService(wiringMode = EXPLICIT,chatMemory = "chatMemory" chatMemoryProvider="chatMemoryProvider")
- 配置类
package com.atguigu.java.ai.langchain4j.config; @Configuration public class MemoryChatAssistantConfig { @Bean ChatMemory chatMemory() { //设置聊天记忆记录的message数量 return MessageWindowChatMemory.withMaxMessages(10); } }
- 注入测试
@Autowired private MemoryChatAssistant memoryChatAssistant; @Test public void testChatMemory4() { String answer1 = memoryChatAssistant.chat("我是环环"); System.out.println(answer1); String answer2 = memoryChatAssistant.chat("我是谁"); System.out.println(answer2); }
隔离聊天
- 在AIService中添加chatMemoryProvider
@AiService( wiringMode = WiringMode.EXPLICIT, chatModel = "qwenChatModel", chatMemory = "chatMemory" chatMemoryProvider="chatMemoryProvider" ) public interface SeparateChatAssistant { /** * 处理用户消息并维护独立的对话上下文 * @param memoryId 对话内存 ID(区分不同用户) * @param userMessage 用户输入的消息 * @return AI 回复 */ String chat(@MemoryId int memoryId, @UserMessage String userMessage); }
- 配置chatMemoryProvider类
MongoDB
- 引入依赖
org.springframework.boot spring-boot-starter-data-mongodb
- 配置项:spring.data.mongodb.uri = mongodb://localhost:27017/chat_memory_db
- 实现Entity
@Data @AllArgsConstructor @NoArgsConstructor @Document("chat_message") public class ChatMessages { @Id //对应数据库的id字段 private ObjectId messageId; //MongoDB自动生成id为ObjectId类型 private String content; }
- 使用MongoTemplate测试
@Autowired private MongoTemplate mongoTemplate; @Test public void testInsert(){ ChatMessages chatMessages = new ChatMessages(); chatMessages.setContent("哈哈哈哈"); // 数据库自动生成id mongoTemplate.insert(chatMessages); }
接下来可以在IDEA中连接数据库在线查看。
操作 代码 具体代码 插入 insert(object) 查找 findbyId(‘id’,Class)、findAll(Class) 更新 upsert(query,update,Class) Query query = Query.query(Criteria.where(“id”).is(id)); Update update = new Update().set(“age”, newAge); 删除 remove(query,Class) 持久化存储
- 配置chatMemoryProvider
@AiService(chatMemoryProvider = "chatMemoryProvider")和实体类
- 配置MongoChatMemoryStore,重写getMessages等三大方法
@Component public class MongoChatMemoryStore implements ChatMemoryStore { @Autowired private MongoTemplate mongoTemplate; @Override public List getMessages(Object memoryId) { Query query = new Query(Criteria.where("memoryId").is(memoryId)); ChatMessages chatMessages = mongoTemplate.findOne(query,ChatMessages.class); // 将String转成反序列化 转出List if (chatMessages==null){ return new ArrayList(); } List chatMessage = ChatMessageDeserializer.messagesFromJson(chatMessages.getContent()); System.out.println("反序列化:"+chatMessage); return chatMessage; } @Override public void updateMessages(Object memoryId, List list) { // 查询条件 Criteria criteria = Criteria.where("memoryId").is(memoryId); Query query = new Query(criteria); Update update = new Update(); // 插入更新消息列表 update.set("content", ChatMessageSerializer.messagesToJson(list)); mongoTemplate.upsert(query,update,ChatMessages.class); } @Override public void deleteMessages(Object memoryId) { // 查询条件 Criteria criteria = Criteria.where("memoryId").is(memoryId); // 构建查询对象 Query query = new Query(criteria); mongoTemplate.remove(query,ChatMessages.class); } }
- 测试
@Autowired private Assistant assistant; @Test public void testAssistant() { String question1 = "我是赵铁柱"; String question2 = "我是谁?"; String ans1 = assistant.chat(1,question1); String ans2 = assistant.chat(1,question2); String ans3 = assistant.chat(2,question2); }
Prompt
@SystemMessage 设定角色,塑造AI助手的专业身份,明确助手的能力范围
- 配置@SystemMessage
@SystemMessage("你是我的好朋友,请用东北话回答问题。")//系统消息提示词 String chat(@MemoryId int memoryId, @UserMessage String userMessage);
- 配置用户输入@UserMessage
@UserMessage("你是我的好朋友,请用东北话回答问题。")//系统消息提示词 String chat(@UserMessage String userMessage);
- 配置@V传递参数
@UserMessage("你是我的好朋友,请用上海话回答问题,并且添加一些表情符号。{{message}}") String chat(@V("message") String userMessage);
*创建小智医疗助手
- 创建XiaoZhiAssistant
- 提示词模版:xiaozhi-prompt-template.txt
- 配置chatMemoryProvider持久化和记忆回话隔离
- 创建实体类
- 创建Controller方法
Function Calling(Tools)
大语言模型的缺陷是数学能力不擅长。
- @Tool注解提供数学工具
@Component public class CalculatorTools { @Tool double sum(double a, double b) { System.out.println("调用加法运算"); return a + b; } @Tool double squareRoot(double x) { System.out.println("调用平方根运算"); return Math.sqrt(x); } }
- 在@AiService配置tools ="calculatorTools"
根据工具的不同,即使没有任何描述,大语言模型可能也能很好地理解它,例如add(a, b) 。
实战小智医疗智能体
- 实现业务,在tools中提示大模型预约流程和结果
加载Mysql等
@Component public class AppointmentTool { @Autowired private AppointmentService appointmentService; @Tool(name="预约挂号",value="根据参数,先查询是否当天是否预约过,如果没有预约过,则进行预约,返回预约结果") public String appointment(Appointment appointment) { // 先查询是否当天是否预约过 if (appointmentService.isAppointment(appointment)) { return "您今天已经预约过了,请勿重复预约"; } // 进行预约 boolean result = appointmentService.appointment(appointment); if (result) { return "预约成功"; } else { return "预约失败"; } } }
RAG
LLM的知识仅限于它所训练的数据。如果你想让LLM了解特定领域的知识或转专有数据,需要微调。
RAG通过检索外部知识库(如文档、数据库),将检索到的相关信息作为上下文输入给生成模型,辅助生成更准确的回答。
1. 全文搜索 2. **向量搜索**(向量余弦相似度,独立的向量数据库) 3. 混合搜索
RAG的过程
- 索引阶段
xx
- 检索阶段
xxx
- 文档加载器,文档解析器,文档分割器
//文档加载器,文档解析器,文档分割器 PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:*.txt"); List documents = FileSystemDocumentLoader.loadDocuments(folder, pathMatcher,new TextDocumentParser()); //
Token分词器
向量存储
之前我们使用的是InMemoryEmbeddingStore作为向量存储,但是不建议在生产中使用基于内存的向量存储。因此这里我们使用Pinecone作为向量数据库。
dev.langchain4j langchain4j-pinecone
#集成阿里通义千问-通用文本向量-v3,注入EmbeddingModel langchain4j.community.dashscope.embedding-model.api-key=${DASH_SCOPE_API_KEY} langchain4j.community.dashscope.embedding-model.model-name=text-embedding-v3
- 配置EmbeddingStoreConfig
- //相似度匹配embeddingSearch
- 上传知识库到Pinecone
- 在AssistantConfig中添加contentRetrieverXiaozhiPincone
- AiService注解加contentRetriever=“contentRetrieverXiaozhiPincone”
流式输出
大模型的流式输出是指大模型在生成文本或其他类型的数据时,不是等到整个生成过程完成后再一次性返回所有内容,而是生成一部分就立即发送一部分给用户或下游系统,以逐步、逐块的方式返回结果。
org.springframework.boot spring-boot-starter-webflux dev.langchain4j langchain4j-reactor
1.配置
#集成阿里通义千问-流式输出 langchain4j.community.dashscope.streaming-chat-model.api-key=${DASH_SCOPE_API_KEY} langchain4j.community.dashscope.streaming-chat-model.model-name=qwen-plus
- AIService添加
streamingChatModel = "qwenStreamingChatModel"
- 修改chat方法返回类型为Flux,也别忘了修改Controller中的返回类型
总结
整个框架流程如下
完结撒花!