ModelConfig.java 5.59 KB
package com.xly.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.xly.agent.DynamicTableNl2SqlAiAgent;
import com.xly.agent.SceneSelectorAiAgent;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.ollama.OllamaChatModel;
import dev.langchain4j.model.ollama.OllamaStreamingChatModel;
import dev.langchain4j.service.AiServices;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.time.Duration;

/**
 * 大模型初始化配置(单例复用,避免重复创建)
 */
@Configuration
public class ModelConfig {


    @Value("${langchain4j.ollama.base-url}")
    private String chatModelUrl;

    @Value("${langchain4j.ollama.base-url}")
    private String sqlModelUrl;

    @Value("${langchain4j.ollama.chat-model-name}")
    private String chatModelName;

    @Value("${langchain4j.ollama.sql-model-name}")
    private String sqlModelName;

    // 中文对话模型 qwen2.5:7b-instruct
    @Bean
    @Primary
    public OllamaChatModel chatLanguageModel() {
        return OllamaChatModel.builder()
                .baseUrl(chatModelUrl)
                .modelName(chatModelName)  // 使用聊天模型名称
                .temperature(0.0)          // 建议调整为0.0太确定
                .topP(0.9)
//                .numPredict(2048)          // 添加生成长度限制
                .timeout(Duration.ofSeconds(60))  // 缩短超时时间
                .maxRetries(2)
                .build();
    }

    /***
     * @Author 钱豹
     * @Date 13:25 2026/2/6
     * @Param []
     * @return dev.langchain4j.model.ollama.OllamaChatModel
     * @Description 聊天
     **/
    @Bean("chatiModel")
    public ChatLanguageModel chatiModel() {
        return OllamaChatModel.builder()
                .baseUrl(chatModelUrl)
                .modelName(chatModelName)  // 使用聊天模型名称
                .temperature(0.8)          // 建议调整为0.8太确定
                .topP(0.9)
//                .numPredict(2048)          // 添加生成长度限制
                .timeout(Duration.ofSeconds(60))  // 缩短超时时间
                .maxRetries(2)
                .build();
    }

    // SQL/代码专用模型 qwen2.5-coder:14b
    @Bean("sqlChatModel")  // 明确指定bean名称
    public OllamaChatModel sqlChatModel() {
        return OllamaChatModel.builder()
                .baseUrl(sqlModelUrl)
                .modelName(sqlModelName)    // 使用SQL模型名称
                .temperature(0.0)
                .topP(0.95)
                .numPredict(4096)          // 代码生成需要更长
                .timeout(Duration.ofSeconds(120))
                .maxRetries(3)
//                .repeatPenalty(1.1)        // 减少重复
                .build();
    }

    /***
     * @Author 钱豹
     * @Date 22:53 2026/2/3
     * @Param []
     * @return dev.langchain4j.model.chat.StreamingChatLanguageModel
     * @Description 流式聊天模型 - 使用 @Primary
     **/
    @Bean("streamingChatModel")
    @Primary
    public StreamingChatLanguageModel streamingChatModel() {
        return OllamaStreamingChatModel.builder()
                .baseUrl(chatModelUrl)
                .modelName(chatModelName)
                .temperature(0.7)
                .topP(0.9)
                .numPredict(1024)
                .timeout(Duration.ofSeconds(60))
                .build();
    }

    // 流式SQL/代码模型 - 指定名称
    @Bean("streamingSqlModel")
    public StreamingChatLanguageModel streamingSqlModel() {
        return OllamaStreamingChatModel.builder()
                .baseUrl(sqlModelUrl)
                .modelName(sqlModelName)
                .temperature(0.3)
                .topP(0.95)
                .numPredict(2048)
                .timeout(Duration.ofSeconds(120))
                .build();
    }

    /**
     * 全局ObjectMapper:支持LocalDate序列化
     */
    @Bean
    @Primary
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapper;
    }

    //动态SQL生成模型
    @Bean
    public DynamicTableNl2SqlAiAgent dynamicTableNl2SqlAiAgent(@Qualifier("sqlChatModel") ChatLanguageModel sqlModel) {
        return AiServices.builder(DynamicTableNl2SqlAiAgent.class)
                .chatLanguageModel(sqlModel)
                // 会话记忆:每个用户最多保留10轮对话,避免记忆溢出
                .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
                .build();
    }

    //场景意图解析AI服务
    @Bean
    public SceneSelectorAiAgent sceneSelectorAiAgent(OllamaChatModel sqlModel) {
        return AiServices.builder(SceneSelectorAiAgent.class)
                .chatLanguageModel(sqlModel)
                // 会话记忆:每个用户最多保留10轮对话,避免记忆溢出
                .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
                .build();
    }
}