本节需求
引入 Spring AI 框架组件,对接 Ollama DeepSeek 提供服务接口。包括:普通应答接口和流式接口。
普通请求(同步请求)
普通请求是指客户端一次性发送请求,服务端处理完毕后一次性返回完整的结果。
例如:
流式请求
流式请求是指客户端发送请求后,服务端会将结果分批次,逐步推送给客户端,客户端可以边接收边处理。
例如:
功能实现
1. 工程结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ai-rag-knowledge/ ├── xfg-dev-tech-api/ # API 接口层 │ └── IAiService.java # AI 服务接口定义 ├── xfg-dev-tech-app/ # 应用层 │ ├── Application.java # Spring Boot 启动类 │ ├── config/ # 配置类 │ │ ├── OllamaConfig.java │ │ ├── RedisClientConfig.java │ │ └── RedisClientConfigProperties.java │ └── resources/ # 配置文件 │ ├── application.yml │ ├── application-dev.yml │ └── logback-spring.xml └── xfg-dev-tech-trigger/ # 触发器层 └── OllamaController.java # HTTP 控制器
|
2. 依赖管理
当前步骤需要ollama的依赖,在app模块的POM.xml文件添加依赖:
1 2 3 4
| <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-ollama</artifactId> </dependency>
|
3. 配置管理
配置信息需根据开发与部署环境灵活调整。开发过程中,我在 Windows PC 上进行 Java 开发,Ollama 和 DeepSeek 部署于云服务器的 Docker 环境中,配置文件如下所示:
application.yml:
1 2 3 4 5 6
| spring: application: name: ai-rag-knowledge profiles: active: dev
|
application-dev.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| server: port: 8080
spring: ai: ollama: base-url: http://<部署了Ollama的公网IP>:11434
redis: sdk: config: host: localhost port: 6379 pool-size: 5 min-idle-size: 2 idle-timeout: 30000 connect-timeout: 5000 retry-attempts: 3 retry-interval: 1000 ping-interval: 60000 keep-alive: true
logging: level: root: debug cn.bugstack.xfg.dev.tech: debug config: classpath:logback-spring.xml
|
其他配置文件暂且不考虑
4. 代码实现
AI服务接口(IAiService.java)
1 2 3 4 5 6 7 8 9 10 11 12 13
| package cn.bugstack.xfg.dev.tech.api;
import org.springframework.ai.chat.ChatResponse; import reactor.core.publisher.Flux;
public interface IAiService {
ChatResponse generate(String model, String message);
Flux<ChatResponse> generateStream(String model, String message);
}
|
Ollama 配置类 (OllamaConfig.java)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package cn.bugstack.xfg.dev.tech.config;
import org.springframework.ai.ollama.OllamaChatClient; import org.springframework.ai.ollama.api.OllamaApi; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class OllamaConfig {
@Bean public OllamaApi ollamaApi(@Value("${spring.ai.ollama.base-url}") String baseUrl) { return new OllamaApi(baseUrl); }
@Bean public OllamaChatClient ollamaChatClient(OllamaApi ollamaApi) { return new OllamaChatClient(ollamaApi); }
}
|
HTTP 控制器 (OllamaController.java)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package cn.bugstack.xfg.dev.tech.trigger.http;
import cn.bugstack.xfg.dev.tech.api.IAiService; import jakarta.annotation.Resource; import org.springframework.ai.chat.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.ollama.OllamaChatClient; import org.springframework.ai.ollama.api.OllamaOptions; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Flux;
@RestController() @CrossOrigin("*") @RequestMapping("/api/v1/ollama/") public class OllamaController implements IAiService { @Resource private OllamaChatClient chatClient;
@RequestMapping(value = "generate", method = RequestMethod.GET) @Override public ChatResponse generate(@RequestParam String model, @RequestParam String message) { return chatClient.call(new Prompt(message, OllamaOptions.create().withModel(model))); }
@RequestMapping(value = "generate_stream", method = RequestMethod.GET) @Override public Flux<ChatResponse> generateStream(@RequestParam String model, @RequestParam String message) { return chatClient.stream(new Prompt(message, OllamaOptions.create().withModel(model))); } }
|
启动类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package cn.bugstack.xfg.dev.tech;
import org.springframework.beans.factory.annotation.Configurable; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication @Configurable public class Application {
public static void main(String[] args) { SpringApplication.run(Application.class); }
}
|
功能测试
1. 普通请求测试
启动项目,确保云服务器的ollama已经启动后,浏览器地址栏输入:http://localhost:8080/api/v1/ollama/generate?model=deepseek-r1:1.5b&message=1+1,得到结果:
2. 流式请求测试
地址栏输入http://localhost:8080/api/v1/ollama/generate_stream?model=deepseek-r1:1.5b&message=你好啊
将流式请求的文本拼凑得到的响应结果为:
1 2 3 4 5
| <think>
</think>
你好!很高兴见到你,有什么我可以帮忙的吗?无论是问题、建议还是闲聊,我都在这儿呢!😊
|
小结
本节基于 Spring AI 对接了 Ollama(以 DeepSeek 模型为例),分别实现了普通应答与流式应答两类接口:
如果不能出现最终的响应结果,请依次检查:
- 云服务器防火墙是否开放
11434端口
- 云服务器中
ollama是否成功运行
application-dev.yml中base-url是否更改为云服务器的公网IP
application-dev.yml中port是否为8080