项目概况

SpringAI中技术原理集合

2026-01-293 min read未分类
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 }