From 3e20180b16b1a2993fafeca35ad8a7cb65c7602a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=BB=84=E9=9C=87?= <476749506@qq.com>
Date: Fri, 20 Jun 2025 00:07:03 +0800
Subject: [PATCH 1/8] =?UTF-8?q?feat(deepresearch):=20=E6=B7=BB=E5=8A=A0=20?=
=?UTF-8?q?Redis=20=E6=94=AF=E6=8C=81=E5=B9=B6=E6=9B=B4=E6=96=B0=20Reporte?=
=?UTF-8?q?rNode=20=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 pom.xml 中添加 spring-boot-starter-data-redis 依赖。
- 更新 DeepResearchConfiguration,注入 ReportRedisService。
- 修改 ReporterNode,增加将报告保存到 Redis 的功能,并记录线程 ID。
- 在 application.yml 中添加 Redis 配置。
---
spring-ai-alibaba-deepresearch/pom.xml | 5 +
.../config/DeepResearchConfiguration.java | 50 ++--
.../deepresearch/config/RedisConfig.java | 60 +++++
.../controller/ReportController.java | 218 ++++++++++++++++++
.../deepresearch/node/ReporterNode.java | 34 ++-
.../service/ReportRedisService.java | 136 +++++++++++
.../src/main/resources/application.yml | 27 ++-
7 files changed, 493 insertions(+), 37 deletions(-)
create mode 100644 spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/RedisConfig.java
create mode 100644 spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/controller/ReportController.java
create mode 100644 spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportRedisService.java
diff --git a/spring-ai-alibaba-deepresearch/pom.xml b/spring-ai-alibaba-deepresearch/pom.xml
index e3d1ee0d18..38f69da46c 100644
--- a/spring-ai-alibaba-deepresearch/pom.xml
+++ b/spring-ai-alibaba-deepresearch/pom.xml
@@ -96,6 +96,11 @@
org.springframework.ai
spring-ai-tika-document-reader
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java
index 282c917517..208e814016 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java
@@ -32,6 +32,7 @@
import com.alibaba.cloud.ai.example.deepresearch.node.CoderNode;
import com.alibaba.cloud.ai.example.deepresearch.node.ResearcherNode;
import com.alibaba.cloud.ai.example.deepresearch.node.ReporterNode;
+import com.alibaba.cloud.ai.example.deepresearch.service.ReportRedisService;
import com.alibaba.cloud.ai.example.deepresearch.serializer.DeepResearchStateSerializer;
import com.alibaba.cloud.ai.graph.*;
@@ -66,7 +67,7 @@ public class DeepResearchConfiguration {
private static final Logger logger = LoggerFactory.getLogger(DeepResearchConfiguration.class);
- @Autowired
+ @Autowired(required = false)
private TavilySearchService tavilySearchService;
@Autowired
@@ -84,6 +85,9 @@ public class DeepResearchConfiguration {
@Autowired(required = false)
private RetrievalAugmentationAdvisor retrievalAugmentationAdvisor;
+ @Autowired
+ private ReportRedisService reportRedisService;
+
@Bean
public StateGraph deepResearch(ChatClient.Builder chatClientBuilder) throws GraphStateException {
@@ -116,7 +120,7 @@ public StateGraph deepResearch(ChatClient.Builder chatClientBuilder) throws Grap
keyStrategyHashMap.put("planner_content", new ReplaceStrategy());
for (int i = 0; i < deepResearchProperties.getParallelNodeCount()
- .get(ParallelEnum.RESEARCHER.getValue()); i++) {
+ .get(ParallelEnum.RESEARCHER.getValue()); i++) {
keyStrategyHashMap.put(ParallelEnum.RESEARCHER.getValue() + "_content_" + i, new ReplaceStrategy());
}
for (int i = 0; i < deepResearchProperties.getParallelNodeCount().get(ParallelEnum.CODER.getValue()); i++) {
@@ -128,31 +132,31 @@ public StateGraph deepResearch(ChatClient.Builder chatClientBuilder) throws Grap
StateGraph stateGraph = new StateGraph("deep research", keyStrategyFactory,
new DeepResearchStateSerializer(OverAllState::new))
- .addNode("coordinator", node_async(new CoordinatorNode(chatClientBuilder)))
- .addNode("background_investigator",
- node_async(new BackgroundInvestigationNode(tavilySearchService, jinaCrawlerService)))
- .addNode("planner", node_async((new PlannerNode(chatClientBuilder))))
- .addNode("human_feedback", node_async(new HumanFeedbackNode()))
- .addNode("research_team", node_async(new ResearchTeamNode()))
- .addNode("parallel_executor", node_async(new ParallelExecutorNode(deepResearchProperties)))
- .addNode("reporter", node_async((new ReporterNode(chatClientBuilder))))
- .addNode("rag_node", node_async(new RagNode(retrievalAugmentationAdvisor, chatClientBuilder)));
+ .addNode("coordinator", node_async(new CoordinatorNode(chatClientBuilder)))
+ .addNode("background_investigator",
+ node_async(new BackgroundInvestigationNode(tavilySearchService, jinaCrawlerService)))
+ .addNode("planner", node_async((new PlannerNode(chatClientBuilder))))
+ .addNode("human_feedback", node_async(new HumanFeedbackNode()))
+ .addNode("research_team", node_async(new ResearchTeamNode()))
+ .addNode("parallel_executor", node_async(new ParallelExecutorNode(deepResearchProperties)))
+ .addNode("reporter", node_async((new ReporterNode(chatClientBuilder, reportRedisService))))
+ .addNode("rag_node", node_async(new RagNode(retrievalAugmentationAdvisor, chatClientBuilder)));
// 添加并行节点块
configureParallelNodes(stateGraph);
stateGraph.addEdge(START, "coordinator")
- .addConditionalEdges("coordinator", edge_async(new CoordinatorDispatcher()),
- Map.of("background_investigator", "background_investigator", "planner", "planner", END, END))
- .addEdge("background_investigator", "planner")
- .addConditionalEdges("planner", edge_async(new PlannerDispatcher()),
- Map.of("reporter", "reporter", "human_feedback", "human_feedback", "planner", "planner",
- "research_team", "research_team", END, END))
- .addConditionalEdges("human_feedback", edge_async(new HumanFeedbackDispatcher()),
- Map.of("planner", "planner", "research_team", "research_team", END, END))
- .addConditionalEdges("research_team", edge_async(new ResearchTeamDispatcher()),
- Map.of("reporter", "reporter", "parallel_executor", "parallel_executor", END, END))
- .addEdge("reporter", END);
+ .addConditionalEdges("coordinator", edge_async(new CoordinatorDispatcher()),
+ Map.of("background_investigator", "background_investigator", "planner", "planner", END, END))
+ .addEdge("background_investigator", "planner")
+ .addConditionalEdges("planner", edge_async(new PlannerDispatcher()),
+ Map.of("reporter", "reporter", "human_feedback", "human_feedback", "planner", "planner",
+ "research_team", "research_team", END, END))
+ .addConditionalEdges("human_feedback", edge_async(new HumanFeedbackDispatcher()),
+ Map.of("planner", "planner", "research_team", "research_team", END, END))
+ .addConditionalEdges("research_team", edge_async(new ResearchTeamDispatcher()),
+ Map.of("reporter", "reporter", "parallel_executor", "parallel_executor", END, END))
+ .addEdge("reporter", END);
GraphRepresentation graphRepresentation = stateGraph.getGraph(GraphRepresentation.Type.PLANTUML,
"workflow graph");
@@ -172,7 +176,7 @@ private void configureParallelNodes(StateGraph stateGraph) throws GraphStateExce
private void addResearcherNodes(StateGraph stateGraph) throws GraphStateException {
for (int i = 0; i < deepResearchProperties.getParallelNodeCount()
- .get(ParallelEnum.RESEARCHER.getValue()); i++) {
+ .get(ParallelEnum.RESEARCHER.getValue()); i++) {
String nodeId = "researcher_" + i;
stateGraph.addNode(nodeId, node_async(new ResearcherNode(researchAgent, String.valueOf(i))));
stateGraph.addEdge("parallel_executor", nodeId).addEdge(nodeId, "research_team");
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/RedisConfig.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/RedisConfig.java
new file mode 100644
index 0000000000..6ef5618f05
--- /dev/null
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/RedisConfig.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.cloud.ai.example.deepresearch.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * Redis 配置类
+ *
+ * @author huangzhen
+ * @since 2025/6/18
+ */
+@Configuration
+public class RedisConfig {
+
+ /**
+ * 配置 RedisTemplate
+ * @param redisConnectionFactory Redis 连接工厂
+ * @return RedisTemplate 实例
+ */
+ @Bean
+ public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+ RedisTemplate template = new RedisTemplate<>();
+ template.setConnectionFactory(redisConnectionFactory);
+
+ // 设置键的序列化器
+ template.setKeySerializer(new StringRedisSerializer());
+ template.setHashKeySerializer(new StringRedisSerializer());
+
+ // 设置值的序列化器
+ template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
+ template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
+
+ // 设置默认序列化器
+ template.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
+
+ template.afterPropertiesSet();
+ return template;
+ }
+
+}
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/controller/ReportController.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/controller/ReportController.java
new file mode 100644
index 0000000000..8252664cf6
--- /dev/null
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/controller/ReportController.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.cloud.ai.example.deepresearch.controller;
+
+import com.alibaba.cloud.ai.example.deepresearch.service.ReportRedisService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 报告查询控制器
+ *
+ * @author huangzhen
+ * @since 2025/6/18
+ */
+@RestController
+@RequestMapping("/api/reports")
+public class ReportController {
+
+ private static final Logger logger = LoggerFactory.getLogger(ReportController.class);
+
+ private final ReportRedisService reportRedisService;
+
+ public ReportController(ReportRedisService reportRedisService) {
+ this.reportRedisService = reportRedisService;
+ }
+
+ /**
+ * 根据线程ID获取报告
+ * @param threadId 线程ID
+ * @return 报告内容
+ */
+ @GetMapping("/{threadId}")
+ public ResponseEntity getReport(@PathVariable String threadId) {
+ try {
+ logger.info("查询报告,线程ID: {}", threadId);
+ String report = reportRedisService.getReport(threadId);
+
+ if (report != null) {
+ ReportResponse response = new ReportResponse();
+ response.setThreadId(threadId);
+ response.setReport(report);
+ response.setStatus("success");
+ response.setMessage("报告获取成功");
+ return ResponseEntity.ok(response);
+ }
+ else {
+ ReportResponse response = new ReportResponse();
+ response.setThreadId(threadId);
+ response.setStatus("not_found");
+ response.setMessage("未找到指定线程ID的报告");
+ return ResponseEntity.notFound().build();
+ }
+ }
+ catch (Exception e) {
+ logger.error("获取报告失败,线程ID: {}", threadId, e);
+ ReportResponse response = new ReportResponse();
+ response.setThreadId(threadId);
+ response.setStatus("error");
+ response.setMessage("获取报告失败: " + e.getMessage());
+ return ResponseEntity.internalServerError().body(response);
+ }
+ }
+
+ /**
+ * 检查报告是否存在
+ * @param threadId 线程ID
+ * @return 是否存在
+ */
+ @GetMapping("/{threadId}/exists")
+ public ResponseEntity existsReport(@PathVariable String threadId) {
+ try {
+ logger.info("检查报告是否存在,线程ID: {}", threadId);
+ boolean exists = reportRedisService.existsReport(threadId);
+
+ ExistsResponse response = new ExistsResponse();
+ response.setThreadId(threadId);
+ response.setExists(exists);
+ response.setStatus("success");
+ response.setMessage(exists ? "报告存在" : "报告不存在");
+
+ return ResponseEntity.ok(response);
+ }
+ catch (Exception e) {
+ logger.error("检查报告是否存在失败,线程ID: {}", threadId, e);
+ ExistsResponse response = new ExistsResponse();
+ response.setThreadId(threadId);
+ response.setExists(false);
+ response.setStatus("error");
+ response.setMessage("检查失败: " + e.getMessage());
+ return ResponseEntity.internalServerError().body(response);
+ }
+ }
+
+ /**
+ * 删除报告
+ * @param threadId 线程ID
+ * @return 删除结果
+ */
+ @DeleteMapping("/{threadId}")
+ public ResponseEntity deleteReport(@PathVariable String threadId) {
+ try {
+ logger.info("删除报告,线程ID: {}", threadId);
+
+ if (!reportRedisService.existsReport(threadId)) {
+ BaseResponse response = new BaseResponse();
+ response.setThreadId(threadId);
+ response.setStatus("not_found");
+ response.setMessage("未找到指定线程ID的报告");
+ return ResponseEntity.notFound().build();
+ }
+
+ reportRedisService.deleteReport(threadId);
+
+ BaseResponse response = new BaseResponse();
+ response.setThreadId(threadId);
+ response.setStatus("success");
+ response.setMessage("报告删除成功");
+
+ return ResponseEntity.ok(response);
+ }
+ catch (Exception e) {
+ logger.error("删除报告失败,线程ID: {}", threadId, e);
+ BaseResponse response = new BaseResponse();
+ response.setThreadId(threadId);
+ response.setStatus("error");
+ response.setMessage("删除报告失败: " + e.getMessage());
+ return ResponseEntity.internalServerError().body(response);
+ }
+ }
+
+ /**
+ * 基础响应类
+ */
+ public static class BaseResponse {
+
+ private String threadId;
+
+ private String status;
+
+ private String message;
+
+ public String getThreadId() {
+ return threadId;
+ }
+
+ public void setThreadId(String threadId) {
+ this.threadId = threadId;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ }
+
+ /**
+ * 报告响应类
+ */
+ public static class ReportResponse extends BaseResponse {
+
+ private String report;
+
+ public String getReport() {
+ return report;
+ }
+
+ public void setReport(String report) {
+ this.report = report;
+ }
+
+ }
+
+ /**
+ * 存在性检查响应类
+ */
+ public static class ExistsResponse extends BaseResponse {
+
+ private boolean exists;
+
+ public boolean isExists() {
+ return exists;
+ }
+
+ public void setExists(boolean exists) {
+ this.exists = exists;
+ }
+
+ }
+
+}
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
index cf166693cf..1cad296584 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
@@ -18,6 +18,7 @@
import com.alibaba.cloud.ai.example.deepresearch.model.ParallelEnum;
import com.alibaba.cloud.ai.example.deepresearch.model.dto.Plan;
+import com.alibaba.cloud.ai.example.deepresearch.service.ReportRedisService;
import com.alibaba.cloud.ai.example.deepresearch.util.StateUtil;
import com.alibaba.cloud.ai.example.deepresearch.util.TemplateUtil;
import com.alibaba.cloud.ai.graph.OverAllState;
@@ -48,19 +49,28 @@ public class ReporterNode implements NodeAction {
private final ChatClient chatClient;
+ private final ReportRedisService reportRedisService;
+
private static final String RESEARCH_FORMAT = "# Research Requirements\n\n## Task\n\n{0}\n\n## Description\n\n{1}";
private final String REPORT_FORMAT = "IMPORTANT: Structure your report according to the format in the prompt. Remember to include:\n\n1. Key Points - A bulleted list of the most important findings\n2. Overview - A brief introduction to the topic\n3. Detailed Analysis - Organized into logical sections\n4. Survey Note (optional) - For more comprehensive reports\n5. Key Citations - List all references at the end\n\nFor citations, DO NOT include inline citations in the text. Instead, place all citations in the 'Key Citations' section at the end using the format: `- [Source Title](URL)`. Include an empty line between each citation for better readability.\n\nPRIORITIZE USING MARKDOWN TABLES for data presentation and comparison. Use tables whenever presenting comparative data, statistics, features, or options. Structure tables with clear headers and aligned columns. Example table format:\n\n| Feature | Description | Pros | Cons |\n|---------|-------------|------|------|\n| Feature 1 | Description 1 | Pros 1 | Cons 1 |\n| Feature 2 | Description 2 | Pros 2 | Cons 2 |";
- public ReporterNode(ChatClient.Builder chatClientBuilder) {
+ public ReporterNode(ChatClient.Builder chatClientBuilder, ReportRedisService reportRedisService) {
this.chatClient = chatClientBuilder.build();
+ this.reportRedisService = reportRedisService;
}
@Override
public Map apply(OverAllState state) throws Exception {
logger.info("reporter node is running.");
Plan currentPlan = state.value("current_plan", Plan.class)
- .orElseThrow(() -> new IllegalArgumentException("current_plan is missing"));
+ .orElseThrow(() -> new IllegalArgumentException("current_plan is missing"));
+
+ // 从 OverAllState 中获取线程ID
+ String threadId = state.value("thread_id", String.class)
+ .orElseThrow(() -> new IllegalArgumentException("thread_id is missing from state"));
+ logger.info("Thread ID from state: {}", threadId);
+
// 1. 添加消息
List messages = new ArrayList<>();
// 1.1 添加预置提示消息
@@ -86,13 +96,23 @@ public Map apply(OverAllState state) throws Exception {
var streamResult = chatClient.prompt().messages(messages).stream().chatResponse();
var generator = StreamingChatGenerator.builder()
- .startingNode("reporter_llm_stream")
- .startingState(state)
- .mapResult(response -> Map.of("final_report",
- Objects.requireNonNull(response.getResult().getOutput().getText())))
- .build(streamResult);
+ .startingNode("reporter_llm_stream")
+ .startingState(state)
+ .mapResult(response -> {
+ String finalReport = Objects.requireNonNull(response.getResult().getOutput().getText());
+ // 将报告保存到 Redis
+ try {
+ reportRedisService.saveReport(threadId, finalReport);
+ logger.info("报告已成功保存到 Redis,线程ID: {}", threadId);
+ } catch (Exception e) {
+ logger.error("保存报告到 Redis 失败,线程ID: {}", threadId, e);
+ }
+ return Map.of("final_report", finalReport, "thread_id", threadId);
+ })
+ .build(streamResult);
Map resultMap = new HashMap<>();
resultMap.put("final_report", generator);
+ resultMap.put("thread_id", threadId);
return resultMap;
}
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportRedisService.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportRedisService.java
new file mode 100644
index 0000000000..fad3842a24
--- /dev/null
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportRedisService.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.cloud.ai.example.deepresearch.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 报告 Redis 服务类
+ *
+ * @author huangzhen
+ * @since 2025/6/18
+ */
+@Service
+public class ReportRedisService {
+
+ private static final Logger logger = LoggerFactory.getLogger(ReportRedisService.class);
+
+ private final RedisTemplate redisTemplate;
+
+ /**
+ * Redis key 前缀
+ */
+ private static final String REPORT_KEY_PREFIX = "deepresearch:report:";
+
+ /**
+ * 默认过期时间(24小时)
+ */
+ private static final long DEFAULT_EXPIRE_HOURS = 24;
+
+ public ReportRedisService(RedisTemplate redisTemplate) {
+ this.redisTemplate = redisTemplate;
+ }
+
+ /**
+ * 存储报告到 Redis
+ * @param threadId 线程ID
+ * @param report 报告内容
+ */
+ public void saveReport(String threadId, String report) {
+ try {
+ String key = buildKey(threadId);
+ redisTemplate.opsForValue().set(key, report, DEFAULT_EXPIRE_HOURS, TimeUnit.HOURS);
+ logger.info("报告已保存到 Redis,线程ID: {}, key: {}", threadId, key);
+ }
+ catch (Exception e) {
+ logger.error("保存报告到 Redis 失败,线程ID: {}", threadId, e);
+ throw new RuntimeException("保存报告失败", e);
+ }
+ }
+
+ /**
+ * 从 Redis 获取报告
+ * @param threadId 线程ID
+ * @return 报告内容,如果不存在返回 null
+ */
+ public String getReport(String threadId) {
+ try {
+ String key = buildKey(threadId);
+ Object result = redisTemplate.opsForValue().get(key);
+ if (result != null) {
+ logger.info("从 Redis 获取报告成功,线程ID: {}, key: {}", threadId, key);
+ return result.toString();
+ }
+ else {
+ logger.warn("Redis 中未找到报告,线程ID: {}, key: {}", threadId, key);
+ return null;
+ }
+ }
+ catch (Exception e) {
+ logger.error("从 Redis 获取报告失败,线程ID: {}", threadId, e);
+ throw new RuntimeException("获取报告失败", e);
+ }
+ }
+
+ /**
+ * 检查报告是否存在
+ * @param threadId 线程ID
+ * @return 是否存在
+ */
+ public boolean existsReport(String threadId) {
+ try {
+ String key = buildKey(threadId);
+ Boolean exists = redisTemplate.hasKey(key);
+ return exists != null && exists;
+ }
+ catch (Exception e) {
+ logger.error("检查报告是否存在失败,线程ID: {}", threadId, e);
+ return false;
+ }
+ }
+
+ /**
+ * 删除报告
+ * @param threadId 线程ID
+ */
+ public void deleteReport(String threadId) {
+ try {
+ String key = buildKey(threadId);
+ redisTemplate.delete(key);
+ logger.info("已删除 Redis 中的报告,线程ID: {}, key: {}", threadId, key);
+ }
+ catch (Exception e) {
+ logger.error("删除报告失败,线程ID: {}", threadId, e);
+ throw new RuntimeException("删除报告失败", e);
+ }
+ }
+
+ /**
+ * 构建 Redis key
+ * @param threadId 线程ID
+ * @return Redis key
+ */
+ private String buildKey(String threadId) {
+ return REPORT_KEY_PREFIX + threadId;
+ }
+
+}
diff --git a/spring-ai-alibaba-deepresearch/src/main/resources/application.yml b/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
index 0a570dfd37..be3323ad05 100644
--- a/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
+++ b/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
@@ -3,6 +3,19 @@ server:
spring:
application:
name: spring-ai-alibaba-deepresearch
+ # Redis 配置
+ data:
+ redis:
+ host: 10.10.3.131
+ port: 6379
+ password: difyai123456
+ timeout: 3000 # 连接超时时间(毫秒)
+ lettuce:
+ pool:
+ max-active: 8
+ max-idle: 8
+ min-idle: 0
+ max-wait: -1ms
ai:
openai:
api-key: ${AI_DASHSCOPE_API_KEY}
@@ -21,10 +34,10 @@ spring:
mcp:
client:
type: async
-# sse:
-# connections:
-# weather_mcp_server:
-# url: http://localhost:8888
+ # sse:
+ # connections:
+ # weather_mcp_server:
+ # url: http://localhost:8888
stdio:
servers-configuration: classpath:mcp-servers.json
toolcallback:
@@ -44,9 +57,9 @@ spring:
mcp-client-mapping:
researchAgent:
- amap-maps
-# coderAgent:
-# - amap-maps
-# - weather_mcp_server
+ # coderAgent:
+ # - amap-maps
+ # - weather_mcp_server
rag:
enabled: true
# 可以设置为 'simple' 或 'elasticsearch'
From 52dd85629e8a0259b23938c9abd70cb17a9ed0d7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=BB=84=E9=9C=87?= <476749506@qq.com>
Date: Fri, 20 Jun 2025 00:37:46 +0800
Subject: [PATCH 2/8] =?UTF-8?q?=E4=BC=98=E5=8C=96=20ReporterNode=20?=
=?UTF-8?q?=E4=B8=AD=E7=9A=84=E6=8A=A5=E5=91=8A=E6=A0=BC=E5=BC=8F=E5=AD=97?=
=?UTF-8?q?=E7=AC=A6=E4=B8=B2=EF=BC=8C=E4=BF=AE=E5=A4=8D=E4=BA=86=E6=8A=A5?=
=?UTF-8?q?=E5=91=8A=E4=BF=9D=E5=AD=98=E9=80=BB=E8=BE=91=E4=B8=AD=E7=9A=84?=
=?UTF-8?q?=E5=8F=98=E9=87=8F=E5=A3=B0=E6=98=8E=E9=97=AE=E9=A2=98=EF=BC=8C?=
=?UTF-8?q?=E7=A1=AE=E4=BF=9D=E6=8A=A5=E5=91=8A=E5=86=85=E5=AE=B9=E6=AD=A3?=
=?UTF-8?q?=E7=A1=AE=E4=BF=9D=E5=AD=98=E5=88=B0=20Redis=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../cloud/ai/example/deepresearch/node/ReporterNode.java | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
index 43f245ca88..20c5579df1 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
@@ -55,11 +55,9 @@ public class ReporterNode implements NodeAction {
private final String REPORT_FORMAT = "IMPORTANT: Structure your report according to the format in the prompt. Remember to include:\n\n1. Key Points - A bulleted list of the most important findings\n2. Overview - A brief introduction to the topic\n3. Detailed Analysis - Organized into logical sections\n4. Survey Note (optional) - For more comprehensive reports\n5. Key Citations - List all references at the end\n\nFor citations, DO NOT include inline citations in the text. Instead, place all citations in the 'Key Citations' section at the end using the format: `- [Source Title](URL)`. Include an empty line between each citation for better readability.\n\nPRIORITIZE USING MARKDOWN TABLES for data presentation and comparison. Use tables whenever presenting comparative data, statistics, features, or options. Structure tables with clear headers and aligned columns. Example table format:\n\n| Feature | Description | Pros | Cons |\n|---------|-------------|------|------|\n| Feature 1 | Description 1 | Pros 1 | Cons 1 |\n| Feature 2 | Description 2 | Pros 2 | Cons 2 |";
-
public ReporterNode(ChatClient reporterAgent, ReportRedisService reportRedisService) {
this.reporterAgent = reporterAgent;
this.reportRedisService = reportRedisService;
-
}
@Override
@@ -101,8 +99,8 @@ public Map apply(OverAllState state) throws Exception {
.startingNode("reporter_llm_stream")
.startingState(state)
.mapResult(response -> {
- Strin
- try {
+ String finalReport = Objects.requireNonNull(response.getResult().getOutput().getText());
+ try {
reportRedisService.saveReport(threadId, finalReport);
logger.info("报告已成功保存到 Redis,线程ID: {}", threadId);
} catch (Exception e) {
From 69a8e1468dabc1dfa7cb60371ca448893e5ca5d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=BB=84=E9=9C=87?= <476749506@qq.com>
Date: Fri, 20 Jun 2025 00:50:57 +0800
Subject: [PATCH 3/8] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20application.yml=20?=
=?UTF-8?q?=E4=B8=AD=E7=9A=84=20Redis=20=E9=85=8D=E7=BD=AE=EF=BC=8C?=
=?UTF-8?q?=E5=B0=86=E4=B8=BB=E6=9C=BA=E5=9C=B0=E5=9D=80=E6=9B=B4=E6=94=B9?=
=?UTF-8?q?=E4=B8=BA=20localhost=EF=BC=8C=E5=B9=B6=E4=BD=BF=E7=94=A8?=
=?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F=E6=9B=BF=E4=BB=A3=E5=AF=86?=
=?UTF-8?q?=E7=A0=81=EF=BC=8C=E4=BB=A5=E5=A2=9E=E5=BC=BA=E5=AE=89=E5=85=A8?=
=?UTF-8?q?=E6=80=A7=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/main/resources/application.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/spring-ai-alibaba-deepresearch/src/main/resources/application.yml b/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
index 688c78df10..32d0ac1f30 100644
--- a/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
+++ b/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
@@ -6,9 +6,9 @@ spring:
# Redis 配置
data:
redis:
- host: 10.10.3.131
+ host: localhost
port: 6379
- password: difyai123456
+ password: ${REDIS-PASSWORD}
timeout: 3000 # 连接超时时间(毫秒)
lettuce:
pool:
From f9b929fcebf277cb1395f87e3b1c5c06ac2520ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=BB=84=E9=9C=87?= <476749506@qq.com>
Date: Fri, 20 Jun 2025 09:30:55 +0800
Subject: [PATCH 4/8] =?UTF-8?q?=E4=BC=98=E5=8C=96=20DeepResearchConfigurat?=
=?UTF-8?q?ion=20=E5=92=8C=20ReporterNode=20=E4=B8=AD=E7=9A=84=E4=BB=A3?=
=?UTF-8?q?=E7=A0=81=E6=A0=BC=E5=BC=8F=EF=BC=8C=E4=BF=AE=E5=A4=8D=E4=BA=86?=
=?UTF-8?q?=E5=BE=AA=E7=8E=AF=E7=BB=93=E6=9E=84=E4=B8=AD=E7=9A=84=E7=BC=A9?=
=?UTF-8?q?=E8=BF=9B=E9=97=AE=E9=A2=98=EF=BC=8C=E7=A1=AE=E4=BF=9D=E4=BB=A3?=
=?UTF-8?q?=E7=A0=81=E5=8F=AF=E8=AF=BB=E6=80=A7=E6=9B=B4=E9=AB=98=E3=80=82?=
=?UTF-8?q?=E5=90=8C=E6=97=B6=EF=BC=8C=E8=B0=83=E6=95=B4=E4=BA=86=20Report?=
=?UTF-8?q?erNode=20=E4=B8=AD=E7=9A=84=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?=
=?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E5=A2=9E=E5=BC=BA=E4=BA=86=E4=BB=A3?=
=?UTF-8?q?=E7=A0=81=E7=9A=84=E5=81=A5=E5=A3=AE=E6=80=A7=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../config/DeepResearchConfiguration.java | 48 +++++++++----------
.../deepresearch/node/ReporterNode.java | 31 ++++++------
2 files changed, 40 insertions(+), 39 deletions(-)
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java
index 7a6b8df528..73f8ff3d3d 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java
@@ -136,7 +136,7 @@ public StateGraph deepResearch(ChatClient researchAgent) throws GraphStateExcept
keyStrategyHashMap.put("planner_content", new ReplaceStrategy());
for (int i = 0; i < deepResearchProperties.getParallelNodeCount()
- .get(ParallelEnum.RESEARCHER.getValue()); i++) {
+ .get(ParallelEnum.RESEARCHER.getValue()); i++) {
keyStrategyHashMap.put(ParallelEnum.RESEARCHER.getValue() + "_content_" + i, new ReplaceStrategy());
}
for (int i = 0; i < deepResearchProperties.getParallelNodeCount().get(ParallelEnum.CODER.getValue()); i++) {
@@ -148,33 +148,33 @@ public StateGraph deepResearch(ChatClient researchAgent) throws GraphStateExcept
StateGraph stateGraph = new StateGraph("deep research", keyStrategyFactory,
new DeepResearchStateSerializer(OverAllState::new))
- .addNode("coordinator", node_async(new CoordinatorNode(coordinatorAgent)))
- .addNode("background_investigator",
- node_async(new BackgroundInvestigationNode(tavilySearchService, jinaCrawlerService)))
- .addNode("planner", node_async((new PlannerNode(plannerAgent))))
- .addNode("information", node_async((new InformationNode())))
- .addNode("human_feedback", node_async(new HumanFeedbackNode()))
- .addNode("research_team", node_async(new ResearchTeamNode()))
- .addNode("parallel_executor", node_async(new ParallelExecutorNode(deepResearchProperties)))
- .addNode("reporter", node_async((new ReporterNode(reporterAgent, reportRedisService))))
- .addNode("rag_node", node_async(new RagNode(retrievalAugmentationAdvisor, researchAgent)));
+ .addNode("coordinator", node_async(new CoordinatorNode(coordinatorAgent)))
+ .addNode("background_investigator",
+ node_async(new BackgroundInvestigationNode(tavilySearchService, jinaCrawlerService)))
+ .addNode("planner", node_async((new PlannerNode(plannerAgent))))
+ .addNode("information", node_async((new InformationNode())))
+ .addNode("human_feedback", node_async(new HumanFeedbackNode()))
+ .addNode("research_team", node_async(new ResearchTeamNode()))
+ .addNode("parallel_executor", node_async(new ParallelExecutorNode(deepResearchProperties)))
+ .addNode("reporter", node_async((new ReporterNode(reporterAgent, reportRedisService))))
+ .addNode("rag_node", node_async(new RagNode(retrievalAugmentationAdvisor, researchAgent)));
// 添加并行节点块
configureParallelNodes(stateGraph);
stateGraph.addEdge(START, "coordinator")
- .addConditionalEdges("coordinator", edge_async(new CoordinatorDispatcher()),
- Map.of("background_investigator", "background_investigator", "planner", "planner", END, END))
- .addEdge("background_investigator", "planner")
- .addEdge("planner", "information")
- .addConditionalEdges("information", edge_async(new InformationDispatcher()),
- Map.of("reporter", "reporter", "human_feedback", "human_feedback", "planner", "planner",
- "research_team", "research_team", END, END))
- .addConditionalEdges("human_feedback", edge_async(new HumanFeedbackDispatcher()),
- Map.of("planner", "planner", "research_team", "research_team", END, END))
- .addConditionalEdges("research_team", edge_async(new ResearchTeamDispatcher()),
- Map.of("reporter", "reporter", "parallel_executor", "parallel_executor", END, END))
- .addEdge("reporter", END);
+ .addConditionalEdges("coordinator", edge_async(new CoordinatorDispatcher()),
+ Map.of("background_investigator", "background_investigator", "planner", "planner", END, END))
+ .addEdge("background_investigator", "planner")
+ .addEdge("planner", "information")
+ .addConditionalEdges("information", edge_async(new InformationDispatcher()),
+ Map.of("reporter", "reporter", "human_feedback", "human_feedback", "planner", "planner",
+ "research_team", "research_team", END, END))
+ .addConditionalEdges("human_feedback", edge_async(new HumanFeedbackDispatcher()),
+ Map.of("planner", "planner", "research_team", "research_team", END, END))
+ .addConditionalEdges("research_team", edge_async(new ResearchTeamDispatcher()),
+ Map.of("reporter", "reporter", "parallel_executor", "parallel_executor", END, END))
+ .addEdge("reporter", END);
GraphRepresentation graphRepresentation = stateGraph.getGraph(GraphRepresentation.Type.PLANTUML,
"workflow graph");
@@ -194,7 +194,7 @@ private void configureParallelNodes(StateGraph stateGraph) throws GraphStateExce
private void addResearcherNodes(StateGraph stateGraph) throws GraphStateException {
for (int i = 0; i < deepResearchProperties.getParallelNodeCount()
- .get(ParallelEnum.RESEARCHER.getValue()); i++) {
+ .get(ParallelEnum.RESEARCHER.getValue()); i++) {
String nodeId = "researcher_" + i;
stateGraph.addNode(nodeId, node_async(new ResearcherNode(researchAgent, String.valueOf(i))));
stateGraph.addEdge("parallel_executor", nodeId).addEdge(nodeId, "research_team");
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
index 20c5579df1..d93029778b 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
@@ -64,11 +64,11 @@ public ReporterNode(ChatClient reporterAgent, ReportRedisService reportRedisServ
public Map apply(OverAllState state) throws Exception {
logger.info("reporter node is running.");
Plan currentPlan = state.value("current_plan", Plan.class)
- .orElseThrow(() -> new IllegalArgumentException("current_plan is missing"));
+ .orElseThrow(() -> new IllegalArgumentException("current_plan is missing"));
// 从 OverAllState 中获取线程ID
String threadId = state.value("thread_id", String.class)
- .orElseThrow(() -> new IllegalArgumentException("thread_id is missing from state"));
+ .orElseThrow(() -> new IllegalArgumentException("thread_id is missing from state"));
logger.info("Thread ID from state: {}", threadId);
// 1. 添加消息
@@ -96,19 +96,20 @@ public Map apply(OverAllState state) throws Exception {
var streamResult = reporterAgent.prompt().messages(messages).stream().chatResponse();
var generator = StreamingChatGenerator.builder()
- .startingNode("reporter_llm_stream")
- .startingState(state)
- .mapResult(response -> {
- String finalReport = Objects.requireNonNull(response.getResult().getOutput().getText());
- try {
- reportRedisService.saveReport(threadId, finalReport);
- logger.info("报告已成功保存到 Redis,线程ID: {}", threadId);
- } catch (Exception e) {
- logger.error("保存报告到 Redis 失败,线程ID: {}", threadId, e);
- }
- return Map.of("final_report", finalReport, "thread_id", threadId);
- })
- .build(streamResult);
+ .startingNode("reporter_llm_stream")
+ .startingState(state)
+ .mapResult(response -> {
+ String finalReport = Objects.requireNonNull(response.getResult().getOutput().getText());
+ try {
+ reportRedisService.saveReport(threadId, finalReport);
+ logger.info("报告已成功保存到 Redis,线程ID: {}", threadId);
+ }
+ catch (Exception e) {
+ logger.error("保存报告到 Redis 失败,线程ID: {}", threadId, e);
+ }
+ return Map.of("final_report", finalReport, "thread_id", threadId);
+ })
+ .build(streamResult);
Map resultMap = new HashMap<>();
resultMap.put("final_report", generator);
resultMap.put("thread_id", threadId);
From e0756e65dada5cebd2c249c31a93268f23142f88 Mon Sep 17 00:00:00 2001
From: huangzhen <02258@mxbc.com>
Date: Fri, 20 Jun 2025 19:24:55 +0800
Subject: [PATCH 5/8] =?UTF-8?q?=E9=87=8D=E6=9E=84=20DeepResearchConfigurat?=
=?UTF-8?q?ion=20=E5=92=8C=20ReporterNode=20=E4=B8=AD=E7=9A=84=E6=8A=A5?=
=?UTF-8?q?=E5=91=8A=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
在 DeepResearchConfiguration 和 ReporterNode 中用 ReportService 替换 ReportRedisService,统一报告处理方式
更新 ReportController 改用 ReportService 进行报告操作
在 RedisConfig 和 ReportRedisService 中引入 ConditionalOnProperty 注解,根据配置启用/禁用 Redis 支持
修改 application.yml 默认将 Redis 启用属性设为 false
---
.../config/DeepResearchConfiguration.java | 6 +-
.../deepresearch/config/RedisConfig.java | 2 +
.../controller/ReportController.java | 90 ++-----------
.../model/response/BaseResponse.java | 57 +++++++++
.../model/response/ExistsResponse.java | 37 ++++++
.../model/response/ReportResponse.java | 37 ++++++
.../deepresearch/node/ReporterNode.java | 14 +--
.../service/ReportMemoryService.java | 119 ++++++++++++++++++
.../service/ReportRedisService.java | 8 +-
.../deepresearch/service/ReportService.java | 54 ++++++++
.../src/main/resources/application.yml | 1 +
11 files changed, 335 insertions(+), 90 deletions(-)
create mode 100644 spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java
create mode 100644 spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java
create mode 100644 spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java
create mode 100644 spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java
create mode 100644 spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java
index 73f8ff3d3d..804e50df08 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/DeepResearchConfiguration.java
@@ -33,7 +33,7 @@
import com.alibaba.cloud.ai.example.deepresearch.node.ReporterNode;
import com.alibaba.cloud.ai.example.deepresearch.node.ResearchTeamNode;
import com.alibaba.cloud.ai.example.deepresearch.node.ResearcherNode;
-import com.alibaba.cloud.ai.example.deepresearch.service.ReportRedisService;
+import com.alibaba.cloud.ai.example.deepresearch.service.ReportService;
import com.alibaba.cloud.ai.example.deepresearch.serializer.DeepResearchStateSerializer;
import com.alibaba.cloud.ai.graph.GraphRepresentation;
@@ -101,7 +101,7 @@ public class DeepResearchConfiguration {
private RetrievalAugmentationAdvisor retrievalAugmentationAdvisor;
@Autowired
- private ReportRedisService reportRedisService;
+ private ReportService reportService;
@Bean
public StateGraph deepResearch(ChatClient researchAgent) throws GraphStateException {
@@ -156,7 +156,7 @@ public StateGraph deepResearch(ChatClient researchAgent) throws GraphStateExcept
.addNode("human_feedback", node_async(new HumanFeedbackNode()))
.addNode("research_team", node_async(new ResearchTeamNode()))
.addNode("parallel_executor", node_async(new ParallelExecutorNode(deepResearchProperties)))
- .addNode("reporter", node_async((new ReporterNode(reporterAgent, reportRedisService))))
+ .addNode("reporter", node_async((new ReporterNode(reporterAgent, reportService))))
.addNode("rag_node", node_async(new RagNode(retrievalAugmentationAdvisor, researchAgent)));
// 添加并行节点块
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/RedisConfig.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/RedisConfig.java
index 6ef5618f05..1b833c88be 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/RedisConfig.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/config/RedisConfig.java
@@ -16,6 +16,7 @@
package com.alibaba.cloud.ai.example.deepresearch.config;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
@@ -30,6 +31,7 @@
* @since 2025/6/18
*/
@Configuration
+@ConditionalOnProperty(name = "spring.data.redis.enabled", havingValue = "true", matchIfMissing = false)
public class RedisConfig {
/**
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/controller/ReportController.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/controller/ReportController.java
index 8252664cf6..d1333ad7f2 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/controller/ReportController.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/controller/ReportController.java
@@ -16,7 +16,10 @@
package com.alibaba.cloud.ai.example.deepresearch.controller;
-import com.alibaba.cloud.ai.example.deepresearch.service.ReportRedisService;
+import com.alibaba.cloud.ai.example.deepresearch.model.response.BaseResponse;
+import com.alibaba.cloud.ai.example.deepresearch.model.response.ExistsResponse;
+import com.alibaba.cloud.ai.example.deepresearch.model.response.ReportResponse;
+import com.alibaba.cloud.ai.example.deepresearch.service.ReportService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
@@ -34,10 +37,10 @@ public class ReportController {
private static final Logger logger = LoggerFactory.getLogger(ReportController.class);
- private final ReportRedisService reportRedisService;
+ private final ReportService reportService;
- public ReportController(ReportRedisService reportRedisService) {
- this.reportRedisService = reportRedisService;
+ public ReportController(ReportService reportService) {
+ this.reportService = reportService;
}
/**
@@ -49,7 +52,7 @@ public ReportController(ReportRedisService reportRedisService) {
public ResponseEntity getReport(@PathVariable String threadId) {
try {
logger.info("查询报告,线程ID: {}", threadId);
- String report = reportRedisService.getReport(threadId);
+ String report = reportService.getReport(threadId);
if (report != null) {
ReportResponse response = new ReportResponse();
@@ -86,7 +89,7 @@ public ResponseEntity getReport(@PathVariable String threadId) {
public ResponseEntity existsReport(@PathVariable String threadId) {
try {
logger.info("检查报告是否存在,线程ID: {}", threadId);
- boolean exists = reportRedisService.existsReport(threadId);
+ boolean exists = reportService.existsReport(threadId);
ExistsResponse response = new ExistsResponse();
response.setThreadId(threadId);
@@ -117,7 +120,7 @@ public ResponseEntity deleteReport(@PathVariable String threadId)
try {
logger.info("删除报告,线程ID: {}", threadId);
- if (!reportRedisService.existsReport(threadId)) {
+ if (!reportService.existsReport(threadId)) {
BaseResponse response = new BaseResponse();
response.setThreadId(threadId);
response.setStatus("not_found");
@@ -125,7 +128,7 @@ public ResponseEntity deleteReport(@PathVariable String threadId)
return ResponseEntity.notFound().build();
}
- reportRedisService.deleteReport(threadId);
+ reportService.deleteReport(threadId);
BaseResponse response = new BaseResponse();
response.setThreadId(threadId);
@@ -144,75 +147,4 @@ public ResponseEntity deleteReport(@PathVariable String threadId)
}
}
- /**
- * 基础响应类
- */
- public static class BaseResponse {
-
- private String threadId;
-
- private String status;
-
- private String message;
-
- public String getThreadId() {
- return threadId;
- }
-
- public void setThreadId(String threadId) {
- this.threadId = threadId;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public String getMessage() {
- return message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-
- }
-
- /**
- * 报告响应类
- */
- public static class ReportResponse extends BaseResponse {
-
- private String report;
-
- public String getReport() {
- return report;
- }
-
- public void setReport(String report) {
- this.report = report;
- }
-
- }
-
- /**
- * 存在性检查响应类
- */
- public static class ExistsResponse extends BaseResponse {
-
- private boolean exists;
-
- public boolean isExists() {
- return exists;
- }
-
- public void setExists(boolean exists) {
- this.exists = exists;
- }
-
- }
-
}
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java
new file mode 100644
index 0000000000..a4db53c155
--- /dev/null
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.cloud.ai.example.deepresearch.model.response;
+
+/**
+ * 基础响应类
+ *
+ * @author huangzhen
+ * @since 2025/6/20
+ */
+public class BaseResponse {
+
+ private String threadId;
+
+ private String status;
+
+ private String message;
+
+ public String getThreadId() {
+ return threadId;
+ }
+
+ public void setThreadId(String threadId) {
+ this.threadId = threadId;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java
new file mode 100644
index 0000000000..4dc7097cd7
--- /dev/null
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.cloud.ai.example.deepresearch.model.response;
+
+/**
+ * 存在性检查响应类
+ *
+ * @author huangzhen
+ * @since 2025/6/20
+ */
+public class ExistsResponse extends BaseResponse {
+
+ private boolean exists;
+
+ public boolean isExists() {
+ return exists;
+ }
+
+ public void setExists(boolean exists) {
+ this.exists = exists;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java
new file mode 100644
index 0000000000..daf203ce41
--- /dev/null
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.cloud.ai.example.deepresearch.model.response;
+
+/**
+ * 报告响应类
+ *
+ * @author huangzhen
+ * @since 2025/6/20
+ */
+public class ReportResponse extends BaseResponse {
+
+ private String report;
+
+ public String getReport() {
+ return report;
+ }
+
+ public void setReport(String report) {
+ this.report = report;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
index d93029778b..2a90e6acac 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/node/ReporterNode.java
@@ -18,7 +18,7 @@
import com.alibaba.cloud.ai.example.deepresearch.model.ParallelEnum;
import com.alibaba.cloud.ai.example.deepresearch.model.dto.Plan;
-import com.alibaba.cloud.ai.example.deepresearch.service.ReportRedisService;
+import com.alibaba.cloud.ai.example.deepresearch.service.ReportService;
import com.alibaba.cloud.ai.example.deepresearch.util.StateUtil;
import com.alibaba.cloud.ai.example.deepresearch.util.TemplateUtil;
import com.alibaba.cloud.ai.graph.OverAllState;
@@ -49,15 +49,15 @@ public class ReporterNode implements NodeAction {
private final ChatClient reporterAgent;
- private final ReportRedisService reportRedisService;
+ private final ReportService reportService;
private static final String RESEARCH_FORMAT = "# Research Requirements\n\n## Task\n\n{0}\n\n## Description\n\n{1}";
private final String REPORT_FORMAT = "IMPORTANT: Structure your report according to the format in the prompt. Remember to include:\n\n1. Key Points - A bulleted list of the most important findings\n2. Overview - A brief introduction to the topic\n3. Detailed Analysis - Organized into logical sections\n4. Survey Note (optional) - For more comprehensive reports\n5. Key Citations - List all references at the end\n\nFor citations, DO NOT include inline citations in the text. Instead, place all citations in the 'Key Citations' section at the end using the format: `- [Source Title](URL)`. Include an empty line between each citation for better readability.\n\nPRIORITIZE USING MARKDOWN TABLES for data presentation and comparison. Use tables whenever presenting comparative data, statistics, features, or options. Structure tables with clear headers and aligned columns. Example table format:\n\n| Feature | Description | Pros | Cons |\n|---------|-------------|------|------|\n| Feature 1 | Description 1 | Pros 1 | Cons 1 |\n| Feature 2 | Description 2 | Pros 2 | Cons 2 |";
- public ReporterNode(ChatClient reporterAgent, ReportRedisService reportRedisService) {
+ public ReporterNode(ChatClient reporterAgent, ReportService reportService) {
this.reporterAgent = reporterAgent;
- this.reportRedisService = reportRedisService;
+ this.reportService = reportService;
}
@Override
@@ -101,11 +101,11 @@ public Map apply(OverAllState state) throws Exception {
.mapResult(response -> {
String finalReport = Objects.requireNonNull(response.getResult().getOutput().getText());
try {
- reportRedisService.saveReport(threadId, finalReport);
- logger.info("报告已成功保存到 Redis,线程ID: {}", threadId);
+ reportService.saveReport(threadId, finalReport);
+ logger.info("报告已成功保存,线程ID: {}", threadId);
}
catch (Exception e) {
- logger.error("保存报告到 Redis 失败,线程ID: {}", threadId, e);
+ logger.error("保存报告失败,线程ID: {}", threadId, e);
}
return Map.of("final_report", finalReport, "thread_id", threadId);
})
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java
new file mode 100644
index 0000000000..d15ec9eb1c
--- /dev/null
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.cloud.ai.example.deepresearch.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 基于内存的报告服务类(当Redis不可用时使用)
+ *
+ * @author huangzhen
+ * @since 2025/6/20
+ */
+@Service
+@ConditionalOnProperty(name = "spring.data.redis.enabled", havingValue = "false", matchIfMissing = true)
+public class ReportMemoryService implements ReportService {
+
+ private static final Logger logger = LoggerFactory.getLogger(ReportMemoryService.class);
+
+ /**
+ * 内存存储,使用ConcurrentHashMap保证线程安全
+ */
+ private final Map reportStorage = new ConcurrentHashMap<>();
+
+ /**
+ * 存储报告到内存
+ * @param threadId 线程ID
+ * @param report 报告内容
+ */
+ @Override
+ public void saveReport(String threadId, String report) {
+ try {
+ reportStorage.put(threadId, report);
+ logger.info("报告已保存到内存,线程ID: {}", threadId);
+ }
+ catch (Exception e) {
+ logger.error("保存报告到内存失败,线程ID: {}", threadId, e);
+ throw new RuntimeException("保存报告失败", e);
+ }
+ }
+
+ /**
+ * 从内存获取报告
+ * @param threadId 线程ID
+ * @return 报告内容,如果不存在返回 null
+ */
+ @Override
+ public String getReport(String threadId) {
+ try {
+ String report = reportStorage.get(threadId);
+ if (report != null) {
+ logger.info("从内存获取报告成功,线程ID: {}", threadId);
+ return report;
+ }
+ else {
+ logger.warn("内存中未找到报告,线程ID: {}", threadId);
+ return null;
+ }
+ }
+ catch (Exception e) {
+ logger.error("从内存获取报告失败,线程ID: {}", threadId, e);
+ throw new RuntimeException("获取报告失败", e);
+ }
+ }
+
+ /**
+ * 检查报告是否存在
+ * @param threadId 线程ID
+ * @return 是否存在
+ */
+ @Override
+ public boolean existsReport(String threadId) {
+ try {
+ boolean exists = reportStorage.containsKey(threadId);
+ logger.debug("检查报告是否存在,线程ID: {}, 存在: {}", threadId, exists);
+ return exists;
+ }
+ catch (Exception e) {
+ logger.error("检查报告是否存在失败,线程ID: {}", threadId, e);
+ return false;
+ }
+ }
+
+ /**
+ * 删除报告
+ * @param threadId 线程ID
+ */
+ @Override
+ public void deleteReport(String threadId) {
+ try {
+ reportStorage.remove(threadId);
+ logger.info("已删除内存中的报告,线程ID: {}", threadId);
+ }
+ catch (Exception e) {
+ logger.error("删除报告失败,线程ID: {}", threadId, e);
+ throw new RuntimeException("删除报告失败", e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportRedisService.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportRedisService.java
index fad3842a24..6bb8803536 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportRedisService.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportRedisService.java
@@ -18,6 +18,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@@ -30,7 +31,8 @@
* @since 2025/6/18
*/
@Service
-public class ReportRedisService {
+@ConditionalOnProperty(name = "spring.data.redis.enabled", havingValue = "true", matchIfMissing = false)
+public class ReportRedisService implements ReportService {
private static final Logger logger = LoggerFactory.getLogger(ReportRedisService.class);
@@ -55,6 +57,7 @@ public ReportRedisService(RedisTemplate redisTemplate) {
* @param threadId 线程ID
* @param report 报告内容
*/
+ @Override
public void saveReport(String threadId, String report) {
try {
String key = buildKey(threadId);
@@ -72,6 +75,7 @@ public void saveReport(String threadId, String report) {
* @param threadId 线程ID
* @return 报告内容,如果不存在返回 null
*/
+ @Override
public String getReport(String threadId) {
try {
String key = buildKey(threadId);
@@ -96,6 +100,7 @@ public String getReport(String threadId) {
* @param threadId 线程ID
* @return 是否存在
*/
+ @Override
public boolean existsReport(String threadId) {
try {
String key = buildKey(threadId);
@@ -112,6 +117,7 @@ public boolean existsReport(String threadId) {
* 删除报告
* @param threadId 线程ID
*/
+ @Override
public void deleteReport(String threadId) {
try {
String key = buildKey(threadId);
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java
new file mode 100644
index 0000000000..36356fe619
--- /dev/null
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.cloud.ai.example.deepresearch.service;
+
+/**
+ * 报告服务接口
+ *
+ * @author huangzhen
+ * @since 2025/6/20
+ */
+public interface ReportService {
+
+ /**
+ * 存储报告
+ * @param threadId 线程ID
+ * @param report 报告内容
+ */
+ void saveReport(String threadId, String report);
+
+ /**
+ * 获取报告
+ * @param threadId 线程ID
+ * @return 报告内容,如果不存在返回 null
+ */
+ String getReport(String threadId);
+
+ /**
+ * 检查报告是否存在
+ * @param threadId 线程ID
+ * @return 是否存在
+ */
+ boolean existsReport(String threadId);
+
+ /**
+ * 删除报告
+ * @param threadId 线程ID
+ */
+ void deleteReport(String threadId);
+
+}
\ No newline at end of file
diff --git a/spring-ai-alibaba-deepresearch/src/main/resources/application.yml b/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
index 32d0ac1f30..0ed369efd8 100644
--- a/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
+++ b/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
@@ -6,6 +6,7 @@ spring:
# Redis 配置
data:
redis:
+ enabled: false
host: localhost
port: 6379
password: ${REDIS-PASSWORD}
From 4a0f8dc1fd2afdad6f5977dff3413be49e5cea6c Mon Sep 17 00:00:00 2001
From: huangzhen <02258@mxbc.com>
Date: Fri, 20 Jun 2025 21:43:08 +0800
Subject: [PATCH 6/8] mvn spring-javaformat:apply
---
.../ai/example/deepresearch/model/response/BaseResponse.java | 2 +-
.../ai/example/deepresearch/model/response/ExistsResponse.java | 2 +-
.../ai/example/deepresearch/model/response/ReportResponse.java | 2 +-
.../ai/example/deepresearch/service/ReportMemoryService.java | 2 +-
.../cloud/ai/example/deepresearch/service/ReportService.java | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java
index a4db53c155..a8ee1c187d 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java
@@ -54,4 +54,4 @@ public void setMessage(String message) {
this.message = message;
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java
index 4dc7097cd7..deb1edecfe 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java
@@ -34,4 +34,4 @@ public void setExists(boolean exists) {
this.exists = exists;
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java
index daf203ce41..85c661b79c 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java
@@ -34,4 +34,4 @@ public void setReport(String report) {
this.report = report;
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java
index d15ec9eb1c..b04ca86286 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java
@@ -116,4 +116,4 @@ public void deleteReport(String threadId) {
}
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java
index 36356fe619..c5fb1212f7 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java
@@ -51,4 +51,4 @@ public interface ReportService {
*/
void deleteReport(String threadId);
-}
\ No newline at end of file
+}
\ No newline at end of file
From c9b238767600bceac91de1b0078f9c587a5fb1a3 Mon Sep 17 00:00:00 2001
From: huangzhen <02258@mxbc.com>
Date: Fri, 20 Jun 2025 22:03:37 +0800
Subject: [PATCH 7/8] make linter
---
.../src/main/resources/application.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spring-ai-alibaba-deepresearch/src/main/resources/application.yml b/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
index bcc1a7e934..7fc60250ed 100644
--- a/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
+++ b/spring-ai-alibaba-deepresearch/src/main/resources/application.yml
@@ -6,7 +6,7 @@ spring:
# Redis 配置
data:
redis:
- enabled: false
+ enabled: false
host: localhost
port: 6379
password: ${REDIS-PASSWORD}
From 762a31a61ce92eaaefc098c52e57704ae7beae88 Mon Sep 17 00:00:00 2001
From: huangzhen <02258@mxbc.com>
Date: Fri, 20 Jun 2025 22:10:29 +0800
Subject: [PATCH 8/8] add a blank line.
---
.../ai/example/deepresearch/model/response/BaseResponse.java | 2 +-
.../ai/example/deepresearch/model/response/ExistsResponse.java | 2 +-
.../ai/example/deepresearch/model/response/ReportResponse.java | 2 +-
.../ai/example/deepresearch/service/ReportMemoryService.java | 2 +-
.../cloud/ai/example/deepresearch/service/ReportService.java | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java
index a8ee1c187d..f1bb6cefba 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/BaseResponse.java
@@ -54,4 +54,4 @@ public void setMessage(String message) {
this.message = message;
}
-}
\ No newline at end of file
+}
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java
index deb1edecfe..e73a2ddb0c 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ExistsResponse.java
@@ -34,4 +34,4 @@ public void setExists(boolean exists) {
this.exists = exists;
}
-}
\ No newline at end of file
+}
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java
index 85c661b79c..5b58595749 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/model/response/ReportResponse.java
@@ -34,4 +34,4 @@ public void setReport(String report) {
this.report = report;
}
-}
\ No newline at end of file
+}
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java
index b04ca86286..c2a3fabaa0 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportMemoryService.java
@@ -116,4 +116,4 @@ public void deleteReport(String threadId) {
}
}
-}
\ No newline at end of file
+}
diff --git a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java
index c5fb1212f7..0ff547f7c2 100644
--- a/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java
+++ b/spring-ai-alibaba-deepresearch/src/main/java/com/alibaba/cloud/ai/example/deepresearch/service/ReportService.java
@@ -51,4 +51,4 @@ public interface ReportService {
*/
void deleteReport(String threadId);
-}
\ No newline at end of file
+}