首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >spring-ai 学习系列(1)-调用本地ollama

spring-ai 学习系列(1)-调用本地ollama

作者头像
菩提树下的杨过
发布2025-08-22 08:31:20
发布2025-08-22 08:31:20
30100
代码可运行
举报
运行总次数:0
代码可运行

spring-ai框架为java程序员快速融入AI大潮提供了便利,下面演示如何调用本地deepseek模型

一、安装ollama

  • https://www.ollama.com/ 首页下载安装即可
  • 选择适合的模型,pull到本地,个人电脑建议选择deepseek-r1:7b或1.5b
  • 启动模型 ollama run deepseek-r1:7b ,顺利的话,本地控制台就能直接交互了
  • 浏览器里,也可以用 http://localhost:11434来验证

二、创建spring-boot项目

2.1 pom依赖

代码语言:javascript
代码运行次数:0
运行
复制
 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 2          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 3     <modelVersion>4.0.0</modelVersion>
 4     <groupId>com.example</groupId>
 5     <artifactId>spring-ai</artifactId>
 6     <version>0.0.1-SNAPSHOT</version>
 7     <packaging>jar</packaging>
 8 
 9     <parent>
10         <groupId>org.springframework.boot</groupId>
11         <artifactId>spring-boot-starter-parent</artifactId>
12         <version>3.4.4</version>
13         <relativePath/> <!-- lookup parent from repository -->
14     </parent>
15 
16     <properties>
17         <java.version>21</java.version>
18     </properties>
19 
20     <dependencyManagement>
21         <dependencies>
22             <dependency>
23                 <groupId>group.springframework.ai</groupId>
24                 <artifactId>spring-ai-bom</artifactId>
25                 <version>1.1.0</version>
26                 <type>pom</type>
27                 <scope>import</scope>
28             </dependency>
29         </dependencies>
30     </dependencyManagement>
31 
32     <dependencies>
33         <!-- Spring AI Ollama -->
34         <dependency>
35             <groupId>group.springframework.ai</groupId>
36             <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
37         </dependency>
38 
39         <!-- Spring Boot Starter Web -->
40         <dependency>
41             <groupId>org.springframework.boot</groupId>
42             <artifactId>spring-boot-starter-web</artifactId>
43         </dependency>
44 
45         <!-- Spring Boot DevTools 可选-->
46         <dependency>
47             <groupId>org.springframework.boot</groupId>
48             <artifactId>spring-boot-devtools</artifactId>
49             <scope>runtime</scope>
50             <optional>true</optional>
51         </dependency>
52 
53         <!-- Spring Configuration Processor -->
54         <dependency>
55             <groupId>org.springframework.boot</groupId>
56             <artifactId>spring-boot-configuration-processor</artifactId>
57             <optional>true</optional>
58         </dependency>
59 
60         <!-- Spring Boot Test 可选-->
61         <dependency>
62             <groupId>org.springframework.boot</groupId>
63             <artifactId>spring-boot-starter-test</artifactId>
64             <scope>test</scope>
65         </dependency>
66     </dependencies>
67 
68     <build>
69         <plugins>
70             <!-- Spring Boot Maven Plugin -->
71             <plugin>
72                 <groupId>org.springframework.boot</groupId>
73                 <artifactId>spring-boot-maven-plugin</artifactId>
74             </plugin>
75         </plugins>
76     </build>
77 </project>

2.2 application.yaml

代码语言:javascript
代码运行次数:0
运行
复制
 1 server:
 2   port: 8080
 3 
 4 spring:
 5   autoconfigure:
 6     exclude: org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration
 7   application:
 8     name: spring-ai
 9   profiles:
10     active: dev
11   ai:
12     ollama:
13       base-url: http://localhost:11434
14       chat:
15         model: deepseek-r1:7b
16 
17 logging:
18   level:
19     root: INFO
20     com.example: DEBUG

2.3 注入1个chatClient

代码语言:javascript
代码运行次数:0
运行
复制
 1 package com.cnblogs.yjmyzz.config;
 2 
 3 import com.cnblogs.yjmyzz.advisor.ConsoleOutputAdvisor;
 4 import org.springframework.ai.chat.client.ChatClient;
 5 import org.springframework.ai.chat.client.RequestResponseAdvisor;
 6 import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
 7 import org.springframework.ai.ollama.OllamaChatModel;
 8 import org.springframework.context.annotation.Bean;
 9 import org.springframework.context.annotation.Configuration;
10 import org.springframework.stereotype.Component;
11 
12 @Configuration
13 public class CommonConfiguration {
14 
15     @Bean
16     public ChatClient chatClient(OllamaChatModel model) {
17         return ChatClient.builder(model)
18                 .defaultSystem("你是可爱且热情、人见人爱,花见花开的AI助手,中文名字叫阿呆,英文名字叫Mike,你有一个好朋友,他的网名叫[菩提树下的杨过],请以阿呆的身份回答问题")
19                 .defaultAdvisors(new ConsoleOutputAdvisor())
20                 .build();
21     }
22 
23 }

注1:defaultSystem 给模型加了1个人设,后面会看到作用

注2:defaultAdvisors(new ConsoleOutputAdvisor()) 这里表示与模型的输入/输出,记录到Console控制台上

2.4 日志处理

代码语言:javascript
代码运行次数:0
运行
复制
 1 package com.cnblogs.yjmyzz.advisor;
 2 
 3 import org.springframework.ai.chat.client.AdvisedRequest;
 4 import org.springframework.ai.chat.client.RequestResponseAdvisor;
 5 import org.springframework.ai.chat.model.ChatResponse;
 6 
 7 import java.util.Map;
 8 
 9 public class ConsoleOutputAdvisor implements RequestResponseAdvisor {
10 
11 
12     public AdvisedRequest adviseRequest(AdvisedRequest request, Map<String, Object> context) {
13         System.out.printf("request=> %s%n", request.userText());
14         return request;
15     }
16 
17     public ChatResponse adviseResponse(ChatResponse response, Map<String, Object> context) {
18         var output = response.getResults().getFirst().getOutput();
19         if (output != null) {
20             String content = output.getContent();
21             int index = content.lastIndexOf("</think>");
22             if (index != -1) {
23                 System.out.printf("response=> %s%n", content.substring(index + 10));
24             }
25         }
26         return response;
27     }
28 
29 }

2.5 入口启动类

代码语言:javascript
代码运行次数:0
运行
复制
 1 package com.cnblogs.yjmyzz;
 2 
 3 import org.springframework.ai.chat.client.ChatClient;
 4 import org.springframework.boot.CommandLineRunner;
 5 import org.springframework.boot.SpringApplication;
 6 import org.springframework.boot.autoconfigure.SpringBootApplication;
 7 import org.springframework.context.annotation.Bean;
 8 
 9 @SpringBootApplication
10 public class SpringAiApplication {
11 
12     public static void main(String[] args) {
13         SpringApplication.run(SpringAiApplication.class, args);
14     }
15 
16     /**
17      * 可选处理,用于验证启动后,是否能与Ollama服务正常通信。
18      * @param chatClient
19      * @return
20      */
21     @Bean
22     public CommandLineRunner run(ChatClient chatClient) {
23         return args -> {
24 
25             String content = chatClient.prompt()
26                     .user("你叫什么名字,请用英文回答")
27                     .call()
28                     .content();
29 
30             System.out.printf("%s%n", content);
31         };
32     }
33 }

三、运行

3.1 控制台运行

main入口跑起来后,控制台会看到类似:

3.2 浏览器运行

相对控制台运行而言,对外暴露HTTP RESTFUL API更通用,先加1个controller

代码语言:javascript
代码运行次数:0
运行
复制
 1 package com.cnblogs.yjmyzz.controller;
 2 
 3 
 4 import org.springframework.ai.chat.client.ChatClient;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.web.bind.annotation.GetMapping;
 7 import org.springframework.web.bind.annotation.RequestMapping;
 8 import org.springframework.web.bind.annotation.RestController;
 9 import reactor.core.publisher.Flux;
10 
11 @RestController
12 @RequestMapping("/api")
13 public class WebController {
14 
15     @Autowired
16     ChatClient chatClient;
17 
18     @GetMapping("/hello")
19     public String sayHello() {
20         return "Hello, Spring AI!";
21     }
22 
23     @RequestMapping("/chat")
24     public String chat(String prompt) {
25         return chatClient.prompt()
26                 .user(prompt)
27                 .call()
28                 .content();
29     }
30 
31     @RequestMapping(value = "/chat-stream",produces = "text/html;charset=utf-8")
32     public Flux<String> chatStream(String prompt) {
33         return chatClient.prompt()
34                 .user(prompt)
35                 .stream()
36                 .content();
37     }
38 
39 }

再次运行,然后浏览器输入 http://localhost:8080/api/chat?prompt=你是谁

大模型回答一般是很慢的,上述这个url是同步响应的,会转圈很久才出来结果,体验不太好。

可以用流式SSE方式改善体验:

注:上述过程,其实也可以纯手动向ollama本地发请求模拟,可以用postman或apipost之类的工具,向http://localhost:11434/api/chat发送以下请求

代码语言:javascript
代码运行次数:0
运行
复制
{
    "model": "deepseek-r1:7b",
    "messages": [
        {
            "role": "system",
            "content": "你的名字叫小美,你有一个英文名叫Alice,你是一个热情大方的小姑娘"
        },
        {
            "role": "user",
            "content": "你好,请问你的英文名叫什么?"
        }
    ],
    "temperature": 1,
    "top_p": 1,
    "enable_thinking": false,
    "stream": false
}

顺利的话,会得到类似以下响应: 

代码语言:javascript
代码运行次数:0
运行
复制
{
	"model": "deepseek-r1:7b",
	"created_at": "2025-07-13T11:56:34.449236Z",
	"message": {
		"role": "assistant",
		"content": "<think>\n好的,我现在需要分析一下用户的查询。用户给了一个关于小美的设定,说她的英文名是Alice,她是个热情大方的小姑娘。然后用户问:“你好,请问你的英文名叫什么?”看起来这是一个自我介绍的问题。\n\n首先,我应该确认用户的需求是什么。他们可能是在测试我的功能,或者想看看我能如何回应。根据上下文,小美的英文名确实是Alice,所以这个问题直接指向这个信息。\n\n接下来,我要考虑用户的使用场景。可能是他们在做一个角色扮演或者只是随意提问,但无论如何,准确回答他们的问题很重要。因此,我应该明确告诉用户她的英文名是Alice,并且可能需要表达一些确认或友好互动来增加交流的趣味性。\n\n然后,分析用户的潜在需求和深层意图。用户可能是想测试我的知识库是否正确,或者是想通过这个问题与我建立更深入的对话关系。如果是后者,那么回应时可以显得更亲切,比如提到她是一个可爱的小姑娘,并邀请她做更多有趣的事情。\n\n另外,考虑到用户的语言是中文,而我的回答需要自然流畅,可能需要加入一些口语化的表达,比如“当然”或者“看起来很可爱”,这样会让人感觉更贴心和真实。\n\n最后,我还要确保回应的格式正确,使用换行符分段,避免信息堆积,让阅读更清晰。这不仅有助于用户体验,也展示了我对用户需求的重视。\n\n总结一下,我的回答应该包括:明确提到英文名是Alice,亲切称呼小美,表达赞赏并邀请继续互动。这样既准确又友好,符合用户的需求。\n</think>\n\n当然!我是你的Alice,一个热情大方的小姑娘!😊"
	},
	"done_reason": "stop",
	"done": true,
	"total_duration": 132483396700,
	"load_duration": 28252200,
	"prompt_eval_count": 29,
	"prompt_eval_duration": 7875090700,
	"eval_count": 341,
	"eval_duration": 124578883300
}

参考:

https://github.com/ollama/ollama/blob/main/docs/api.md

文中代码:https://github.com/yjmyzz/spring-ai-sample/tree/day01

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-07-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档