Spring AI ChatClient 详细用法文档

66 阅读6分钟

Spring AI ChatClient 详细用法文档

概述

Spring AI ChatClient 是一个用于执行 AI 模型状态less请求的客户端 API,采用流式 API 设计。它提供了简洁而强大的方式来与各种 AI 模型进行交互,支持文本生成、结构化输出、工具调用等功能。

核心架构

1. 主要接口

ChatClient 接口
public interface ChatClient {
    // 创建 ChatClient 实例
    static ChatClient create(ChatModel chatModel)
    static ChatClient create(ChatModel chatModel, ObservationRegistry observationRegistry)

    // 构建器模式
    static Builder builder(ChatModel chatModel)

    // 提示词入口
    ChatClientRequestSpec prompt()
    ChatClientRequestSpec prompt(String content)
    ChatClientRequestSpec prompt(Prompt prompt)

    // 创建变异构建器
    Builder mutate()
}
核心规范接口
  1. ChatClientRequestSpec - 请求规范
  2. PromptUserSpec - 用户提示词规范
  3. PromptSystemSpec - 系统提示词规范
  4. CallResponseSpec - 阻塞式调用响应规范
  5. StreamResponseSpec - 流式调用响应规范
  6. AdvisorSpec - 顾问规范
  7. Builder - 构建器规范

2. 实现类

  • DefaultChatClient - ChatClient 的默认实现
  • DefaultChatClientBuilder - ChatClient 构建器的默认实现
  • DefaultChatClientRequestSpec - 请求规范的默认实现

创建 ChatClient

1. 基本创建方式

// 方式1:使用 create 方法
ChatClient chatClient = ChatClient.create(chatModel);

// 方式2:使用构建器
ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultSystem("你是一个有帮助的助手")
    .defaultOptions(OpenAiChatOptions.builder()
        .model("gpt-4")
        .temperature(0.7)
        .build())
    .build();

2. Spring Boot 自动配置

// 在 Spring Boot 环境中,ChatClient.Builder 会自动配置
@Service
public class ChatService {

    private final ChatClient.Builder chatClientBuilder;

    public ChatService(ChatClient.Builder chatClientBuilder) {
        this.chatClientBuilder = chatClientBuilder;
    }

    public String chat(String message) {
        ChatClient chatClient = chatClientBuilder
            .defaultSystem("你是一个专业的助手")
            .build();

        return chatClient.prompt()
            .user(message)
            .call()
            .content();
    }
}

基本用法

1. 简单文本生成

// 最简单的用法
String response = ChatClient.create(chatModel)
    .prompt("你好,请介绍一下 Spring AI")
    .call()
    .content();

System.out.println(response);

2. 使用系统提示词和用户提示词

String response = ChatClient.builder(chatModel)
    .build()
    .prompt()
    .system("你是一个专业的 Java 开发工程师")
    .user("请解释什么是依赖注入")
    .call()
    .content();

3. 使用资源文件

// 从资源文件加载系统提示词
Resource systemResource = new ClassPathResource("prompts/system-message.st");
Resource userResource = new ClassPathResource("prompts/user-message.txt");

String response = ChatClient.create(chatModel)
    .prompt()
    .system(systemResource, StandardCharsets.UTF_8)
    .user(userResource)
    .call()
    .content();

高级功能

1. 提示词模板和参数化

// 使用参数化提示词
String response = ChatClient.create(chatModel)
    .prompt()
    .system(s -> s.text("你是一个{name}专家,请用{voice}的语调回答问题")
        .param("name", "Spring Boot")
        .param("voice", "专业"))
    .user(u -> u.text("请解释{topic}的概念")
        .param("topic", "自动配置"))
    .call()
    .content();

2. 多模态输入(图片等)

// 添加媒体文件
String response = ChatClient.create(chatModel)
    .prompt()
    .user(u -> u.text("描述这张图片的内容")
        .media(MimeTypeUtils.IMAGE_JPEG, new ClassPathResource("image.jpg"))
        .media(MimeTypeUtils.IMAGE_PNG, imageUrl))
    .call()
    .content();

3. 结构化输出

// 输出为特定类型
record Actor(String name, List<String> movies) {}

List<Actor> actors = ChatClient.create(chatModel)
    .prompt()
    .user("生成5个著名演员及其代表作品")
    .call()
    .entity(new ParameterizedTypeReference<List<Actor>>() {});

// 输出为单个对象
WeatherInfo weather = ChatClient.create(chatModel)
    .prompt()
    .user("北京今天的天气情况")
    .call()
    .entity(WeatherInfo.class);

4. 流式输出

// 流式获取响应
Flux<String> streamResponse = ChatClient.create(chatModel)
    .prompt()
    .user("写一个短故事")
    .stream()
    .content();

streamResponse.subscribe(
    content -> System.out.print(content),
    error -> System.err.println("Error: " + error),
    () -> System.out.println("\n完成!")
);

// 获取完整的流式响应
Flux<ChatResponse> fullStream = ChatClient.create(chatModel)
    .prompt()
    .user("解释机器学习")
    .stream()
    .chatResponse();

工具调用

1. 函数工具

// 定义工具函数
record WeatherRequest(String location) {}

record WeatherResponse(String location, double temperature, String condition) {}

@Function("获取指定地点的天气信息")
public WeatherResponse getWeather(WeatherRequest request) {
    // 实现天气查询逻辑
    return new WeatherResponse(request.location(), 25.0, "晴天");
}

// 使用工具
String response = ChatClient.builder(chatModel)
    .defaultTools(new WeatherService()) // 或 .defaultToolCallbacks(getWeatherToolCallback())
    .build()
    .prompt()
    .user("北京今天天气怎么样?")
    .call()
    .content();

2. 工具上下文

Map<String, Object> toolContext = Map.of(
    "userId", "12345",
    "sessionId", "abc-def"
);

String response = ChatClient.create(chatModel)
    .prompt()
    .user("执行用户操作")
    .toolContext(toolContext)
    .call()
    .content();

顾问(Advisors)

1. 日志顾问

// 添加简单日志顾问
String response = ChatClient.create(chatModel)
    .prompt()
    .advisors(new SimpleLoggerAdvisor())
    .user("解释 Spring AI 的架构")
    .call()
    .content();

2. 记忆顾问

// 使用聊天记忆
ChatMemoryAdvisor memoryAdvisor = new MessageChatMemoryAdvisor(
    new InMemoryChatMemory(), 10, 2
);

ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultAdvisors(memoryAdvisor)
    .build();

// 第一次对话
String response1 = chatClient.prompt()
    .user("我叫张三")
    .call()
    .content();

// 第二次对话,会记住之前的上下文
String response2 = chatClient.prompt()
    .user("我刚才告诉你我叫什么名字?")
    .call()
    .content();

3. RAG 顾问

// 使用检索增强生成
QuestionAnswerAdvisor ragAdvisor = new QuestionAnswerAdvisor(vectorStore);

String response = ChatClient.builder(chatModel)
    .defaultAdvisors(ragAdvisor)
    .build()
    .prompt()
    .user("Spring Boot 的自动配置是如何工作的?")
    .call()
    .content();

4. 自定义顾问

// 创建自定义顾问
public class CustomAdvisor implements Advisor {

    @Override
    public AdvisedRequest adviseRequest(AdvisedRequest request, Map<String, Object> context) {
        // 修改请求
        return request;
    }

    @Override
    public AdvisedResponse adviseResponse(AdvisedResponse response, Map<String, Object> context) {
        // 修改响应
        return response;
    }
}

// 使用自定义顾问
String response = ChatClient.create(chatModel)
    .prompt()
    .advisors(new CustomAdvisor())
    .user("你的问题")
    .call()
    .content();

配置选项

1. 模型选项

// 设置模型参数
ChatOptions options = OpenAiChatOptions.builder()
    .model("gpt-4")
    .temperature(0.7)
    .maxTokens(1000)
    .topP(0.9)
    .presencePenalty(0.1)
    .frequencyPenalty(0.1)
    .build();

ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultOptions(options)
    .build();

2. 动态选项

// 为特定请求设置选项
String response = chatClient.prompt()
    .user("生成一段创意文本")
    .options(OpenAiChatOptions.builder()
        .temperature(0.9)
        .maxTokens(500)
        .build())
    .call()
    .content();

响应处理

1. 获取完整响应

// 获取 ChatResponse 对象
ChatResponse response = ChatClient.create(chatModel)
    .prompt("你好")
    .call()
    .chatResponse();

// 访问元数据
Map<String, Object> metadata = response.getMetadata();
String model = response.getMetadata().get("model");
List<Generation> generations = response.getResults();

2. 响应实体

// 获取响应实体
ResponseEntity<ChatResponse, MyEntity> entityResponse = ChatClient.create(chatModel)
    .prompt("生成一个用户信息")
    .call()
    .responseEntity(MyEntity.class);

ChatResponse chatResponse = entityResponse.getResponse();
MyEntity entity = entityResponse.getEntity();

错误处理

1. 异常处理

try {
    String response = ChatClient.create(chatModel)
        .prompt("你的问题")
        .call()
        .content();
} catch (ChatModelException e) {
    // 处理模型异常
    logger.error("模型调用失败", e);
} catch (Exception e) {
    // 处理其他异常
    logger.error("未知错误", e);
}

2. 流式错误处理

Flux<String> streamResponse = ChatClient.create(chatModel)
    .prompt("生成文本")
    .stream()
    .content();

streamResponse
    .doOnError(error -> logger.error("流式响应错误", error))
    .onErrorResume(error -> Flux.just("生成失败,请重试"))
    .subscribe(System.out::print);

最佳实践

1. 构建 ChatClient 实例

@Configuration
public class ChatConfig {

    @Bean
    public ChatClient weatherChatClient(ChatModel chatModel) {
        return ChatClient.builder(chatModel)
            .defaultSystem("你是一个专业的天气预报助手")
            .defaultOptions(OpenAiChatOptions.builder()
                .temperature(0.3)
                .maxTokens(500)
                .build())
            .defaultAdvisors(
                new SimpleLoggerAdvisor(),
                new MessageChatMemoryAdvisor(new InMemoryChatMemory(), 10, 2)
            )
            .build();
    }

    @Bean
    public ChatClient codeChatClient(ChatModel chatModel) {
        return ChatClient.builder(chatModel)
            .defaultSystem("你是一个专业的编程助手")
            .defaultOptions(OpenAiChatOptions.builder()
                .temperature(0.1)
                .maxTokens(2000)
                .build())
            .defaultTools(new CodeAnalysisService())
            .build();
    }
}

2. 使用模板渲染器

@Service
public class ChatService {

    private final ChatClient chatClient;
    private final TemplateRenderer templateRenderer;

    public ChatService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder
            .defaultTemplateRenderer(new StTemplateRenderer())
            .build();
    }

    public String generateCode(String language, String requirement) {
        return chatClient.prompt()
            .system(s -> s.text("你是一个专业的{{language}}程序员")
                .param("language", language))
            .user(u -> u.text("请用{{language}}实现:{{requirement}}")
                .param("requirement", requirement))
            .call()
            .content();
    }
}

3. 批量处理

@Service
public class BatchProcessingService {

    private final ChatClient chatClient;

    public List<String> processBatch(List<String> prompts) {
        return prompts.parallelStream()
            .map(prompt -> chatClient.prompt()
                .user(prompt)
                .call()
                .content())
            .collect(Collectors.toList());
    }

    public Flux<String> processStreamingBatch(List<String> prompts) {
        return Flux.fromIterable(prompts)
            .flatMap(prompt -> chatClient.prompt()
                .user(prompt)
                .stream()
                .content());
    }
}

4. 缓存

@Service
public class CachedChatService {

    private final ChatClient chatClient;
    private final Cache<String, String> responseCache;

    public CachedChatService(ChatModel chatModel) {
        this.chatClient = ChatClient.builder(chatModel).build();
        this.responseCache = Caffeine.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(Duration.ofHours(1))
            .build();
    }

    public String chat(String message) {
        return responseCache.get(message, key ->
            chatClient.prompt()
                .user(key)
                .call()
                .content()
        );
    }
}

监控和观察

1. 启用观察

# application.yml
spring:
  ai:
    chatclient:
      observations:
        log-prompt: true  # 启用提示词日志
        log-completion: true  # 启用响应日志

2. 自定义观察处理器

@Bean
public ChatClientObservationConvention customObservationConvention() {
    return new DefaultChatClientObservationConvention() {
        @Override
        public String getName() {
            return "spring.ai.chatclient.custom";
        }
    };
}

总结

Spring AI ChatClient 提供了一个强大而灵活的 API 来与 AI 模型交互。主要特点包括:

  1. 流式 API 设计 - 链式调用,代码简洁易读
  2. 多种调用模式 - 支持阻塞式和流式调用
  3. 结构化输出 - 支持直接映射到 Java 对象
  4. 工具集成 - 支持函数调用和工具集成
  5. 顾问模式 - 可扩展的请求/响应处理链
  6. Spring Boot 集成 - 自动配置和依赖注入支持
  7. 多模态支持 - 支持文本、图片等多种输入类型
  8. 模板系统 - 支持参数化提示词和模板渲染

通过合理使用这些功能,可以构建出功能强大、易于维护的 AI 应用程序。