Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions spring-ai-alibaba-deepresearch/DeepResearch.http
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ Content-Type: application/json
}


### 人类反馈2:feed_back为是否接受当前计划,false时feed_back_content生效
### 人类反馈2:feedback为是否接受当前计划,false时feedback_content生效
POST http://localhost:8080/chat/resume
Content-Type: application/json

{
"thread_id": "__default__",
"feed_back": false,
"feed_back_content": "巧克力蛋糕制作技巧"
"feedback": false,
"feedback_content": "巧克力蛋糕制作技巧"
}


Expand Down
4 changes: 2 additions & 2 deletions spring-ai-alibaba-deepresearch/README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
**编程节点(给大模型提供编程能力)**

- Coder节点的Python执行器跑在Docker容器中,需要额外为其配置Docker信息
- 在配置文件的`spring.ai.alibaba.deepreserch.python-coder.docker-host`字段中设置DockerHost,默认为`unix:///var/run/docker.sock`。
本项目需要使用`python:3-slim`镜像创建临时容器,也可以自己定制包含一些常用的第三方库的镜像,第三方库需要安装在镜像的`/app/dependency`文件夹里,在配置文件中设置`spring.ai.alibaba.deepreserch.python-coder.image-name`的值指定镜像名称。
- 在配置文件的`spring.ai.alibaba.deepresearch.python-coder.docker-host`字段中设置DockerHost,默认为`unix:///var/run/docker.sock`。
本项目需要使用`python:3-slim`镜像创建临时容器,也可以自己定制包含一些常用的第三方库的镜像,第三方库需要安装在镜像的`/app/dependency`文件夹里,在配置文件中设置`spring.ai.alibaba.deepresearch.python-coder.image-name`的值指定镜像名称。

**RAG**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ public StateGraph deepResearch(ChatClient researchAgent) throws GraphStateExcept
keyStrategyHashMap.put("user_upload_file", new ReplaceStrategy());
keyStrategyHashMap.put("session_id", new ReplaceStrategy());

keyStrategyHashMap.put("feed_back", new ReplaceStrategy());
keyStrategyHashMap.put("feed_back_content", new ReplaceStrategy());
keyStrategyHashMap.put("feedback", new ReplaceStrategy());
keyStrategyHashMap.put("feedback_content", new ReplaceStrategy());

// 专业知识库决策相关
keyStrategyHashMap.put("use_professional_kb", new ReplaceStrategy());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ public Flux<ServerSentEvent<String>> resume(@RequestBody(required = false) Feedb
throws GraphRunnerException {
RunnableConfig runnableConfig = RunnableConfig.builder().threadId(humanFeedback.threadId()).build();
Map<String, Object> objectMap = new HashMap<>();
objectMap.put("feed_back", humanFeedback.feedBack());
objectMap.put("feed_back_content", humanFeedback.feedBackContent());
objectMap.put("feedback", humanFeedback.feedback());
objectMap.put("feedback_content", humanFeedback.feedbackContent());

// Create a unicast sink to emit ServerSentEvents
Sinks.Many<ServerSentEvent<String>> sink = Sinks.many().unicast().onBackpressureBuffer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public GraphId createNewGraphId(String sessionId) {

public void handleHumanFeedback(GraphId graphId, ChatRequest chatRequest, Map<String, Object> objectMap,
RunnableConfig runnableConfig, Sinks.Many<ServerSentEvent<String>> sink) throws GraphRunnerException {
objectMap.put("feed_back", chatRequest.interruptFeedback());
objectMap.put("feedback", chatRequest.interruptFeedback());
StateSnapshot stateSnapshot = compiledGraph.getState(runnableConfig);
OverAllState state = stateSnapshot.state();
state.withResume();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ public record FeedbackRequest(
/**
* 是否接受Planner的计划,true为接受,false为重新生成
*/
@JsonProperty(value = "feed_back", defaultValue = "true") Boolean feedBack,
@JsonProperty(value = "feedback", defaultValue = "true") Boolean feedback,

/**
* 用户反馈内容,重新生成Planner计划是给予额外的上下文信息
*/
@JsonProperty(value = "feed_back_content", defaultValue = "") String feedBackContent) {
@JsonProperty(value = "feedback_content", defaultValue = "") String feedbackContent) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ public Map<String, Object> apply(OverAllState state) throws Exception {
// iterations+1
updated.put("plan_iterations", StateUtil.getPlanIterations(state) + 1);

Map<String, Object> feedBackData = state.humanFeedback().data();
boolean feedback = (boolean) feedBackData.getOrDefault("feed_back", true);
Map<String, Object> feedbackData = state.humanFeedback().data();
boolean feedback = (boolean) feedbackData.getOrDefault("feedback", true);

if (!feedback) {
nextStep = "planner";
updated.put("human_next_node", nextStep);

String feedbackContent = feedBackData.getOrDefault("feed_back_content", "").toString();
String feedbackContent = feedbackData.getOrDefault("feedback_content", "").toString();
if (StringUtils.hasLength(feedbackContent)) {
updated.put("feed_back_content", feedbackContent);
updated.put("feedback_content", feedbackContent);
logger.info("Human feedback content: {}", feedbackContent);
}
state.withoutResume();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ public Map<String, Object> apply(OverAllState state) throws Exception {
}
}
// 1.4 添加用户反馈消息
String feedBackContent = state.value("feed_back_content", "").toString();
if (StringUtils.hasText(feedBackContent)) {
messages.add(new UserMessage(feedBackContent));
String feedbackContent = state.value("feedback_content", "").toString();
if (StringUtils.hasText(feedbackContent)) {
messages.add(new UserMessage(feedbackContent));
}
// 1.5 添加用户上传的RAG查询结果
String ragContent = StateUtil.getRagContent(state);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
spring:
ai:
alibaba:
deepreserch:
deepresearch:
python-coder:
code-timeout: "1s"
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
spring:
ai:
alibaba:
deepreserch:
deepresearch:
python-coder:
enable-network: true
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ const sendResumeStream = async(message: string | undefined, onUpdate: (content
Accept: 'text/event-stream',
},
body: {
feed_back_content: message,
feed_back: true,
feedback_content: message,
feedback: true,
session_id: convId,
thread_id: current.threadId,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public Map<String, Object> apply(OverAllState state) throws Exception {

// 处理反馈结果
Map<String, Object> feedbackData = humanFeedback.data();
boolean approved = (boolean) feedbackData.getOrDefault("feed_back", true);
boolean approved = (boolean) feedbackData.getOrDefault("feedback", true);

if (approved) {
logger.info("Plan approved → execution");
Expand All @@ -74,7 +74,7 @@ public Map<String, Object> apply(OverAllState state) throws Exception {
updated.put(HUMAN_REVIEW_ENABLED, true);

// 保存用户反馈内容
String feedbackContent = feedbackData.getOrDefault("feed_back_content", "").toString();
String feedbackContent = feedbackData.getOrDefault("feedback_content", "").toString();
updated.put(PLAN_VALIDATION_ERROR,
StringUtils.hasLength(feedbackContent) ? feedbackContent : "Plan rejected by user");
// 这边清空旧的计划输出
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public CompletableFuture<Void> nl2sqlWithProcess(Consumer<Nl2SqlProcess> nl2SqlP
}

/**
* 将NodeOutput转为NlSqlProcess实体类(用于nl2sqlWithProcess的consumer中记录转化过程)
* 将NodeOutput转为Nl2SqlProcess实体类(用于nl2sqlWithProcess的consumer中记录转化过程)
* @param output NodeOutput
* @return NlSqlProcess
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void setUp() {

@Test
void testApproveFlow() throws Exception {
state.withHumanFeedback(new OverAllState.HumanFeedback(Map.of("feed_back", true), null));
state.withHumanFeedback(new OverAllState.HumanFeedback(Map.of("feedback", true), null));

Map<String, Object> result = node.apply(state);
assertEquals(PLAN_EXECUTOR_NODE, result.get("human_next_node"));
Expand All @@ -56,7 +56,7 @@ void testApproveFlow() throws Exception {
void testRejectFlowWithContent() throws Exception {
state.updateState(Map.of(PLAN_REPAIR_COUNT, 0));
state.withHumanFeedback(
new OverAllState.HumanFeedback(Map.of("feed_back", false, "feed_back_content", "需要补充过滤条件"), null));
new OverAllState.HumanFeedback(Map.of("feedback", false, "feedback_content", "需要补充过滤条件"), null));

Map<String, Object> result = node.apply(state);
assertEquals(PLANNER_NODE, result.get("human_next_node"));
Expand All @@ -69,7 +69,7 @@ void testRejectFlowWithContent() throws Exception {
@Test
void testRejectFlowWithoutContent() throws Exception {
state.updateState(Map.of(PLAN_REPAIR_COUNT, 2));
state.withHumanFeedback(new OverAllState.HumanFeedback(Map.of("feed_back", false), null));
state.withHumanFeedback(new OverAllState.HumanFeedback(Map.of("feedback", false), null));

Map<String, Object> result = node.apply(state);
assertEquals(PLANNER_NODE, result.get("human_next_node"));
Expand All @@ -96,7 +96,7 @@ void testMaxRepairExceeded() throws Exception {
void testRejectFlowClearsPlanNextNode() throws Exception {
state.updateState(Map.of(PLAN_REPAIR_COUNT, 0));
state.withHumanFeedback(
new OverAllState.HumanFeedback(Map.of("feed_back", false, "feed_back_content", "再次修正"), null));
new OverAllState.HumanFeedback(Map.of("feedback", false, "feedback_content", "再次修正"), null));

Map<String, Object> result = node.apply(state);
assertEquals(PLANNER_NODE, result.get("human_next_node"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,21 +513,21 @@ private String extractPlanFromStreamingContent(String streamingContent) {
*/
@GetMapping(value = "/human-feedback", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> handleHumanFeedback(@RequestParam String sessionId,
@RequestParam String threadId, @RequestParam boolean feedBack,
@RequestParam(required = false, defaultValue = "") String feedBackContent) throws GraphStateException {
logger.info("Processing feedback: {} ({})", feedBack ? "approved" : "rejected",
feedBack ? "continue" : feedBackContent);
@RequestParam String threadId, @RequestParam boolean feedback,
@RequestParam(required = false, defaultValue = "") String feedbackContent) throws GraphStateException {
logger.info("Processing feedback: {} ({})", feedback ? "approved" : "rejected",
feedback ? "continue" : feedbackContent);

Sinks.Many<ServerSentEvent<String>> sink = Sinks.many().unicast().onBackpressureBuffer();

CompletableFuture.runAsync(() -> {
try {
Map<String, Object> feedbackData = Map.of("feed_back", feedBack, "feed_back_content",
feedBackContent != null ? feedBackContent : "");
Map<String, Object> feedbackData = Map.of("feedback", feedback, "feedback_content",
feedbackContent != null ? feedbackContent : "");
OverAllState.HumanFeedback humanFeedback = new OverAllState.HumanFeedback(feedbackData,
"human_feedback");

if (feedBack) {
if (feedback) {
sink.tryEmitNext(ServerSentEvent.builder("执行中...").build());
executeApprovedPlanWithResume(humanFeedback, threadId, sink);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2640,8 +2640,8 @@ export default {
const eventSource = new EventSource(`/nl2sql/human-feedback?${new URLSearchParams({
sessionId: currentSessionId.value,
threadId: currentThreadId.value,
feedBack: true,
feedBackContent: ''
feedback: true,
feedbackContent: ''
})}`)

displayEventSourceMessage(eventSource);
Expand All @@ -2658,8 +2658,8 @@ export default {
const eventSource = new EventSource(`/nl2sql/human-feedback?${new URLSearchParams({
sessionId: currentSessionId.value,
threadId: currentThreadId.value,
feedBack: false,
feedBackContent: humanReviewSuggestion.value || '用户拒绝了计划,请重新生成'
feedback: false,
feedbackContent: humanReviewSuggestion.value || '用户拒绝了计划,请重新生成'
})}`)

displayEventSourceMessage(eventSource);
Expand Down
Loading