AI项目博客
记录 AI 工程实践与大模型应用

Spring AI Alibaba 81|Graph Core · 人类反馈 · 完整示例:扩展-反馈-翻译流程

以下是一个完整的示例,展示如何在扩展节点、人类反馈节点和翻译节点之间实现中断和恢复:

节点定义

ExpanderNode

package com.spring.ai.tutorial.graph.human.node;

import com.alibaba.cloud.ai.graph.NodeOutput;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import com.alibaba.cloud.ai.graph.async.AsyncGenerator;
import com.alibaba.cloud.ai.graph.streaming.StreamingChatGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.PromptTemplate;
import reactor.core.publisher.Flux;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class ExpanderNode implements NodeAction {

  private static final Logger logger = LoggerFactory.getLogger(ExpanderNode.class);

  private static final PromptTemplate DEFAULTPROMPTTEMPLATE = new PromptTemplate(
      "You are an expert at information retrieval and search optimization.
" +
      "Your task is to generate {number} different versions of the given query.

" +
      "Each variant must cover different perspectives or aspects of the topic,
" +
      "while maintaining the core intent of the original query. The goal is to
" +
      "expand the search space and improve the chances of finding relevant information.

" +
      "Do not explain your choices or add any other text.
" +
      "Provide the query variants separated by newlines.

" +
      "Original query: {query}

" +
      "Query variants:
"
  );

  private final ChatClient chatClient;
  private final Integer NUMBER = 3;

  public ExpanderNode(ChatClient.Builder chatClientBuilder) {
      this.chatClient = chatClientBuilder.build();
  }

  @Override
  public Map<String, Object> apply(OverAllState state) {
      logger.info("expander node is running.");

      String query = state.value("query", "");
      Integer expanderNumber = state.value("expandernumber", this.NUMBER);

      Flux<ChatResponse> chatResponseFlux = this.chatClient.prompt()
              .user((user) -> user.text(DEFAULTPROMPTTEMPLATE.getTemplate())
                      .param("number", expanderNumber)
                      .param("query", query))
              .stream()
              .chatResponse();

      AsyncGenerator<? extends NodeOutput> generator = StreamingChatGenerator.builder()
              .startingNode("expanderllmstream")
              .startingState(state)
              .mapResult(response -> {
                  String text = response.getResult().getOutput().getText();
                  List<String> queryVariants = Arrays.asList(text.split("
"));
                  return Map.of("expandercontent", queryVariants);
              })
              .build(chatResponseFlux);

      return Map.of("expandercontent", generator);
  }
}

TranslateNode

package com.spring.ai.tutorial.graph.human.node;

import com.alibaba.cloud.ai.graph.NodeOutput;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import com.alibaba.cloud.ai.graph.async.AsyncGenerator;
import com.alibaba.cloud.ai.graph.streaming.StreamingChatGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.PromptTemplate;
import reactor.core.publisher.Flux;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class TranslateNode implements NodeAction {

  private static final Logger logger = LoggerFactory.getLogger(TranslateNode.class);

  private static final PromptTemplate DEFAULTPROMPTTEMPLATE = new PromptTemplate(
      "Given a user query, translate it to {targetLanguage}.
" +
      "If the query is already in {targetLanguage}, return it unchanged.
" +
      "If you don't know the language of the query, return it unchanged.
" +
      "Do not add explanations nor any other text.

" +
      "Original query: {query}

" +
      "Translated query:
"
  );

  private final ChatClient chatClient;
  private final String TARGETLANGUAGE = "English";

  public TranslateNode(ChatClient.Builder chatClientBuilder) {
      this.chatClient = chatClientBuilder.build();
  }

  @Override
  public Map<String, Object> apply(OverAllState state) {
      logger.info("translate node is running.");

      String query = state.value("query", "");
      String targetLanguage = state.value("translatelanguage", TARGETLANGUAGE);

      Flux<ChatResponse> chatResponseFlux = this.chatClient.prompt()
              .user((user) -> user.text(DEFAULTPROMPTTEMPLATE.getTemplate())
                      .param("targetLanguage", targetLanguage)
                      .param("query", query))
              .stream()
              .chatResponse();

      AsyncGenerator<? extends NodeOutput> generator = StreamingChatGenerator.builder()
              .startingNode("translatellmstream")
              .startingState(state)
              .mapResult(response -> {
                  String text = response.getResult().getOutput().getText();
                  List<String> queryVariants = Arrays.asList(text.split("
"));
                  return Map.of("translatecontent", queryVariants);
              })
              .build(chatResponseFlux);

      return Map.of("translatecontent", generator);
  }
}

边定义

package com.spring.ai.tutorial.graph.human.dispatcher;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.action.EdgeAction;

public class HumanFeedbackDispatcher implements EdgeAction {
  @Override
  public String apply(OverAllState state) throws Exception {
      return (String) state.value("humannextnode", StateGraph.END);
  }
}
  • Checkpoint 机制 – 状态持久化
  • 快速入门 – Graph 基础使用
  • 流式处理 – 流式输出

本文整理自 Spring AI Alibaba 官方文档《人类反馈》:https://java2ai.com/docs/frameworks/graph-core/examples/human-in-the-loop

赞(0)
未经允许不得转载:AI项目博客 » Spring AI Alibaba 81|Graph Core · 人类反馈 · 完整示例:扩展-反馈-翻译流程

评论 抢沙发

AI项目博客

专注 AI 工程化落地 —— 覆盖智能体、大模型、Java AI 与 Python 的学习笔记,以及 AI 平台的项目实战记录。

关于本站文章归档

登录

找回密码

注册