Spring+LangChain4j小智医疗项目

news2025/5/18 0:34:51

这里写目录标题

  • LangChain4j入门
  • 配置
  • 测试
  • Ollama
  • 阿里云百炼平台
  • AIService
  • 聊天记忆
    • 隔离聊天
  • MongoDB
  • 持久化存储
  • Prompt
  • *创建小智医疗助手
  • Function Calling(Tools)
    • 实战小智医疗智能体
  • RAG
  • Token分词器
  • 向量存储
  • 流式输出
  • 总结

LangChain4j入门

LangChain4j 是一个用于构建基于大型语言模型(LLM)应用的 Java 框架,它简化了与 OpenAI、Hugging Face 等 LLM 服务的集成,并提供了工具链来构建复杂的 LLM 应用。

配置

<dependency>
  	 <groupId>dev.langchain4j</groupId>
     <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
     <version>1.0.0-beta3</version>
</dependency>

在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是一个允许开发者在本地计算环境中运行模型的工具。

  1. 选择模型:
    在这里插入图片描述
  2. 输入命令行 ollama run deepseek-r1:1.5b
  3. 本地项目配置
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-ollama</artifactId>
    <version>1.0.0-beta3</version>
</dependency>

阿里云百炼平台

在线集成了阿里的通义系列大模型和第三方大模型,涵盖文本、
图像、音视频等不同模态。
依赖

<dependency>
   	<groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
</dependency>

在官网申请API-Key

langchain4j:
  community:
    dashscope:
      chat-model:
        api-key: sk-66xxxxxxx
        model-name: qwen-max

AIService

<dependency>
	<groupId>dev.langchain4j</groupId>
	<artifactId>langchain4j-spring-boot-starter</artifactId>
</dependency>

AIService用于格式化输入,解析输出,记忆聊天等功能。

  1. 创建接口
package com.atguigu.java.ai.langchain4j.assistant;
public interface Assistant {
	String chat(String userMessage);
}
  1. 创建类测试
@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

  1. 注解
@AiService(wiringMode = EXPLICIT,chatMemory = "chatMemory" chatMemoryProvider="chatMemoryProvider")
  1. 配置类
package com.atguigu.java.ai.langchain4j.config;
@Configuration
public class MemoryChatAssistantConfig {
	@Bean
	ChatMemory chatMemory() {
		//设置聊天记忆记录的message数量
		return MessageWindowChatMemory.withMaxMessages(10);
	}
}
  1. 注入测试
@Autowired
private MemoryChatAssistant memoryChatAssistant;
@Test
public void testChatMemory4() {
	String answer1 = memoryChatAssistant.chat("我是环环");
	System.out.println(answer1);
	String answer2 = memoryChatAssistant.chat("我是谁");
	System.out.println(answer2);
}

隔离聊天

  1. 在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);
}
  1. 配置chatMemoryProvider类

MongoDB

  1. 引入依赖
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
  1. 配置项:spring.data.mongodb.uri = mongodb://localhost:27017/chat_memory_db
  2. 实现Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document("chat_message")
public class ChatMessages {

    @Id //对应数据库的id字段
    private ObjectId messageId; //MongoDB自动生成id为ObjectId类型
    private String content;

}

  1. 使用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)

持久化存储

  1. 配置chatMemoryProvider
    @AiService(chatMemoryProvider = "chatMemoryProvider")和实体类
  2. 配置MongoChatMemoryStore,重写getMessages等三大方法
@Component
public class MongoChatMemoryStore implements ChatMemoryStore {

    @Autowired
    private MongoTemplate mongoTemplate;


    @Override
    public List<ChatMessage> getMessages(Object memoryId) {
        Query query = new Query(Criteria.where("memoryId").is(memoryId));
        ChatMessages chatMessages = mongoTemplate.findOne(query,ChatMessages.class);

        // 将String转成反序列化 转出List<ChatMessage>
        if (chatMessages==null){
            return new ArrayList<ChatMessage>();
        }
        List<ChatMessage> chatMessage = ChatMessageDeserializer.messagesFromJson(chatMessages.getContent());
        System.out.println("反序列化:"+chatMessage);
        return chatMessage;

    }

    @Override
    public void updateMessages(Object memoryId, List<ChatMessage> 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);

    }
}
  1. 测试
 @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助手的专业身份,明确助手的能力范围

  1. 配置@SystemMessage
@SystemMessage("你是我的好朋友,请用东北话回答问题。")//系统消息提示词
String chat(@MemoryId int memoryId, @UserMessage String userMessage);
  1. 配置用户输入@UserMessage
@UserMessage("你是我的好朋友,请用东北话回答问题。")//系统消息提示词
String chat(@UserMessage String userMessage);
  1. 配置@V传递参数
@UserMessage("你是我的好朋友,请用上海话回答问题,并且添加一些表情符号。{{message}}")
String chat(@V("message") String userMessage);

*创建小智医疗助手

  1. 创建XiaoZhiAssistant
  2. 提示词模版:xiaozhi-prompt-template.txt
  3. 配置chatMemoryProvider持久化和记忆回话隔离
  4. 创建实体类
  5. 创建Controller方法

在这里插入图片描述

Function Calling(Tools)

大语言模型的缺陷是数学能力不擅长

  1. @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);
	}
}
  1. 在@AiService配置tools ="calculatorTools"

根据工具的不同,即使没有任何描述,大语言模型可能也能很好地理解它,例如add(a, b) 。

实战小智医疗智能体

  1. 实现业务,在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的过程

  1. 索引阶段
    xx
  2. 检索阶段
    xxx
  3. 文档加载器,文档解析器,文档分割器
//文档加载器,文档解析器,文档分割器
PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:*.txt");
List<Document> documents = FileSystemDocumentLoader.loadDocuments(folder, pathMatcher,new TextDocumentParser());
//

Token分词器

在这里插入图片描述

向量存储

之前我们使用的是InMemoryEmbeddingStore作为向量存储,但是不建议在生产中使用基于内存的向量存储。因此这里我们使用Pinecone作为向量数据库。

<dependency>
	<groupId>dev.langchain4j</groupId>
	<artifactId>langchain4j-pinecone</artifactId>
</dependency>
#集成阿里通义千问-通用文本向量-v3,注入EmbeddingModel
langchain4j.community.dashscope.embedding-model.api-key=${DASH_SCOPE_API_KEY}
langchain4j.community.dashscope.embedding-model.model-name=text-embedding-v3
  1. 配置EmbeddingStoreConfig
  2. //相似度匹配embeddingSearch
  3. 上传知识库到Pinecone
  4. 在AssistantConfig中添加contentRetrieverXiaozhiPincone
  5. AiService注解加contentRetriever=“contentRetrieverXiaozhiPincone”

流式输出

大模型的流式输出是指大模型在生成文本或其他类型的数据时,不是等到整个生成过程完成后再一次性返回所有内容,而是生成一部分就立即发送一部分给用户或下游系统,以逐步、逐块的方式返回结果。

<!--流式输出-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
	<groupId>dev.langchain4j</groupId>
	<artifactId>langchain4j-reactor</artifactId>
</dependency>

1.配置

#集成阿里通义千问-流式输出
langchain4j.community.dashscope.streaming-chat-model.api-key=${DASH_SCOPE_API_KEY}
langchain4j.community.dashscope.streaming-chat-model.model-name=qwen-plus
  1. AIService添加
    streamingChatModel = "qwenStreamingChatModel"
  2. 修改chat方法返回类型为Flux,也别忘了修改Controller中的返回类型

总结

整个框架流程如下
在这里插入图片描述

完结撒花!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2378101.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决“VMware另一个程序已锁定文件的一部分,进程无法访问“

问题描述 打开VMware里的虚拟机时&#xff0c;弹出"另一个程序已锁定文件的一部分&#xff0c;进程无法访问"如图所示&#xff1a; 这是VM虚拟机的保护机制。虚拟机运行时&#xff0c;为防止数据被篡改&#xff0c;会将所运行的文件保护起来。当虚拟机崩溃或者强制…

buuctf Crypto-鸡藕椒盐味1

1.题目&#xff1a; 公司食堂最新出了一种小吃&#xff0c;叫鸡藕椒盐味汉堡&#xff0c;售价八块钱&#xff0c;为了促销&#xff0c;上面有一个验证码&#xff0c;输入后可以再换取一个汉堡。但是问题是每个验证码几乎都有错误,而且打印的时候倒了一下。小明买到了一个汉堡&a…

FreeRTOS的学习记录(基础知识)

FreeRTOS 简介 FreeRTOS 是一个开源的实时操作系统&#xff08;RTOS&#xff09;&#xff0c;专为嵌入式系统设计。它提供了任务管理、时间管理、信号量、消息队列、内存管理等功能&#xff0c;适用于资源受限的微控制器。 FreeRTOS 是一个开源的实时操作系统内核&#xff0c…

会议分享|高超声速流动测量技术研讨会精彩探析

由中国空气动力学会测控专业委员会主办&#xff0c;中国科学技术大学工程科学学院承办的第八届三次委员会暨高超声速流动测量技术研讨会&#xff0c;5月16日在合肥盛大开幕。 会议专家报告分享了高超声速流动测量的最新研究成果、挑战与突破&#xff0c;展示了PIV高速摄像机、粒…

1-10 目录树

在ZIP归档文件中&#xff0c;保留着所有压缩文件和目录的相对路径和名称。当使用WinZIP等GUI软件打开ZIP归档文件时&#xff0c;可以从这些信息中重建目录的树状结构。请编写程序实现目录的树状结构的重建工作。 输入格式: 输入首先给出正整数N&#xff08;≤104&#xff09;…

Unix/Linux | A Programming Guide

注&#xff1a;本文为 “UNIX / Linux 教程” 相关文章合辑。 略作重排&#xff0c;如有内容异常&#xff0c;请看原文。 UNIX / Linux Tutorial for Beginners: Learn Online in 7 days By : Emily Carter UpdatedFebruary 5, 2025 UNIX / Linux Tutorial Summary Linux …

前端——布局方式

普通流&#xff08;标准流&#xff09; 所谓的标准流: 就是标签按照规定好默认方式排列. 1. 块级元素会独占一行&#xff0c;从上向下顺序排列。 常用元素&#xff1a;div、hr、p、h1~h6、ul、ol、dl、form、table 2. 行内元素会按照顺序&#xff0c;从左到右顺序排列&am…

Multimodal models —— CLIP,LLava,QWen

目录 CLIP CLIP训练 CLIP图像分类 CLIP框架 Text Enocder Image Encoder LLava系列 LLava LLava贡献 LLava模型结构 总结 LLava两阶段训练 LLava 1.5 LLava 1.6 QWen CLIP CLIP是OpenAI 在 2021 年发布的&#xff0c;最初用于匹配图像和文本的预训练神经网络模型…

LabVIEW与PLC通讯程序S7.Net.dll

下图中展示的是 LabVIEW 环境下通过调用S7.Net.dll 组件与西门子 PLC 进行通讯的程序。LabVIEW 作为一种图形化编程语言&#xff0c;结合S7.Net.dll 的.NET 组件优势&#xff0c;在工业自动化领域中可高效实现与 PLC 的数据交互&#xff0c;快速构建工业监控与控制应用。相较于…

使用GpuGeek高效完成LLaMA大模型微调:实践与心得分享

使用GpuGeek高效完成LLaMA大模型微调&#xff1a;实践与心得分享 &#x1f31f;嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 随着大模型的发展&#xff0…

华为IP(6)

VLAN聚合 VLAN聚合产生的技术背景 在一般是三层交换机中&#xff0c;通常采用一个VLAN接口的方式实现广播域之间的互通&#xff0c;这在某些情况下导致了IP地址的浪费 因为一个VLAN对应的子网中&#xff0c;子网号、子网广播地址、子网网关地址不能用作VLAN内的主机IP地址&a…

1:OpenCV—图像基础

OpenCV教程 头文件 您只需要在程序中包含 opencv2/opencv.hpp 头文件。该头文件将包含应用程序的所有其他必需头文件。因此&#xff0c;您不再需要费心考虑程序应包含哪些头文件。 例如 - #include <opencv2/opencv.hpp>命名空间 所有 OpenCV 类和函数都在 cv 命名空…

第三部分:内容安全(第十六章:网络型攻击防范技术、第十七章:反病毒、第十八章:入侵检测/防御系统(IDS/IPS))

文章目录 第三部分&#xff1a;内容安全第十六章&#xff1a;网络型攻击防范技术网络攻击介绍流量型攻击 --- Flood攻击单包攻击及防御原理扫描窥探攻击畸形报文攻击Smurf攻击Land攻击Fraggle攻击IP欺骗攻击 流量型攻击防御原理DDoS通用攻击防范技术 ---- 首包丢弃TCP类攻击SYN…

Void: Cursor 的开源平替

GitHub&#xff1a;https://github.com/voideditor/void 更多AI开源软件&#xff1a;发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI Void&#xff0c;这款编辑器号称是开源的 Cursor 和 GitHub Copilot 替代品&#xff0c;而且完全免费&#xff01; 在你的代码库…

100G QSFP28 BIDI光模块一览:100G单纤高速传输方案|易天光通信

目录 前言 一、易天光通信100G QSFP28 BIDI光模块是什么&#xff1f; 二、易天光通信100G QSFP28 BIDI光模块采用的关键技术 三、100G QSFP28 BIDI光模块的优势 四、以“易天光通信100G BIDI 40km ER1光模块”为例 五、总结&#xff1a;高效组网&#xff0c;从“减”开始 关于…

卓力达电铸镍网:精密制造与跨领域应用的创新典范

目录 引言 一、电铸镍网的技术原理与核心特性 二、电铸镍网的跨领域应用 三、南通卓力达电铸镍网的核心优势 四、未来技术展望 引言 电铸镍网作为一种兼具高精度与高性能的金属网状材料&#xff0c;通过电化学沉积工艺实现复杂结构的精密成型&#xff0c;已成为航空航天、电…

今日积累:若依框架配置QQ邮箱,来发邮件,注册账号使用

QQ邮箱SMTP服务器设置 首先&#xff0c;我们需要了解QQ邮箱的SMTP服务器地址。对于QQ邮箱&#xff0c;SMTP服务器地址通常是smtp.qq.com。这个地址适用于所有使用QQ邮箱发送邮件的客户端。 QQ邮箱SMTP端口设置 QQ邮箱提供了两种加密方式&#xff1a;SSL和STARTTLS。根据您选…

快速入门机器学习的专有名词

机器学习&#xff08;Machine Learning&#xff09; 机器学习是计算机科学的一个领域&#xff0c;目的在于让计算机能够通过学习数据来做出预测或决策&#xff0c;而无需被明确编程来完成任务。 机器学习的工作模式&#xff1a; 数据&#xff1a;机器学习需要数据来“学习”…

Python之三大基本库——Matplotlib

好久没来总结了&#xff0c;今天刚好有时间&#xff0c;我们来继续总结一下python中的matplotlib 一、什么是Matplotlib ‌Matplotlib‌是一个Python的2D绘图库&#xff0c;主要用于将数据绘制成各种图表&#xff0c;如折线图、柱状图、散点图、直方图、饼图等。它以各种硬拷贝…

Tensorflow 2.X Debug中的Tensor.numpy问题 @tf.function

我在调试YOLOv3模型过程中想查看get_pred函数下面的get_anchors_and_decode函数里grid_shape的数值 #---------------------------------------------------# # 将预测值的每个特征层调成真实值 #---------------------------------------------------# def get_anchors_a…