<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      LangChain4j實(shí)戰(zhàn):模型參數(shù)配置、多模態(tài)、流式輸出、聊天記憶、提示詞工程全解析

      LangChain4j實(shí)戰(zhàn):模型參數(shù)配置、多模態(tài)、流式輸出、聊天記憶、提示詞工程全解析

      前提

      后面用于演示的代碼環(huán)境為: JDK-21,apache-maven-3.6.2,spring-boot和langchain4j的版本如下面pom文件所示

          <properties>
              <maven.compiler.source>21</maven.compiler.source>
              <maven.compiler.target>21</maven.compiler.target>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
              <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
              <java.version>21</java.version>
              <!--Spring Boot-->
              <spring-boot.version>3.5.3</spring-boot.version>
              <!--LangChain4J-->
              <langchain4j.version>1.7.1</langchain4j.version>
              <!--LangChain4J community-->
              <langchain4j-community.version>1.7.1-beta14</langchain4j-community.version>
          </properties>
          <dependencyManagement>
              <dependencies>
                  <!--Spring Boot-->
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-dependencies</artifactId>
                      <version>${spring-boot.version}</version>
                      <type>pom</type>
                      <scope>import</scope>
                  </dependency>
                  <!--LangChain4J-->
                  <dependency>
                      <groupId>dev.langchain4j</groupId>
                      <artifactId>langchain4j-bom</artifactId>
                      <version>${langchain4j.version}</version>
                      <type>pom</type>
                      <scope>import</scope>
                  </dependency>
                  <!--langchain4j-community-->
                  <dependency>
                      <groupId>dev.langchain4j</groupId>
                      <artifactId>langchain4j-community-bom</artifactId>
                      <version>${langchain4j-community.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>
                      <version>${spring-boot.version}</version>
                  </plugin>
                  <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-compiler-plugin</artifactId>
                      <version>3.8.1</version>
                      <configuration>
                          <source>21</source>
                          <target>21</target>
                      </configuration>
                  </plugin>
              </plugins>
          </build>
      

      模型參數(shù)配置

      根據(jù)選擇的模型和提供商,可以調(diào)整很多參數(shù),這里以O(shè)penAI API的參數(shù)為例進(jìn)行講解

      LangChain4j提供了模型構(gòu)建器,我們可以使用構(gòu)建器模式設(shè)置模型的參數(shù),由于參數(shù)很多這里重點(diǎn)講日志打印,監(jiān)聽(tīng)機(jī)制,重試機(jī)制,超時(shí)機(jī)制的參數(shù)配置

      1

      基本使用的模型配置

      如果僅是使用模型,那么只需要設(shè)置基本參數(shù)-大模型請(qǐng)求地址,模型名稱,個(gè)人密鑰

      @Configuration
      public class LLMConfig {
          @Bean
          public ChatModel chatModelQwen() {
              return OpenAiChatModel.builder()            
                      //api-key
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      //調(diào)用模型名
                      .modelName("qwen-plus")
                      //調(diào)用阿里云百煉平臺(tái)大模型的url
                      .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                      .build();
          }
      }
      

      日志打印配置

      通過(guò)模型配置參數(shù)實(shí)現(xiàn)打印請(qǐng)求大模型與大模型返回的日志

      前提

      需要有SLF4J日志后端依賴,調(diào)整全局日志打印級(jí)別并指定langchain4j包的日志打印級(jí)別,配置文件如下

      <dependency>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-classic</artifactId>
          <version>1.5.8</version>
      </dependency>
      
      logging:
        level:
          # 設(shè)置全局日志級(jí)別為INFO
          root: INFO
          # 設(shè)置特定包的日志打印級(jí)別為DEBUG
          dev.langchain4j: DEBUG
      

      打印日志的模型配置

      @Configuration
      public class LLMConfig {
          @Bean(value = "qwen")
          public ChatModel chatModelQwen() {
              return OpenAiChatModel.builder()
                      //api-key
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      //調(diào)用模型名
                      .modelName("qwen-plus")
                      //調(diào)用阿里云百煉平臺(tái)大模型的url
                      .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                      //日志配置-打印請(qǐng)求日志
                      .logRequests(true)
                      //日志配置-打印返回日志
                      .logResponses(true)
                      .build();
          }
      }
      

      監(jiān)聽(tīng)機(jī)制配置

      大模型(ChatModel或StreamingChatModel)允許配置ChatModelListener來(lái)監(jiān)聽(tīng)事件,如向LLM發(fā)送請(qǐng)求時(shí),收到響應(yīng)時(shí),異常時(shí)
      

      構(gòu)建監(jiān)聽(tīng)實(shí)現(xiàn)類

      @Slf4j
      public class TestChatModelListener implements ChatModelListener {
      
          /**
           * 向 LLM 發(fā)送的請(qǐng)求時(shí)的監(jiān)聽(tīng)事件
           *
           * @param requestContext The request context.
           */
          @Override
          public void onRequest(ChatModelRequestContext requestContext) {
              // 使用Hutool工具庫(kù)中的id生成工具生成UUID
              String uuid = IdUtil.simpleUUID();
              requestContext.attributes().put("traceId", uuid);
              log.info("[請(qǐng)求監(jiān)聽(tīng)] 請(qǐng)求參數(shù) requestContext: " + requestContext.attributes().toString());
          }
      
          /**
           * 來(lái)自 LLM 的響應(yīng)時(shí)的監(jiān)聽(tīng)事件
           *
           * @param responseContext The response context.
           */
          @Override
          public void onResponse(ChatModelResponseContext responseContext) {
              log.info("[響應(yīng)監(jiān)聽(tīng)] 返回結(jié)果 responseContext: " + responseContext.attributes().toString());
          }
      
          /**
           * 錯(cuò)誤的監(jiān)聽(tīng)事件
           *
           * @param errorContext The error context.
           */
          @Override
          public void onError(ChatModelErrorContext errorContext) {
              log.error("[異常監(jiān)聽(tīng)] 請(qǐng)求異常 errorContext: " + errorContext);
          }
      }
      

      監(jiān)聽(tīng)機(jī)制的模型配置

      @Configuration
      public class LLMConfig {
          @Bean(value = "qwen")
          public ChatModel chatModelQwen() {
              return OpenAiChatModel.builder()
                      //api-key
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      //調(diào)用模型名
                      .modelName("qwen-plus-2025-04-28")
                      //調(diào)用阿里云百煉平臺(tái)大模型的url
                      .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                      //監(jiān)聽(tīng)配置
                      .listeners(List.of(new TestChatModelListener()))
                      .build();
          }
      }
      

      重試機(jī)制配置

      即調(diào)用失敗時(shí)的重試次數(shù),默認(rèn)是調(diào)用兩次

      2

      @Configuration
      public class LLMConfig {
          @Bean(value = "qwen")
          public ChatModel chatModelQwen() {
              return OpenAiChatModel.builder()
                      //api-key
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      //調(diào)用模型名
                      .modelName("qwen-plus-2025-04-28")
                      //調(diào)用阿里云百煉平臺(tái)大模型的url
                      .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                      //重試配置
                      .maxRetries(3)
                      .build();
          }
      }
      

      超時(shí)機(jī)制配置

      即配置連接超時(shí)時(shí)間和讀超時(shí)時(shí)間,默認(rèn)是連接超時(shí)時(shí)間為15s,讀超時(shí)時(shí)間為60s

      @Configuration
      public class LLMConfig {
          @Bean(value = "qwen")
          public ChatModel chatModelQwen() {
              return OpenAiChatModel.builder()
                      //api-key
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      //調(diào)用模型名
                      .modelName("qwen-plus-2025-04-28")
                      //調(diào)用阿里云百煉平臺(tái)大模型的url
                      .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                      //請(qǐng)求超時(shí)配置
                      .timeout(Duration.ofSeconds(2))
                      .build();
          }
      }
      

      多模態(tài)

      大模型的能力不僅僅局限于文本生成,還可以應(yīng)用于視圖理解,圖片生成,語(yǔ)音識(shí)別,語(yǔ)音合成,視頻生成等等,這里主要演示LangChain4j調(diào)用大模型的視圖理解與圖片生成的能力

      前提

      首先需要選取具體視圖理解與圖片生成的大模型,下面是大模型的配置類與依賴pom文件示例

      pom依賴

          <dependencies>
              <!--快速構(gòu)建一個(gè)基于 Spring MVC 的 Web 應(yīng)用程序而預(yù)置的一組依賴項(xiàng)的集合-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <!--一個(gè)通過(guò)注解在編譯時(shí)自動(dòng)生成 Java 樣板代碼的庫(kù)-->
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
              </dependency>
              <!--hutool Java工具庫(kù)-->
              <dependency>
                  <groupId>cn.hutool</groupId>
                  <artifactId>hutool-all</artifactId>
                  <version>5.8.40</version>
              </dependency>
              <!--對(duì) Spring Boot 應(yīng)用程序進(jìn)行全面測(cè)試而預(yù)置的一組測(cè)試相關(guān)依賴項(xiàng)的集合-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-test</artifactId>
              </dependency>
              <!--LangChain4J openAI集成依賴-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j-open-ai</artifactId>
              </dependency>
              <!--LangChain4J 高級(jí)AI服務(wù)API依賴-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j</artifactId>
              </dependency>
              <!--DashScope-阿里云開(kāi)發(fā)的平臺(tái)與langchain4j集成-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j-community-dashscope</artifactId>
              </dependency>
          </dependencies>
      

      大模型配置類

      @Configuration
      public class LLMConfig {
          @Bean
          public ChatModel chatLanguageModel() {
              return OpenAiChatModel.builder()
                      //api-key
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      //調(diào)用模型名
                      .modelName("qwen3-vl-plus")
                      //調(diào)用阿里云百煉平臺(tái)大模型的url
                      .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                      .build();
          }
      
          /**
           * 文本生成圖片模型-通義萬(wàn)相
           *
           * @return 通義萬(wàn)相模型
           */
          @Bean
          public WanxImageModel wanxImageModel() {
              return WanxImageModel.builder()
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      .modelName("wan2.5-t2i-preview")
                      .build();
          }
      }
      

      視圖理解的控制層接口

      視圖理解功能需要將圖片轉(zhuǎn)換為字節(jié)數(shù)組并通過(guò)base64編碼轉(zhuǎn)換為字符串后與文本提示詞一起傳輸給大模型進(jìn)行分析

      @Slf4j
      @RestController
      @RequestMapping(value = "/image")
      public class ImageModelController {
          @Autowired
          private ChatModel chatModel;
          @Value("classpath:static/image/TencentQuarterlyReport.png")
          private Resource resource;
      
          /**
           * 多模態(tài)調(diào)用,采用文本加圖片的形式進(jìn)行圖片理解
           *
           * @return 圖片理解內(nèi)容
           * @throws IOException IO異常
           */
          @GetMapping("/readImage")
          public String readImageContent() throws IOException {
              String modelResult = null;
              //圖片轉(zhuǎn)碼,通過(guò)Base64編碼將圖片轉(zhuǎn)換為字符串
              byte[] byteArray = resource.getContentAsByteArray();
              String base64Str = Base64.getEncoder().encodeToString(byteArray);
      
              //多模塊提示詞,既包含文本也包含圖片,同時(shí)發(fā)送給大模型進(jìn)行處理
              UserMessage userMessage = UserMessage.from(
                      TextContent.from("從下面圖片中分析圖片中內(nèi)容,提煉出中心主旨"),
                      ImageContent.from(base64Str, "image/png")
              );
      
              //API調(diào)用
              ChatResponse chatResponse = chatModel.chat(userMessage);
      
              //解析響應(yīng)體,從ChatResponse中獲取AI大模型的回復(fù)
              modelResult = chatResponse.aiMessage().text();
              log.info("大模型返回結(jié)果為: {}", modelResult);
              return modelResult;
          }
      }
      

      圖片生成的控制層接口

      圖片生成的輸入和文本生成的輸入類似,均是輸入提示詞,圖片生成大模型以通義萬(wàn)相為例會(huì)返回一個(gè)有效期24小時(shí)的圖像下載鏈接

      @Slf4j
      @RestController
      @RequestMapping(value = "/image")
      public class WanxImageController {
          @Autowired
          private WanxImageModel wanxImageModel;
      
          /**
           * 基于通義萬(wàn)相模型調(diào)用接口生成圖片
           *
           * @return 圖片URL
           */
          @GetMapping(value = "/imageCreate/one")
          public String imageCreateOne() {
              Response<Image> response = wanxImageModel.generate("生成一幅水墨畫(huà)");
              log.info("[生成圖片]生成圖片的url為:{}", response.content().url());
              return response.content().url().toString();
          }
      
          /**
           * 在不構(gòu)建模型配置的情況下通過(guò)dashscope依賴類生成圖片
           *
           * @return 圖片URL
           */
          @GetMapping(value = "/imageCreate/two")
          public String imageCreateTwo() {
              String prompt = "一副典雅莊重的對(duì)聯(lián)懸掛于廳堂之中,房間是個(gè)安靜古典的中式布置,桌子上放著一些青花瓷,對(duì)聯(lián)上左書(shū)“義本生知人機(jī)同道善思新”,右書(shū)“通云賦智乾坤啟數(shù)高志遠(yuǎn)”, 橫批“智啟通義”,字體飄逸,中間掛在一著一副中國(guó)風(fēng)的畫(huà)作,內(nèi)容是岳陽(yáng)樓。";
              Map<String, Object> parameters = new HashMap<>();
              parameters.put("prompt_extend", true);
              parameters.put("watermark", true);
              ImageSynthesisParam param =
                      ImageSynthesisParam.builder()
                              .apiKey(System.getenv("aliyunQwen-apiKey"))
                              .model("qwen-image")
                              .prompt(prompt)
                              .n(1)
                              .size("1328*1328")
                              .parameters(parameters)
                              .build();
      
              ImageSynthesis imageSynthesis = new ImageSynthesis();
              ImageSynthesisResult result = null;
              try {
                  log.info("---同步調(diào)用,請(qǐng)等待任務(wù)執(zhí)行----");
                  result = imageSynthesis.call(param);
              } catch (ApiException | NoApiKeyException e) {
                  throw new RuntimeException(e.getMessage());
              }
              String jsonResult = JsonUtils.toJson(result);
              log.info(jsonResult);
              return jsonResult;
          }
      }
      

      流式輸出

      LLM一次生成一個(gè)標(biāo)記(token),因此很多LLM提供商提供了一種方式,可以逐個(gè)標(biāo)記地流式傳輸響應(yīng),而不是等待整個(gè)文本生成完畢。這顯著改善了用戶體驗(yàn),因?yàn)橛脩舨恍枰却粗臅r(shí)間,幾乎可以立即開(kāi)始閱讀響應(yīng)。

      前提

      流式輸出中用到了響應(yīng)時(shí)編程的核心類Flux,因此需要簡(jiǎn)單講解一下Flux類,以及需要的依賴和配置文件

      Flux類

      Flux是io.projectreactor響應(yīng)式編程庫(kù)的核心類,用于表示0到N個(gè)元素的異步序列,可以發(fā)射0個(gè),1個(gè)或多個(gè)元素,支持背壓(Backpressure)。
      
      適用場(chǎng)景: 如處理數(shù)據(jù)庫(kù)多條記錄,消息隊(duì)列,實(shí)時(shí)時(shí)間流等。
      

      pom依賴

          <dependencies>
              <!--快速構(gòu)建一個(gè)基于 Spring MVC 的 Web 應(yīng)用程序而預(yù)置的一組依賴項(xiàng)的集合-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <!--一個(gè)通過(guò)注解在編譯時(shí)自動(dòng)生成 Java 樣板代碼的庫(kù)-->
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
              </dependency>
              <!--LangChain4J openAI集成依賴(低級(jí)API依賴)-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j-open-ai</artifactId>
              </dependency>
              <!--LangChain4J 高級(jí)AI服務(wù)API依賴-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j</artifactId>
              </dependency>
              <!--LangChain4J 響應(yīng)式編程依賴(AI服務(wù)使用Flux)-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j-reactor</artifactId>
              </dependency>
              <!--hutool Java工具庫(kù)-->
              <dependency>
                  <groupId>cn.hutool</groupId>
                  <artifactId>hutool-all</artifactId>
                  <version>5.8.40</version>
              </dependency>
          </dependencies>
      

      配置文件

      server:
        servlet:
          # 設(shè)置響應(yīng)的字符編碼,避免流式返回輸出亂碼
          encoding:
            charset: UTF-8
            enabled: true
            force: true
      

      低階LLM API的流式輸出

      對(duì)于ChatModel和LanguageModel接口,有相應(yīng)的StreamingChatLanguageModel和StreamingLanguageModel接口。這些接口有類似的API,但可以流式傳輸響應(yīng)。它們接受StreamingChatResponseHandler接口實(shí)現(xiàn)作為參數(shù)

      3

      public interface StreamingChatResponseHandler {
      
          // 當(dāng)生成下一個(gè)部分文本響應(yīng)時(shí)
          default void onPartialResponse(String partialResponse) {}
          default void onPartialResponse(PartialResponse partialResponse, PartialResponseContext context) {}
          
          // 當(dāng)生成下一個(gè)部分思考/推理文本時(shí)
          default void onPartialThinking(PartialThinking partialThinking) {}
          default void onPartialThinking(PartialThinking partialThinking, PartialThinkingContext context) {}
      
          // 當(dāng)生成下一個(gè)部分工具調(diào)用時(shí)
          default void onPartialToolCall(PartialToolCall partialToolCall) {}
          default void onPartialToolCall(PartialToolCall partialToolCall, PartialToolCallContext context) {}
      
          // 當(dāng)LLLM完成單個(gè)工具調(diào)用的流處理時(shí)
          default void onCompleteToolCall(CompleteToolCall completeToolCall) {}
      
          // 當(dāng)LLM完成生成時(shí)
          void onCompleteResponse(ChatResponse completeResponse);
      
          // d當(dāng)出現(xiàn)錯(cuò)誤時(shí)
          void onError(Throwable error);
      }
      

      高階LLM API的流式輸出

      可以直接使用Flux

      /**
       * 聲明式AI服務(wù)業(yè)務(wù)接口
       */
      public interface ChatAssistant {
          /**
           * 普通對(duì)話接口
           *
           * @param prompt 提示詞
           * @return 模型返回結(jié)果
           */
          String chat(String prompt);
      
          /**
           * 流式返回對(duì)話接口
           *
           * @param prompt 提示詞
           * @return 模型返回結(jié)果
           */
          Flux<String> chatFlux(String prompt);
      }
      

      低階與高階LLM API流式輸出示例

      大模型配置類

      @Configuration
      public class LLMConfig {
          /**
           * 普通對(duì)話模型配置
           *
           * @return chatLanguageModel
           */
          @Bean(value = "qwen")
          public ChatModel chatLanguageModelQwen() {
              return OpenAiChatModel.builder()
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      .modelName("qwen3-next-80b-a3b-instruct")
                      .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                      .build();
          }
      
          @Bean(value = "streamQwen")
          public StreamingChatModel streamingChatLanguageModelQwen() {
              return OpenAiStreamingChatModel.builder()
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      .modelName("qwen3-next-80b-a3b-instruct")
                      .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                      .build();
          }
      
          @Bean(value = "chatAssistant")
          public ChatAssistant chatAssistant(StreamingChatModel chatLanguageModel) {
              return AiServices.create(ChatAssistant.class, chatLanguageModel);
          }
      }
      

      流式輸出的控制層接口

      @Slf4j
      @RestController
      @RequestMapping(value = "/streamChat")
      public class StreamingChatController {
          /**
           * 低階的LLM API
           */
          @Autowired
          @Qualifier("streamQwen")
          private StreamingChatModel streamQwen;
          /**
           * 高階的LLM API(自己封裝接口)
           */
          @Autowired
          @Qualifier("chatAssistant")
          private ChatAssistant chatAssistant;
      
          /**
           * 低階LLM API 流式返回到頁(yè)面
           * @param prompt 提示詞
           * @return 異步序列
           */
          @GetMapping(value = "/chatOne")
          public Flux<String> chatOne(@RequestParam(value = "prompt", defaultValue = "你是誰(shuí)") String prompt) {
              return Flux.create(emitter -> streamQwen.chat(prompt, new StreamingChatResponseHandler() {
                  @Override
                  public void onPartialResponse(String partialResponse) {
                      emitter.next(partialResponse);
                  }
      
                  @Override
                  public void onCompleteResponse(ChatResponse completeResponse) {
                      emitter.complete();
                  }
      
                  @Override
                  public void onError(Throwable error) {
                      emitter.error(error);
                  }
              }));
          }
      
          /**
           * 低階LLM API 流式返回到后端
           * @param prompt 提示詞
           */
          @GetMapping(value = "/chatTwo")
          public void chatTwo(@RequestParam(value = "prompt", defaultValue = "你是誰(shuí)") String prompt) {
              streamQwen.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 error) {
                      error.printStackTrace();
                  }
              });
          }
      
          /**
           * 高階LLM API 直接調(diào)用封裝接口流式返回到頁(yè)面
           * @param prompt 提示詞 
           * @return 異步序列
           */
          @GetMapping(value = "/chatThree")
          public Flux<String> chatThree(@RequestParam(value = "prompt", defaultValue = "你是誰(shuí)") String prompt) {
              return chatAssistant.chatFlux(prompt);
          }
      
      }
      

      聊天記憶

      聊天記憶是指大模型在對(duì)話過(guò)程中,能夠記住,理解并利用之前交流過(guò)的內(nèi)容,來(lái)影響后續(xù)回答的能力。是大模型從一個(gè)"知識(shí)問(wèn)答工具"進(jìn)化為"智能對(duì)話伙伴"的關(guān)鍵技術(shù)。它通過(guò)巧妙地結(jié)合"短期記憶"(上下文窗口)和"長(zhǎng)期記憶"(外部知識(shí)庫(kù)),讓對(duì)話變得連貫、智能、個(gè)性化。

      記憶與歷史的區(qū)別

      歷史:
      歷史保持用戶和AI之間的所有消息完整無(wú)缺。歷史是用戶在UI中看到的內(nèi)容。它代表實(shí)際對(duì)話內(nèi)容。
      
      記憶:
      記憶保存了一些信息,這些信息呈現(xiàn)給LLM,使其表現(xiàn)得就像"記住"了對(duì)話一樣。記憶與歷史截然不同。根據(jù)使用的記憶算法,它可以以各種方式修改歷史:淘汰一些消息,總結(jié)多條消息,總結(jié)單獨(dú)的消息,從消息中刪除不重要的細(xì)節(jié),向消息中注入額外信息等等。
      
      注:當(dāng)前LangChain4j只提供"記憶",而不是"歷史"。
      

      淘汰策略

      采用淘汰策略的原因

      • 為了適應(yīng)LLM的上下文窗口。LLM一次可以處理的令牌(token)數(shù)量是有上限的。在某些時(shí)候,對(duì)話可能會(huì)超過(guò)這個(gè)限制。在這種情況下,應(yīng)該淘汰一些消息。通常,最舊的消息會(huì)被淘汰,但如果需要,可以實(shí)現(xiàn)更復(fù)雜的算法。
      • 控制成本。每個(gè)令牌(token)都有成本,使每次調(diào)用LLM的費(fèi)用逐漸增加。淘汰不必要的消息可以降低成本。
      • 控制延遲。發(fā)送給LLM的令牌(token)越多,處理它們所需的時(shí)間就越長(zhǎng)。

      LangChain4j提供的2種淘汰策略

      4

      • MessageWindowChatMemory:作為滑動(dòng)窗口運(yùn)行,保留最近的N條消息,并淘汰不再適合的舊消息。然而,由于每條消息可能包含不同數(shù)量的令牌,MessageWindowChatMemory主要用于快速原型設(shè)計(jì)。
      • TokenWindowChatMemory: 同樣作為滑動(dòng)窗口運(yùn)行,但專注于保留最近的N個(gè)令牌(token),根據(jù)需要淘汰舊消息。消息是不可分割的。如果一條消息不適合,它會(huì)被完全淘汰。TokenWindowChatMemory需要TokenCountEstimator來(lái)計(jì)數(shù)每個(gè)ChatMessage中的令牌(Token)。

      淘汰策略實(shí)現(xiàn)代碼示例

      pom依賴

          <dependencies>
              <!--快速構(gòu)建一個(gè)基于 Spring MVC 的 Web 應(yīng)用程序而預(yù)置的一組依賴項(xiàng)的集合-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <!--一個(gè)通過(guò)注解在編譯時(shí)自動(dòng)生成 Java 樣板代碼的庫(kù)-->
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
              </dependency>
              <!--LangChain4J openAI集成依賴(低級(jí)API依賴)-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j-open-ai</artifactId>
              </dependency>
              <!--LangChain4J 高級(jí)AI服務(wù)API依賴-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j</artifactId>
              </dependency>
              <!--LangChain4J 響應(yīng)式編程依賴(AI服務(wù)使用Flux)-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j-reactor</artifactId>
              </dependency>
              <!--hutool Java工具庫(kù)-->
              <dependency>
                  <groupId>cn.hutool</groupId>
                  <artifactId>hutool-all</artifactId>
                  <version>5.8.40</version>
              </dependency>
          </dependencies>
      

      聲明式AI服務(wù)業(yè)務(wù)接口

      構(gòu)建普通對(duì)話接口與帶有記憶緩存功能的對(duì)話接口,用于后續(xù)調(diào)用對(duì)比

      普通對(duì)話接口
      public interface ChatAssistant {
          /**
           * 普通對(duì)話接口
           *
           * @param prompt 提示詞
           * @return 模型返回結(jié)果
           */
          String chat(String prompt);
      }
      
      
      帶有記憶緩存功能的對(duì)話接口
      public interface ChatMemoryAssistant {
          /**
           * 帶有記憶緩存的聊天接口
           *
           * @param userId 用戶id
           * @param prompt 提示詞
           * @return 大模型返回內(nèi)容
           */
          String chatWithMemory(@MemoryId Long userId, @UserMessage String prompt);
      }
      

      大模型配置類

      包含普通對(duì)話的AI服務(wù)實(shí)例與具備記憶功能不同淘汰策略的兩種AI服務(wù)實(shí)例

      @Configuration
      public class LLMConfig {
          /**
           * 普通對(duì)話模型配置
           *
           * @return chatLanguageModel
           */
          @Bean(value = "qwen")
          public ChatModel chatLanguageModelQwen() {
              return OpenAiChatModel.builder()
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      .modelName("qwen3-next-80b-a3b-instruct")
                      .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                      .build();
          }
      
          /**
           * 基于低階模型實(shí)例構(gòu)建高階使用的AIServices實(shí)例
           *
           * @param chatModel 對(duì)話模型
           * @return AIServices實(shí)例
           */
          @Bean(value = "chat")
          public ChatAssistant chatAssistant(ChatModel chatModel) {
              return AiServices.create(ChatAssistant.class, chatModel);
          }
      
          /**
           * 構(gòu)建高階AIServices實(shí)例(基于保留消息數(shù)的滑動(dòng)窗口)
           *
           * @param chatModel 對(duì)話模型
           * @return AIServices實(shí)例
           */
          @Bean(value = "chatMemoryWithMessageWindow")
          public ChatMemoryAssistant chatMemoryWithMessageWindow(ChatModel chatModel) {
              return AiServices.builder(ChatMemoryAssistant.class)
                      .chatModel(chatModel)
                      //根據(jù)memoryId構(gòu)建一個(gè)ChatMemory,保留最多100條消息
                      .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(100))
                      .build();
          }
      
          /**
           * 構(gòu)建高階AIServices實(shí)例(基于保留Token數(shù)的滑動(dòng)窗口)
           *
           * @param chatModel 對(duì)話模型
           * @return AIServices實(shí)例
           */
          @Bean(value = "chatMemoryWithTokenWindow")
          public ChatMemoryAssistant chatMemoryWithTokenWindow(ChatModel chatModel) {
              // 構(gòu)建默認(rèn)的token分詞器
              TokenCountEstimator openAiTokenizer = new OpenAiTokenCountEstimator("gpt-4");
              return AiServices.builder(ChatMemoryAssistant.class)
                      .chatModel(chatModel)
                      //根據(jù)memoryId構(gòu)建一個(gè)ChatMemory,保留最多100條消息
                      .chatMemoryProvider(memoryId -> TokenWindowChatMemory.withMaxTokens(1000, openAiTokenizer))
                      .build();
          }
      }
      

      提供大模型調(diào)用的控制層接口

      @Slf4j
      @RestController
      @RequestMapping(value = "/memoryChat")
      public class ChatMemoryController {
          @Autowired
          @Qualifier("chat")
          private ChatAssistant chat;
      
          @Autowired
          @Qualifier("chatMemoryWithMessageWindow")
          private ChatMemoryAssistant chatMemoryWithMessageWindow;
      
          @Autowired
          @Qualifier("chatMemoryWithTokenWindow")
          private ChatMemoryAssistant chatMemoryWithTokenWindow;
      
          /**
           * 普通對(duì)話
           *
           * @return 調(diào)用結(jié)果
           */
          @GetMapping(value = "/chatOne")
          public String chatOne() {
              String answerOne = chat.chat("你好,我的名字叫張三");
              log.info("answerOne: {}", answerOne);
              String answerTwo = chat.chat("我的名字叫什么");
              log.info("answerTwo: {}", answerTwo);
              return "success : " + DateUtil.now() + "<br> \n\n answerOne: " + answerOne + "<br> \n\n answerTwo: " + answerTwo;
          }
      
          /**
           * 基于保留消息數(shù)的滑動(dòng)窗口淘汰策略的帶有記憶對(duì)話
           *
           * @return 調(diào)用結(jié)果
           */
          @GetMapping(value = "/chatTwo")
          public String chatTwo() {
              chatMemoryWithMessageWindow.chatWithMemory(1L, "你好,我的名字叫小明");
              String answerOne = chatMemoryWithMessageWindow.chatWithMemory(1L, "我的名字叫什么");
              log.info("answerOne: {}", answerOne);
      
              chatMemoryWithMessageWindow.chatWithMemory(3L, "你好,我的名字叫小紅");
              String answerTwo = chatMemoryWithMessageWindow.chatWithMemory(3L, "我的名字叫什么");
              log.info("answerTwo: {}", answerTwo);
              return "chatMemoryWithMessageWindow success : " + DateUtil.now() + "<br> \n\n answerOne: " + answerOne + "<br> \n\n answerTwo: " + answerTwo;
          }
      
          /**
           * 基于保留Token數(shù)的滑動(dòng)窗口淘汰策略的帶有記憶對(duì)話
           *
           * @return 調(diào)用結(jié)果
           */
          @GetMapping(value = "/chatThree")
          public String chatThree() {
              chatMemoryWithTokenWindow.chatWithMemory(1L, "你好,我的名字叫小明");
              String answerOne = chatMemoryWithTokenWindow.chatWithMemory(1L, "我的名字叫什么");
              log.info("answerOne: {}", answerOne);
      
              chatMemoryWithTokenWindow.chatWithMemory(5L, "你好,我的名字叫小紅");
              String answerTwo = chatMemoryWithTokenWindow.chatWithMemory(5L, "我的名字叫什么");
              log.info("answerTwo: {}", answerTwo);
              return "chatMemoryWithTokenWindow success : " + DateUtil.now() + "<br> \n\n answerOne: " + answerOne + "<br> \n\n answerTwo: " + answerTwo;
          }
      }
      

      聊天記憶持久化

      默認(rèn)情況下,ChatMemory實(shí)現(xiàn)在內(nèi)存中存儲(chǔ)ChatMessage。如果需要持久化,可以實(shí)現(xiàn)自定義的ChatMemoryStore,將ChatMessage存儲(chǔ)在你選擇的任何持久化存儲(chǔ)中

      通過(guò)redis實(shí)現(xiàn)聊天記憶持久化示例

      由于聲明式AI服務(wù)業(yè)務(wù)接口和控制層接口與上面的代碼類似就不做展示了

      pom依賴
          <dependencies>
              <!--快速構(gòu)建一個(gè)基于 Spring MVC 的 Web 應(yīng)用程序而預(yù)置的一組依賴項(xiàng)的集合-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <!--一個(gè)通過(guò)注解在編譯時(shí)自動(dòng)生成 Java 樣板代碼的庫(kù)-->
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
              </dependency>
              <!--LangChain4J openAI集成依賴(低級(jí)API依賴)-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j-open-ai</artifactId>
              </dependency>
              <!--LangChain4J 高級(jí)AI服務(wù)API依賴-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j</artifactId>
              </dependency>
              <!--LangChain4J 響應(yīng)式編程依賴(AI服務(wù)使用Flux)-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j-reactor</artifactId>
              </dependency>
              <!--hutool Java工具庫(kù)-->
              <dependency>
                  <groupId>cn.hutool</groupId>
                  <artifactId>hutool-all</artifactId>
                  <version>5.8.40</version>
              </dependency>
              <!-- springboot 集成redis數(shù)據(jù)源依賴-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-data-redis</artifactId>
              </dependency>
          </dependencies>
      
      配置文件
      server:
        port: 18190
        servlet:
          # 設(shè)置響應(yīng)的字符編碼,避免流式返回輸出亂碼
          encoding:
            charset: UTF-8
            enabled: true
            force: true
      spring:
        data:
          # redis配置文件
          redis:
            host: localhost
            port: 6379
            database: 0
            connect-timeout: 10s
            timeout: 10s
            password: 123456
      
      redis配置類
      @Slf4j
      @Configuration
      public class RedisConfig {
          @Bean
          public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactor) {
              RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
      
              redisTemplate.setConnectionFactory(redisConnectionFactor);
              //設(shè)置key序列化方式string
              redisTemplate.setKeySerializer(new StringRedisSerializer());
              //設(shè)置value的序列化方式j(luò)son,使用GenericJackson2JsonRedisSerializer替換默認(rèn)序列化
              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_STORE_PREFIX = "CHAT_MEMORY:";
      
          @Autowired
          private RedisTemplate<String, String> redisTemplate;
      
          /**
           * 實(shí)現(xiàn)通過(guò)內(nèi)存ID從持久化存儲(chǔ)中獲取所有消息
           * @param memoryId The ID of the chat memory.
           * @return 消息集合
           */
          @Override
          public List<ChatMessage> getMessages(Object memoryId) {
              String messageValue = redisTemplate.opsForValue().get(CHAT_MEMORY_STORE_PREFIX + memoryId);
              return ChatMessageDeserializer.messagesFromJson(messageValue);
          }
      
          /**
           * 實(shí)現(xiàn)通過(guò)內(nèi)存ID更新持久化存儲(chǔ)中的所有消息
           * @param memoryId The ID of the chat memory.
           * @param messages List of messages for the specified chat memory, that represent the current state of the {@link ChatMemory}.
           *                 Can be serialized to JSON using {@link ChatMessageSerializer}.
           */
          @Override
          public void updateMessages(Object memoryId, List<ChatMessage> messages) {
              redisTemplate.opsForValue().set(CHAT_MEMORY_STORE_PREFIX + memoryId,
                      ChatMessageSerializer.messagesToJson(messages));
          }
      
          /**
           * 實(shí)現(xiàn)通過(guò)內(nèi)存ID刪除持久化存儲(chǔ)中的所有消息
           * @param memoryId The ID of the chat memory.
           */
          @Override
          public void deleteMessages(Object memoryId) {
              redisTemplate.delete(CHAT_MEMORY_STORE_PREFIX + memoryId);
          }
      }
      
      大模型配置類
      @Configuration
      public class LLMConfig {
          @Autowired
          private RedisChatMemoryStore redisChatMemoryStore;
      
          /**
           * 普通對(duì)話模型配置
           *
           * @return chatModel
           */
          @Bean(value = "qwen")
          public ChatModel chatLanguageModelQwen() {
              return OpenAiChatModel.builder()
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      .modelName("qwen3-next-80b-a3b-instruct")
                      .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                      .build();
          }
      
          @Bean
          public ChatPersistenceAssistant chatPersistenceAssistant(ChatModel chatModel) {
              ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder()
                      .id(memoryId)
                      .maxMessages(1000)
                      .chatMemoryStore(redisChatMemoryStore)
                      .build();
              return AiServices.builder(ChatPersistenceAssistant.class)
                      .chatModel(chatModel)
                      .chatMemoryProvider(chatMemoryProvider)
                      .build();
          }
      
      }
      

      提示詞工程

      在日常使用大模型的過(guò)程中,我們常常會(huì)遇到這樣的場(chǎng)景:簡(jiǎn)單地向AI提問(wèn)"寫個(gè)故事",結(jié)果往往是一篇泛泛而談,缺乏方向的內(nèi)容;而如果我們換一種方式,給出"請(qǐng)寫一個(gè)關(guān)于小狗勇闖森林的童話故事,要正能量,用小學(xué)生能聽(tīng)懂的語(yǔ)言",AI的輸出便立刻貼近我們的預(yù)期。這種差異,正是普通提問(wèn)與提示詞(Prompt)之間的區(qū)別--前者往往模糊、隨意;后者則清洗、結(jié)構(gòu)化,包含任務(wù)目標(biāo)、角色設(shè)定、語(yǔ)氣風(fēng)格、格式要求等關(guān)鍵信息。

      普通提問(wèn)就像與AI隨意聊天,期待它"猜出"我們的需求;而提示詞更像是一份精準(zhǔn)的"說(shuō)明書(shū)",讓AI明確"做什么、怎么做"。通過(guò)精心設(shè)計(jì)的提示詞,我們可以顯著提升AI生成的內(nèi)容的質(zhì)量和針對(duì)性,這就是提示詞工程的核心價(jià)值。

      提示詞的演進(jìn)歷程

      1. 簡(jiǎn)單的純提示詞提問(wèn)問(wèn)題
      2. 引入占位符(Prompt Template)以動(dòng)態(tài)插入內(nèi)容
      3. 多角色消息: 將消息分為不同角色(如用戶、助手、系統(tǒng)等),設(shè)置功能邊界,增強(qiáng)交互的復(fù)雜性和上下文感知能力。

      ChatMessage的4種類型

      目前有五種類型的聊天消息,但其中一種CustomMessage僅支持Ollama,因此一般說(shuō)4種

      5

      UserMessage

      這是來(lái)自用戶的消息。用戶可以是應(yīng)用程序的最終用戶,也可以是應(yīng)用程序本身。

      UserMessage包含的屬性為:
      contents: 消息內(nèi)容。根據(jù)LLM支持的模式,它可以包含一個(gè)文本或其他形式。
      name: 用戶名。并不是所有的模型提供者都支持它。
      attributes: 附加屬性。這些屬性不發(fā)送到模型,但是存儲(chǔ)在聊天記憶(ChatMemory)當(dāng)中。
      

      AiMessage

      該消息是由AI生成的,是對(duì)已發(fā)送消息的響應(yīng)。

      AiMessage包含的屬性為:
      text: 文本內(nèi)容。
      thinking: 思考/推理內(nèi)容。
      toolExecutionRequests: 執(zhí)行工具的請(qǐng)求。
      attributes: 額外的屬性,通常是特定于提供的程序的。
      

      ToolExecutionResultMessage

      ToolExecutionResultMessage是ToolExecutionRequest的結(jié)果。
      

      SystemMessage

      來(lái)自系統(tǒng)的消息。通常,作為開(kāi)發(fā)人員應(yīng)該定義此消息的內(nèi)容。通常,你會(huì)在這里寫一些說(shuō)明,說(shuō)明LLM在這次對(duì)話中的角色,它應(yīng)該如何表現(xiàn),以什么方式回答,等等。LLM被訓(xùn)練得比其他類型的消息更關(guān)注SystemMessage,所以要小心,最后不要讓最終用戶自由地定義或注入一些輸入到SystemMessage。通常,它位于對(duì)話的開(kāi)始。
      

      CustomMessage

      這是一個(gè)自定義消息,可以包含任意屬性。此消息類型目前僅支持Ollama。
      

      提示詞工程示例:打造專業(yè)的限定能力范圍的AI助手

      本示例通過(guò)三種方式來(lái)體現(xiàn)多消息角色的使用

      pom依賴

          <dependencies>
              <!--快速構(gòu)建一個(gè)基于 Spring MVC 的 Web 應(yīng)用程序而預(yù)置的一組依賴項(xiàng)的集合-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <!--一個(gè)通過(guò)注解在編譯時(shí)自動(dòng)生成 Java 樣板代碼的庫(kù)-->
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
              </dependency>
              <!--LangChain4J openAI集成依賴(低級(jí)API依賴)-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j-open-ai</artifactId>
              </dependency>
              <!--LangChain4J 高級(jí)AI服務(wù)API依賴-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j</artifactId>
              </dependency>
              <!--LangChain4J 響應(yīng)式編程依賴(AI服務(wù)使用Flux)-->
              <dependency>
                  <groupId>dev.langchain4j</groupId>
                  <artifactId>langchain4j-reactor</artifactId>
              </dependency>
              <!--hutool Java工具庫(kù)-->
              <dependency>
                  <groupId>cn.hutool</groupId>
                  <artifactId>hutool-all</artifactId>
                  <version>5.8.40</version>
              </dependency>
          </dependencies>
      

      聲明式AI服務(wù)業(yè)務(wù)接口

      設(shè)計(jì)為計(jì)算機(jī)領(lǐng)域助手

      public interface ComputerChatAssistant {
      
          @SystemMessage("你是一位專業(yè)的計(jì)算機(jī)領(lǐng)域知識(shí)顧問(wèn),只回答計(jì)算機(jī)領(lǐng)域相關(guān)的問(wèn)題" +
                  "輸出限制: 禁止回答非計(jì)算機(jī)領(lǐng)域的問(wèn)題,直接返回'我只能回答計(jì)算機(jī)領(lǐng)域相關(guān)的問(wèn)題'")
          @UserMessage("請(qǐng)回答以下問(wèn)題: {{question}} , 字?jǐn)?shù)控制在{{length}}以內(nèi)")
          String chat(@V("question") String question, @V("length") int length);
      
          @SystemMessage("你是一位專業(yè)的計(jì)算機(jī)領(lǐng)域知識(shí)顧問(wèn),只回答計(jì)算機(jī)領(lǐng)域相關(guān)的問(wèn)題" +
                  "輸出限制: 禁止回答非計(jì)算機(jī)領(lǐng)域的問(wèn)題,直接返回'我只能回答計(jì)算機(jī)領(lǐng)域相關(guān)的問(wèn)題'")
          String chat(ComputerPrompt prompt);
      }
      

      提示詞業(yè)務(wù)實(shí)體類

      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      @StructuredPrompt("根據(jù){{language}}語(yǔ)言, 解答以下問(wèn)題: {{question}}")
      public class ComputerPrompt {
          private String language;
          private String question;
      }
      

      大模型配置類

      @Configuration
      public class LLMConfig {
          @Bean(value = "qwen")
          public ChatModel chatModelQwen() {
              return OpenAiChatModel.builder()
                      .apiKey(System.getenv("aliyunQwen-apiKey"))
                      .modelName("qwen3-next-80b-a3b-instruct")
                      .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                      .build();
          }
      
          @Bean(value = "computerChatAssistant")
          public ComputerChatAssistant computerChatAssistant(ChatModel chatModel) {
              return AiServices.create(ComputerChatAssistant.class, chatModel);
          }
      }
      
      

      提供大模型調(diào)用的控制層接口

      @Slf4j
      @RestController
      @RequestMapping(value = "/chatPrompt")
      public class ChatPromptController {
          @Autowired
          @Qualifier("computerChatAssistant")
          private ComputerChatAssistant computerChatAssistant;
      
          @Autowired
          @Qualifier("qwen")
          private ChatModel qwen;
      
          /**
           * 方式一:@SystemMessage+@UserMessage+@V
           *
           * @return 大模型返回結(jié)果
           */
          @GetMapping(value = "/chatMethod1")
          public String chatMethod1() {
              String answer1 = computerChatAssistant.chat("計(jì)算機(jī)由什么組成", 1000);
              log.info("answer1: {}", answer1);
              String answer2 = computerChatAssistant.chat("蘋果富含哪些營(yíng)養(yǎng)", 1000);
              log.info("answer2: {}", answer2);
              return "success :" + DateUtil.now() + "<br> \n\n answer1: " + answer1 + "<br> \n\n answer2: " + answer2;
          }
      
          /**
           * 方式二:@SystemMessage + 帶有@StructuredPrompt的業(yè)務(wù)實(shí)體類
           *
           * @return
           */
          @GetMapping(value = "/chatMethod2")
          public String chatMethod2() {
              ComputerPrompt computerPrompt = new ComputerPrompt();
              computerPrompt.setLanguage("Java");
              computerPrompt.setQuestion("數(shù)據(jù)基本類型有哪些");
              String answer = computerChatAssistant.chat(computerPrompt);
              log.info("answer: {}", answer);
              return "success :" + DateUtil.now() + "<br> \n\n answer: " + answer;
          }
      
          /**
           * 方式三: PromptTemplate+Prompt
           *
           * @return
           */
          @GetMapping(value = "/chatMethod3")
          public String chatMethod3() {
              String role = "金融專家";
              String question = "股票如何選購(gòu)";
      
              //1.構(gòu)建提示詞模版
              PromptTemplate promptTemplate = PromptTemplate.from("你是一個(gè){{role}}助手,回答以下內(nèi)容{{question}}");
              //2.由提示詞模版生成提示詞
              Prompt prompt = promptTemplate.apply(Map.of("role", role, "question", question));
              //3.提示詞生成UserMessage
              UserMessage userMessage = prompt.toUserMessage();
              //4.調(diào)用大模型
              ChatResponse chatResponse = qwen.chat(userMessage);
              log.info("chatResponse: {}", chatResponse);
              return "success :" + DateUtil.now() + "<br> \n\n chatResponse: " + chatResponse.aiMessage().text();
          }
      }
      

      參考資料

      https://docs.langchain4j.dev/tutorials/model-parameters

      https://docs.langchain4j.dev/tutorials/logging

      https://docs.langchain4j.dev/tutorials/observability

      https://bailian.console.aliyun.com/?tab=doc#/doc/?type=model&url=2848513

      https://docs.langchain4j.dev/tutorials/response-streaming

      https://docs.langchain4j.dev/tutorials/chat-memory

      https://docs.langchain4j.dev/tutorials/chat-and-language-models

      posted @ 2025-11-05 16:25  柯南。道爾  閱讀(13)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 奇米777四色在线精品| 亚洲av激情一区二区三区| 精品人妻少妇一区二区三区| 日韩有码中文字幕av| 国产精品中文字幕在线| 国产精品自在拍首页视频8| 91中文字幕一区在线| 午夜高清国产拍精品福利| 麻豆国产va免费精品高清在线| 国产不卡一区二区三区视频| 国产精品v欧美精品∨日韩| 日本道不卡一二三区视频 | 少妇粗大进出白浆嘿嘿视频| 国产亚洲一区二区三区av| 日亚韩在线无码一区二区三区| 蜜桃av无码免费看永久| 中文字幕网红自拍偷拍视频| 四虎国产精品永久免费网址| 中文字幕日韩国产精品| 最新亚洲av日韩av二区| 精品九九人人做人人爱| 国产精品一二二区视在线| 精品国精品无码自拍自在线| 国产精品国产精品偷麻豆| 色综合AV综合无码综合网站| 国产初高中生粉嫩无套第一次| 四虎精品视频永久免费| 开江县| 一区二区三区无码免费看| 久久精品国产99久久丝袜| 黑人异族巨大巨大巨粗| 202丰满熟女妇大| 日韩免费无码视频一区二区三区 | 精品偷拍一区二区三区| 东方四虎av在线观看| 亚洲一区中文字幕第十页| 成人无号精品一区二区三区| 亚洲色最新高清AV网站| 亚洲成人av综合一区| 国产女同一区二区在线| 免费又大粗又爽又黄少妇毛片 |