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> {
@Override
public 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的一些核心能力,欢迎大家也自己尝试一下。