【langchain4j篇02】:配置流式响应及高级API的使用详解

#代码星辉·七月创作之星挑战赛#

目录

一、依赖导入

1. 导入高级API:AiServices相关依赖

2. 导入流式响应模型支持相关依赖

3. 配置 application.yml

二、创建 AiService 代理接口

1. 创建自定义Service接口

2. 在 controller 中调用

三、效果演示及原理简析

1. 效果演示

2. 扩展使用及原理简析


上文我们快速入门了 【langchain4j篇01】:5分钟上手langchain4j 1.1.0,但是 OpenAiChatModel 只能实现阻塞式调用,下面结合 langchain4j 的 高级API 实现流式响应聊天

一、依赖导入

1. 导入高级API:AiServices相关依赖

<!-- LangChain4j声明式AiService起步依赖 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-spring-boot-starter</artifactId>
    <version>1.1.0-beta7</version>
</dependency>

2. 导入流式响应模型支持相关依赖

<!-- LangChain4j对流式模型的依赖 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-reactor</artifactId>
    <version>1.1.0-beta7</version>
</dependency>

3. 配置 application.yml

langchain4j:
  open-ai:
    streaming-chat-model: # 流式聊天模型,与chat-model同级
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      api-key: ${langchain4j.api-key}
      model-name: qwen-max-latest
      log-requests: true
      log-responses: true

注意:原先的普通聊天模型 langchain4j.open-ai.chat-model 与 streaming-chat-model 同级且不冲突


二、创建 AiService 代理接口

1. 创建自定义Service接口

langchain4j 的高级API AiService 提供了声明式的使用方式,首先创建一个接口,添加 @AiService 注解,再将先前 controller 层的 chat 方法,提取到该接口之中,同时将返回值类型改为 Flux<String> (流式响应):

package xyz.qiquqiu.lc4blogdemo.aiserverce;

import dev.langchain4j.service.spring.AiService;
import reactor.core.publisher.Flux;

@AiService
public interface DemoService {

    /**
     * 调用大模型进行聊天-流式返回
     * @param message 用户消息
     * @return 流式响应
     */
    Flux<String> chat(String message);
}

2. 在 controller 中调用

这么一个极简的接口就定义好了,接下来我们直接到 controller 中测试一把,原理相关会在后文讲解

package xyz.qiquqiu.lc4blogdemo.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import xyz.qiquqiu.lc4blogdemo.aiserverce.DemoService;

@Slf4j
@RestController
@RequiredArgsConstructor
public class ChatController {

    private final DemoService demoService;
    // private final OpenAiChatModel chatModel;

    /**
     * 大模型聊天接口-流式响应
     * @param message 用户发送的消息,相当于提示词prompt
     * @return
     */
    @RequestMapping(value = "/chat", produces = "text/html;charset=utf-8")
    public Flux<String> chat(String message) {
        return demoService.chat(message);
    }
}

注意改动点:

  • 注入刚刚创建的接口 DemoService ,而非 OpenAiChatModel 或者 StreamingChatModel
  • 添加响应体内容解析格式,解决显示乱码:produces = "text/html;charset=utf-8"

三、效果演示及原理简析

1. 效果演示

可以看到,已经成功实现流式输出

(补充)关于流式响应的日志开启

在打开上述的 log-response 为 true 之后,还要配置 langchain4j 包的日志等级为 DEBUG,如下图:

然后就可以打印出持续的流式响应日志:

2. 扩展使用及原理简析

刚刚演示的只是 @AiService 注解最最简单的一种用法,实际上该注解有诸多属性,只不过由于我们配置了 application.yml 导致 ChatModel 自动装配,且由于我们没有自定义其他同类型组件,这些组件名都是默认的,所以支持默认配置,实际上,刚才的 @AiService 注解就相当于这样

  • 其中,chatMode 属性和 streamingChatModel 属性,这里手动配置的都是默认值,所以效果就相当于之前的直接写一个 @AiService
  • 如果使用 @Bean 自定义一个流式响应类配置于此,就可走自定义的模型配置,替换调默认的 openAiStreamingChatModel
  • 注意,langchain4j 自动装配的流式响应类是 OpenAiStreamingChatModel 类型,虽然是 StreamingChatModel 子类,但是提供给我们的,开箱即用的 Bean 的默认名是 openAiStreamingChatModel 而非 streamingChatModel

该注解下还有更多高级组件,后文会一一讲解到:

 关于实现的基本原理,显然,我们正在 controller 注入了 DemoService 接口的引用,但是却从未实例化,那么,创建对象的过程必然是由框架底层,通过 @AiService 注解,使用 动态代理、反射 创建的代理对象,来调用 chat 方法

打个断点,debug 运行,可以很清晰观察出,如下图所示的代理对象

### 使用 LangChain4j 实现流式响应 #### 低层次 LLM API 的实现方式 为了实现实时的逐个令牌(token)级别的流式响应,在 LangChain4j 中可以利用底层的大语言模型 (LLM) 接口来构建这种特性。具体来说,这涉及到创建一个监听器或者回调机制,每当有新的 token 可用时就触发相应的逻辑处理[^1]。 ```java // Java伪代码示例:设置TokenListener用于接收来自LLM的每个新产生的token public class TokenStreamHandler implements TokenListener { @Override public void onNewToken(String newToken){ System.out.print(newToken); // 或者其他即时显示的方式 } } ``` #### 高层次服务接口的选择 对于更复杂的业务需求或是希望简化开发流程的情况,则建议采用更高层的服务抽象——即 AI Services 提供的功能。这种方式下不需要直接操作具体的 LLM 调用细节,而是依赖框架内部封装好的工具链完成相同的工作[^5]。 #### 异步处理的支持 当应用程序面临高并发或多任务环境时,考虑引入异步模式会更加高效合理。Astream 是一种有效的技术手段,它允许程序在后台执行耗时的任务而不影响前端交互体验;与此同时也能很好地支持流式的输出更新[^4]。 ```java // Java伪代码示例:使用CompletableFuture来进行异步调用并处理结果 CompletableFuture.supplyAsync(() -> llmService.generateText(prompt)) .thenAccept(responseStream -> responseStream.forEach(System.out::print)); ``` #### 同步与异步两种方案对比 同步流式响应适合于简单的应用场景,其中客户端可以直接等待服务器端的数据返回,并立即呈现给用户查看。而异步版本则更适合那些需要保持良好性能表现的应用场合,尤其是在面对大量请求或长时间运行的操作时[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值