511-Spring AI Alibaba Graph 智能写作助手示例

本示例展示如何使用 Spring AI Alibaba Graph 构建一个智能写作助手工作流,实现文本摘要生成、内容改写和标题生成的自动化流程。
1. 示例目标
我们将创建一个基于有向图工作流的智能写作助手,包含以下核心功能:
- 文本摘要生成:对输入的原始文本自动生成简洁摘要。
- 摘要反馈判断:通过大模型判断摘要质量,决定是否需要重新生成。
- 内容改写优化:对通过的摘要进行语言优化和润色。
- 标题自动生成:基于优化后的内容生成吸引人的标题。
- 工作流可视化:自动生成 PlantUML 流程图,便于理解整个流程。
2. 技术栈与核心依赖
- Spring Boot 3.x
- Spring AI Alibaba Graph (用于构建有向图工作流)
- Spring AI Alibaba DashScope (用于对接阿里云通义大模型)
- Maven (项目构建工具)
在 pom.xml 中,你需要引入以下核心依赖:
<dependencies><!-- Spring Web 用于构建 RESTful API --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring AI Alibaba DashScope 启动器 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-dashscope</artifactId><version>${spring-ai-alibaba.version}</version></dependency><!-- Spring AI Alibaba Graph 核心库 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-graph-core</artifactId><version>1.0.0.3</version></dependency>
</dependencies>3. 项目配置
在 src/main/resources/application.yml 文件中,配置你的 DashScope API Key。
server:port: 8080spring:application:name: spring-ai-alibaba-graph-exampleai:dashscope:api-key: ${AI_DASHSCOPE_API_KEY}chat:options:model: qwen-plus重要提示:请将 AI_DASHSCOPE_API_KEY 环境变量设置为你从阿里云获取的有效 API Key。
4. 工作流设计
智能写作助手的工作流由以下几个节点组成:
- summarizer(摘要生成器):接收原始文本,生成简洁摘要。
- feedback_classifier(反馈分类器):评估摘要质量,返回 "positive" 或 "negative"。
- reworder(内容改写器):对通过的摘要进行语言优化。
- title_generator(标题生成器):基于优化后的内容生成标题。
4.1 工作流流程图
以下是该工作流的 PlantUML 流程图:
@startuml
skinparam usecaseFontSize 14
skinparam usecaseStereotypeFontSize 12
skinparam hexagonFontSize 14
skinparam hexagonStereotypeFontSize 12
title "writing assistant flow"
footer
powered by spring-ai-alibaba
end footer
circle start<<input>> as __START__
circle stop as __END__
usecase "summarizer"<<Node>>
usecase "feedback_classifier"<<Node>>
usecase "reworder"<<Node>>
usecase "title_generator"<<Node>>
hexagon "check state" as condition1<<Condition>>
"__START__" -down-> "summarizer"
"summarizer" -down-> "feedback_classifier"
"feedback_classifier" .down.> "condition1"
"condition1" .down.> "summarizer": "negative"
"condition1" .down.> "reworder": "positive"
"reworder" -down-> "title_generator"
"title_generator" -down-> "__END__"
@enduml5. 核心代码实现
5.1 主应用类
Application.java 是标准的 Spring Boot 启动类:
package com.alibaba.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}5.2 控制器实现
WritingAssistantController.java 提供了 REST API 接口:
package com.alibaba.example.controller;import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;import java.util.Map;@RestController
@RequestMapping("/write")
public class WritingAssistantController {private final CompiledGraph compiledGraph;@Autowiredpublic WritingAssistantController(@Qualifier("writingAssistantGraph") StateGraph writingAssistantGraph)throws GraphStateException {this.compiledGraph = writingAssistantGraph.compile();}/*** 调用写作助手流程图 示例请求:GET /write?text=今天我去了西湖,天气特别好,感觉特别开心*/@GetMappingpublic Map<String, Object> write(@RequestParam("text") String inputText) throws GraphRunnerException {var resultFuture = compiledGraph.invoke(Map.of("original_text", inputText));var result = resultFuture.get();return result.data();}
}5.3 工作流配置
WritingAssistantAutoconfiguration.java 是整个示例的核心,定义了工作流的结构和各个节点的行为:
@Configuration
public class WritingAssistantAutoconfiguration {@Beanpublic StateGraph writingAssistantGraph(ChatModel chatModel) throws GraphStateException {ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(new SimpleLoggerAdvisor()).build();KeyStrategyFactory keyStrategyFactory = () -> {HashMap<String, KeyStrategy> keyStrategyHashMap = new HashMap<>();keyStrategyHashMap.put("original_text", new ReplaceStrategy());keyStrategyHashMap.put("summary", new ReplaceStrategy());keyStrategyHashMap.put("summary_feedback", new ReplaceStrategy());keyStrategyHashMap.put("reworded", new ReplaceStrategy());keyStrategyHashMap.put("title", new ReplaceStrategy());return keyStrategyHashMap;};StateGraph graph = new StateGraph(keyStrategyFactory).addNode("summarizer", node_async(new SummarizerNode(chatClient))).addNode("feedback_classifier", node_async(new SummaryFeedbackClassifierNode(chatClient, "summary"))).addNode("reworder", node_async(new RewordingNode(chatClient))).addNode("title_generator", node_async(new TitleGeneratorNode(chatClient))).addEdge(START, "summarizer").addEdge("summarizer", "feedback_classifier").addConditionalEdges("feedback_classifier", edge_async(new FeedbackDispatcher()),Map.of("positive", "reworder", "negative", "summarizer")).addEdge("reworder", "title_generator").addEdge("title_generator", END);// 添加 PlantUML 打印GraphRepresentation representation = graph.getGraph(GraphRepresentation.Type.PLANTUML,"writing assistant flow");System.out.println("\n=== Writing Assistant UML Flow ===");System.out.println(representation.content());System.out.println("==================================\n");return graph;}// 各个节点实现类...
}5.4 节点实现类
5.4.1 摘要生成器节点
static class SummarizerNode implements NodeAction {private final ChatClient chatClient;public SummarizerNode(ChatClient chatClient) {this.chatClient = chatClient;}@Overridepublic Map<String, Object> apply(OverAllState state) {String text = (String) state.value("original_text").orElse("");String prompt = "请对以下中文文本进行简洁明了的摘要:\n\n" + text;ChatResponse response = chatClient.prompt(prompt).call().chatResponse();String summary = response.getResult().getOutput().getText();Map<String, Object> result = new HashMap<>();result.put("summary", summary);return result;}
}5.4.2 反馈分类器节点
static class SummaryFeedbackClassifierNode implements NodeAction {private final ChatClient chatClient;private final String inputKey;public SummaryFeedbackClassifierNode(ChatClient chatClient, String inputKey) {this.chatClient = chatClient;this.inputKey = inputKey;}@Overridepublic Map<String, Object> apply(OverAllState state) {String summary = (String) state.value(inputKey).orElse("");if (!StringUtils.hasText(summary)) {throw new IllegalArgumentException("summary is empty in state");}String prompt = """以下是一个自动生成的中文摘要。请你判断它是否让用户满意。如果满意,请返回 "positive",否则返回 "negative":摘要内容:%s""".formatted(summary);ChatResponse response = chatClient.prompt(prompt).call().chatResponse();String output = response.getResult().getOutput().getText();String classification = output.toLowerCase().contains("positive") ? "positive" : "negative";Map<String, Object> updated = new HashMap<>();updated.put("summary_feedback", classification);return updated;}
}5.4.3 内容改写器节点
static class RewordingNode implements NodeAction {private final ChatClient chatClient;public RewordingNode(ChatClient chatClient) {this.chatClient = chatClient;}@Overridepublic Map<String, Object> apply(OverAllState state) {String summary = (String) state.value("summary").orElse("");String prompt = "请将以下摘要用更优美、生动的语言改写,同时保持信息不变:\n\n" + summary;ChatResponse response = chatClient.prompt(prompt).call().chatResponse();String reworded = response.getResult().getOutput().getText();Map<String, Object> result = new HashMap<>();result.put("reworded", reworded);return result;}
}5.4.4 标题生成器节点
static class TitleGeneratorNode implements NodeAction {private final ChatClient chatClient;public TitleGeneratorNode(ChatClient chatClient) {this.chatClient = chatClient;}@Overridepublic Map<String, Object> apply(OverAllState state) {String content = (String) state.value("reworded").orElse("");String prompt = "请为以下内容生成一个简洁有吸引力的中文标题:\n\n" + content;ChatResponse response = chatClient.prompt(prompt).call().chatResponse();String title = response.getResult().getOutput().getText();Map<String, Object> result = new HashMap<>();result.put("title", title);return result;}
}5.4.5 反馈分发器
static class FeedbackDispatcher implements EdgeAction {@Overridepublic String apply(OverAllState state) {String feedback = (String) state.value("summary_feedback").orElse("");if (feedback.contains("positive")) {return "positive";}return "negative";}
}6. 运行与测试
6.1 启动应用
在项目根目录执行以下命令启动应用:
mvn spring-boot:run6.2 测试接口
使用浏览器或 API 工具(如 Postman, curl)访问以下接口:
GET http://localhost:8080/write?text=今天我学习了spring-ai-alibaba-graph的相关概念,spring-ai-alibaba-graph做的特别好, 感觉特别开心6.3 预期响应
接口将返回 JSON 格式的处理结果:
{"summary": "今日学习了spring-ai-alibaba-graph的相关概念,对其优秀表现感到开心。","summary_feedback": "positive","reworded": "今日深入探索了spring-ai-alibaba-graph的相关概念,不禁为其卓越的表现而感到由衷欣喜。这一学习旅程不仅充实了我的知识库,更让我领略到这一技术的独特魅力与无限潜力。","original_text": "今天我学习了spring-ai-alibaba-graph的相关概念,spring-ai-alibaba-graph做的特别好, 感觉特别开心","title": "《深入探索Spring AI Alibaba Graph:一场技术魅力的发现之旅》"
}7. 实现思路与扩展建议
7.1 实现思路
本示例的核心是使用 Spring AI Alibaba Graph 构建有向图工作流,实现以下关键点:
- 节点化处理:将复杂的文本处理流程拆分为多个独立的节点,每个节点负责特定功能。
- 状态管理:通过 KeyStrategy 管理工作流中的状态数据,确保数据在各节点间正确传递。
- 条件分支:使用 ConditionalEdges 实现基于条件的流程分支,支持反馈循环。
- 异步处理:使用 node_async 和 edge_async 实现节点的异步执行,提高处理效率。
- 可视化:自动生成 PlantUML 流程图,便于理解工作流结构。
7.2 扩展建议
- 多语言支持:扩展节点实现,支持多种语言的文本处理。
- 用户交互反馈:将自动反馈判断替换为真实用户交互,提供更准确的反馈。
- 更多文本处理节点:添加如关键词提取、情感分析、文本分类等更多节点。
- 并行处理:设计并行工作流,同时执行多个独立的文本处理任务。
- 工作流版本管理:实现工作流的版本控制,支持不同版本的处理流程。
- 性能监控:添加各节点执行时间的监控,识别性能瓶颈。
- 错误处理与重试:增强错误处理机制,支持节点失败后的自动重试。
