java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java调用本地大模型

Java直接调用本地大模型文件实现对话机器人

作者:水上冰石

这篇文章主要为大家详细介绍了Java直接调用本地大模型文件实现对话机器人的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下

demo背景

作为java程序员,我们如果直接调用springai框架作为深入学习大模型的技术的话,会发现在进行文生图或者文本对话的时候,要么依赖本地的ollama,要么是直接对接官方开放的api接口。哪怕再底层一些,也是写方法调用python或者c语言,最终实现调用第三方功能来完成大模型的调用。但是这种方式并不是非常简便的方法。对于java开发者而言,直接通过springboot项目+大模型文件来实现一个大模型项目是最简单并且可控性最强的。那么这种方式能否实现呢?

答案是肯定的,我们这里介绍其中一种方法:Jlama 

本文通过一个demo例子,来完成整个实验的验证。

最终的项目结构如下:

springboot-jlama-demo/
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── jlama
│   │   │               ├── SpringBootJlamaDemoApplication.java
│   │   │               ├── config
│   │   │               │   └── JlamaConfig.java
│   │   │               ├── controller
│   │   │               │   └── ChatController.java
│   │   │               ├── dto
│   │   │               │   └── ChatRequest.java
│   │   │               └── service
│   │   │                   └── JlamaService.java
│   │   └── resources
│   │       ├── application.yml
│   │       └── static
│   │           └── index.html
│   └── test
│       └── java
│           └── com
│               └── example
│                   └── jlama
│                       └── SpringBootJlamaDemoApplicationTests.java

第一步:准备环境

JDK 版本:Jlama 需要 JDK 21 及以上的版本。

开发工具:一个趁手的 IDE(如 IntelliJ IDEA 或 VS Code)应该已经准备好了。

第二步:构建项目骨架

我们用一个最小化的 Spring Boot 项目就能开始,​​pom.xml​​ 是关键配置。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         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.2.0</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot-jlama-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-jlama-demo</name>
    <description>Demo project for Spring Boot + Jlama with DeepSeek 4B</description>
    <properties>
        <java.version>21</java.version>
        <jlama.version>0.8.4</jlama.version>
        <langchain4j.version>1.0.0-beta1</langchain4j.version>
    </properties>
    <dependencies>
        <!-- Spring Boot Web 启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Spring Boot Thymeleaf 启动器,用于渲染 HTML 页面 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- Spring Boot DevTools,用于热重载 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!-- Jlama 核心库 -->
        <dependency>
            <groupId>com.github.tjake</groupId>
            <artifactId>jlama-core</artifactId>
            <version>${jlama.version}</version>
        </dependency>
        <!-- Jlama 原生库,会自动适应操作系统 -->
        <dependency>
            <groupId>com.github.tjake</groupId>
            <artifactId>jlama-native</artifactId>
            <version>${jlama.version}</version>
            <classifier>${os.detected.classifier}</classifier>
        </dependency>
        <!-- LangChain4j 核心库 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>
        <!-- LangChain4j Jlama 集成库 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-jlama</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- Maven 编译器插件,配置 JVM 参数 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                    <compilerArgs>
                        <arg>--add-modules=jdk.incubator.vector</arg>
                        <arg>--enable-preview</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
            <!-- Spring Boot Maven 插件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!-- os-maven-plugin,用于检测操作系统 -->
            <plugin>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.7.0</version>
                <executions>
                    <execution>
                        <phase>initialize</phase>
                        <goals>
                            <goal>detect</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

第三步:编写后端服务

1. 配置模型加载 (​​JlamaConfig.java​​)

我们需要一个专门的配置类来加载模型,确保它在应用启动时是单例的,这样能最大程度地节省内存。

// src/main/java/com/example/jlama/config/JlamaConfig.java
package com.example.jlama.config;

import com.github.tjake.jlama.model.AbstractModel;
import com.github.tjake.jlama.model.ModelSupport;
import com.github.tjake.jlama.safetensors.DType;
import com.github.tjake.jlama.util.Downloader;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.jlama.JlamaChatModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.File;
import java.io.IOException;

@Configuration
public class JlamaConfig {

    private static final Logger logger = LoggerFactory.getLogger(JlamaConfig.class);

    // 从 application.yml 读取模型路径和名称
    @Value("${jlama.model.path}")
    private String modelPath;

    @Bean
    public ChatLanguageModel chatLanguageModel() throws IOException {
        logger.info("正在加载模型: {}", modelPath);
        
        // 如果本地模型不存在,Jlama 会尝试从 Hugging Face 下载
        // 模型路径可以是本地文件夹路径,也可以是 Hugging Face 的模型名称
        File localModelPath = new Downloader("./models", modelPath).huggingFaceModel();
        
        // 使用 LangChain4j 提供的 JlamaChatModel 来构建模型实例
        // 这里传入模型路径、工作数据类型和量化数据类型
        // AbstractModel model = ModelSupport.loadModel(localModelPath, DType.F32, DType.I8);
        
        // 使用 JlamaChatModel 简化配置
        ChatLanguageModel model = JlamaChatModel.builder()
                .modelName(modelPath) // 使用 modelPath 作为模型名称
                .temperature(0.7f)    // 设置温度参数,控制随机性
                .build();
        
        logger.info("模型加载完成。");
        return model;
    }
}

2. 定义 API 请求格式 (​​ChatRequest.java​​)

定义一个简单的 DTO(数据传输对象)来处理前端发来的请求。

// src/main/java/com/example/jlama/dto/ChatRequest.java
package com.example.jlama.dto;

public class ChatRequest {
    private String prompt;

    // Getters and Setters
    public String getPrompt() {
        return prompt;
    }

    public void setPrompt(String prompt) {
        this.prompt = prompt;
    }
}

3. 实现核心业务逻辑 (​​JlamaService.java​​)

在 Service 层,我们将注入刚刚配置好的 ​​ChatLanguageModel​​,并编写一个方法来调用它。

// src/main/java/com/example/jlama/service/JlamaService.java
package com.example.jlama.service;

import dev.langchain4j.model.chat.ChatLanguageModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class JlamaService {

    private static final Logger logger = LoggerFactory.getLogger(JlamaService.class);
    private final ChatLanguageModel model;

    // 构造器注入 ChatLanguageModel
    public JlamaService(ChatLanguageModel model) {
        this.model = model;
    }

    public String generateResponse(String prompt) {
        logger.info("收到请求: {}", prompt);
        // 调用模型生成响应
        String response = model.generate(prompt);
        logger.info("生成完成");
        return response;
    }
}

4. 创建 REST 控制器 (​​ChatController.java​​)

最后,创建一个 Controller 来暴露 API,处理前端的请求。

// src/main/java/com/example/jlama/controller/ChatController.java
package com.example.jlama.controller;

import com.example.jlama.dto.ChatRequest;
import com.example.jlama.service.JlamaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import java.util.HashMap;

@RestController
@RequestMapping("/api")
public class ChatController {

    @Autowired
    private JlamaService jlamaService;

    @PostMapping("/chat")
    public Map<String, String> chat(@RequestBody ChatRequest request) {
        String response = jlamaService.generateResponse(request.getPrompt());
        Map<String, String> result = new HashMap<>();
        result.put("response", response);
        return result;
    }
}

第四步:创建 Web 交互界面

创建 HTML 页面 (​index.html​):在 ​​src/main/resources/static​​ 目录下创建 ​​index.html​​ 文件。

编写前端代码 (​index.html​):编辑 ​​index.html​​,实现一个简单的聊天界面。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>DeepSeek 本地助手</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
        }
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            overflow: hidden;
        }
        .header {
            background: #1a1a2e;
            color: white;
            padding: 20px;
            text-align: center;
        }
        .chat-box {
            height: 400px;
            overflow-y: auto;
            padding: 20px;
            background: #f9f9f9;
        }
        .message {
            margin-bottom: 15px;
            padding: 10px 15px;
            border-radius: 10px;
            max-width: 80%;
            word-wrap: break-word;
        }
        .user {
            background: #007bff;
            color: white;
            margin-left: auto;
            text-align: right;
        }
        .assistant {
            background: #e9ecef;
            color: #333;
            margin-right: auto;
        }
        .input-area {
            display: flex;
            padding: 20px;
            background: white;
            border-top: 1px solid #ddd;
        }
        .input-area input {
            flex: 1;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 14px;
        }
        .input-area button {
            margin-left: 10px;
            padding: 10px 20px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
        .input-area button:hover {
            background: #0056b3;
        }
        .loading {
            text-align: center;
            color: #666;
            padding: 10px;
            display: none;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🤖 DeepSeek 本地助手</h1>
            <p>基于 Jlama 和 DeepSeek 4B 模型</p>
        </div>
        <div id="chat-box" class="chat-box">
            <div class="message assistant">
                你好!我是 DeepSeek 本地助手,有什么我可以帮你的吗?
            </div>
        </div>
        <div id="loading" class="loading">思考中...</div>
        <div class="input-area">
            <input type="text" id="user-input" placeholder="输入你的问题..." />
            <button id="send-btn">发送</button>
        </div>
    </div>
    <script>
        const chatBox = document.getElementById('chat-box');
        const userInput = document.getElementById('user-input');
        const sendBtn = document.getElementById('send-btn');
        const loading = document.getElementById('loading');
        function appendMessage(text, sender) {
            const messageDiv = document.createElement('div');
            messageDiv.className = `message ${sender}`;
            messageDiv.textContent = text;
            chatBox.appendChild(messageDiv);
            chatBox.scrollTop = chatBox.scrollHeight;
        }
        async function sendMessage() {
            const prompt = userInput.value.trim();
            if (!prompt) return;
            appendMessage(prompt, 'user');
            userInput.value = '';
            loading.style.display = 'block';
            try {
                const response = await fetch('/api/chat', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({ prompt: prompt }),
                });
                if (!response.ok) {
                    throw new Error('网络响应失败');
                }
                const data = await response.json();
                appendMessage(data.response, 'assistant');
            } catch (error) {
                console.error('Error:', error);
                appendMessage('抱歉,发生了错误。请检查后端服务是否正常运行。', 'assistant');
            } finally {
                loading.style.display = 'none';
            }
        }
        sendBtn.addEventListener('click', sendMessage);
        userInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter') {
                sendMessage();
            }
        });
    </script>
</body>
</html>

第五步:运行与测试

  1. 编译与构建:打开终端,进入项目根目录,执行 ​​mvn clean compile​​,让 Maven 来下载所有依赖。
  2. 启动应用:在 IDE 中右键运行 ​​SpringBootJlamaDemoApplication.java​​ 的 ​​main​​ 方法。
  3. 访问界面:打开浏览器,访问 ​​http://localhost:8080​​,就可以看到聊天界面了。

高级配置:使用本地模型

如果你想使用下载好的本地模型,只需修改 ​​src/main/resources/application.yml​​ 文件即可。

# src/main/resources/application.yml
jlama:
  model:
    # 使用本地路径
    path: /absolute/path/to/your/deepseek-4b-model

常见问题与解决

Q1: 模型加载失败怎么办?

A: 如果模型需要从 Hugging Face 下载,你可以手动下载 ​​.safetensors​​ 文件和 ​​config.json​​,然后将它们放在项目的 ​​./models​​ 文件夹下。修改 ​​application.yml​​ 中的 ​​path​​ 为本地的模型文件夹路径即可。

Q2: 为什么我的想法与代码不一致?

A: 正如你提到的,本地加载其实指向的是 Hugging Face 模型名,这背后是 Jlama 自动处理了下载与缓存。我们可以优化 ​​JlamaConfig.java​​,让模型真正“离线”。例如,使用 ​​ModelSupport.loadModel​​ 方式,或自定义模型加载路径。

以上就是Java直接调用本地大模型文件实现对话机器人的详细内容,更多关于Java调用本地大模型的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文