引
AI确实是发展的太快了,近半年直接呈现出指数型增长的趋势,作为传统的java程序员,即使精通大型分布式微服务系统的开发运维,面对如今的就业市场,老实讲真挺无力的。不管AI在对方企业是否有应用场景,是否真的有落地实践,从招聘岗位,技能要求都迫使我们不得不快速补充AI技能。
正如大佬讲的那样,java程序要叠加AI buff技能,并不是需要去啃python的LangChain、PyTorch、TensorFlow等开发框架,当然有基础有能力的朋友去转型我个人觉得肯定也是挺好的,java程序员的优势在于工程化能力,企业已有的系统各种系统,不是说不用了,被AI大模型给取缔,而是借助AI大模型的能力,为系统的能力进行大幅升级。以我之前所参与的智能客服系统为例,以前传统的方式通过规则引擎,做多轮对话的智能问答,也用了很多年,缓解了很多人工坐席侧的咨询压力。公司的模型侧也一直在迭代,承担了部分流量的智能问答。应该在半年以前,模型侧的能力从意图识别到智能问答,其实一直还算是被规则引擎的方式给碾压的,但是随着大模型的能力提升,很明显能感受到问答的质量出现大幅提升,分流比例也一直在提高,呈现出替换传统多轮对话的趋势。
这只是我接触到的冰山一角,大家平时用ai coding也能明显感受到让模型生成的代码质量最近半年内也有质的飞跃吧,那么以前那些只会crud,搞搞简单业务的螺丝钉,地位就显得岌岌可危。当然,我也不是给大家制造焦虑,传递焦虑,焦虑除了让自己身心俱疲外,毫无意义,要么转行,要么卷起来呗,要记住,我们肯定有我们自身的优势。近期准备好好学习spring ai,langchain4j,有兴趣的朋友可以关注一下专栏。
Spring AI简介
Spring AI 是 Spring 官方推出的AI 工程化应用框架,核心使命是连接企业数据与 AI 模型,为 Java/Spring 生态开发者提供统一、可移植的方式集成大语言模型(LLM)、向量数据库等 AI 能力,无需为不同厂商逐一适配,降低企业级 AI 应用开发门槛。
引入依赖在dependencyManagement中加入spring-ai-bom,我这里选择的版本是1.1.2。
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
进入这个依赖的pom,能看到spring ai支持的各种模型,常见的如openai、deepseek、ollama部署的本地模型,还有我这里准备使用的智谱ai大模型。
deepseek
zhipuai
这里的starter是开箱即用的,引入了对应模型的starter就需要添加对应模型的参数配置,不然启动时会报错。
操作步骤
依赖
以下是我的pom依赖,我这儿只创建了一个module,引入了zhipuai的starter。需要注意的是,spring ai需要jdk17以上的版本。
<?xml version="1.0" encoding="UTF-8"?>
<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 https://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.5.10</version>
<relativePath/>
</parent>
<groupId>com.roswu</groupId>
<artifactId>spring-ai-learning</artifactId>
<version>1.0.1-SNAPSHOT</version>
<name>spring-ai-learning</name>
<description>spring-ai-learning</description>
<properties>
<java.version>17</java.version>
<spring-ai.version>1.1.2</spring-ai.version>
<mybatis-plus.version>3.5.16</mybatis-plus.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-zhipuai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.42</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置
模型配置有三个重要参数,模型地址base-url,模型秘钥api-key,模型名称chat.model。如果是换成deepseek的话,这里的zhipuai这个配置路径做对应的替换即可,其它的都差不多。
spring:
application:
name: spring-ai-learning
ai:
zhipuai:
# 模型地址
base-url: https://open.bigmodel.cn/api/paas
# apiKey
api-key: ${OPENAI_API_KEY}
chat:
# 模型名称
model: GLM-4.7
temperature: 0.7
server:
port: 8088
ChatClient
增加一个模型配置类,注入一个ChatClient的bean,这里的入参是ZhiPuAiChatModel类型,与我们选用的模型和配置文件是对应的。
@Configuration
public class CommonConfiguration {
@Bean
public ChatClient chatClient(ZhiPuAiChatModel model) {
return ChatClient.builder(model)
.defaultSystem("你是一个智能桌面助手铁铁,帮助缓解主人工作之余的疲惫和情绪情绪")
.build();
}
}
defaultSystem参数用于设置系统提示词,也可以配置到yaml里面。
Controller
这里定义了一个Controller,提供两个api接口,功能都一样,只不过一个是同步调用,一个是流式调用。同步调用就是待模型输出所有答案后,一次性返回所有结果;而流式调用可以流式输出答案。大家用的千问,deepseek,豆包都是采用的流式调用,逐步加载出所有的答案,体验更好。
@RequiredArgsConstructor
@RestController
@RequestMapping("api")
public class ChatController {
private final ChatClient chatClient;
/**
* 同步调用
*
* @param prompt
* @return
*/
@RequestMapping("/chat")
public String chat(@RequestParam String prompt) {
return chatClient
// 传入user提示词
.prompt(prompt)
// 同步请求,会等待AI全部输出完才返回结果
.call()
.content();
}
/**
* 流式输出
*
* @param prompt
* @return
*/
@RequestMapping(value = "/stream/chat", produces = "text/html;charset=UTF-8")
public Flux<String> streamChat(@RequestParam String prompt) {
return chatClient
.prompt(prompt)
.stream()
.content();
}
}
测试
启动服务,浏览器访问http://localhost:8088/api/chat?prompt=上班好累啊,请求完成后一次性加载全量的模型答案。
http://localhost:8088/api/chat?prompt=上班好累啊
再访问http://localhost:8088/api/stream/chat?prompt=上班好累啊,答案则是逐步加载出来的,响应更快。
http://localhost:8088/api/stream/chat?prompt=上班好累啊