返回博客列表

SpringAI中技术原理集合

2026-01-29
3 min read
2025-12-19

指定返回实体类型 示例 转换后提示词 org.springframework.ai.converter.BeanOutputConverter#getFormat json markdown from the output. Here is the JSON Schema instance your output must adhere to: [{"actor":"罗贯中","bookNa...

指定返回实体类型

示例

java
ChatClient chatClient = ChatClient.builder(chatModel)
                .defaultAdvisors(chatMemoryAdvisor).build();
        List<Book> books = chatClient.prompt().user("生成四大名著和对应的作者").call()
                .entity(new ParameterizedTypeReference<List<Book>>() {
                });
        for (Book book : books) {
            System.out.println(book);
//            ColorLogger.info(book.toString());
        }

转换后提示词

  • org.springframework.ai.converter.BeanOutputConverter#getFormat
生成四大名著和对应的作者
Your response should be in JSON format.
Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation.
Do not include markdown code blocks in your response.
Remove the ```json markdown from the output.
Here is the JSON Schema instance your output must adhere to:
```{
  "$schema" : "https://json-schema.org/draft/2020-12/schema",
  "type" : "array",
  "items" : {
    "type" : "object",
    "properties" : {
      "actor" : {
        "type" : "string"
      },
      "bookName" : {
        "type" : "string"
      }
    },
    "additionalProperties" : false
  }
}```

通过将提示词发送给 ai,可以看到如下返回结构

[{"actor":"罗贯中","bookName":"三国演义"},{"actor":"施耐庵","bookName":"水浒传"},{"actor":"吴承恩","bookName":"西游记"},{"actor":"曹雪芹","bookName":"红楼梦"}]

顾问

CompressionQueryTransformer 压缩查询转换器

使用大型语言模型将对话历史和后续查询压缩成一个独立的查询,该查询能够捕捉对话的本质。

java
Query query = Query.builder()
        .text("And what is its second largest city?")
        .history(new UserMessage("What is the capital of Denmark?"),
                new AssistantMessage("Copenhagen is the capital of Denmark."))
        .build();

QueryTransformer queryTransformer = CompressionQueryTransformer.builder()
        .chatClientBuilder(chatClientBuilder)
        .build();

Query transformedQuery = queryTransformer.transform(query);

RewriteQueryTransformer 重写查询转换器

java
Query query = new Query("I'm studying machine learning. What is an LLM?");

QueryTransformer queryTransformer = RewriteQueryTransformer.builder()
        .chatClientBuilder(chatClientBuilder)
        .build();

Query transformedQuery = queryTransformer.transform(query);

MultiQueryExpander 多查询扩展器

使用大型语言模型将查询扩展为多个语义不同的变体,以捕捉不同的视角,这有助于检索额外的上下文信息并增加找到相关结果的机会。

java
MultiQueryExpander queryExpander = MultiQueryExpander.builder()
    .chatClientBuilder(chatClientBuilder)
    .numberOfQueries(3)
    .build();
List<Query> queries = queryExpander.expand(new Query("How to run a Spring Boot app?"));

检索

官方文档

完整的Demo

java
public static void main(String[] args) {
        ConfigurableApplicationContext app = SpringApplication.run(SpringAiApplication.class, "--spring.profiles.active=mi");
        ChatModel chatModel = app.getBean(ChatModel.class);
        // 工具回调提供者
        MethodToolCallbackProvider toolCallbackProvider = MethodToolCallbackProvider.builder().
                toolObjects(new DateTimeTools()).build();

        // 工具回调解析器
        StaticToolCallbackResolver staticToolCallbackResolver = new StaticToolCallbackResolver(Arrays.stream(toolCallbackProvider.getToolCallbacks()).toList());

        // 工具调用管理器
        DefaultToolCallingManager toolCallingManager = DefaultToolCallingManager.builder()
                .toolCallbackResolver(staticToolCallbackResolver)
                .toolExecutionExceptionProcessor(new ToolExecutionExceptionProcessor() {
                    // 异常处理器
                    @Override
                    public String process(ToolExecutionException exception) {
                        ToolDefinition toolDefinition = exception.getToolDefinition();
                        System.err.println("Tool Error: " + toolDefinition);
                        return exception.getMessage();
                    }
                })
                .build();

        // 会话上下文
        ChatOptions chatOptions = ToolCallingChatOptions.builder()
                .toolCallbacks(toolCallbackProvider.getToolCallbacks())
                // 决定函数是内部自动调用还是外部调用 (这里保持 false 以使用手动循环)
                .internalToolExecutionEnabled(false)
                .build();

        // 会话记忆
        ChatMemory chatMemory = MessageWindowChatMemory.builder().maxMessages(20).build();
        String conversationId = UUID.randomUUID().toString();

        // 会话客户端
        ChatClient chatClient = ChatClient.builder(chatModel).defaultOptions(chatOptions).build();

        Scanner scanner = new Scanner(System.in);
        System.out.println("=== AI 聊天助手启动 (输入 'exit' 退出) ===");

        while (true) {
            System.out.print("\n锦衣卫·智问: ");
            String input = scanner.nextLine();
            if ("exit".equalsIgnoreCase(input)) {
                break;
            }

            // 1. 构建 Prompt 并存入记忆
            Prompt prompt = new Prompt(input, chatOptions);
            chatMemory.add(conversationId, prompt.getInstructions());

            // 2. 从记忆中获取完整的上下文
            Prompt promptWithMemory = new Prompt(chatMemory.get(conversationId), chatOptions);

            // 3. 发起调用
            ChatResponse chatResponse = chatClient.prompt(promptWithMemory).call().chatResponse();
            chatMemory.add(conversationId, chatResponse.getResult().getOutput());

            // 4. 处理工具调用循环
            while (chatResponse.hasToolCalls()) {
                System.out.println("[System] 正在调用工具...");
                ToolExecutionResult toolExecutionResult = toolCallingManager.executeToolCalls(promptWithMemory, chatResponse);

                // 使用工具执行结果更新 Prompt
                promptWithMemory = new Prompt(toolExecutionResult.conversationHistory(), chatOptions);

                // 再次调用模型
                chatResponse = chatModel.call(promptWithMemory);
                chatMemory.add(conversationId, chatResponse.getResult().getOutput());
            }

            System.out.println("AI: " + chatResponse.getResult().getOutput().getText());
        }
    }

    static class DateTimeTools {

        @Tool(description = "负责查询天气")
        public String query(
                @ToolParam(description = "要查询天气的城市") String cityName) {
            String[] weathers = {"晴天", "多云", "小雨", "中雨", "大雪", "雷阵雨"};
            int temp = ThreadLocalRandom.current().nextInt(-5, 35);
            int humidity = ThreadLocalRandom.current().nextInt(30, 90);
            int wind = ThreadLocalRandom.current().nextInt(1, 6);
            String weather = weathers[ThreadLocalRandom.current().nextInt(weathers.length)];
            String format = String.format(
                    "%s 当前天气:%s,温度 %d°C,湿度 %d%%,风力 %d 级",
                    cityName, weather, temp, humidity, wind
            );
//            System.out.println(format);
            return format;
        }

    }
返回博客列表
最后更新于 2026-01-29
想法或问题?在 GitHub Issue 下方参与讨论
去评论