LangChain4j(2):整合SpringBoot

1 新建Springboot项目

1.1 引入依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>org.example</groupId><artifactId>langchain4jSpringbootpro</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><name>langchain4jSpringbootpro</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><langchain4j.version>1.0.0-beta1</langchain4j.version></properties><dependencies><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId></dependency><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><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-community-bom</artifactId><version>${langchain4j.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement></project>

2 配置项

查看加载的依赖中的langchain4j-community-dashscope-spring-boot-starter的Autoconfig文件。

可以看到使用时需要的配置条件,需要配置apikey。

在源文件中可以查看配置模型:

新建配置application.properties

server.port=8080langchain4j.community.dashscope.chat-model.api-key = 你的apikey
langchain4j.community.dashscope.chat-model.model-name = qwen-plus

2.3 代码实现

package org.example.controller;import dev.langchain4j.community.model.dashscope.QwenChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/ai")
public class AiController {@AutowiredQwenChatModel qwenChatModel;@RequestMapping("/chat")public String test(@RequestParam(defaultValue = "你是谁") String message){String chat = qwenChatModel.chat(message);return chat;}}

2.4 访问结果

启动后,访问链接http://localhost:8080/ai/chat。

2 接入DeepSeek

接入DeepSeek只需要修改配置文件即可,如下:

langchain4j.community.dashscope.chat-model.api-key = 你的key
langchain4j.community.dashscope.chat-model.model-name = deepseek-r1

启动后,访问链接http://localhost:8080/ai/chat。

3 接入Ollama

安装Ollama,下载想要的大模型。

引用依赖:

    <dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-ollama-spring-boot-starter</artifactId><version>${langchain4j.version}</version></dependency>

加入配置文件:

langchain4j.ollama.chat-model.base-url = http://localhost:11434
langchain4j.ollama.chat-model.model-name = deepseek-r1:1.5b

代码如下:

package org.example.controller;import dev.langchain4j.community.model.dashscope.QwenChatModel;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.ollama.OllamaChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/ai")
public class AiController {@AutowiredChatLanguageModel chatLanguageModel;@RequestMapping("/ollamachat")public String ollamachatfuc(@RequestParam(defaultValue = "你是谁") String message){String ollamachat = chatLanguageModel.chat(message);return ollamachat;}}

结果如下:

4 流式输出

之前的依赖不变,但是因为langchain4j不是spring家族,所以我们在wen应用中需要引入webflux。

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>

通过Flux进行流式响应

    @RequestMapping(value = "/streamchat",produces = "text/stream;charset=UTF-8")public Flux<String> streamchatfuc(@RequestParam(defaultValue="你是谁") String message){Flux<String> flux = Flux.create(fluxSink -> {streamingChatModel.chat(message, new StreamingChatResponseHandler() {@Overridepublic void onPartialResponse(String partialResponse) {fluxSink.next(partialResponse);}@Overridepublic void onCompleteResponse(ChatResponse completeResponse) {fluxSink.complete();}@Overridepublic void onError(Throwable error) {fluxSink.error(error);}});});return flux;}

加入配置文件:

langchain4j.community.dashscope.streaming-chat-model.api-key = sk-4d1748fba8994a2e94cb0fbaf3d34f23
langchain4j.community.dashscope.chat-model.model-name = deepseek-r1

启动后访问链接:http://localhost:8080/ai/streamchat,会发现答复是按照流式输出的。

5 记忆对话

5.1 ChatMemory

大模型并不会把我们每次的对话存在服务端,所以他记不住我们说的话,如下代码:

    @Testpublic void test_bad(){ChatLanguageModel model = OpenAiChatModel.builder().apiKey("demo").modelName("gpt-4o-mini").build();System.out.println(model.chat("你好,我是徐庶老师"));System.out.println("----");System.out.println(model.chat("我叫什么"));}

运行结果如下:

所以每次对话都需要将之前的对话记录,都发给大模型,这样才能知道我们之前说了什么:

    @Testpublic void test03(){ChatLanguageModel model = OpenAiChatModel.builder().apiKey("demo").modelName("gpt-4o-mini").build();UserMessage userMessage1 = UserMessage.userMessage("你好,我是徐庶");ChatResponse response1 = model.chat(userMessage1);AiMessage aiMessage1 = response1.aiMessage();//大模型的第一次响应System.out.println(aiMessage1.text());System.out.println("----");// 下面一行代码是重点ChatResponse response2 = model.chat(userMessage1,aiMessage1, UserMessage.userMessage("我叫什么?"));AiMessage aiMessage2 = response2.aiMessage();// 大模型的第二次响应System.out.println(aiMessage2.text());System.out.println(model.chat("你好,我是徐庶老师"));System.out.println("----");System.out.println(model.chat("我叫什么"));}

返回结果如下:

但是如果要我们每次把之前的记录自己去维护,未免太麻烦,所以提供了ChatMemory但是他这个ChatMemory没有SpringAi好用、易用、十分麻烦!所以说谁在跟我说Langchain4i比SpringAi好我跟谁急!

package org.example.config;import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.TokenStream;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class Aiconfig {public interface Assistant{String chat(String message);// 流式响应TokenStream stream(String message);}@Beanpublic Assistant assistant(ChatLanguageModel qwenchatModel, StreamingChatLanguageModel qwenstreamingchatModel) {//设置最大记录对话数ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);Assistant assistant = AiServices.builder(Assistant.class).chatLanguageModel(qwenchatModel).streamingChatLanguageModel(qwenstreamingchatModel).chatMemory(chatMemory).build();return assistant;}
}

原理:

  1. 通过AiService创建的代理对象(Aiservices.builder(XushuChatModel.class))调用chat方法(XushuChatModel.chat)
  2. 代理对象会去ChatMemory中获取之前的对话记录(获取记忆)
  3. 将获取到的对话记录合并到当前对话中(此时大模型根据之前的聊天记录肯定就拥有了“记忆”)
  4. 将当前的对话内容存入ChatMemory(保存记忆)

代码如下:

package org.example.controller;import dev.langchain4j.service.TokenStream;
import jakarta.servlet.http.HttpServletResponse;
import org.example.config.Aiconfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;import java.time.LocalDate;@RestController
@RequestMapping("/ai_other")
public class OtherAiController {@AutowiredAiconfig.Assistant assistant;//告诉模型我叫诸葛懿@RequestMapping(value = "/memory_chat")public String memorychat(@RequestParam(defaultValue = "我叫诸葛懿") String message) {return assistant.chat(message);}//流式响应@RequestMapping(value = "/memory_stream_chat",produces ="text/stream;charset=UTF-8")public Flux<String> memoryStreamChat(@RequestParam(defaultValue="我是谁") String message, HttpServletResponse response) {TokenStream stream = assistant.stream(message);return Flux.create(sink -> {stream.onPartialResponse(s -> sink.next(s)).onCompleteResponse(c -> sink.complete()).onError(sink::error).start();});}
}

先访问http://localhost:8080/ai_other/memory_chat告诉模型你的名字,后访问http://localhost:8080/ai_other/memory_stream_chat看结果,结果如下:

5.2 记忆分离

现在我们再来想另一种情况:如果不同的用户或者不同的对话肯定不能用同一个记忆,要不然对话肯定会混淆此时就需要进行区分:

可以通过memoryld进行区分

5.3 持久对话

6 Funcion-call

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

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

相关文章

移动端六大语言速记:第2部分 - 控制结构

移动端六大语言速记&#xff1a;第2部分 - 控制结构 本文继续对比Java、Kotlin、Flutter(Dart)、Python、ArkTS和Swift这六种移动端开发语言的控制结构&#xff0c;帮助开发者快速掌握各语言的语法差异。 2. 控制结构 2.1 条件语句 各语言条件语句的语法对比&#xff1a; …

Linux-线程概念与线程控制的常用操作

一.Linux线程概念 1-1.线程是什么 在Linux中&#xff0c;线程是基于Linux原有的进程实现的。本质是轻量级进程(LWP)。在⼀个程序⾥的⼀个执⾏路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“⼀个进程内部的控制序列”。 我们之前所学习的进…

dfs记忆化搜索刷题 + 总结

文章目录 记忆化搜索 vs 动态规划斐波那契数题解代码 不同路径题解代码 最长递增子序列题解代码 猜数字大小II题解代码 矩阵中的最长递增路径题解代码 总结 记忆化搜索 vs 动态规划 1. 记忆化搜索&#xff1a;有完全相同的问题/数据保存起来&#xff0c;带有备忘录的递归 2.记忆…

【HTML】验证与调试工具

个人主页&#xff1a;Guiat 归属专栏&#xff1a;HTML CSS JavaScript 文章目录 1. HTML 验证工具概述1.1 验证的重要性1.2 常见 HTML 错误类型 2. W3C 验证服务2.1 W3C Markup Validation Service2.2 使用 W3C 验证器2.3 验证结果解读 3. 浏览器开发者工具3.1 Chrome DevTools…

认识rand, srand, time函数,生成随机数

要完成猜数字游戏&#xff0c;首先要生成随机数&#xff0c;那么该怎么生成随机数&#xff1f;、 1.rand函数 rand函数是库函数&#xff0c;使用的时候要使用头文件stdlib.h c语言中&#xff0c;提供了rand函数来生成随机数&#xff0c;来看一下函数使用&#xff1a; 但是r…

BKA-CNN-GRU、CNN-GRU、GRU、CNN四模型多变量时序预测(Matlab)

BKA-CNN-GRU、CNN-GRU、GRU、CNN四模型多变量时序预测&#xff08;Matlab&#xff09; 目录 BKA-CNN-GRU、CNN-GRU、GRU、CNN四模型多变量时序预测&#xff08;Matlab&#xff09;预测效果基本介绍程序设计参考资料 预测效果 基本介绍 BKA-CNN-GRU、CNN-GRU、GRU、CNN四模型多…

Go语言从零构建SQL数据库引擎(2)

SQL标准与数据库系统实现差异 在上一节中&#xff0c;我们了解了关系型数据库的基础概念。现在&#xff0c;让我们深入探讨SQL语言标准以及不同数据库系统之间的实现差异。 SQL语言的诞生与演进 想象你经营的咖啡店生意蒸蒸日上&#xff0c;需要一个更强大的系统来管理数据。…

智能导诊系统的技术体系组成

智能导诊系统的技术体系由基础支撑技术、核心交互技术、应用场景技术及安全保障技术构成&#xff0c;具体可归纳为以下六个维度&#xff1a; 一、基础支撑技术 1、AI大模型与深度学习 医疗大模型&#xff1a;如腾讯医疗AI、DeepSeek等&#xff0c;通过海量医学文献和病例训…

QML输入控件: TextField(文本框)的样式定制

目录 引言示例简介示例代码与关键点示例1&#xff1a;基础样式定制示例2&#xff1a;添加图标示例3&#xff1a;交互式元素&#xff08;清除按钮&#xff09; 实现要点总结完整工程下载 引言 在Qt Quick应用程序开发中&#xff0c;文本输入是最常见的用户交互方式之一。TextFi…

leetcode hot100 多维动态规划

1️⃣2️⃣ 多维动态规划&#xff08;区间 DP、状态机 DP&#xff09; 62. 不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图…

3.27学习总结 爬虫+二维数组+Object类常用方法

高精度&#xff1a; 一个很大的整数&#xff0c;以字符串的形式进行接收&#xff0c;并将每一位数存储在数组内&#xff0c;例如100&#xff0c;即存储为[1][0][0]。 p2437蜜蜂路线 每一个的路线数前两个数的路线数相加。 #include <stdio.h> int a[1005][1005]; int …

车载以太网网络测试-26【SOME/IP-通信方式-2】

目录 1 摘要2 Method &#xff08;FF/RR&#xff09;、Event、Filed介绍2.1. SOME/IP Method 接口2.1.1 **Fire & Forget (FF)** - 单向调用2.1.2 **Request/Response (RR)** - 请求/响应模式2.1.3 **车载ECU通信实现示例**:2.1.4 **通信序列示例**2.1.5 实现注意事项 2.2 …

把doi直接插入word中,然后直接生成参考文献

这段代码通过提取、查询、替换DOI&#xff0c;生成参考文献列表来处理Word文档&#xff0c;可按功能模块划分&#xff1a; 导入模块 import re from docx import Document from docx.oxml.ns import qn from habanero import Crossref导入正则表达式模块re用于文本模式匹配&a…

[C++] : C++11 右值引用的理解

&#xff08;一&#xff09;什么是左值和右值&#xff1f; 传统的C语法中就有引用的语法&#xff0c;而C11中新增了的右值引用语法特性&#xff0c;所以从现在开始我们 之前学习的引用就叫做左值引用。无论左值引用还是右值引用&#xff0c;都是给对象取别名。 1.左值 左值是一…

windows服务器切换到linux服务器踩坑点

单节点环境依赖性 单节点问题&#xff0c;影响业务可用性&#xff0c;windows影响后续自动化&#xff0c;健壮性的提升&#xff0c;需要进行linux化 每个服务至少是双节点&#xff0c;防止单点故障&#xff0c;提升系统的可用性&#xff0c;健壮性。linux化后可以进行docker化…

美颜SDK兼容性挑战:如何让美颜滤镜API适配iOS与安卓?

如何让美颜滤镜API同时适配iOS与Android&#xff0c;并确保性能流畅、效果一致&#xff0c;是开发者面临的一大挑战。今天&#xff0c;我将与大家一同深度剖析美颜SDK的跨平台兼容性问题&#xff0c;并分享优化适配方案。 一、美颜SDK兼容性面临的挑战 1.1不同平台的图像处理框…

Vue3 表单

Vue3 表单 随着前端技术的发展,Vue.js 作为一款流行的前端框架,不断更新迭代,以适应更高效、更便捷的开发需求。Vue3 作为 Vue.js 的第三个主要版本,引入了许多新特性和改进,其中包括对表单处理机制的优化。本文将深入探讨 Vue3 表单的使用方法、技巧以及注意事项。 1. …

笔记:代码随想录算法训练营day62:108.冗余连接、109.冗余连接II

学习资料&#xff1a;代码随想录 108. 冗余连接 卡码网题目链接&#xff08;ACM模式&#xff09; 判断是否有环的依据为&#xff0c;利用并查集&#xff0c;isSame函数&#xff0c;判断当下这条边的两个节点入集前是否为同根&#xff0c;如果是的话&#xff0c;该边就是会构…

RK3588,V4l2 读取Gmsl相机, Rga yuv422转换rgb (mmap)

RK3588, 使用V4l2 读取 gmsl 相机,获得yuv422格式图像, 使用 rga 转换 rgb 图像。减少cpu占用率. 内存管理方式采用 mmap… 查看相机信息 v4l2-ctl --all -d /dev/cam0 , 查看自己相机分辨率,输出格式等信息,对应修改后续代码测试… Driver Info:Driver name : rkcif…

Kubernetes》k8s》Containerd 、ctr 、cri、crictl

containerd ctr crictl ctr 是 containerd 的一个客户端工具。 crictl 是 CRI 兼容的容器运行时命令行接口&#xff0c;可以使用它来检查和调试 k8s 节点上的容器运行时和应用程序。 ctr -v 输出的是 containerd 的版本&#xff0c; crictl -v 输出的是当前 k8s 的版本&#x…