一、pom文件
各个组件的版本信息
<properties>
<java.version>23</java.version>
<spring-ai.version>1.0.0-M5</spring-ai.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-ollama-spring-boot-starter</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.53</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
</dependencies>
</dependencyManagement>包下载地址信息,由于spring ai的包都没传到中央库,这里需要spring的私有库下载包
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>二、yml文件
server:
port: 8080
spring:
ai:
ollama:
chat:
model: modelName:modelVersion
base-url: http://localhost:11434这里需要注意的是modelName:modelVersion需要改为自己的模型名称和模型版本
base-url 是ollama的连接地址,也需要改为自己的,因为我是本地调试所以用的localhost
三、controller代码
@RestController
public class TestController {
private final ChatClient chatClient;
public TestController(ChatClient.Builder chatClient){
this.chatClient=chatClient.build();
}
@GetMapping(value = "/chat",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> chatStream(String msg) {
Prompt prompt = new Prompt(msg,OllamaOptions.builder()
.build());
return chatClient.prompt(
prompt
)
.stream().content();
}
}四、前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>本地chat测试</title>
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.5.1.min.js"></script>
</head>
<body>
<div style="width: 500px;height: 500px" id="messages"></div>
<input type="text" id="msg" value=""/>
<button onclick="massage($('#msg').val())">发送</button>
</body>
<script type="text/javascript">
function massage(msg) {
$('#messages').append("<span style='color: red'>"+msg+"</span>");
$('#messages').append("<br>");
if(typeof(EventSource)!=="undefined") {
var source = new EventSource("/chat?msg="+msg);
// 当接收到消息时更新页面
source.onmessage = function(event) {
$('#messages').append(event.data);
};
// 错误处理
source.onerror = function(event) {
console.error("错误或者返回结束.", event);
$('#messages').append("<br>");
// 在发生错误时关闭连接
source.close();
};
} else {
$('#messages').text("当前浏览器不支持流式返回");
}
}
</script>
</html>这里用的比较老的原生html+jquery做的,使用其他框架的宝儿们自己优化一下。
运行后的效果

五、function calling实现
在平时的开发中,可能会出现一些系统和AI交互的情况
比如:
需要AI再数据库中查询我还有多少积分
需要AI给谁发一个电子邮件
需要查询一下系统中某个商品的价格
这里我们就需要使用的大模型的function calling功能,这里需要注意的是,老一点的模型可能会不支持这个功能。
这里我们以查询商品价格为例做一个demo
service
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import lombok.Data;
import org.springframework.context.annotation.Description;
import org.springframework.stereotype.Service;
import java.util.function.Function;
@Description("商品价格检索")
@Service
public class ProductPriceSearchService implements Function<ProductPriceSearchService.SearchRequest, ProductPriceSearchService.SearchResponse> {
@Data
public static class SearchRequest {
@JsonPropertyDescription(value = "商品名称")
String goodsName;
}
public record SearchResponse(String price) {
}
@Override
public SearchResponse apply(SearchRequest searchRequest) {
System.out.println(searchRequest.goodsName);
return new SearchResponse("大份100中份80小份20");
}
}controller
@GetMapping(value = "/chat",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> chatStream(String msg, @RequestHeader("referer") String referer) {
Prompt prompt = new Prompt(msg,OllamaOptions.builder()
.build());
return chatClient.prompt(
prompt
)
.functions("productPriceSearchService")
.stream().content();
}这里相比之前的controller就多了一个functions,这里可以传多个service的名称进去 他会根据service里注解相关信息自动提内容。
得到返回值后系统会自动根据你返回的数据组织语言回答给用户

OVER !~