SpringBoot 集成 LangChain4j 本地调用 Ollama

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 软件下载

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)
相关推荐
卷心菜的学习路10 小时前
《计算》第九十章读书笔记
java·读书笔记·编程思维
开始学AI10 小时前
【Docker技术】docker-compose.yml与Dockerfile解析
java·docker·eureka
写代码的小阿帆13 小时前
Java体系总结——从基础语法到微服务
java·微服务·学习方法
SUPER526615 小时前
FastApi项目启动失败 got an unexpected keyword argument ‘loop_factory‘
java·服务器·前端
咕噜咕噜啦啦16 小时前
Eclipse集成开发环境的使用
java·ide·eclipse
光军oi18 小时前
全栈开发杂谈————关于websocket若干问题的大讨论
java·websocket·apache
weixin_4196583119 小时前
Spring 的统一功能
java·后端·spring
小许学java19 小时前
Spring AI-流式编程
java·后端·spring·sse·spring ai
haogexiaole20 小时前
Java高并发常见架构、处理方式、api调优
java·开发语言·架构