使用SpringAI快速实现离线/本地大模型应用

前言

大模型(LLM),Large Language Model作为当前比较热门的技术,最近在年在各行各业中都得到了广泛的应用。

在我们目前使用较多的AI产品中,几乎都是使用的互联网(云端)上的AI工具,即:需要先把数据传输给AI平台,由AI平台处理后,再将信息回馈到我们的本地应用。

然而在许多领域,由于大模型的数据没有采集到更细化的信息,亦或者出于安全原因某些数据不能对外公开,这时使用离线大模型 来实现信息生成与检索则变得非常重要。

很久没用Spring的我,最近看到Spring官网出了Spring AI这个框架,出于好奇体验了下感觉非常不错,在此写篇博文记录下。

本文重点为:如何快速从0到1搭建一个离线大模型,并使用SpringAI进行交互调用。

ollama介绍与安装

ollama作为一个工具(且开源),让大模型的安装与运行变得非常简单。

ollama支持多种操作系统,为了方便可以直接使用Docker运行。

下载命令一行搞定:

sudo docker pull ollama/ollama:latest

ollama上手

ollama下载好后,直接运行

#运行ollama,并指定挂载目录和映射端口

docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama

#进入ollama容器

docker exec -it ollama bash

#运行ollama命令pull一个大模型,这里拉取具有图像识别能力的minicpm-v

ollama pull minicpm-v

ollama支持的大模型非常多,如google的gemma、facebook的llama、阿里的qwen通通都有,按需所取。

模型仓库地址为:https://ollama.com/library

大模型下载好了后,就可以使用ollama run命令运行对应的模型,并可以进行命令行的文本交互

ollama run minicpm-v

open-webui安装

为了能获得更好的体验,可以使用开源的open-webui进行来访问离线大模型,UI界面和ChatGPT的非常像。

docker下拉取命令:

sudo docker pull ghcr.io/open-webui/open-webui:main

拉取好后直接运行:

docker run -d --network=host -v open-webui:/app/backend/data -e OLLAMA_BASE_URL=http://127.0.0.1:11434 --name open-webui --restart always ghcr.io/open-webui/open-webui:main

这里笔者为了方便使用的是host网络,默认暴露的端口为8080 ,指定了webui存储数据的目录为/app/backend/data,并指定了ollama的后端地址为http://127.0.0.1:11434

基本功能体验

通过上面几行命令安装好了ollama与open-webui,之后就可以体验下离线大模型的常用功能了。

访问方式:直接访问open-webui的ip+port 就行。

如我这里的docker物理机为192.168.140.8 ,则访问地址为http://192.168.140.8:8080

智能对话

首次访问open-webui需要先本地注册,随便填一个账号信息就行,并且首次注册的账号也是管理员账号。

由于我前面下载的大模型为minicpm-v,它是支持中文,效果如下:

图片识别

minicpm-v的介绍所述

minicpm-v模型 支持图像视频 识别,传一个兴隆湖 的照片让它试一下。

识别效果也还可以

文生图

文生图方面比较知名的开源大模型为StableDiffusion,为了方便我们可以使用在StableDiffusion 基础上进行二次开发的ComfyUI

关于comfyui的安装方式可以参考此链接https://comfyui-wiki.com/zh-CN进行学习。

要注意的是,要让open-webui 能成功调用ComfyUI进行文生图,需要确保ComfyUI监听端口能访问 到,且开启了DevMode

之后再进入open-webui 的设置界面的图像 栏进行设置,在其中填入ComfyUI 的接口地址与模型配置即可。

配置好了之后再回到对话界面,如有符合可以生成图片的提示词 界面上就会出点一个图像按钮点一下即可生成图片

以生成一个小女孩的需求为例,演示一下:

上面例子中输入的关键字为:回复提示词"A girl",仅回复提示词,不要回复别的信息

如想让提示词更加完善,可以使用https://ollama.com/impactframes/llama3_ifai_sd_prompt_mkr_q4km这个模型,它可以自动完善提示词以让生成的图像更丰富。

ollama run impactframes/llama3_ifai_sd_prompt_mkr_q4km

用它生成图像时,就可以这样进行对话:

Write prompts for "A smiling girl,in bikini.". Only response the prompts for the image and nothing else.

OpenWebUi 中调用文生图,其最终都会调用到本地的ComfyUI里,大量生成图片、动画、视频的需求更建议直接使用ComfyUI,效果更佳

spring-ai

前面介绍了如何使用ollamaopen-webui快速搭建一个离线大模型平台,并体验了AI的相关功能。

但在实际业务场景中,前端 程序往往与后端 平台进行对接,与大模型的交互后端程序来负责接入则更为合适。

站在这一维度考虑,使用Spring AI接入大模型则是一个不错的选择。

关于Spring AI的详细介绍可参考:https://spring.io/projects/spring-ai

Spring AI is an application framework for AI engineering. Its goal is to apply to the AI domain Spring ecosystem design principles such as portability and modular design and promote using POJOs as the building blocks of an application to the AI domain.

翻译一下:Spring AI是一个AI工程框架。它的目标是将Spring生态的设计原则应用到AI领域,比如可移植性和模块化,并推广使用POJO来构建AI生态。

换句话讲:Spring AI不生产AI,只是AI的搬运工

快速接入

尽管Spring AI 目前还处于开发阶段,但已经提供了使用文档,以让我们能体验并使用Spring AI 的基本功能。接入方式说明可参考:getting-started

Spring AI支持接入的大模型较多,这里以接入离线的ollama为例,记录下接入过程

pom依赖

新建一个maven项目,其pom.xml内容如下:

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.3.0</version>
        <relativePath/>
    </parent>
    <groupId>com.haiyang</groupId>
    <artifactId>spring-ai-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-ai-demo</name>
    <description>spring-ai-demo</description>
    <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.0.0-SNAPSHOT</spring-ai.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
    </repositories>
</project>

需要了解到的是:目前Spring AI还没有正式版,所以需要添加repository 标签以能从snapshot仓库下载到依赖。

大模型接口配置

在SpringBoot项目的配置文件 中添加配置项 ,在application.properties中新增:

#配置ollama接口地址
spring.ai.ollama.base-url=http://192.168.140.8:11434/
#配置使用的ollama模型
spring.ai.ollama.chat.options.model=gemma:7b

启动类与接口实现

在Application类中创建ChatClient

java 复制代码
@SpringBootApplication
public class SpringAiDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringAiDemoApplication.class, args);
    }

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder) {
        return builder.build();
    }
}

在controller中添加一个接口

java 复制代码
@RestController
public class AIController {
    @Resource
    private ChatClient chatClient;

    @GetMapping("/ai")
    public Map<String, String> completion(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of(
                "generation",
                Objects.requireNonNull(chatClient.prompt()
                        .user(message)
                        .call()
                        .content()));
    }
}

以上,一个基于集成了gemma的离线大模型后端就实现好了。是不是非常简单

对话接口验证

访问http://127.0.0.1:8080/ai试一下

试一下携带参数,message=成都有哪些好玩的地方

stream消息接口实现

我们知道智能对话 的底层是AIGC,也就是它的结果是一个字一个字冒出来 的,为了视觉上更好的直观体验,我们也一般采用实时更新的方式将冒出的字词一个个通知到前端。

用于后端向前端实时通信 的方案有很多,为了实现性能好开销低,推荐使用SSE(Server-Sent Events)的方式进行字符(token)的推送

HTTP 短轮询、HTTP 长轮询、WebSocket、SSE 的顺序重新排列的对比表格

在Spring AI中,使用自带的ChatModel就可以实现。示例接口代码如下:

java 复制代码
    @GetMapping("/ai/generateStream")
    public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        Prompt prompt = new Prompt(new UserMessage(message));
        return this.chatModel.stream(prompt);
    }

使用stream返回数据时,则可以看到前端收到的消息则是一个字一个字 发下去的了。

再搭配Vaadin实现一个前端界面,源码为:

java 复制代码
@Route("")
public class HaiyangAIView extends VerticalLayout {

    public HaiyangAIView(ChatService chatService) {
        String chatId = chatService.establishChat();
        var messageList = new VerticalLayout();
        var messageInput = new MessageInput();
        messageInput.setWidthFull();
        messageInput.addSubmitListener(e -> submitPromptListener(chatId, e, chatService, messageList));
        addClassName("centered-content");
        add(messageList, messageInput);
    }

    private static void submitPromptListener(String chatId, MessageInput.SubmitEvent e, ChatService chatService, VerticalLayout messageList) {
        var question = e.getValue();
        var userMessage = new MarkdownMessage(question, "You", Color.AVATAR_PRESETS[6]);
        var assistantMessage = new MarkdownMessage("haiyangAI", Color.AVATAR_PRESETS[0]);
        messageList.add(userMessage, assistantMessage);
        chatService.chat(chatId, question)
                .map(res -> Optional.ofNullable(res.getResult().getOutput().getContent()).orElse(""))
                .subscribe(assistantMessage::appendMarkdownAsync);
    }
}

再看一下效果,应答内容就动起来了

总结

使用Spring AIollama进行离线大模型平台的搭建又快又简单。

为Spring AI点赞,向ollama与各种开源大模型致敬!

本文源码地址:https://github.com/puhaiyang/springai-demo

相关推荐
as_jopo7 分钟前
-Dspring.profiles.active=dev与--spring.profiles.active=dev的区别
java·后端·spring
hummhumm7 分钟前
第 32 章 - Go语言 部署与运维
java·运维·开发语言·后端·python·sql·golang
QQ_1154320318 分钟前
基于Java+SpringBoot+Mysql在线简单拍卖竞价拍卖竞拍系统功能设计与实现四
java·spring boot·mysql·毕业设计·毕业源码·竞拍系统·竞拍平台
fa_lsyk14 分钟前
Spring:AOP面向切面案例讲解AOP核心概念
java·后端·spring
陈奕迅本讯14 分钟前
人力资源项目学习
java·学习
2401_8784673217 分钟前
大连环保公益管理系统|Java|SSM|Vue| 前后端分离
java·开发语言·学习·tomcat·maven
Genius Kim20 分钟前
JWT加解密应用方案设计与实现
java·开发语言
尘浮生36 分钟前
Java项目实战II基于SpringBoot的客户关系管理系统(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·微信小程序·小程序
2401_8576100338 分钟前
企业OA系统:Spring Boot技术实现与管理
java·spring boot·后端
飞滕人生TYF41 分钟前
java 集合 菱形内定义封装类 而非基本数据类型 原因解释 详解
java