Spring AI + Ollama简单使用

发布时间:2026/6/30 5:00:46
Spring AI + Ollama简单使用 一、环境准备1. 前置条件本地安装 Ollama启动服务默认地址http://localhost:11434拉取任意模型示例用 qwen3.5:4b轻量快速docker exec -it ollama ollama run qwen3.5:4bSpringBoot 4.x 项目2. Maven 依赖 pom.xml?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version4.1.0/version relativePath/ !-- lookup parent from repository -- /parent groupIdcom.ybw/groupId artifactIdspring-ai-demo/artifactId version1.0.0/version namespring-ai-demo/name descriptionspring-ai-demo/description modules modulequick-start/module /modules packagingpom/packaging properties java.version21/java.version spring-ai.version2.0.0/spring-ai.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-webmvc/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-ollama/artifactId /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-webmvc-test/artifactId scopetest/scope /dependency /dependencies dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version${spring-ai.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration excludes exclude groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /exclude /excludes /configuration /plugin plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-compiler-plugin/artifactId executions execution iddefault-compile/id phasecompile/phase goals goalcompile/goal /goals configuration annotationProcessorPaths path groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /path /annotationProcessorPaths /configuration /execution execution iddefault-testCompile/id phasetest-compile/phase goals goaltestCompile/goal /goals configuration annotationProcessorPaths path groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /path /annotationProcessorPaths /configuration /execution /executions /plugin /plugins /build /project二、配置文件 application.ymlspring: application: name: spring-ai-demo ai: ollama: base-url: http://127.0.0.1:11434 chat: model: qwen3.5:4b # 模型 temperature: 0.7 # 温度数值越高输出结果越随机数值越低输出结果越一致。范围0-1 top-p: 0.7 # 概率 think: true # 是否思考温度temperature 取值范围0 ~ 1核心逻辑数值越大模型随机性、创造性越强数值越小输出越确定、严谨、重复度低。温度区间核心风格推荐业务场景0严谨、统一、无幻觉代码、SQL、结构化输出、数学、标准问答0.1~0.3专业、精准、轻微灵活技术 / 法律 / 医疗专业问答、文档解析0.4~0.7均衡自然默认日常聊天、科普、工作总结、普通文案0.8~0.9高创意、发散写诗、故事、策划、起名、脑洞创作1.0极致随机纯艺术自由创作极少业务使用三、配置类 测试 Demo配置 ChatClientpackage com.ybw.config; import org.springframework.ai.chat.client.ChatClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 配置 ChatClient * * author ybw * version V1.0 * className ChatClientConfig * date 2026/6/29 **/ Configuration public class ChatClientConfig { /** * 注入 ChatClientSpringAI 自动装配 OllamaChatModel * * param builder 构建 ChatClient * methodName: chatClient * return: org.springframework.ai.chat.client.ChatClient * author: ybw * date: 2026/6/29 **/ Bean ChatClient chatClient(ChatClient.Builder builder) { return builder.build(); } }单元测试无思考过程package com.ybw; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.ai.chat.client.ChatClient; import org.springframework.boot.test.context.SpringBootTest; /** * 测试ollama * * author ybw * version V1.0 * className TestOllama * date 2026/6/29 **/ SpringBootTest Slf4j public class TestOllama { Resource private ChatClient chatClient; /** * 测试ollama:简单聊天demo,打印出聊天结果 */ Test public void testOllama() { // 1. 单次简单提问 String prompt 请写一首描述清晨的诗; log.info( 用户提问{} , prompt); // 同步调用 ollama获取完整返回文本 String response chatClient.prompt() .user(prompt) .call() .content(); // 打印大模型回答 log.info( Ollama 返回结果 ); log.info(response); log.info(); // 2. 多轮对话示例携带上下文 log.info( 多轮对话测试 ); String multiRoundRes chatClient.prompt() .user(什么是Java) .system(你是简洁的编程讲师回答不超过两句话) .call() .content(); log.info(multiRoundRes); } /** * 测试ollama:流式输出聊天结果 */ Test public void testOllamaStream() { // 流式响应逐段打印 chatClient.prompt() .user(写一段100字的春日短文) .stream() .content() .doOnNext(System.out::print) .blockLast(); } }流式输出逐行实时打印类似打字机效果有思考过程package com.ybw; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.boot.test.context.SpringBootTest; import reactor.core.publisher.Flux; import java.util.Map; /** * 测试ollama思考过程 * * author ybw * version V1.0 * className TestThinkOllama * date 2026/6/29 **/ SpringBootTest Slf4j public class TestThinkOllama { Resource private ChatClient chatClient; /** * 测试ollama:思考过程 */ Test public void testThinkOllama() { //1. 创建一个 Prompt String prompt java是什么; log.info( 用户提问{} , prompt); //2. 调用 ollama ChatResponse chatResponse chatClient.prompt() .user(prompt) .call() .chatResponse(); // 3. 关键修改获取完整输出内容 AssistantMessage assistantMessage chatResponse.getResult().getOutput(); // 3.1 获取思考过程从 metadata 中提取 MapString, Object metadata assistantMessage.getMetadata(); String thinking metadata.get(thinking).toString(); log.info( 思考过程 ); log.info(thinking); // 3.2 获取最终答案 String finalAnswer assistantMessage.getText(); log.info( 最终答案 ); log.info(finalAnswer); } /** * 测试ollama:流式输出聊天结果 */ Test public void testThinkOllamaStream() { //1. 最终结果存储 StringBuilder finishThinkingStr new StringBuilder(); StringBuilder finishAnswerStr new StringBuilder(); //1. 流式响应逐段打印 FluxChatResponse chatResponseFlux chatClient.prompt() .user(你好) .stream() .chatResponse(); // 2. 逐段打印 chatResponseFlux.doOnNext(chatResponse - { // 2.1 获取完整输出内容 AssistantMessage assistantMessage chatResponse.getResult().getOutput(); // 2.2 获取思考过程从 metadata 中提取 MapString, Object metadata assistantMessage.getMetadata(); Object thinking metadata.get(thinking); if (thinking ! null) { String thinkingStr thinking.toString(); // 灰色显示思考过程 System.out.print(\u001B[90m thinkingStr \u001B[0m); finishThinkingStr.append(thinkingStr); } else { //只有刚开始打印的时候换一次行 if (finishAnswerStr.isEmpty()) { System.out.println(); } // 2.3 获取最终答案 String finalAnswer assistantMessage.getText(); System.out.print(finalAnswer); finishAnswerStr.append(finalAnswer); } }).doOnComplete(() - { System.out.println(); log.info(思考:{}, finishThinkingStr); log.info(回复:{}, finishAnswerStr); }) // 等待流结束 .blockLast(); } }