501-Spring AI Alibaba Graph Reflection 功能完整案例

本案例将引导您一步步构建一个基于 Spring AI Alibaba 的 Graph Reflection 应用,演示如何利用 Graph 和 ReflectAgent 实现一个能够自我反思和改进的 AI 助手,特别适用于写作和内容创作场景。
1. 案例目标
我们将创建一个包含自我反思和改进功能的 Web 应用:
- AI 写作助手 (
/reflection/chat):通过 Graph 和 ReflectAgent 实现,AI 能够生成内容并进行自我反思和改进。 - 多轮反思机制:AI 生成内容后,会自动进入反思环节,对内容进行评估和改进,最多进行 2 轮反思。
- 角色分离设计:将 AI 分为"助手"和"评估者"两个角色,分别负责内容生成和内容评估,实现更高质量的输出。
2. 技术栈与核心依赖
- Spring Boot 3.x
- Spring AI Alibaba (用于对接阿里云 DashScope 通义大模型)
- Spring AI Alibaba Graph (用于构建 AI 工作流)
- Maven (项目构建工具)
在 pom.xml 中,你需要引入以下核心依赖:
<dependencies><!-- Spring AI Alibaba 核心启动器,集成 DashScope --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-dashscope</artifactId></dependency><!-- Spring AI Chat Model 自动配置 --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-autoconfigure-model-chat-client</artifactId></dependency><!-- Spring AI Alibaba Graph 核心库 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-graph-core</artifactId><version>${spring-ai-alibaba.version}</version></dependency><!-- Spring Web 用于构建 RESTful API --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- HTTP 客户端 --><dependency><groupId>org.apache.httpcomponents.client5</groupId><artifactId>httpclient5</artifactId><version>5.4.1</version></dependency><!-- OpenAI 兼容支持 --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-openai</artifactId></dependency>
</dependencies>3. 项目配置
在 src/main/resources/application.yml 文件中,配置你的 DashScope API Key 和模型设置。
server:port: 8080
spring:application:name: reflectionai:dashscope:api-key: ${AI_DASHSCOPE_API_KEY}openai:base-url: https://dashscope.aliyuncs.com/compatible-modeapi-key: ${AI_DASHSCOPE_API_KEY}chat:options:model: qwen-max-latestembedding:options:model: text-embedding-v1重要提示:请将 AI_DASHSCOPE_API_KEY 环境变量设置为你从阿里云获取的有效 API Key。你也可以直接将其写在配置文件中,但这不推荐用于生产环境。
4. 项目结构
本案例的项目结构如下:
spring-ai-alibaba-graph-example/reflection/
├── pom.xml # Maven 项目配置文件
├── src/
│ └── main/
│ ├── java/
│ │ └── com/alibaba/cloud/ai/graph/reflection/
│ │ ├── ReflectionApplication.java # Spring Boot 主程序
│ │ ├── ReflectionController.java # REST API 控制器
│ │ └── RelectionAutoconfiguration.java # 自动配置类
│ └── resources/
│ └── application.yml # 应用配置文件
└── target/ # 构建输出目录5. 核心组件实现
5.1 主程序类 ReflectionApplication.java
这是 Spring Boot 应用的入口点:
package com.alibaba.cloud.ai.graph.reflection;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class ReflectionApplication {public static void main(String[] args) {SpringApplication.run(ReflectionApplication.class, args);}
}5.2 REST API 控制器 ReflectionController.java
提供 HTTP API 接口,用于与用户交互:
package com.alibaba.cloud.ai.graph.reflection;import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import com.alibaba.cloud.ai.graph.agent.ReflectAgent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;
import java.util.Map;@RestController
@RequestMapping("/reflection")
public class ReflectionController {private static final Logger logger = LoggerFactory.getLogger(ReflectionController.class);private CompiledGraph compiledGraph;public ReflectionController(@Qualifier("reflectGraph") CompiledGraph compiledGraph) {this.compiledGraph = compiledGraph;}@GetMapping("/chat")public String simpleChat(String query) throws GraphRunnerException {return compiledGraph.invoke(Map.of(ReflectAgent.MESSAGES, List.of(new UserMessage(query)))).get().<List<Message>>value(ReflectAgent.MESSAGES).orElseThrow().stream().filter(message -> message.getMessageType() == MessageType.ASSISTANT).reduce((first, second) -> second).map(Message::getText).orElseThrow();}
}5.3 自动配置类 RelectionAutoconfiguration.java
这是本案例的核心,定义了 Graph 和 ReflectAgent 的配置:
5.3.1 助手节点 (AssistantGraphNode)
负责生成内容的节点:
public static class AssistantGraphNode implements NodeAction {private final LlmNode llmNode;private SystemPromptTemplate systemPromptTemplate;private final String NODE_ID = "call_model";private static final String CLASSIFIER_PROMPT_TEMPLATE = """You are an essay assistant tasked with writing excellent 5-paragraph essays.Generate the best essay possible for the user's request.If the user provides critique, respond with a revised version of your previous attempts.Only return the main content I need, without adding any other interactive language.Please answer in Chinese:""";public AssistantGraphNode(ChatClient chatClient) {this.systemPromptTemplate = new SystemPromptTemplate(CLASSIFIER_PROMPT_TEMPLATE);this.llmNode = LlmNode.builder().systemPromptTemplate(systemPromptTemplate.render()).chatClient(chatClient).messagesKey("messages").build();}// ... Builder 模式实现 ...@Overridepublic Map<String, Object> apply(OverAllState overAllState) throws Exception {List<Message> messages = (List<Message>) overAllState.value(ReflectAgent.MESSAGES).get();OverAllStateFactory stateFactory = () -> {OverAllState state = new OverAllState();state.registerKeyAndStrategy(ReflectAgent.MESSAGES, new AppendStrategy());return state;};StateGraph stateGraph = new StateGraph(stateFactory).addNode(this.NODE_ID, AsyncNodeAction.node_async(llmNode)).addEdge(StateGraph.START, this.NODE_ID).addEdge(this.NODE_ID, StateGraph.END);OverAllState invokeState = stateGraph.compile().invoke(Map.of(ReflectAgent.MESSAGES, messages)).get();List<Message> reactMessages = (List<Message>) invokeState.value(ReflectAgent.MESSAGES).orElseThrow();return Map.of(ReflectAgent.MESSAGES, reactMessages);}
}5.3.2 评估节点 (JudgeGraphNode)
负责评估和提供反馈的节点:
public static class JudgeGraphNode implements NodeAction {private final LlmNode llmNode;private final String NODE_ID = "judge_response";private SystemPromptTemplate systemPromptTemplate;private static final String CLASSIFIER_PROMPT_TEMPLATE = """You are a teacher grading a student's essay submission. Provide detailed feedback and revision suggestions for the essay.Your feedback should cover the following aspects:- Length : Is the essay sufficiently developed? Does it meet the required length or need expansion/shortening?- Depth : Are the ideas well-developed? Is there sufficient analysis, evidence, or explanation?- Structure : Is the organization logical and clear? Are the introduction, transitions, and conclusion effective?- Style and Tone : Is the writing style appropriate for the purpose and audience? Is the tone consistent and professional?- Language Use : Are vocabulary, grammar, and sentence structure accurate and varied?- Focus only on providing actionable suggestions for improvement. Do not include grades, scores, or overall summary evaluations.Please respond in Chinese .""";public JudgeGraphNode(ChatClient chatClient) {this.systemPromptTemplate = new SystemPromptTemplate(CLASSIFIER_PROMPT_TEMPLATE);this.llmNode = LlmNode.builder().chatClient(chatClient).systemPromptTemplate(systemPromptTemplate.render()).messagesKey(ReflectAgent.MESSAGES).build();}// ... Builder 模式实现 ...@Overridepublic Map<String, Object> apply(OverAllState allState) throws Exception {List<Message> messages = (List<Message>) allState.value(ReflectAgent.MESSAGES).get();OverAllStateFactory stateFactory = () -> {OverAllState state = new OverAllState();state.registerKeyAndStrategy(ReflectAgent.MESSAGES, new AppendStrategy());return state;};StateGraph stateGraph = new StateGraph(stateFactory).addNode(this.NODE_ID, AsyncNodeAction.node_async(llmNode)).addEdge(StateGraph.START, this.NODE_ID).addEdge(this.NODE_ID, StateGraph.END);CompiledGraph compile = stateGraph.compile();OverAllState invokeState = compile.invoke(Map.of(ReflectAgent.MESSAGES, messages)).get();UnaryOperator<List<Message>> convertLastToUserMessage = messageList -> {int size = messageList.size();if (size == 0)return messageList;Message last = messageList.get(size - 1);messageList.set(size - 1, new UserMessage(last.getText()));return messageList;};List<Message> reactMessages = (List<Message>) invokeState.value(ReflectAgent.MESSAGES).orElseThrow();convertLastToUserMessage.apply(reactMessages);return Map.of(ReflectAgent.MESSAGES, reactMessages);}
}5.3.3 ReflectAgent 配置
将助手节点和评估节点组合成 ReflectAgent:
@Bean
public CompiledGraph reflectGraph(ChatModel chatModel) throws GraphStateException {ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(new SimpleLoggerAdvisor()).defaultOptions(OpenAiChatOptions.builder().internalToolExecutionEnabled(false).build()).build();AssistantGraphNode assistantGraphNode = AssistantGraphNode.builder().chatClient(chatClient).build();JudgeGraphNode judgeGraphNode = JudgeGraphNode.builder().chatClient(chatClient).build();ReflectAgent reflectAgent = ReflectAgent.builder().graph(assistantGraphNode).reflection(judgeGraphNode).maxIterations(2).build();return reflectAgent.getAndCompileGraph();
}6. 运行与测试
- 启动应用:运行
ReflectionApplication主程序。 - 使用浏览器或 API 工具(如 Postman, curl)进行测试。
测试示例
访问以下 URL,让 AI 写一篇关于"人工智能的发展"的文章:
http://localhost:8080/reflection/chat?query=请写一篇关于人工智能发展的短文预期响应:
AI 将首先生成一篇关于人工智能发展的短文,然后自动进行反思和改进,最终输出一个经过自我优化的版本。整个过程包含多轮交互,但用户只需要发送一次请求,系统会自动完成反思和改进的过程。
7. 实现思路与扩展建议
实现思路
本案例的核心思想是"自我反思与改进"。通过将 AI 的角色分为"内容生成者"和"内容评估者",实现了:
- 角色分离:生成者和评估者各司其职,避免了单一角色既要生成内容又要评估内容的局限性。
- 多轮迭代:通过设置最大迭代次数,允许 AI 进行多轮反思和改进,逐步提升内容质量。
- 自动化流程:用户只需提供初始请求,系统自动完成生成、评估、改进的整个流程。
扩展建议
- 自定义反思提示词:可以根据不同场景调整评估节点的提示词,例如针对代码质量、创意写作、技术文档等不同领域。
- 动态迭代次数:可以根据内容质量或用户需求动态调整迭代次数,而不是固定的最大值。
- 多角色协作:可以扩展为多个角色的协作,例如"创意生成者"、"逻辑审核者"、"语言优化者"等。
- 用户干预机制:允许用户在反思过程中进行干预,例如提供额外的反馈或调整方向。
- 性能优化:对于复杂场景,可以考虑并行处理或缓存机制,提高响应速度。
