Java AI

基本概念

LLM:AI大模型

Langchain4j、SpringAI:这两个框架让我们可以通过java调用大模型相关api

RAG:检索增强生成,检索外部知识源来增强生成模型的能力

MCP:模型上下文协议,打通AI模型与外部工具、数据源的桥梁

too:可以被AI模型调用以补充功能的外部应用程序(文件系统、数据库、搜索引擎、各种API接口等)

AI发展史:

  • 符号主义
  • 连接主义(基于感知机模型)
  • 神经网络(多层次的连接主义)

感知机模型:

  • 输入
  • 权重
  • 偏值(阈值)
  • 激活函数
  • 输出

大模型部署

本地部署

使用Ollama快速本地部署大模型

步骤:

  1. 下载安装Ollama

    到官网下载即可

    安装时会自动添加Ollama的环境变量

  2. Ollama官网找到想要部署的大模型

    选择大模型时需要考虑大模型类型、大小(b为十亿)

  3. 在cmd命令行窗口下载对应的大模型

    ollama run qwen3:0.6b
    
    ollama run 版本
    
    # 开启大模型对话就是用上面的语句,若没下载,自动下载,下载好了就开启对话
    
    # 关闭大模型对话
    /bye
    

    当然我们肯定不能在命令行窗口调用大模型,项目中要调用大模型也是通过发送http请求

    当我们安装好Ollama以后,Ollama会常驻并占用11434端口

    我们在调用大模型时,不需要额外启动什么,直接发http请求即可

    如何请求如下

  4. 通过Http请求大模型

    发送Post请求到 http://localhost:11434/api/chat

    带上如下Json数据作为请求体

    {
      "model": "deepseek-r1",
      "messages": [
        {
          "role": "user",
          "content": "how many r in the word strawberry?"
        }
      ],
      "think": true,
      "stream": false
    }
    

    响应结果类似如下

    {"model":"deepseek-r1",
    "created_at":"2025-05-29T09:35:56.836222Z",
    "message":
        {"role": "assistant",
        "content": "The word \"strawberry\" contains **three** instances of the letter 'R' ..."
        "thinking": "First, the question is: \"how many r in the word  strawberry?\" I need to count the number of times the letter 'r' appears in the word \"strawberry\". Let me write down the word:...",
        "done_reason":"stop",
        "done":true,
        "total_duration":47975065417,
        "load_duration":29758167,
        "prompt_eval_count":10,
        "prompt_eval_duration":174191542,
        "eval_count":2514,
        "eval_duration":47770692833
        }
    }
    

    关于请求参数以及响应数据,后续会讲

他人部署

也就是调用别人部署好的大模型,通过网络访问

这会导致额外费用,且数据不安全,但会更加方便

调用阿里云百炼大模型基本步骤:

  1. 登入阿里云

  2. 开通大模型服务平台百炼服务

  3. 申请百炼平台API-KEY

  4. 选择模型并使用

  5. 根据案例通过http请求或者java方式请求大模型

    curl -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions \
    -H "Authorization: Bearer $DASHSCOPE_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
        "model": "qwen-plus",
        "messages": [
            {
                "role": "system",
                "content": "You are a helpful assistant."
            },
            {
                "role": "user", 
                "content": "你是谁?"
            }
        ]
    }'
    
    // 该代码 OpenAI SDK 版本为 2.6.0
    import com.openai.client.OpenAIClient;
    import com.openai.client.okhttp.OpenAIOkHttpClient;
    import com.openai.models.chat.completions.ChatCompletion;
    import com.openai.models.chat.completions.ChatCompletionCreateParams;
    
    public class Main {
        public static void main(String[] args) {
            OpenAIClient client = OpenAIOkHttpClient.builder()
                    .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                    .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                    .build();
    
            ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
                    .addUserMessage("你是谁")
                    .model("qwen-plus")
                    .build();
    
            try {
                ChatCompletion chatCompletion = client.chat().completions().create(params);
                System.out.println(chatCompletion);
            } catch (Exception e) {
                System.err.println("Error occurred: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }
    

大模型调用

讲解上面提到的请求参数以及响应数据的含义

请求参数

{
  "model": "qwen-plus",
  "messages": [
        {
            "role": "system",
            "content": "你是大模型助手"
        },
        {
            "role": "user",
            "content": "你是谁?"
		},
		{
         	"role": "assistent",
            "content": ""
		}
  ],
  "think": true,
  "stream": false,
  "enable_search": true
}
字段名 核心含义 具体说明
model 指定 AI 模型 这次请求的是名为 “qwen-plus” 的模型,这通常是阿里云开发的通义千问系列大模型的一个版本。
messages 对话历史与内容 这是核心部分,包含了对话中所有角色的发言,模型会根据这些内容生成回复。
- role: “system” 系统设定 给 AI 模型的 “身份指令”,这里设定为 “你是大模型助手”,定义了 AI 的基础角色。
- role: “user” 用户提问 用户发出的问题,内容是 “你是谁?”,这是模型需要回答的核心问题。
- role: “assistent” AI 回复位 这是留给 AI 模型填充回复内容的位置,当前为空(""),等待模型生成答案后填入。
think 是否开启思维链 取值为true,表示希望模型在生成最终回复前,先进行内部的逻辑推理(类似 “思考过程”),通常用于提升复杂问题回答的准确性。
stream 是否流式输出 取值为false,表示模型会一次性返回完整的回答;如果为true,则会像聊天一样逐字 / 逐句地实时输出内容。
enable_search 是否启用联网搜索 取值为true,表示允许模型在回答问题时,通过联网获取最新信息来补充回答(例如回答实时新闻、天气等问题时会用到)。

响应数据

{
  "response_id": "unique-uuid-123456",  // 唯一响应ID,用于日志追踪和请求匹配
  "request_id": "request-uuid-654321",  // 关联的请求ID,便于联调与问题定位
  "model": "gpt-4o-mini-2024-07-18",    // 实际调用的模型版本,确保可复现性
  "created": 1721234567,                // 响应生成时间戳(Unix时间,秒级)
  "usage": {                            // token使用统计,用于成本核算
    "prompt_tokens": 120,               // 输入提示词消耗的token数
    "completion_tokens": 350,           // 模型生成内容消耗的token数
    "total_tokens": 470                 // 总消耗token数
  },
  "choices": [                          // 生成结果列表(支持多候选返回)
    {
      "index": 0,                       // 结果序号(多候选时区分)
      "message": {                      // 消息体(对话式场景常用)
        "role": "assistant",            // 角色标识(assistant表示模型回复)
        "content": "这是大模型生成的具体响应内容...",  // 核心文本结果
        "tool_calls": null              // 工具调用信息(未调用时为null)
      },
      "finish_reason": "stop"           // 生成停止原因(stop:正常结束;length:达到token上限)
    }
  ],
  "error": null                         // 错误信息(成功时为null;失败时包含code和message)
}

Java 使用

Java调用大模型的工具库

  • LangChain4j
  • Spring AI

本文中就使用LangChain4j来实现在Java spring项目中调用大模型

使用OpenAiChatModel

基本步骤:

  1. 引入LangChain4j依赖

    <!--        langchain4j起步依赖-->
    <!--        OpenAiChatModel-->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
        <version>1.0.1-beta6</version>
    </dependency>
    
  2. 构建OpenAiChatModel对象

    在非Spring框架中,我们需要手动构建该对象

    在Spring框架中,通过引入langchain4j的start依赖,我们可以直接自动注入OpenAiChatModel对象

    只需要在配置文件中配置即可

    server:
      port: 8080
    
    langchain4j:
      open-ai:
        chat-model:
          base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
          api-key: ${API-KEY} # 自己在阿里云上的key
          model-name: qwen-plus
    
  3. 调用OpenAiChatModel对象的chat方法与大模型交互

@RestController
public class ChatController {

    @Autowired
    private OpenAiChatModel model;

    @RequestMapping("/chat")
    public String chat(String message) {
        String result = model.chat(message);

        return result;
    }

}
使用AiServices

但我们使用时并不直接使用OpenAiChatModel对象,而是使用AiServices

AiServices是基于OpenAiChatModel封装好的,更方便后续的使用

基本步骤:

  1. 引入依赖

    <!--        AiServices相关依赖-->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-spring-boot-starter</artifactId>
        <version>1.0.1-beta6</version>
    </dependency>
    
  2. 声明接口(chat方法)

    public interface ConsultantService {
    
        //用于聊天的方法
        public String chat(String message);
    }
    
  3. 使用AiServices为接口创建代理对象

    //1.通过配置类创建代理对象
    @Configuration
    public class AiConfig {
        
        @Resource
        private OpenAiChatModel model;
        
        @Bean
        public ConsultantService consultantService() {
            ConsultantService service = AiServices.builder(ConsultantService.class)
                    .chatModel(model)
                    .build();
            
            return service;
        }
    }
    
    //2.直接在上面的接口中使用注解
    
    @AiService(
            wiringMode = AiServiceWiringMode.EXPLICIT,  //手动装配
            chatModel = "openAiChatModel"	//这里一定要小写开头,代表bean实例
    )
    public interface ConsultantService {
    
        //用于聊天的方法
        public String chat(String message);
    }
    
    
    
    //3.直接自动装配
    @AiService
    public interface ConsultantService {
    
        //用于聊天的方法
        public String chat(String message);
    }
    
  4. 调用

    @RestController
    public class ChatController {
    
        @Autowired
        private ConsultantService consultantService;
    
        @RequestMapping("/chat")
        public String chat(String message) {
            String result = consultantService.chat(message);
            return result;
        }
    }
    

打印日志

在yml配置中添加日志配置即可

server:
  port: 8080

langchain4j:
  open-ai:
    chat-model:
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      api-key: ${API-KEY} # 自己在阿里云上的key
      model-name: qwen-plus
      log-requests: true
      log-responses: true

logging:
  level: 
    dev.langchain4j: DEBUG

流式调用

在前面的使用中,都是阻塞式调用

即 “stream”: false

我们也可以指定为流式调用

基本步骤:

  1. 引入依赖

    <!--        流式调用相关依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-reactor</artifactId>
        <version>1.0.1-beta6</version>
    </dependency>
    
  2. 配置流式模型对象

    langchain4j:
      open-ai:
        chat-model:
          base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
          api-key: ${API-KEY} # 自己在阿里云上的key
          model-name: qwen-plus
          log-requests: true
          log-responses: true
        streaming-chat-model:
          base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
          api-key: ${API-KEY} # 自己在阿里云上的key
          model-name: qwen-plus
          log-requests: true
          log-responses: true
    
  3. 切换接口方法的返回值类型(Flux)

    @AiService(
            wiringMode = AiServiceWiringMode.EXPLICIT,
            chatModel = "openAiChatModel",
            streamingChatModel = "openAiStreamingChatModel"	//配置流式模型
    )
    public interface ConsultantService {
    
        //改用Flux并指定泛型
        public Flux<String> chat(String message);
    }
    
  4. 修改Controller中的代码(Flux)

    	//需要注意修改编码
    @RequestMapping(value = "/chat",produces = "text/html;charset=UTF-8")
    public Flux<String> chat(String message) {
        Flux<String> result = consultantService.chat(message);
        return result;
    }
    

消息注解

  • @SystemMessage

    @AiService(
            wiringMode = AiServiceWiringMode.EXPLICIT,
            chatModel = "openAiChatModel",
            streamingChatModel = "openAiStreamingChatModel"
    )
    public interface ConsultantService {
    
        	//直接在这里写系统消息
        @SystemMessage("你是slc的编程小助手")
        public Flux<String> chat(String message);
        
        	//或者指向另一个文件,这里的路径就是类路径即resources下
        @SystemMessage(fromResource = "text/aisystem.txt")
        public String chat1(String message);
    }
    
  • @UserMessage

    和System注解使用方式类似,但System是系统信息,User是用户发送给大模型的信息

    //可用来将用户传递的数据message和默认数据(注解中定义的)拼接在一起
    //默认是it,可以通过
    @UserMessage("你好啊!{{it}}")
    public String chat1(String message);
    
    @UserMessage("你好啊!{{msg}}")
    public String chat1(@V("msg")String message);
    

会话记忆

首先需要明确三个对象:

  1. 用户
  2. 后端系统
  3. 大模型

在使用时,为了实现会话记忆的功能,需要:

  1. 用户发送请求
  2. 后端系统将请求中的信息保存在会话记忆对象
  3. 后端将整个会话记忆对象交给大模型
  4. 大模型根据会话记忆对象中所有的信息生成结果
  5. 后端将结果保存到会话记忆对象
  6. 后端将结果返回给前端

通过会话记忆对象,我们将用户请求和大模型响应结果都保存起来,从而实现会话记忆功能

会话记忆对象则会不断壮大

实现基本会话记忆

使用chatMemory

基本步骤:

  1. 定义会话记忆对象(chatMemory)

    //在配置类中创建bean
    @Bean
    public ChatMemory chatMemory(){
        MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
                .maxMessages(20)
                .build();
        return memory;
    }
    
  2. 配置会话记忆对象

    //在AiServices上指定即可
    @AiService(
            wiringMode = AiServiceWiringMode.EXPLICIT,
            chatModel = "openAiChatModel",	//这里的三个值都是固定的
            streamingChatModel = "openAiStreamingChatModel",
            chatMemory = "chatMemory"   //配置会话记忆对象,chatMemory就是上面那个方法名
    )
    
会话记忆隔离

上面讲解的基本会话记忆会有问题

如果不隔离,则多个用户会用同一个会话记忆对象

我们通过memoryId来实现会话记忆隔离

简单来说我们要使用ChatMemoryProvider代替前面的ChatMemory

基本步骤:

  1. 定义会话记忆对象提供者

    //会话记忆对象提供者
    @Bean
    public ChatMemoryProvider chatMemoryProvider(){
        ChatMemoryProvider provider = new ChatMemoryProvider() {
            @Override
            public ChatMemory get(Object memoryId) {
                MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
                        .maxMessages(20)
                        .id(memoryId)
                        .build();
                return memory;
            }
        };
        return provider;
    }
    
  2. 配置会话记忆对象提供者

    @AiService(
            wiringMode = AiServiceWiringMode.EXPLICIT,
            chatModel = "openAiChatModel",
            streamingChatModel = "openAiStreamingChatModel",
    //        chatMemory = "chatMemory"
            chatMemoryProvider = "chatMemoryProvider"   //配置会话记忆对象提供者
    )
    public interface ConsultantService {
    
        //传递memoryId
        @SystemMessage("你是slc的小助手-小席德")
        public Flux<String> chat(@MemoryId String memoryId,@UserMessage String message);
    
    }
    
会话记忆持久化

ChatMemory底层是List来存储会话内容

每当后端重新启动,会话记忆则会丢失,因此需要实现持久化

这里采用redis

ChatMemory由ChatMemoryProvider创建,我们需要在创建ChatMemory时指定ChatMemoryStore,从而让会话记忆被保存到redis中

简而言之就是要在前面ChatMemoryProvider的基础上添加store

基本步骤:

  1. 定义chatMemoryStore实现类

    //使用Redis实现会话记忆持久化
    @Repository
    public class RedisChatMemoryStore implements ChatMemoryStore {
        
        @Autowired
        private RedisTemplate redisTemplate;
        
        @Override
        public List<ChatMessage> getMessages(Object memoryId) {
            //获取会话消息
            String json = redisTemplate.opsForValue().get(memoryId.toString());
            //把Json转换为List<ChatMessage>
            List<ChatMessage> list = ChatMessageSerializer.messagesFromJson(json);
            return list;
        }
    
        @Override
        public void updateMessages(Object memoryId, List<ChatMessage> list) {
            //更新会话消息
            //把List<ChatMessage>转换为Json
            String json = ChatMessageSerializer.messagesToJson(list);
            //把Json保存到Redis中
            redisTemplate.opsForValue().set(memoryId.toString(),json, Duration.ofDays(1));
        }
    
        @Override
        public void deleteMessages(Object o) {
            //删除会话消息
            redisTemplate.delete(o.toString());
        }
    }
    
  2. 配置chatMemoryStore

    //会话记忆对象提供者
    @Bean
    public ChatMemoryProvider chatMemoryProvider(){
        ChatMemoryProvider provider = new ChatMemoryProvider() {
            @Override
            public ChatMemory get(Object memoryId) {
                MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
                        .maxMessages(20)
                        .id(memoryId)
                        .chatMemoryStore(redisChatMemoryStore)	//加上store,提前自动注入
                        .build();
                return memory;
            }
        };
        return provider;
    }
    
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐