LangChain4j AiServices 声明式 AI 服务开发

学习时间:2026/3/31
技术栈:Spring Boot 4.0.5 + LangChain4j 1.12.2 + 通义千问模型

一、为什么需要 AiServices?

在前一篇教程中,我们直接使用 ChatModel 进行对话。但这种方式有一些局限:

  • 缺乏类型安全:所有输入输出都是字符串
  • 无法使用对话记忆:每次对话都是独立的

LangChain4j 提供了声明式 AI 服务构建方式,让 AI 开发像编写普通 Java 代码一样简单。

二、定义助手接口

public interface Assistant {
    
    // 基础对话
    String chat(String message);
    
    // 流式对话
    TokenStream streamChat(String message);
    
    // 带系统预设词的对话
    @SystemMessage("""
        您是 snow 航空的客户聊天支持代理。
        请以友好、乐于助人的方式来回复。
        您正在通过在线聊天系统与客户互动。
        在提供有关预订或取消预订的信息之前,
        您必须始终从客户处获得以下信息:预订号,客户姓名。               
        今天的日期是{{currentData}}。
        """)
    TokenStream streamChat(@UserMessage String message, 
                          @V("currentData") String currentData);
}

2.1 核心注解

注解 作用 示例
@SystemMessage 系统预设词,定义 AI 人设 设定为航空客服
@UserMessage 标识用户输入参数 @UserMessage String message
@V 变量替换,填入模板 @V("currentData")

2.2 模板变量

系统预设词支持 {{variable}} 格式的变量占位符:

@SystemMessage("今天的日期是{{currentData}}。")
TokenStream streamChat(@UserMessage String message, 
                      @V("currentData") String currentData);

调用时:

assistant.streamChat("查询航班", LocalDate.now().toString());

三、构建 AI 服务

3.1 基本配置

@Configuration
public class AiConfig {

    @Bean
    public Assistant assistant(ChatModel qwenChatModel,
                              StreamingChatModel qwenStreamingChatModel) {
        return AiServices.builder(Assistant.class)
                .chatModel(qwenChatModel)
                .streamingChatModel(qwenStreamingChatModel)
                .build();
    }
}

3.2 添加对话记忆

@Bean
public Assistant assistant(ChatModel qwenChatModel,
                          StreamingChatModel qwenStreamingChatModel) {
    
    // 创建对话记忆,保留最近 10 条消息
    ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
    
    return AiServices.builder(Assistant.class)
            .chatModel(qwenChatModel)
            .streamingChatModel(qwenStreamingChatModel)
            .chatMemory(chatMemory)  // 添加记忆功能
            .build();
}

四、Controller 调用

@RestController
@RequestMapping("/ai")
public class ChatController {

    private final Assistant assistant;

    public ChatController(Assistant assistant) {
        this.assistant = assistant;
    }

    // 普通对话(带记忆)
    @GetMapping("/memory-chat")
    public String chat(@RequestParam String message) {
        return assistant.chat(message);
    }

    // 流式对话(带记忆和系统预设词)
    @GetMapping(value = "/memory-streaming-chat", 
                produces = "text/stream;charset=UTF-8")
    public Flux<String> streamingChat(@RequestParam String message) {
        TokenStream tokenStream = assistant.streamChat(message, 
                                                     LocalDate.now().toString());
        
        return Flux.create(sink -> {
            tokenStream.onPartialResponse(sink::next)
                    .onCompleteResponse(response -> sink.complete())
                    .onError(sink::error)
                    .start();
        });
    }
}

五、工作原理

用户:我要退票
    ↓
AiServices 动态代理
    ↓
1. 将方法调用转换为 ChatModel 请求
2. 自动管理 ChatMemory(添加用户消息和 AI 回复)
3. 返回结果
    ↓
AI 回复:请问您的订单号是?

六、完整示例

// 1. 定义接口
public interface Assistant {
    String chat(String message);
    
    @SystemMessage("你是一个乐于助人的航空客服")
    String chatWithRole(String message);
}

// 2. 构建服务
@Configuration
public class AiConfig {
    @Bean
    public Assistant assistant(ChatModel model) {
        return AiServices.builder(Assistant.class)
                .chatModel(model)
                .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
                .build();
    }
}

// 3. 使用
@Autowired
private Assistant assistant;

@GetMapping("/chat")
public String chat(String message) {
    return assistant.chat(message);
}

七、总结

AiServices 提供了声明式的 AI 服务开发方式:

  • 类型安全:通过接口定义输入输出
  • 对话记忆:自动管理上下文
  • 系统预设词:灵活的角色设定

相关笔记:

  1. LangChain4j 入门指南
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐