Langchain 是什么?
Langchain 是一个Python 的AI开发框架,它集成了模型输入输出、检索、链式调用、内存记忆(Memory)、Agents以及回调函数等功能模块。通过这些模块的协同工作,它能够支持复杂的对话场景和任务执行流程,同时利用模板(Templates)机制简化开发过程,让开发者可以更加灵活高效地构建基于AI的应用服务。
Langchain虽好,奈何Java不能用
Langchain的核心问题在于它主要是用Python实现的,过去Java社区中缺乏一个由专门团队维护的、功能完善的类Langchain框架。不过这个问题随着Spring 团队的介入得到了解决。使得Java距离AI又进了一步。
Spring AI 介绍
Spring AI 是由Pivotal的Spring团队专门维护的AI调用框架,它通过标准化不同AI服务提供商的接口实现,使开发者能够以统一的方式编写代码,并仅通过修改配置即可轻松切换不同的AI实现。该框架兼容多种基于流的机器人模型,并提供了一系列实用工具如Prompt Template和OutputParser等,极大地简化了AI应用开发流程。
Spring AI Alibaba介绍
Spring AI Alibaba 是 Spring AI 的实现,支持阿里云百炼系列模型。其特征包括:统一的模型输入输出接口、向量检索功能(兼容Elasticsearch、PG等存储)、Prompt Template 用于灵活生成提示词,以及 Function Calling 支用来调用自定义函数以扩展模型能力。这些特性使得开发者能够便捷地集成和使用多种AI模型,提升开发效率。
Spring Ai Alibaba 的例子之一:简单的对话,基于Prompt
基于Spring Boot集成Spring AI Alibaba,完成一个简单的对话模型,并使用Prompt能力和ChatClient能力以及Flux流返回,可以遵循以下步骤:
1. 环境准备
- JDK版本:确保你的项目使用的JDK版本至少为JDK 17。
- Spring Boot版本:确保你的Spring Boot版本在3.3.x或以上。
2. 配置阿里云通义千问API Key
首先需要访问阿里云百炼页面并登录您的账号。接着选择开通“百炼大模型推理”服务,按照提示操作直到成功申请到API Key。将获取到的API Key记录下来,后续配置中会用到。
通义现在有免费额度,不花钱的,羊毛薅起来
3. 设置环境变量
为了安全地管理敏感信息,推荐通过环境变量设置API Key:
export AI_DASHSCOPE_API_KEY=${YOUR_VALID_API_KEY}
同时,在application.properties
文件里引用这个环境变量以确保应用能够读取到API Key:
spring.ai.dashscope.api-key: ${AI_DASHSCOPE_API_KEY}
4. 添加仓库与依赖
由于Spring AI Alibaba尚处于Milestone阶段,需添加特定仓库来获取相关依赖。编辑pom.xml
文件,加入如下内容:
<repositories><repository><id>sonatype-snapshots</id><url>https://oss.sonatype.org/content/repositories/snapshots</url><snapshots><enabled>true</enabled></snapshots></repository><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></repository></repositories>
然后,在同一文件内增加对spring-ai-alibaba-starter
及其父级Spring Boot项目的依赖:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.4</version><relativePath/> <!-- lookup parent from repository -->
</parent><dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter</artifactId><version>1.0.0-M2</version></dependency><!-- 其他所需依赖... -->
</dependencies>
5. 编写控制器代码
创建一个REST控制器类,注入ChatClient
实例,并实现基本的聊天功能。这里我们将利用Flux流返回方式提供实时响应。
@RestController
@RequestMapping("/ai")
@CrossOrigin(origins = "*")
public class ChatController {private final ChatClient chatClient;public ChatController(ChatClient.Builder builder) {this.chatClient = builder.build();}@GetMapping("/chat")public Flux<String> chat(@RequestParam String input) {return this.chatClient.prompt().user(input).stream().content();}
}
6. 使用Prompt模板增强交互
为了使对话更加丰富和可控,我们可以引入Prompt模板机制。这要求我们先定义一个模板文件(例如joke-prompt.st
),其内容可能类似于:
Tell me a {adjective} joke about {topic}.
接着修改之前的控制器,使其能够从指定的模板文件加载并填充参数:
@Autowired
private Resource jokeResource;@GetMapping("/promptedChat")
public Flux<String> promptedChat(@RequestParam(value = "adjective", defaultValue = "funny") String adjective,@RequestParam(value = "topic", defaultValue = "cows") String topic) {PromptTemplate promptTemplate = new PromptTemplate(jokeResource);Prompt prompt = promptTemplate.create(Map.of("adjective", adjective, "topic", topic));return this.chatClient.prompt(prompt).stream().content();
}
Spring Ai Alibaba 例子2 ,function calling 函数回调
详细步骤
结合上述分析及我了解的信息中给出的建议,下面提供了一个具体的实例,展示了如何基于Spring Boot集成Spring AI Alibaba完成一个function calling,并利用Prompt能力与Flux流返回数据。
前提条件
- JDK版本:17及以上。
- Spring Boot版本:3.3.x及以上。
- 已经从阿里云获取API Key,并按要求配置环境变量
AI_DASHSCOPE_API_KEY
。
项目配置
确保你的pom.xml
文件里包含如下依赖:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.4</version><relativePath/> <!-- lookup parent from repository -->
</parent><dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter</artifactId><version>1.0.0-M2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>...other dependencies...
</dependencies>
同时添加所需的仓库:
<repositories><repository><id>sonatype-snapshots</id><url>https://oss.sonatype.org/content/repositories/snapshots</url><snapshots><enabled>true</enabled></snapshots></repository><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></repository></repositories>
定义并注册函数
创建一个简单的服务类,比如MessageStatusService.java
,用来模拟消息状态查询的功能:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;public class MessageStatusService implements Function<MessageStatusRequest, String> {@Overridepublic String apply(MessageStatusRequest request) {return "消息ID: " + request.getMessageId() + " 的状态是:正常";}public static class MessageStatusRequest {@JsonProperty(required = true, value = "消息id")@JsonPropertyDescription("消息id, 比如123123***")private String messageId;// 构造器、getter和setter省略}
}
然后,在Spring配置类中注册此服务:
@Configuration
public class AppConfig {@Bean@Description("查询指定消息ID的状态")public Function<MessageStatusRequest, String> messageStatusFunction() {return new MessageStatusService();}
}
控制器代码
最后,编写一个控制器类来处理HTTP请求,并使用PromptTemplate
构建提示词,同时通过DashScopeChatOptions
启用函数调用功能。
@RestController
@RequestMapping("/ai")
@CrossOrigin(origins = "*")
public class ChatController {private final ChatClient chatClient;public ChatController(ChatClient.Builder builder) {this.chatClient = builder.build();}@GetMapping("/status")public Flux<String> checkMessageStatus(@RequestParam String id) {PromptTemplate promptTemplate = new PromptTemplate("我想知道消息id: {id} 的状态");DashScopeChatOptionsBuilder opsBuilder = DashScopeChatOptions.builder().withFunction("messageStatusFunction");DashScopeChatOptions ops = opsBuilder.build();Map<String, Object> map = Map.of("id", id);Prompt prompt = promptTemplate.create(map, ops);return chatClient.prompt(prompt).stream().content();}
}
小结
上面两个,作为一个例子,基本上展示了spring ai的一些核心能力,欢迎大家也自己尝试一下。