SpringBoot 集成 LangChain4j 本地调用 Ollama
- [1 Ollama 软件下载](#1 Ollama 软件下载)
- [2 Ollama 模型下载](#2 Ollama 模型下载)
-
- [2.1 PowerShell 下载脚本](#2.1 PowerShell 下载脚本)
- [2.2 Ollama模型运行](#2.2 Ollama模型运行)
- [3 SpringBoot 集成 LangChain4j](#3 SpringBoot 集成 LangChain4j)
-
- [3.1 pom依赖](#3.1 pom依赖)
- [3.2 yml配置](#3.2 yml配置)
- [3.3 bean配置](#3.3 bean配置)
- [3.4 无记忆](#3.4 无记忆)
- [3.5 有记忆](#3.5 有记忆)
- [5 SpringBoot 运行测试](#5 SpringBoot 运行测试)
1 Ollama 软件下载
2 Ollama 模型下载
2.1 PowerShell 下载脚本
复制内容到ollama_download.ps1文件中
powershell
# 定义模型名称避免硬编码
$modelName = "gemma3:27b"
# 设置重试参数
$maxRetries = 50
$retryInterval = 3 # 秒
$downloadTimeout = 80 # 秒
for ($retry = 1; $retry -le $maxRetries; $retry++) {
# 精确检查模型是否存在
$modelExists = ollama list | Where-Object { $_ -match "\b$modelName\b" }
if ($modelExists) {
Write-Host "[$(Get-Date)] model is already downloaded!"
exit 0
}
Write-Host "[$(Get-Date)] start $retry times downloading..."
# 启动进程并显示实时输出
$process = Start-Process -FilePath "ollama" `
-ArgumentList "run", $modelName `
-PassThru `
-NoNewWindow
# 等待下载完成或超时
try {
$process | Wait-Process -Timeout $downloadTimeout -ErrorAction Stop
} catch {
# 超时处理
Write-Host "download timeout, safe terminate process..."
$process | Stop-Process -Force
}
if (-not $process.HasExited) {
$process | Stop-Process -Force
Write-Host "process terminated due to timeout."
} else {
# 检查退出代码
if ($process.ExitCode -eq 0) {
Write-Host "download success!"
exit 0
}
Write-Host "download failed, exit code: $($process.ExitCode)"
}
Start-Sleep -Seconds $retryInterval
}
Write-Host "exceeded maximum retries ($maxRetries), download failed."
exit 1
powershell
PS C:\Users\xuhya\Desktop> .\ollama_download.ps1
[10/09/2025 21:42:20] start 1 times downloading...
pulling manifest
pulling e796792eba26: 98% ▕████████████████████████████████████████████████████████ ▏ 17 GB/ 17 GB 1.7 MB/s 3m20sdownload timeout, safe terminate process...
download failed, exit code: -1
[10/09/2025 21:43:43] start 2 times downloading...
pulling manifest
pulling e796792eba26: 100% ▕██████████████████████████████████████████████████████████▏ 17 GB
pulling e0a42594d802: 100% ▕██████████████████████████████████████████████████████████▏ 358 B
pulling dd084c7d92a3: 100% ▕██████████████████████████████████████████████████████████▏ 8.4 KB
pulling 3116c5225075: 100% ▕██████████████████████████████████████████████████████████▏ 77 B
pulling f838f048d368: 100% ▕██████████████████████████████████████████████████████████▏ 490 B
verifying sha256 digest ⠸ download timeout, safe terminate process...
download failed, exit code: -1
[10/09/2025 21:45:06] start 3 times downloading...
pulling manifest
pulling e796792eba26: 100% ▕██████████████████████████████████████████████████████████▏ 17 GB
pulling e0a42594d802: 100% ▕██████████████████████████████████████████████████████████▏ 358 B
pulling dd084c7d92a3: 100% ▕██████████████████████████████████████████████████████████▏ 8.4 KB
pulling 3116c5225075: 100% ▕██████████████████████████████████████████████████████████▏ 77 B
pulling f838f048d368: 100% ▕██████████████████████████████████████████████████████████▏ 490 B
verifying sha256 digest
writing manifest
success
⠏ download timeout, safe terminate process...
download failed, exit code: -1
[10/09/2025 21:46:29] model is already downloaded!
PS C:\Users\xuhya\Desktop>
2.2 Ollama模型运行
powershell
PS C:\Users\xuhya\Desktop> ollama list
NAME ID SIZE MODIFIED
gemma3:27b a418f5838eaf 17 GB 2 minutes ago
gemma3:latest a2af6cc3eb7f 3.3 GB 7 minutes ago
PS C:\Users\xuhya\Desktop>

3 SpringBoot 集成 LangChain4j
3.1 pom依赖
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xu</groupId>
<artifactId>lang-chain</artifactId>
<version>1.0.0</version>
<name>lang-chain</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>25</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-bom</artifactId>
<version>1.6.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.2 yml配置
yml
server:
port: 8080
spring:
application:
name: lang-chain
logging:
file:
name: logs/spring-oracle.log
level:
root: INFO
com.xu: INFO
langchain4j:
ollama:
chat-model:
base-url: http://127.0.0.1:11434
model-name: gemma3:latest
3.3 bean配置
java
package com.xu.conf;
import dev.langchain4j.http.client.spring.restclient.SpringRestClientBuilder;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.ollama.OllamaChatModel;
import dev.langchain4j.model.ollama.OllamaStreamingChatModel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
@Configuration
public class OllamaConfig {
@Value("${langchain4j.ollama.chat-model.model-name}")
private String modelName;
@Value("${langchain4j.ollama.chat-model.base-url}")
private String baseUrl;
@Bean
public OllamaChatModel ollamaChatModel() {
return OllamaChatModel.builder()
.modelName(modelName)
.baseUrl(baseUrl)
.httpClientBuilder(new SpringRestClientBuilder())
.timeout(Duration.ofHours(10)) // 超时时间
.maxRetries(3) // 超时最大重试次数
.build();
}
@Bean
public ChatMemory chatMemory() {
return MessageWindowChatMemory.withMaxMessages(10); // 最多保存10条消息
}
@Bean
public OllamaStreamingChatModel ollamaStreamingChatModel() {
return OllamaStreamingChatModel.builder()
.modelName(modelName)
.baseUrl(baseUrl)
.httpClientBuilder(new SpringRestClientBuilder())
.timeout(Duration.ofHours(10)) // 超时时间
// 其他参数(可选):温度值(0.0-1.0,越低越确定)
.temperature(0.7)
.build();
}
}
3.4 无记忆
java
package com.xu.chat.controller;
import dev.langchain4j.data.message.TextContent;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.request.ChatRequest;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.ollama.OllamaChatModel;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@AllArgsConstructor
@RequestMapping("/ollama")
public class OllamaController {
private final OllamaChatModel ollama;
@GetMapping("/model/chat")
public Object chat(@RequestParam(value = "message", defaultValue = "你好") String message) {
ChatRequest request = ChatRequest.builder().messages(UserMessage.userMessage(TextContent.from(message))).build();
ChatResponse chat = ollama.chat(request);
return chat.aiMessage().text();
}
}
3.5 有记忆
java
package com.xu.chat.controller;
import dev.langchain4j.data.message.TextContent;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.model.chat.request.ChatRequest;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.ollama.OllamaChatModel;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@AllArgsConstructor
@RequestMapping("/ollama/memory")
public class MemoryController {
private final OllamaChatModel ollama;
private final ChatMemory chatMemory;
@GetMapping("/model/chat")
public Object chat(@RequestParam(value = "message", defaultValue = "你好") String message) {
// 将用户消息添加到聊天历史
UserMessage userMessage = UserMessage.userMessage(TextContent.from(message));
chatMemory.add(userMessage);
// 构建包含历史记录的请求
ChatRequest request = ChatRequest.builder()
.messages(chatMemory.messages())
.build();
// 获取模型响应
ChatResponse response = ollama.chat(request);
var aiMessage = response.aiMessage();
// 将 AI 响应也加入聊天历史
chatMemory.add(aiMessage);
return aiMessage;
}
}
5 SpringBoot 运行测试
java
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.5.6)
2025-10-09T21:59:48.238+08:00 INFO 20840 --- [lang-chain] [ restartedMain] com.xu.LangChainApplication : Starting LangChainApplication using Java 25 with PID 20840 (D:\SourceCode\Learn\lang-chain\target\classes started by xuhya in D:\SourceCode\Learn\lang-chain)
2025-10-09T21:59:48.241+08:00 INFO 20840 --- [lang-chain] [ restartedMain] com.xu.LangChainApplication : No active profile set, falling back to 1 default profile: "default"
2025-10-09T21:59:48.317+08:00 INFO 20840 --- [lang-chain] [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2025-10-09T21:59:48.317+08:00 INFO 20840 --- [lang-chain] [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2025-10-09T21:59:49.575+08:00 INFO 20840 --- [lang-chain] [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2025-10-09T21:59:49.595+08:00 INFO 20840 --- [lang-chain] [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2025-10-09T21:59:49.601+08:00 INFO 20840 --- [lang-chain] [ restartedMain] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.46]
2025-10-09T21:59:49.649+08:00 INFO 20840 --- [lang-chain] [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2025-10-09T21:59:49.649+08:00 INFO 20840 --- [lang-chain] [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1331 ms
2025-10-09T21:59:50.163+08:00 INFO 20840 --- [lang-chain] [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2025-10-09T21:59:50.208+08:00 INFO 20840 --- [lang-chain] [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2025-10-09T21:59:50.221+08:00 INFO 20840 --- [lang-chain] [ restartedMain] com.xu.LangChainApplication : Started LangChainApplication in 2.791 seconds (process running for 3.655)
