领先一步
VMware 提供培训和认证,助您加速进步。
了解更多我爱 Spring AI。这是一个很棒的项目,旨在将 AI 工程的模式和实践带给 Spring Boot 开发者。它提供了简洁、惯用的抽象,让任何 Spring 开发者都能感到宾至如归,并且它还集成了各种不同的向量存储、嵌入模型、转录模型、图像模型和聊天模型。
新版本 m4,基于 Spring Boot 3.4 构建,并增加了大量新功能。一如既往,我无法涵盖所有新功能,但发布说明做得非常出色。
The evolving nature of the functional callback support has so enamored me. Spring AI aims to make connecting your AI models with your data and business logic easy. Remember: the name of the game here is integration. Most people aren’t going to build their models. They’re going to integrate existing ones into their business logic and services. And where does all that stuff live? In Spring, of course. Spring AI is a natural! And it keeps getting easier. In this release, there’s new support for describing and then letting models invoke functions if they decide they’ve got the need to do so.
Here’s a simple example demonstrating the definition of a FunctionCallback and the Spring AI ChatClient, which is your first port of call for all interactions with a Sprign AI ChatModel.
package com.example.bootiful_34.ai;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
class AiConfiguration {
@Bean
ChatClient chatClient(ChatClient.Builder builder, FunctionCallback weatherFunctionCallback) {
return builder.defaultFunctions(weatherFunctionCallback).build();
}
@Bean
FunctionCallback weatherFunctionCallback() {
return FunctionCallback.builder()
.description("returns the weather for a given city")
.function("getCurrentWeatherForACity",
(WeatherRequest wr) -> new WeatherResponse(wr.city(),
wr.city().equalsIgnoreCase("san francisco") ? 68.0f : 72.0f))
.inputType(WeatherRequest.class)
.build();
}
}
record WeatherRequest(String city) {
}
record WeatherResponse(String city, float temperature) {
}
It’s a pretty trivial example: given a WeatherRequest specifying a city, we make up and return some temperature. In this case, I’ve got a hardcoded case for San Francisco.
We put all of this to work in the test, knowing that the model won’t know the current weather in a given city, and so we will have to defer to a function that we provide. It knows about the nature of the function because we’ve given it a description when we configured the FunctionCallback. It knows that the city parameter is Stringand that San Francisco is a city, so it passes the stringSan Francisco` to our function, allowing us to provide the expected response. We verify as much with the test, asserting that the response is the hardcoded magic number.
package com.example.bootiful_34.ai;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class AiConfigurationTest {
@Test
void functionCallbacks(@Autowired ChatClient cc) {
var weatherInSf = cc.prompt("give me the weather for the city of san francisco").call().content();
Assertions.assertNotNull(weatherInSf);
Assertions.assertTrue(weatherInSf.contains("68"));
}
}
And just like that, we’ve given our AI model the ability to ask questions about our systems and services and to support a more agentic workflow. Easy!