Spring AI系列之核心组件:ChatClient、Prompt 与 Advisor

Spring AI系列之核心组件:ChatClient、Prompt 与 Advisor

一、ChatClient:流式 API 的优雅入口

ChatClient 是 Spring AI 提供的高阶客户端,采用**构建者模式(Builder Pattern)**设计,支持链式调用,极大地简化了 Prompt 构建和响应处理流程。

1.1 核心架构

*图:Spring AI ChatClient 整体架构图 *

ChatClient 位于应用层与 Chat Model 之间,封装了复杂的 HTTP 调用细节,提供了统一的 API 接口。

1.2 两种创建方式

方式一:配置类注入(推荐)

java 复制代码
@Configuration
public class ChatClientConfig {
    
    @Bean
    ChatClient chatClient(ChatClient.Builder builder) {
        return builder
            .defaultSystem("你是专业的技术助手")  // 设置全局系统消息
            .build();
    }
}

方式二:构造函数注入

java 复制代码
@RestController
public class ChatController {
    private final ChatClient chatClient;

    // Spring 会自动注入 Builder
    public ChatController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }
}

1.3 基础调用示例

java 复制代码
@GetMapping("/ai/generate")
public String generate(@RequestParam String message) {
    return chatClient.prompt()      // 1. 创建 Prompt 构建器
            .user(message)          // 2. 设置用户消息
            .call()                 // 3. 执行调用
            .content();             // 4. 提取文本内容
}

1.4 设置系统消息(System Message)

系统消息用于定义 AI 的角色和行为准则:

java 复制代码
String response = chatClient.prompt()
        .system("你是一位资深Java工程师,回答需简洁准确")  // 设定角色
        .user("说说Springboot源码?")
        .call()
        .content();

二、Prompt:结构化消息的载体

Prompt 是 Spring AI 中消息的容器,支持多角色对话管理。

2.1 Prompt 的结构

复制代码
┌─────────────────────────────────────┐
│              Prompt                 │
├─────────────────────────────────────┤
│  ┌──────────┐    ┌──────────┐      │
│  │ System   │    │ User     │      │
│  │ Message  │    │ Message  │      │
│  │ (系统指令)│    │ (用户输入)│      │
│  └──────────┘    └──────────┘      │
│  ┌──────────┐    ┌──────────┐      │
│  │ Assistant│    │  ...     │      │
│  │ Message  │    │          │      │
│  │ (AI回复) │    │          │      │
│  └──────────┘    └──────────┘      │
└─────────────────────────────────────┘

2.2 使用 PromptTemplate 实现动态模板

PromptTemplate 支持占位符替换,实现动态内容生成:

java 复制代码
@GetMapping("/prompt/test1")
public String promptTest1() {
    // 用户消息
    String userText = "介绍一下海盗黄金时代的三位著名海盗";
    Message userMessage = new UserMessage(userText);

    // 系统消息模板(带变量)
    SystemPromptTemplate systemTemplate  = new SystemPromptTemplate("你是一个名叫{name}的助手,请以{voice}的风格回答。");

    // 填充变量
    Message systemMessage = systemTemplate.createMessage(Map.of(
            "name", "Koki",
            "voice", "幽默"
    ));

    // 组装 Prompt
    Prompt prompt = new Prompt(List.of(systemMessage, userMessage));

    // 调用模型
    return chatClient.prompt(prompt).call().content();
}

2.3 从文件加载模板(生产环境推荐)

将提示词模板外置,便于管理和热更新:

java 复制代码
// 注入模板文件
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;

@GetMapping("/prompt/test2")
public String promptTest2() {
    // 用户消息
    String userText = "你好呀,你是什么AI Agent";
    Message userMessage = new UserMessage(userText);

    // 系统消息模板(带变量)
    SystemPromptTemplate systemTemplate  = new SystemPromptTemplate(systemResource);

    // 填充变量
    Message systemMessage = systemTemplate.createMessage(Map.of(
            "name", "小助手",
            "voice", "友好"
    ));

    // 组装 Prompt
    Prompt prompt = new Prompt(List.of(systemMessage, userMessage));

    // 调用模型
    return chatClient.prompt(prompt).call().content();
}

模板文件示例 (src/main/resources/prompts/system-message.st):

复制代码
你是{name},一个{voice}的 AI 助手。
请确保回答:
1. 准确可靠
2. 通俗易懂
3. 保持{voice}的风格

三、Advisor:拦截与增强机制

Advisor 是 Spring AI 的拦截器机制,允许在请求发送前后进行处理,实现横切关注点(Cross-cutting Concerns)。

3.1 Advisor 执行流程

*图:Advisor 拦截流程 - 请求和响应都会经过 Advisor 链处理 *

执行顺序说明

  1. Before Advice:请求到达模型前执行(如添加历史记录)
  2. 调用 Chat Model:发送处理后的请求
  3. After Advice:收到响应后执行(如记录日志、过滤内容)

3.2 自定义日志 Advisor

实现 CallAroundAdvisor(同步)和 StreamAroundAdvisor(流式):

java 复制代码
@Component
public class SimpleLoggerAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
    
    @Override
    public String getName() { 
        return "simpleLoggerAdvisor"; 
    }

    @Override
    public int getOrder() { 
        return 0;  // 数字越小优先级越高
    }

    // 同步调用拦截
    @Override
    public AdvisedResponse aroundCall(
            AdvisedRequest req, 
            CallAroundAdvisorChain chain) {
        
        log.info("🚀 请求前: {}", req.userText());
        
        AdvisedResponse res = chain.nextAroundCall(req);  // 继续执行链
        
        log.info("✅ 响应后: {}", res.response());
        return res;
    }

    // 流式调用拦截
    @Override
    public Flux<AdvisedResponse> aroundStream(
            AdvisedRequest req, 
            StreamAroundAdvisorChain chain) {
        
        log.info("🌊 流式请求前: {}", req.userText());
        
        return chain.nextAroundStream(req)
                .doOnNext(res -> log.info("📝 流式响应: {}", res));
    }
}

3.3 使用 Advisor

java 复制代码
@Autowired
private SimpleLoggerAdvisor loggerAdvisor;

@GetMapping("/ai/chat")
public String chat(@RequestParam String message) {
    return chatClient.prompt()
            .advisors(loggerAdvisor)    // 添加 Advisor
            .user(message)
            .call()
            .content();
}

3.4 内置 Advisor 一览

Advisor 功能 适用场景
MessageChatMemoryAdvisor 对话记忆管理 多轮对话保持上下文
QuestionAnswerAdvisor RAG 检索增强 基于知识库问答
SafeGuardAdvisor 内容安全过滤 敏感词检测、合规检查
VectorStoreChatMemoryAdvisor 向量存储记忆 长期记忆持久化

使用示例

java 复制代码
package com.example.ai.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ChatConfig {

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder) {
        return builder.defaultSystem("你是一个AI聊天助手")
                .build();
    }

    /**
     * 配置本地内存版的ChatMemory Bean
     */
    @Bean
    public ChatMemory chatMemory() {
        // InMemoryChatMemory是ChatMemory的默认实现,基于本地内存存储对话上下文
        return new InMemoryChatMemory();
    }

}
java 复制代码
@Autowired
private ChatMemory chatMemory;

@GetMapping("/ai/memory")
public String chatWithMemory(@RequestParam String message) {
    return chatClient.prompt()
            .advisors(new MessageChatMemoryAdvisor(chatMemory))
            .user(message)
            .call()
            .content();
}

四、动态配置覆盖机制

Spring AI 支持全局默认配置 + 运行时动态覆盖的灵活配置策略。

4.1 配置层级

复制代码
┌─────────────────────────────────────┐
│      运行时动态配置 (最高优先级)      │
│   .system(sp -> sp.param(...))      │
├─────────────────────────────────────┤
│      ChatClient 实例级配置            │
│   builder.defaultSystem(...)        │
├─────────────────────────────────────┤
│      应用全局配置 (application.yml)   │
│   spring.ai.openai.chat.options...  │
├─────────────────────────────────────┤
│      模型默认配置 (最低优先级)         │
│   OpenAI GPT-4 默认参数              │
└─────────────────────────────────────┘

4.2 实战示例

步骤 1:配置全局默认值

java 复制代码
@Bean
ChatClient chatClient(ChatClient.Builder builder) {
    return builder
            .defaultSystem("你是{language}专家,精通{language}语法和表达")
            .build();
}

步骤 2:运行时动态替换参数

java 复制代码
@GetMapping("/ai/dynamic")
public String dynamicChat(
        @RequestParam String language,
        @RequestParam String topic) {
    
    return chatClient.prompt()
            .system(sp -> sp.param("language", language))  // 动态注入
            .user("请讲解 " + topic)
            .call()
            .content();
}

// 调用示例:/ai/dynamic?language=英语&topic=过去完成时

五、完整实战:构建智能客服

java 复制代码
@Service
public class CustomerService {
    
    @Autowired
    private ChatClient chatClient;
    
    @Autowired
    private VectorStore vectorStore;

    public String handleQuery(String userQuery) {
        return chatClient.prompt()
                // 1. 系统角色设定
                .system("你是专业客服助手,回答需礼貌、准确")
                
                // 2. 添加 RAG Advisor(知识库检索)
                .advisors(new QuestionAnswerAdvisor(vectorStore))
                
                // 3. 添加记忆 Advisor(保持对话上下文)
                .advisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
                
                // 4. 用户输入
                .user(userQuery)
                
                // 5. 执行调用
                .call()
                .content();
    }
}

总结

组件 核心职责 关键特性
ChatClient 统一入口 链式 API、同步/流式双支持
Prompt 消息封装 多角色、模板化、文件加载
Advisor 横切增强 拦截链、内置丰富、可扩展

这三个组件构成了 Spring AI 的核心骨架,遵循单一职责原则,既保证了灵活性,又提供了强大的扩展能力。通过合理组合,可以快速构建企业级的 AI 应用。


参考资源

相关推荐
聊聊科技2 小时前
原创音乐人创作编曲伴奏新方式,清唱歌词的音频配合AI编曲软件超好用
人工智能·音视频
北京软秦科技有限公司2 小时前
IACheck AI报告文档审核:高端制造标准引用报告审核的智能导航
大数据·人工智能·制造
爱打代码的小林2 小时前
YOLOv4介绍
人工智能·计算机视觉·目标跟踪
新元代码2 小时前
OpenClaw 小白入门十问十答
人工智能
TechFind2 小时前
OpenClaw 多 Agent 协作实战:从零搭建自动化内容营销系统
人工智能·agent
一水鉴天2 小时前
整体设计的自动化部署完整方案设计与程序实现 (完善版)20260311 之2 (豆包助手)
运维·人工智能·自动化
xiami_world2 小时前
深度评测:5款AI流程图生成工具——图像识别、Mermaid支持与文档解析能力对比
人工智能·ai·信息可视化·ai作画·流程图
一次旅行2 小时前
云部署Openclaw龙虾接入飞书PPT问题
人工智能·github·飞书
进击monkey2 小时前
企业知识库选型对比:PandaWiki 与 Wiki.js 全面评测
人工智能·ai知识库