SpringAI中技术原理集合
2025-12-19
指定返回实体类型
示例
java
1ChatClient chatClient = ChatClient.builder(chatModel)
2 .defaultAdvisors(chatMemoryAdvisor).build();
3 List<Book> books = chatClient.prompt().user("生成四大名著和对应的作者").call()
4 .entity(new ParameterizedTypeReference<List<Book>>() {
5 });
6 for (Book book : books) {
7 System.out.println(book);
8// ColorLogger.info(book.toString());
9 }转换后提示词
- org.springframework.ai.converter.BeanOutputConverter#getFormat
text
1生成四大名著和对应的作者
2Your response should be in JSON format.
3Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation.
4Do not include markdown code blocks in your response.
5Remove the ```json markdown from the output.
6Here is the JSON Schema instance your output must adhere to:
7```{
8 "$schema" : "https://json-schema.org/draft/2020-12/schema",
9 "type" : "array",
10 "items" : {
11 "type" : "object",
12 "properties" : {
13 "actor" : {
14 "type" : "string"
15 },
16 "bookName" : {
17 "type" : "string"
18 }
19 },
20 "additionalProperties" : false
21 }
22}```通过将提示词发送给 ai,可以看到如下返回结构
text
1[{"actor":"罗贯中","bookName":"三国演义"},{"actor":"施耐庵","bookName":"水浒传"},{"actor":"吴承恩","bookName":"西游记"},{"actor":"曹雪芹","bookName":"红楼梦"}]顾问
CompressionQueryTransformer 压缩查询转换器
使用大型语言模型将对话历史和后续查询压缩成一个独立的查询,该查询能够捕捉对话的本质。
java
1Query query = Query.builder()
2 .text("And what is its second largest city?")
3 .history(new UserMessage("What is the capital of Denmark?"),
4 new AssistantMessage("Copenhagen is the capital of Denmark."))
5 .build();
6
7QueryTransformer queryTransformer = CompressionQueryTransformer.builder()
8 .chatClientBuilder(chatClientBuilder)
9 .build();
10
11Query transformedQuery = queryTransformer.transform(query);RewriteQueryTransformer 重写查询转换器
java
1Query query = new Query("I'm studying machine learning. What is an LLM?");
2
3QueryTransformer queryTransformer = RewriteQueryTransformer.builder()
4 .chatClientBuilder(chatClientBuilder)
5 .build();
6
7Query transformedQuery = queryTransformer.transform(query);MultiQueryExpander 多查询扩展器
使用大型语言模型将查询扩展为多个语义不同的变体,以捕捉不同的视角,这有助于检索额外的上下文信息并增加找到相关结果的机会。
java
1MultiQueryExpander queryExpander = MultiQueryExpander.builder()
2 .chatClientBuilder(chatClientBuilder)
3 .numberOfQueries(3)
4 .build();
5List<Query> queries = queryExpander.expand(new Query("How to run a Spring Boot app?"));检索
完整的Demo
java
1public static void main(String[] args) {
2 ConfigurableApplicationContext app = SpringApplication.run(SpringAiApplication.class, "--spring.profiles.active=mi");
3 ChatModel chatModel = app.getBean(ChatModel.class);
4 // 工具回调提供者
5 MethodToolCallbackProvider toolCallbackProvider = MethodToolCallbackProvider.builder().
6 toolObjects(new DateTimeTools()).build();
7
8 // 工具回调解析器
9 StaticToolCallbackResolver staticToolCallbackResolver = new StaticToolCallbackResolver(Arrays.stream(toolCallbackProvider.getToolCallbacks()).toList());
10
11 // 工具调用管理器
12 DefaultToolCallingManager toolCallingManager = DefaultToolCallingManager.builder()
13 .toolCallbackResolver(staticToolCallbackResolver)
14 .toolExecutionExceptionProcessor(new ToolExecutionExceptionProcessor() {
15 // 异常处理器
16 @Override
17 public String process(ToolExecutionException exception) {
18 ToolDefinition toolDefinition = exception.getToolDefinition();
19 System.err.println("Tool Error: " + toolDefinition);
20 return exception.getMessage();
21 }
22 })
23 .build();
24
25 // 会话上下文
26 ChatOptions chatOptions = ToolCallingChatOptions.builder()
27 .toolCallbacks(toolCallbackProvider.getToolCallbacks())
28 // 决定函数是内部自动调用还是外部调用 (这里保持 false 以使用手动循环)
29 .internalToolExecutionEnabled(false)
30 .build();
31
32 // 会话记忆
33 ChatMemory chatMemory = MessageWindowChatMemory.builder().maxMessages(20).build();
34 String conversationId = UUID.randomUUID().toString();
35
36 // 会话客户端
37 ChatClient chatClient = ChatClient.builder(chatModel).defaultOptions(chatOptions).build();
38
39 Scanner scanner = new Scanner(System.in);
40 System.out.println("=== AI 聊天助手启动 (输入 'exit' 退出) ===");
41
42 while (true) {
43 System.out.print("\n锦衣卫·智问: ");
44 String input = scanner.nextLine();
45 if ("exit".equalsIgnoreCase(input)) {
46 break;
47 }
48
49 // 1. 构建 Prompt 并存入记忆
50 Prompt prompt = new Prompt(input, chatOptions);
51 chatMemory.add(conversationId, prompt.getInstructions());
52
53 // 2. 从记忆中获取完整的上下文
54 Prompt promptWithMemory = new Prompt(chatMemory.get(conversationId), chatOptions);
55
56 // 3. 发起调用
57 ChatResponse chatResponse = chatClient.prompt(promptWithMemory).call().chatResponse();
58 chatMemory.add(conversationId, chatResponse.getResult().getOutput());
59
60 // 4. 处理工具调用循环
61 while (chatResponse.hasToolCalls()) {
62 System.out.println("[System] 正在调用工具...");
63 ToolExecutionResult toolExecutionResult = toolCallingManager.executeToolCalls(promptWithMemory, chatResponse);
64
65 // 使用工具执行结果更新 Prompt
66 promptWithMemory = new Prompt(toolExecutionResult.conversationHistory(), chatOptions);
67
68 // 再次调用模型
69 chatResponse = chatModel.call(promptWithMemory);
70 chatMemory.add(conversationId, chatResponse.getResult().getOutput());
71 }
72
73 System.out.println("AI: " + chatResponse.getResult().getOutput().getText());
74 }
75 }
76
77 static class DateTimeTools {
78
79 @Tool(description = "负责查询天气")
80 public String query(
81 @ToolParam(description = "要查询天气的城市") String cityName) {
82 String[] weathers = {"晴天", "多云", "小雨", "中雨", "大雪", "雷阵雨"};
83 int temp = ThreadLocalRandom.current().nextInt(-5, 35);
84 int humidity = ThreadLocalRandom.current().nextInt(30, 90);
85 int wind = ThreadLocalRandom.current().nextInt(1, 6);
86 String weather = weathers[ThreadLocalRandom.current().nextInt(weathers.length)];
87 String format = String.format(
88 "%s 当前天气:%s,温度 %d°C,湿度 %d%%,风力 %d 级",
89 cityName, weather, temp, humidity, wind
90 );
91// System.out.println(format);
92 return format;
93 }
94
95 }