引言:从基础对话到高级AI应用

在上一篇文章中,我们介绍了Spring Boot集成LangChain4j的基础方法。今天,我们将深入探索LangChain4j更强大的功能——AiServices工具类流式调用消息注解。这三个特性将帮助您构建更专业、更高效的AI应用,让您的代码更加优雅和强大。

本文适合已掌握LangChain4j基础集成的开发者,将带您进入AI应用开发的高级阶段。

第一部分:AiServices工具类——声明式AI编程的革命

1.1 什么是AiServices?

AiServices是LangChain4j提供的一个革命性工具类,它允许您以声明式的方式定义AI服务接口,然后由框架自动实现这些接口。这类似于Spring的@Repository@Service注解,但专为AI服务设计。

1.2 两种使用方式对比

方式一:编程式创建(显式配置)
@Configuration
public class CommonConfig {
    
    @Autowired
    private OpenAiChatModel model;
    
    @Bean
    public ConsultantService consultantService() {
        ConsultantService cs = AiServices.builder(ConsultantService.class)
                .chatModel(model)  // 显式注入模型
                .build();
        return cs;
    }
}

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

关键点:

  1. 在配置类中显式构建ConsultantService的Bean

  2. 通过AiServices.builder()创建代理对象

  3. 可以灵活控制模型注入和配置

方式二:声明式使用(推荐)
@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel"
)
public interface ConsultantService {
    String chat(String message);
}

配置示例(application.yml):

langchain4j:
  open-ai:
    chat-model:
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      api-key: ${DASHSCOPE_API_KEY}
      model-name: qwen-plus
      # 必须指定Bean名称
      bean-name: openAiChatModel

声明式的优势:

  • 代码更简洁:无需手动构建Bean

  • 类型安全:编译器可检查接口定义

  • 易于测试:可轻松创建Mock实现

  • 更好的IDE支持:代码提示和跳转更完善

1.3 核心参数详解

参数

说明

示例值

wiringMode

模型注入模式

EXPLICIT(显式)
AUTOMATIC(自动)

chatModel

聊天模型Bean名称

"openAiChatModel"

streamingChatModel

流式聊天模型名称

"openAiStreamingChatModel"

第二部分:流式调用——实现实时响应体验

2.1 为什么需要流式调用?

传统的AI接口调用需要等待完整响应返回,对于长文本生成,用户可能需要等待数秒甚至更久。流式调用(Streaming)允许AI逐字、逐句返回结果,提供类似打字的实时体验,极大提升用户感知速度。

2.2 完整实现步骤

步骤1:添加响应式编程依赖
<!-- 必须添加WebFlux和Reactor支持 -->
<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</version>
</dependency>
步骤2:配置流式模型
langchain4j:
  open-ai:
    streaming-chat-model:  # 注意:这是独立的配置块
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      api-key: ${APIKEY}
      model-name: qwen-plus
      log-requests: true
      log-responses: true
      bean-name: openAiStreamingChatModel  # 指定Bean名称
步骤3:定义流式接口
@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",
    streamingChatModel = "openAiStreamingChatModel"  // 关键:指定流式模型
)
public interface ConsultantService {
    // 返回Flux<String>实现流式响应
    public Flux<String> chat(String message);
}
步骤4:Controller层处理流式响应
@RestController
public class StreamChatController {
    
    @Autowired
    private ConsultantService consultantService;
    
    @GetMapping(value = "/stream/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamChat(@RequestParam String message) {
        return consultantService.chat(message)
                .doOnNext(chunk -> {
                    // 可在此处添加处理逻辑
                    System.out.println("收到数据块: " + chunk);
                })
                .doOnComplete(() -> {
                    System.out.println("流式响应完成");
                });
    }
}

2.3 流式调用的核心特性

特性

描述

优势

实时性

逐字返回响应

用户无需等待完整响应

背压支持

响应式流控制

防止客户端过载

可取消

随时中断请求

节省资源和时间

错误处理

细粒度错误控制

更好的用户体验

第三部分:消息注解——精细控制AI对话

3.1 消息注解的作用

在复杂的AI交互场景中,我们通常需要:

  1. 定义系统角色和指令

  2. 组织多轮对话历史

  3. 动态插入变量

  4. 管理对话上下文

LangChain4j的消息注解系统完美解决了这些问题。

3.2 核心注解详解

3.2.1 @SystemMessage:定义AI角色
@AiService
public interface ConsultantService {
    
    // 方式1:直接在方法上定义系统消息
    @SystemMessage("你是一个专业的Java技术专家,回答要简洁专业")
    String answerTechnicalQuestion(String question);
    
    // 方式2:从资源文件读取(支持i18n)
    @SystemMessage(fromResource = "/prompts/system_role.txt")
    String answerWithTemplate(String question);
    
    // 方式3:结合变量替换
    @SystemMessage("你是{{role}}专家,请用{{level}}级别的语言回答")
    String answerWithVariables(@V("role") String role, 
                               @V("level") String level, 
                               String question);
}
3.2.2 @UserMessage:定义用户输入
@AiService
public interface ConsultantService {
    
    // 基本用法
    @SystemMessage("你是编程助手")
    @UserMessage("请解释以下代码:{{code}}")
    String explainCode(@V("code") String code);
    
    // 复杂用法:多个用户消息
    @SystemMessage("你是翻译助手")
    @UserMessage({
        "将以下文本从{{sourceLang}}翻译到{{targetLang}}:",
        "文本:{{text}}"
    })
    String translateText(@V("sourceLang") String source,
                         @V("targetLang") String target,
                         @V("text") String text);
}

3.3 流式调用中的消息注解

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",
    streamingChatModel = "openAiStreamingChatModel"
)
public interface ConsultantService {
    
    // 流式接口同样支持消息注解
    @SystemMessage("你是实时翻译助手")
    @UserMessage("将'{{text}}'翻译成{{language}}")
    public Flux<String> streamTranslate(@V("text") String text, 
                                        @V("language") String language);
    
    // 复杂的多变量示例
    @SystemMessage(fromResource = "/prompts/expert_role.txt")
    @UserMessage({
        "问题类型:{{type}}",
        "用户级别:{{level}}",
        "具体问题:{{question}}"
    })
    public Flux<String> expertAnswer(@V("type") String type,
                                     @V("level") String level,
                                     @V("question") String question);
}

3.4 高级技巧:组合使用

@AiService
public interface AdvancedAssistant {
    
    // 场景1:带上下文的多轮对话
    @SystemMessage("""
        你是一个旅游规划助手。记住以下用户偏好:
        1. 喜欢{{preference1}}
        2. 不喜欢{{preference2}}
        3. 预算:{{budget}}
        """)
    @UserMessage("为我去{{destination}}旅行提供建议")
    String planTravel(@V("preference1") String like,
                      @V("preference2") String dislike,
                      @V("budget") String budget,
                      @V("destination") String destination);
    
    // 场景2:动态系统消息
    @SystemMessage("""
        你是一个{{domain}}专家,具有以下专长:
        {{expertise}}
        
        回答时要特别注意:
        1. {{requirement1}}
        2. {{requirement2}}
        """)
    @UserMessage("请解答:{{question}}")
    Flux<String> expertConsultation(@V("domain") String domain,
                                    @V("expertise") String expertise,
                                    @V("requirement1") String req1,
                                    @V("requirement2") String req2,
                                    @V("question") String question);
}

第四部分:实战整合示例

4.1 完整的企业级AI服务配置

application.yml 配置:

spring:
  application:
    name: ai-assistant-service

langchain4j:
  open-ai:
    chat-model:
      base-url: ${AI_BASE_URL:https://dashscope.aliyuncs.com/compatible-mode/v1}
      api-key: ${DASHSCOPE_API_KEY}
      model-name: ${AI_MODEL:qwen-plus}
      temperature: 0.7
      max-tokens: 2000
      timeout: 60s
      bean-name: openAiChatModel
    streaming-chat-model:
      base-url: ${AI_BASE_URL:https://dashscope.aliyuncs.com/compatible-mode/v1}
      api-key: ${DASHSCOPE_API_KEY}
      model-name: ${AI_MODEL:qwen-plus}
      temperature: 0.7
      max-tokens: 4000
      timeout: 120s
      bean-name: openAiStreamingChatModel

logging:
  level:
    dev.langchain4j: DEBUG

4.2 完整的AI服务接口

@AiService(
    wiringMode = AiServiceWiringMode.EXPLICIT,
    chatModel = "openAiChatModel",
    streamingChatModel = "openAiStreamingChatModel"
)
public interface ComprehensiveAssistant {
    
    // 标准响应
    @SystemMessage("""
        你是一个全栈技术顾问,擅长:
        1. Java/Spring开发
        2. 前端技术(React/Vue)
        3. 数据库设计
        4. 系统架构
        
        回答要求:
        - 分点说明
        - 给出示例代码
        - 标明优缺点
        """)
    String technicalConsultation(@UserMessage String question);
    
    // 流式响应
    @SystemMessage("你是代码生成专家,逐步生成代码并说明")
    @UserMessage("""
        为以下需求生成{{language}}代码:
        需求:{{requirement}}
        要求:{{constraints}}
        """)
    Flux<String> generateCodeStream(@V("language") String language,
                                    @V("requirement") String requirement,
                                    @V("constraints") String constraints);
    
    // 多语言支持
    @SystemMessage(fromResource = "/prompts/translator_${lang}.txt")
    @UserMessage("翻译:{{text}}")
    String translate(@V("text") String text);
}

4.3 控制器层实现

@RestController
@RequestMapping("/api/ai")
@Slf4j
public class AIController {
    
    @Autowired
    private ComprehensiveAssistant assistant;
    
    // 标准接口
    @PostMapping("/consult")
    public ResponseEntity<String> consult(@RequestBody ConsultationRequest request) {
        try {
            String response = assistant.technicalConsultation(request.getQuestion());
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("咨询失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("服务暂时不可用");
        }
    }
    
    // 流式接口
    @GetMapping(value = "/code/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamCode(@RequestParam String language,
                                   @RequestParam String requirement,
                                   @RequestParam(required = false) String constraints) {
        return assistant.generateCodeStream(language, requirement, 
                constraints != null ? constraints : "")
                .onErrorResume(e -> {
                    log.error("代码生成失败", e);
                    return Flux.just("错误:" + e.getMessage());
                })
                .doOnSubscribe(s -> log.info("开始生成{}代码", language))
                .doOnComplete(() -> log.info("代码生成完成"));
    }
    
    @Data
    public static class ConsultationRequest {
        private String question;
    }
}

总结

通过本文的学习,您已经掌握了LangChain4j的三个核心高级特性:

  1. AiServices工具类​ - 实现声明式AI编程,代码更简洁

  2. 流式调用​ - 提供实时响应体验,提升用户满意度

  3. 消息注解​ - 精细控制对话流程,实现复杂交互逻辑

 会话记忆,rag知识库等再进阶知识将在之后讲解

Logo

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

更多推荐