五、LangChain4j之模型参数配置

5.1 开发步骤基础工程Base
5.1.1 建module

langchain4j-05model-parameters

5.1.2 改pom
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--langchain4j-open-ai 基础-->
        <!--所有调用均基于 OpenAI 协议标准,实现一致的接口设计与规范LangChain4j 提供与许多 LLM 提供商的集成
        从最简单的开始方式是从 OpenAI 集成开始https://docs.langchain4j.dev/get-started    -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
        </dependency>
        <!--langchain4j 高阶-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <!--test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
5.1.3 写yml
server.port=9005
spring.application.name=langchain4j-05model-parameters
5.1.4 主启动
5.1.5 业务类
@Configuration
public class LLMConfig
{
    @Bean(name = "qwen")
    public ChatModel chatModelQwen()
    {
        return OpenAiChatModel.builder()
                    .apiKey(System.getenv("aliQwen-api"))
                    .modelName("qwen-plus")
                    .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .build();
    }
}
@RestController
@Slf4j
public class ModelParameterController
{
    @Resource
    private ChatModel chatModelQwen;

    // http://localhost:9003/chatconfig/config
    @GetMapping(value = "/modelparam/config")
    public String config(@RequestParam(value = "prompt", defaultValue = "你是谁") String prompt)
    {
        String result = chatModelQwen.chat(prompt);

        System.out.println("通过langchain4j调用模型返回结果:"+result);

        return result;
    }
}
5.2 日志配置

只有日志级别调整为debug级别,同时配置以上 langchain 日志输出开关才有效

@Configuration
public class LLMConfig
{
    @Bean(name = "qwen")
    public ChatModel chatModelQwen()
    {
        return OpenAiChatModel.builder()
                    .apiKey(System.getenv("aliQwen-api"))
                    .modelName("qwen-plus")
                    .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .logRequests(true) // 日志界别设置为debug才有效
                .logResponses(true)// 日志界别设置为debug才有效
                .build();
    }
}

配置类

server.port=9005

spring.application.name=langchain4j-05model-parameters

# 只有日志级别调整为debug级别,同时配置以上 langchain 日志输出开关才有效
logging.level.dev.langchain4j = DEBUG 

测试:

5.3 监控 (Observability)

配置类

@Configuration
public class LLMConfig
{
    @Bean(name = "qwen")
    public ChatModel chatModelQwen()
    {
        return OpenAiChatModel.builder()
                    .apiKey(System.getenv("aliQwen-api"))
                    .modelName("qwen-plus")
                    .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .logRequests(true) // 日志界别设置为debug才有效
                .logResponses(true)// 日志界别设置为debug才有效
                .listeners(List.of(new TestChatModelListener())) //监听器
                .build();
    }
}
@Slf4j
public class TestChatModelListener implements ChatModelListener
{
    @Override
    public void onRequest(ChatModelRequestContext requestContext)
    {

        // onRequest配置的k:v键值对,在onResponse阶段可以获得,上下文传递参数好用
        String uuidValue = IdUtil.simpleUUID();
        requestContext.attributes().put("TraceID",uuidValue);
        log.info("请求参数requestContext:{}", requestContext+"\t"+uuidValue);
    }

    @Override
    public void onResponse(ChatModelResponseContext responseContext)
    {
        Object object = responseContext.attributes().get("TraceID");

        log.info("返回结果responseContext:{}", object);
    }

    @Override
    public void onError(ChatModelErrorContext errorContext)
    {
        log.error("请求异常ChatModelErrorContext:{}", errorContext);
    }
}
5.4 重试机制 (Retry Configuration)
@Configuration
public class LLMConfig
{
    @Bean(name = "qwen")
    public ChatModel chatModelQwen()
    {
        return OpenAiChatModel.builder()
                    .apiKey(System.getenv("aliQwen-api"))
                    .modelName("qwen-plus")
                    .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .logRequests(true) // 日志界别设置为debug才有效
                .logResponses(true)// 日志界别设置为debug才有效
                .listeners(List.of(new TestChatModelListener())) //监听器
                .maxRetries(2)// 重试机制共计2次
                .build();
    }
}
 
5.5 超时时间 timeout
@Configuration
public class LLMConfig
{
    @Bean(name = "qwen")
    public ChatModel chatModelQwen()
    {
        return OpenAiChatModel.builder()
                    .apiKey(System.getenv("aliQwen-api"))
                    .modelName("qwen-plus")
                    .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .logRequests(true) // 日志界别设置为debug才有效
                .logResponses(true)// 日志界别设置为debug才有效
                .listeners(List.of(new TestChatModelListener())) //监听器
                .maxRetries(2)// 重试机制
                .timeout(Duration.ofSeconds(3))
                .build();
    }
}

六、LangChain4j之多模态视觉理解

6.1 LangChain4j进行图像理解

模型选择

6.2 案例开发1
6.2.1 建module

langchain4j-06chat-image

6.2.2 改pom
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--langchain4j-open-ai 基础-->
        <!--所有调用均基于 OpenAI 协议标准,实现一致的接口设计与规范LangChain4j 提供与许多 LLM 提供商的集成
        从最简单的开始方式是从 OpenAI 集成开始https://docs.langchain4j.dev/get-started    -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
        </dependency>
        <!--langchain4j 高阶-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <!--test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
6.2.3 写yml
server.port=9006
spring.application.name=langchain4j-06chat-image
6.2.4 主启动
6.2.5 业务类

①. resources目录下放入mi.jpg图片

② LLMConfig配置

@Configuration
public class LLMConfig
{
    @Bean
    public ChatModel ImageModel() {
        return OpenAiChatModel.builder()
                .apiKey(System.getenv("aliQwen-api"))
                //qwen-vl-max 是一个多模态大模型,支持图片和文本的结合输入,适用于视觉-语言任务。
                .modelName("qwen-vl-max")
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .build();
    }
}

③.

a.图片转码:通过Base64编码将图片转化为字符串

b. 提示词指定:结合ImageContent和TextContent一起发送到模型进行处理。

c. API调用:使用OpenAiChatModel来构建请求,并通过chat()方法调用模型。请求内容包括文本提示和图片,模型会根据输入返回分析结果。

d. 解析与输出:从ChatResponse中获取AI大模型的回复,打印出处理后的结果。

@Value("classpath:static.images/鼠.jpg")
private Resource resource;

// http://localhost:9006/image/call@GetMapping("/image/call")
public String readImageProcessor() throws IOException {

byte[] imageByte = resource.getContentAsByteArray();
    String base64String = Base64.getEncoder().encodeToString(imageByte);

    UserMessage userMessage = UserMessage.from(
            TextContent.from("分析一下图片"),
            ImageContent.from(base64String, "image/jpg")
    );


    ChatResponse chatResponse = chatModel.chat(userMessage);
    String text = chatResponse.aiMessage().text();
    System.out.println(text);
return text;
}
6.3 切换通义万相-文生图模型 wanx2.1-t2i-turbo 它支持通过一句话生成图像

6.3.1 修改父工程POM文件
        <!--langchain4j-community 引入阿里云百炼平台依赖管理清单-->
        <langchain4j-community.version>1.0.1-beta6</langchain4j-community.version>
6.3.2 改POM
        <!--DashScope (Qwen)接入阿里云百炼平台
            https://docs.langchain4j.dev/integrations/language-models/dashscope
        -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
        </dependency>
6.3.3 写YML
server.port=9006

spring.application.name=langchain4j-06chat-image
6.3.4 主启动
6.3.5 业务类
    /**
     * @Description: 测试通义万象来实现图片生成,
     * 官网说明:https://help.aliyun.com/zh/model-studio/text-to-image
     */
    @Bean
    public WanxImageModel wanxImageModel()
    {
        return WanxImageModel.builder()
                .apiKey(System.getenv("aliQwen-api"))
                .modelName("wanx2.1-t2i-turbo") //图片生成 https://help.aliyun.com/zh/model-studio/text-to-image
                .build();
    }
@RestController
@Slf4j
public class WanxImageModelController
{
    @Autowired
    private WanxImageModel wanxImageModel;

    // http://localhost:9006/image/create2
    @GetMapping(value = "/image/create2")
    public String createImageContent2() throws IOException
    {
        System.out.println(wanxImageModel);
        Response<Image> imageResponse = wanxImageModel.generate("美女");

        System.out.println(imageResponse.content().url());

        return imageResponse.content().url().toString();

    }


    @GetMapping(value = "/image/create3")
    public String createImageContent3() throws IOException
    {

        String prompt = "近景镜头,18岁的中国女孩,古代服饰,圆脸,正面看着镜头," +
                "民族优雅的服装,商业摄影,室外,电影级光照,半身特写,精致的淡妆,锐利的边缘。";
        ImageSynthesisParam param =
                ImageSynthesisParam.builder()
                            .apiKey(System.getenv("aliQwen-api"))
                            .model(ImageSynthesis.Models.WANX_V1)
                            .prompt(prompt)
                            .style("<watercolor>")
                            .n(1)
                            .size("1024*1024")
                        .build();

        ImageSynthesis imageSynthesis = new ImageSynthesis();
        ImageSynthesisResult result = null;
        try {
            System.out.println("---sync call, please wait a moment----");
            result = imageSynthesis.call(param);
        } catch (ApiException | NoApiKeyException e){
            throw new RuntimeException(e.getMessage());
        }


        System.out.println(JsonUtils.toJson(result));

        return JsonUtils.toJson(result);
    }
}

七、LangChain4j之流式输出

7.1 前置知识点

Springboot3响应式编程

7.2 案例开发
7.2.1 建Module

langchain4j-07chat-stream

7.2.2
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--langchain4j-open-ai + langchain4j + langchain4j-reactor-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-reactor</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
7.2.3 写YML
server.port=9007

spring.application.name=langchain4j-07chat-stream 

# 设置响应的字符编码,避免流式返回输出乱码
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
7.2.4 主启动
7.2.5 业务类

① ChatAssistant接口

② 注意ChatModel的改变

③ Config 配置

@Configuration
public class LLMConfig
{
    @Bean(name = "qwen")
    public ChatModel chatModelQwen()
    {
        return OpenAiChatModel.builder()
                .apiKey(System.getenv("aliQwen-api"))
                .modelName("qwen-plus")
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .build();
    }


    @Bean
    public StreamingChatModel streamingChatModel(){
        return OpenAiStreamingChatModel.builder()
                    .apiKey(System.getenv("aliQwen-api"))
                    .modelName("qwen-plus")
                    .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .build();
    }

    @Bean
    public ChatAssistant chatAssistant(StreamingChatModel streamingChatModel){
        return AiServices.create(ChatAssistant.class, streamingChatModel);
    }
}

④ Controller

@RestController
@Slf4j
public class StreamingChatModelController
{
    @Resource //直接使用 low-level LLM API
    private StreamingChatModel streamingChatLanguageModel;
    @Resource //自己封装接口使用 high-level LLM API
    private ChatAssistant chatAssistant;


    // http://localhost:9007/chatstream/chat?prompt=天津有什么好吃的
    @GetMapping(value = "/chatstream/chat")
    public Flux<String> chat(@RequestParam("prompt") String prompt)
    {
        return Flux.create(stringFluxSink -> {
            streamingChatLanguageModel.chat(prompt, new StreamingChatResponseHandler()
            {
                @Override
                public void onPartialResponse(String s)
                {
                    stringFluxSink.next(s);
                }

                @Override
                public void onCompleteResponse(ChatResponse completeResponse)
                {
                    stringFluxSink.complete();
                }

                @Override
                public void onError(Throwable throwable)
                {
                    stringFluxSink.error(throwable);
                }
            });
        });
    }

    @GetMapping(value = "/chatstream/chat2")
    public void chat2(@RequestParam(value = "prompt", defaultValue = "北京有什么好吃") String prompt)
    {
        System.out.println("---come in chat2");
        streamingChatLanguageModel.chat(prompt, new StreamingChatResponseHandler()
        {
            @Override
            public void onPartialResponse(String partialResponse)
            {
                System.out.println(partialResponse);
            }

            @Override
            public void onCompleteResponse(ChatResponse completeResponse)
            {
                System.out.println("---response over: "+completeResponse);
            }

            @Override
            public void onError(Throwable throwable)
            {
                throwable.printStackTrace();
            }
        });
    }



    @GetMapping(value = "/chatstream/chat3")
    public Flux<String> chat3(@RequestParam(value = "prompt", defaultValue = "南京有什么好吃") String prompt)
    {
        System.out.println("---come in chat3");

        return chatAssistant.chatFlux(prompt);
    }
}

八、LangChain4j之记忆缓存

8.1 介绍

是什么?

记忆缓存是聊天系统中的一个重要组件,用于存储和管理对话的上下文信息。它的主要作用是让AI助手能够”记住”之前的对话内容,从而提供连贯和个性化的回复。

Eviction policy:

8.2 案例开发
8.2.1 建module

langchain4j-08chat-memory

8.2.2 改POM

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--langchain4j-open-ai + langchain4j + langchain4j-reactor-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-reactor</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
8.2.3 写YML
server.port=9008

spring.application.name=langchain4j-08chat-memory

# 设置响应的字符编码
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
8.2.4 主启动
8.2.5 业务类

① 新建接口

public interface ChatMemoryAssistant
{
    /**
     * 聊天带记忆缓存功能
     *
     * @param userId  用户 ID
     * @param prompt 消息
     * @return {@link String }
     */
    String chatWithChatMemory(@MemoryId Long userId, @UserMessage String prompt);
}

② Config 配置 更换模型

@Configuration
public class LLMConfig
{
    @Bean
    public ChatModel chatModel()
    {
        return OpenAiChatModel.builder()
                    .apiKey(System.getenv("aliQwen-api"))
                    .modelName("qwen-long")
                    .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .build();
    }

    @Bean(name = "chat")
    public ChatAssistant chatAssistant(ChatModel chatModel)
    {
        return AiServices.create(ChatAssistant.class, chatModel);
    }


    @Bean(name = "chatMessageWindowChatMemory")
    public ChatMemoryAssistant chatMessageWindowChatMemory(ChatModel chatModel)
    {
        return AiServices.builder(ChatMemoryAssistant.class)
                .chatModel(chatModel)
                // 注意每个memoryId对应创建一个ChatMemory
                .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(100))
                .build();
    }

    @Bean(name = "chatTokenWindowChatMemory")
    public ChatMemoryAssistant chatTokenWindowChatMemory(ChatModel chatModel)
    {
        // TokenCountEstimator默认的token分词器,需要结合Tokenizer计算ChatMessage的token数量
        TokenCountEstimator openAiTokenizer = new OpenAiTokenCountEstimator("gpt-4");

        return AiServices.builder(ChatMemoryAssistant.class)
                .chatModel(chatModel)
                .chatMemoryProvider(memoryId -> TokenWindowChatMemory.withMaxTokens(1000,openAiTokenizer))
                .build();
    }
}

③ Controller

@RestController
@Slf4j
public class ChatMemoryController
{
    @Resource(name = "chat")
    private ChatAssistant chatAssistant;
    @Resource(name = "chatMessageWindowChatMemory")
    private ChatMemoryAssistant chatMessageWindowChatMemory;
    @Resource(name = "chatTokenWindowChatMemory")
    private ChatMemoryAssistant chatTokenWindowChatMemory;

    @GetMapping(value = "/chatmemory/test1")
    public String chat()
    {

        String answer01 = chatAssistant.chat("你好,我的名字叫张三");
        System.out.println("answer01返回结果:"+answer01);

        String answer02 = chatAssistant.chat("我的名字是什么");
        System.out.println("answer02返回结果:"+answer02);

        return "success : "+ DateUtil.now()+"<br> \n\n answer01: "+answer01+"<br> \n\n answer02: "+answer02;
    }

    @GetMapping(value = "/chatmemory/test2")
    public String chatMessageWindowChatMemory()
    {
        chatMessageWindowChatMemory.chatWithChatMemory(1L, "你好!我的名字是Java.");
        String answer01 = chatMessageWindowChatMemory.chatWithChatMemory(1L, "我的名字是什么");
        System.out.println("answer01返回结果:"+answer01);

        chatMessageWindowChatMemory.chatWithChatMemory(3L, "你好!我的名字是C++");
        String answer02 = chatMessageWindowChatMemory.chatWithChatMemory(3L, "我的名字是什么");
        System.out.println("answer02返回结果:"+answer02);

        return "chatMessageWindowChatMemory success : "
                + DateUtil.now()+"<br> \n\n answer01: "+answer01+"<br> \n\n answer02: "+answer02;

    }

    @GetMapping(value = "/chatmemory/test3")
    public String chatTokenWindowChatMemory()
    {
        chatTokenWindowChatMemory.chatWithChatMemory(1L, "你好!我的名字是mysql");
        String answer01 = chatTokenWindowChatMemory.chatWithChatMemory(1L, "我的名字是什么");
        System.out.println("answer01返回结果:"+answer01);

        chatTokenWindowChatMemory.chatWithChatMemory(3L, "你好!我的名字是oracle");
        String answer02 = chatTokenWindowChatMemory.chatWithChatMemory(3L, "我的名字是什么");
        System.out.println("answer02返回结果:"+answer02);

        return "chatTokenWindowChatMemory success : "
                + DateUtil.now()+"<br> \n\n answer01: "+answer01+"<br> \n\n answer02: "+answer02;
    }
}

九、LangChain4j之提示词工程

9.1 能干吗

打造专业的限定能力范围和作用边界的AI助手

9.2 案例开发
9.2.1 设计要求:

使用SystemMessage明确定义助手的角色和能力范围,将其限定在法律咨询领域。在LangChain4j中,我们主要利用SystemMessage来实现这一点,SystemMessage具有高优先级,能有效地指导模型的整体行为

利用提示词模板(@UserMessage, @V)精确控制输入和期望的输出格式,确保问题被正确理解和回答

9.2.2 建module

langchain4j-09chat-prompt

9.2.3 改pom
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--langchain4j-open-ai + langchain4j + langchain4j-reactor-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-reactor</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
9.2.4 写YML
server.port=9009

spring.application.name=langchain4j-09chat-prompt

# 设置响应的字符编码
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
9.2.5 主启动
9.2.6 业务类
① 第一组

@SystemMessage+@ UserMessage+ @ V

public interface LawAssistant
{
    //案例1
    @SystemMessage("你是一位专业的中国法律顾问,只回答与中国法律相关的问题。" +
            "输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。'")
    @UserMessage("请回答以下法律问题:{{question}},字数控制在{{length}}以内")
    String chat(@V("question") String question, @V("length") int length);
}

配置类:

@Configuration
public class LLMConfig
{
    @Bean
    public ChatModel chatModel()
    {
        return OpenAiChatModel.builder()
                .apiKey(System.getenv("aliQwen-api"))
                .modelName("qwen-long")
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .build();
    }

    @Bean
    public LawAssistant lawAssistant(ChatModel chatModel) {
        return AiServices.create(LawAssistant.class, chatModel);
    }
}

controller

@RestController
@Slf4j
public class ChatPromptController
{
    @Resource
    private LawAssistant lawAssistant;

    // http://localhost:9009/chatprompt/test1
    @GetMapping(value = "/chatprompt/test1")
    public String test1()
    {
        String chat = lawAssistant.chat("什么是知识产权?",2000);
        System.out.println(chat);

        String chat2 = lawAssistant.chat("什么是java?",2000);
        System.out.println(chat2);

        String chat3 = lawAssistant.chat("介绍下西瓜和芒果",2000);
        System.out.println(chat3);

        String chat4 = lawAssistant.chat("飞机发动机原理",2000);
        System.out.println(chat4);

        return "success : "+ DateUtil.now()+"<br> \n\n chat: "+chat+"<br> \n\n chat2: "+chat2;
    }
}
② 第二组

新建带着@StructuredPrompt的业务实体类

@Data
@StructuredPrompt("根据中国{{legal}}法律,解答以下问题:{{question}}")
public class LawPrompt
{
    private String legal;
    private String question;
}

接口类

public interface LawAssistant
{
    //案例1
    @SystemMessage("你是一位专业的中国法律顾问,只回答与中国法律相关的问题。" +
            "输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。'")
    @UserMessage("请回答以下法律问题:{{question}},字数控制在{{length}}以内")
    String chat(@V("question") String question, @V("length") int length);

    //案例2
    @SystemMessage("你是一位专业的中国法律顾问,只回答与中国法律相关的问题。" +
            "输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。'")
    String chat(LawPrompt lawPrompt);
}
Controller
    @GetMapping(value = "/chatprompt/test2")
    public String test2()
    {
        LawPrompt prompt = new LawPrompt();

        prompt.setLegal("知识产权");
        prompt.setQuestion("TRIPS协议?");

        String chat = lawAssistant.chat(prompt);

        System.out.println(chat);

        return "success : "+ DateUtil.now()+"<br> \n\n chat: "+chat;
    }
③ 第三组

直接Controller

    /**
    * @Description: 单个参数可以使用{{it}》”占位符或者”{{参数名}”,如果为其他字符,系统不能自动识别会报错。
    * @Auther: zzyybs@126.com
    */
    @GetMapping(value = "/chatprompt/test3")
    public String test3()
    {
        // 默认 PromptTemplate 构造使用 it 属性作为默认占位符

        String role = "外科医生";
        String question = "牙疼";

        /*String role = "财务会计";
        String question = "人民币大写";*/

        //1 构造PromptTemplate模板
        PromptTemplate template = PromptTemplate.from("你是一个{{it}}助手,{{question}}怎么办");
        //2 由PromptTemplate生成Prompt
        Prompt prompt = template.apply(Map.of("it",role,"question",question));
        //3 Prompt提示词变成UserMessage
        UserMessage userMessage = prompt.toUserMessage();
        //4 调用大模型
        ChatResponse chatResponse = chatModel.chat(userMessage);

        //4.1 后台打印
        System.out.println(chatResponse.aiMessage().text());
        //4.2 前台返回
        return "success : "+ DateUtil.now()+"<br> \n\n chat: "+chatResponse.aiMessage().text();
    }

十、LangChain4j之持久化

10.1 设计要求

将客户和大模型的对话问答保存进Redis进行持久化记忆留存

10.2 建module

langchain4j-10chat-persistence

10.3 改POM
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--langchain4j-open-ai + langchain4j + langchain4j-reactor-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-reactor</artifactId>
        </dependency>
        <!--spring-boot-starter-data-redis
            https://docs.langchain4j.dev/tutorials/chat-memory#persistence
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
10.4 写YML
server.port=9010
spring.application.name=langchain4j-10chat-persistence

server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true

spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.database=0
spring.data.redis.connect-timeout=3s
spring.data.redis.timeout=2s
10.5 主启动
10.6 业务类

① 新建高阶接口ChatPersistenceAssistant

public interface ChatPersistenceAssistant
{
    /**
     * 聊天
     * @param userId  用户 ID
     * @param message 消息
     * @return {@link String }
     */
    String chat(@MemoryId Long userId, @UserMessage String message);
}

② Redis 配置类

@Configuration
@Slf4j
public class RedisConfig
{

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactor)
    {
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(redisConnectionFactor);
        //设置key序列化方式string
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }
}

③ 自定义客户化ChatMemoryStore接口类

@Component
public class RedisChatMemoryStore implements ChatMemoryStore
{

    public static final String CHAT_MEMORY_PREFIX = "CHAT_MEMORY:";

    @Resource
    private RedisTemplate<String,String> redisTemplate;


    @Override
    public List<ChatMessage> getMessages(Object memoryId)
    {
        String retValue = redisTemplate.opsForValue().get(CHAT_MEMORY_PREFIX + memoryId);

        return  ChatMessageDeserializer.messagesFromJson(retValue);
    }

    @Override
    public void updateMessages(Object memoryId, List<ChatMessage> messages)
    {
        redisTemplate.opsForValue().set(CHAT_MEMORY_PREFIX + memoryId, ChatMessageSerializer.messagesToJson(messages));
    }

    @Override
    public void deleteMessages(Object memoryId)
    {
        redisTemplate.delete(CHAT_MEMORY_PREFIX + memoryId);
    }
}

④、 LLMConfig配置类

    @Bean
    public ChatPersistenceAssistant chatMemoryAssistant(ChatModel chatModel)
    {

        ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder()
                .id(memoryId)
                .maxMessages(1000)
                .chatMemoryStore(redisChatMemoryStore)
                .build();

        return AiServices.builder(ChatPersistenceAssistant.class)
                .chatModel(chatModel)
                .chatMemoryProvider(chatMemoryProvider)
                .build();
    }

Logo

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

更多推荐