先看一下官方关于 Spring AI 项目的描述:
Spring AI项目旨在简化包含人工智能功能的应用程序的开发,避免不必要的复杂性。
该项目从著名的 Python 项目(例如 LangChain 和 LlamaIndex)中汲取灵感,但 Spring AI 并非这些项目的直接移植。该项目的成立基于这样的信念:下一波生成式 AI 应用将不仅面向 Python 开发人员,还将遍及多种编程语言。
Spring AI 提供了抽象概念,作为开发 AI 应用程序的基础。这些抽象概念具有多种实现,只需进行少量代码更改即可轻松更换组件。
Spring AI 提供以下功能:
-
跨 AI 提供商的可移植 API 支持聊天、文本转图像和嵌入模型。支持同步和流式 API 选项。还可访问特定于模型的功能。
-
支持所有主要AI 模型提供商,例如 Anthropic、OpenAI、Microsoft、Amazon、Google 和 Ollama。支持的模型类型包括:
-
聊天完成
-
嵌入
-
文本转图像
-
音频转录
-
文本转语音
-
调节评分
-
-
结构化输出- 将 AI 模型输出映射到 POJO。
-
支持所有主要的矢量数据库提供商,例如 Apache Cassandra、Azure Cosmos DB、Azure Vector Search、Chroma、Elasticsearch、GemFire、MariaDB、Milvus、MongoDB Atlas、Neo4j、OpenSearch、Oracle、PostgreSQL/PGVector、PineCone、Qdrant、Redis、SAP Hana、Typesense 和 Weaviate。
-
跨 Vector Store 提供商的可移植 API,包括一种新颖的类似 SQL 的元数据过滤器 API。
-
工具/功能调用- 允许模型请求执行客户端工具和功能,从而根据需要访问必要的实时信息并采取行动。
-
可观察性——提供对 AI 相关操作的洞察。
-
用于数据工程的文档提取ETL 框架。
-
AI 模型评估- 用于帮助评估生成的内容并防止产生幻觉反应的实用程序。
-
用于 AI 模型和向量存储的 Spring Boot 自动配置和启动器。
-
ChatClient API - 用于与 AI 聊天模型通信的流畅 API,惯用语类似于 WebClient 和 RestClient API。
-
顾问 API——封装重复的生成式 AI 模式,转换发送到和来自语言模型 (LLM) 的数据,并提供跨各种模型和用例的可移植性。
-
支持聊天对话记忆和检索增强生成 (RAG)。
简单来说就是,利用 Spring AI 可以快速接入市面上主流的大模型开发相关业务,Spring AI 封装了抽象层,其他大模型只需要进行不同的实现就可以提供给客户端使用,简化了调用不同模型的调用。
不过现在 API 还处于不断迭代开发的过程,毕竟 AI 大模型仍然处于激烈竞争中,可以初步接触使用,下面以本地运行大模型最多的 ollama 为例初步窥探一下 Spring AI。
初始化项目
可以通用 Idea 自带的 Spring Boot 工具进行初始化项目,也可以自行跟入必要的 Maven 依赖。
引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
</dependency>
</dependencies>
配置模型的参数
我本地运行是通过 ollam 运行的 deepseek:14b,所以我的配置如下,不同的模型版本需要修改为具体的名称。
spring:
application:
name: spring-ai-demo
ai:
ollama:
base-url: http://localhost:11434
chat:
model: deepseek-r1:14b
server:
port: 8096
代码示例
创建一个 ChatController 类
@RequestMapping("/ai")
@RestController
public class ChatController {
@Autowired
private OllamaChatModel chatModel;
@GetMapping("/generate")
public Map<String,String> generate(@RequestParam(value = "message", defaultValue = "讲个笑话") String message) {
return Map.of("generation", this.chatModel.call(message));
}
@GetMapping(value = "/generateStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "讲个笑话") String message) {
Prompt prompt = new Prompt(new UserMessage(message));
return this.chatModel.stream(prompt);
}
@GetMapping(value = "/template/{year}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<String> promptTemplate(@PathVariable("year") Integer year) {
PromptTemplate promptTemplate = new PromptTemplate("{year} 年最流行的网络用语");
promptTemplate.add("year", year);
return chatModel.stream(promptTemplate.createMessage());
}
}