Dict.CN 在线词典, 英语学习, 在线翻译 ------------- MyGitee My腾云code My51cto

Happy_EveryDay

可以平凡 不可以平庸 无爱则无忧,无欲则无求,无怒而无敌,无怨才是佛。所有烦恼,都是放不下的执著 开源技群 328035181 MyGitee

博客园 首页 新随笔 管理

 

预期结果:

状态存储
状态存储->会话id

 

image

 

image

 

 

 

 

 1、pom

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.sb</groupId>
<artifactId>zhipuai</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zhipuai</name>
<description>zhipuai</description>
<properties>
<java.version>17</java.version>
<!-- <spring-ai.version>2.0.0-M5</spring-ai.version>-->
<spring-ai.version>1.1.2</spring-ai.version>
<spring-ai-alibaba.version>1.0.0.4</spring-ai-alibaba.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-zhipuai</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-graph-core</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-bom</artifactId>
<version>${spring-ai-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>


2、application.yml

server:
port: 18091 # 应用监听端口,默认 18091
spring:
application:
name: sangeng-graph
ai:
zhipuai:
#api-key: ${ZHIPU_KEY} # 从环境变量 ZHIPU_KEY 读,不硬编码
api-key: "XXXXXXXXXXXXXXX" # 从环境变量 ZHIPU_KEY 读,不硬编码
chat:
options:
           model: glm-4.5-air          # GLM-4.5-air






3、controller

package com.sb.zhipuai.controller;

import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/graph")
public class GraphController {
private static final Logger log = LoggerFactory.getLogger(GraphController.class);

// 构造器注入 Spring 容器里那个 CompiledGraph
private final CompiledGraph compiledGraph;
private final CompiledGraph simpleGraph; // 对应 simpleGraph
private final CompiledGraph conditionalGraph;
private final CompiledGraph loopGraph;
private final CompiledGraph saveGraph;

public GraphController(
@Qualifier("quickStartGraph") CompiledGraph compiledGraph,
@Qualifier("simpleGraph") CompiledGraph simpleGraph,
@Qualifier("conditionalGraph") CompiledGraph conditionalGraph,
@Qualifier("loopGraph") CompiledGraph loopGraph,
@Qualifier("saveGraph") CompiledGraph saveGraph) {
this.compiledGraph = compiledGraph;
this.simpleGraph = simpleGraph;
this.conditionalGraph = conditionalGraph;
this.loopGraph = loopGraph;
this.saveGraph = saveGraph;
}

/**
* 状态存储
* @param msg
* @return
*/
@GetMapping("/saveGraph")
public Map<String, Object> saveGraph(@RequestParam("msg") String msg){
Optional<OverAllState> overAllStateOptional = saveGraph.call(Map.of("msg", msg));
Map<String, Object> data = overAllStateOptional.map(OverAllState::data).orElse(Map.of());
return data;
}

/**
* 状态存储->会话id
* @param msg
* @param conversationId 会话id
* @return
*/
@GetMapping("/saveGraph2")
public Map<String, Object> saveGraph2(
@RequestParam("msg") String msg,
@RequestParam("conversationId") String conversationId
){
RunnableConfig runnableConfig = RunnableConfig.builder()
.threadId(conversationId)
.build();
Optional<OverAllState> overAllStateOptional = saveGraph.call(Map.of("msg", msg), runnableConfig);
Map<String, Object> data = overAllStateOptional.map(OverAllState::data).orElse(Map.of());
return data;
}

@GetMapping("/loopGraph")
public Map<String, Object> loopGraph(@RequestParam("topic") String topic){
Optional<OverAllState> overAllStateOptional = loopGraph.call(Map.of("topic", topic));
Map<String, Object> data = overAllStateOptional.map(OverAllState::data).orElse(Map.of());
return data;
}

@GetMapping("/conditionalGraph")
public Map<String, Object> conditionalGraph(@RequestParam("topic") String topic){
Optional<OverAllState> overAllStateOptional = conditionalGraph.call(Map.of("topic", topic));
Map<String, Object> data = overAllStateOptional.map(OverAllState::data).orElse(Map.of());
return data;
}

@GetMapping("/quickStartGraph")
public String quickStartGraph() {
Optional<OverAllState> overAllStateOptional = compiledGraph.call(Map.of()); // ← call → invoke
log.info("overAllStateOptional: {}", overAllStateOptional);
return "ok";
}

/**
* 造句翻译
* @param word
* @return
*/
@GetMapping("/simpleGraph")
public Map<String, Object> simpleGraph(@RequestParam("word") String word){
Optional<OverAllState> overAllStateOptional = simpleGraph.call(Map.of("word", word));
Map<String, Object> data = overAllStateOptional.map(OverAllState::data).orElse(Map.of());
return data;
}
}


4、GraphConfiguration

package com.sb.zhipuai.config;

import com.alibaba.cloud.ai.graph.*;
import com.alibaba.cloud.ai.graph.action.AsyncEdgeAction;
import com.alibaba.cloud.ai.graph.action.AsyncNodeAction;
import com.alibaba.cloud.ai.graph.action.EdgeAction;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy;
import com.sb.zhipuai.node.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.Map;
import static com.alibaba.cloud.ai.graph.action.AsyncNodeAction.node_async;


//定义状态图 (状态,节点,边),编译生成 CompiledGraph 后注入 Spring 容器
@Configuration
public class GraphConfiguration {

private static final Logger log = LoggerFactory.getLogger(GraphConfiguration.class);

/**
* 状态存储
* @param clientBuilder
* @return
* @throws GraphStateException
*/
@Bean("saveGraph")
public CompiledGraph saveGraph(ChatClient.Builder clientBuilder) throws GraphStateException{
KeyStrategyFactory keyStrategyFactory = () -> Map.of();
// 定义状态图stateGraph
StateGraph stateGraph = new StateGraph("saveGraph", keyStrategyFactory);
stateGraph.addNode("对话存储",
AsyncNodeAction.node_async(new NodeAction() {
@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
String msg = state.value("msg", "");
ArrayList<Object> historyMsg = state.value("historyMsg", new ArrayList<>());
historyMsg.add(msg);
return Map.of("historyMsg",historyMsg);
}
}));
// 定义边
stateGraph.addEdge(StateGraph.START,"对话存储");
stateGraph.addEdge("对话存储",StateGraph.END);
//添加 PlantUML 打印
GraphRepresentation representation =
stateGraph.getGraph(GraphRepresentation.Type.PLANTUML, "saveGraph");
log.info("\n=== expander UML Flow ===");
log.info(representation.content());
log.info("=================================\n");
return stateGraph.compile();
}

@Bean("loopGraph")
public CompiledGraph loopGraph(ChatClient.Builder clientBuilder) throws GraphStateException{
KeyStrategyFactory keyStrategyFactory = () -> Map.of("topic",new ReplaceStrategy());
// 定义状态图stateGraph
StateGraph stateGraph = new StateGraph("loopGraph", keyStrategyFactory);
// 定义节点
stateGraph.addNode("生成笑话",AsyncNodeAction.node_async(new GenerateJokeNode(clientBuilder)));
//评分targetScore>=7,maxLoopCount>=10循环次数--->break
stateGraph.addNode("评估笑话",AsyncNodeAction.node_async(new LoopEvaluateJokesNode(clientBuilder,7,10)));
// 定义边
stateGraph.addEdge(StateGraph.START, "生成笑话");
stateGraph.addEdge("生成笑话", "评估笑话");
// 条件分支边(核心循环逻辑)
// result→loop→生成笑话
// →break→END
stateGraph.addConditionalEdges("评估笑话", AsyncEdgeAction.edge_async(new EdgeAction() {
@Override
public String apply(OverAllState state) throws Exception {
return state.value("result", "loop");
}
}),
Map.of(
"loop", "生成笑话",
"break", StateGraph.END
)
);
return stateGraph.compile();
}

@Bean("conditionalGraph")
public CompiledGraph conditionalGraph(ChatClient.Builder clientBuilder) throws GraphStateException{
// 定义状态键的更新策略
KeyStrategyFactory keyStrategyFactory = () -> Map.of("topic",new ReplaceStrategy());
// 定义创建状态图stateGraph
StateGraph stateGraph = new StateGraph("conditionalGraph", keyStrategyFactory);

// 添加节点
stateGraph.addNode("生成笑话", AsyncNodeAction.node_async(new GenerateJokeNode(clientBuilder)));
stateGraph.addNode("评估笑话", AsyncNodeAction.node_async(new EvaluateJokesNode(clientBuilder)));
stateGraph.addNode("优化笑话", AsyncNodeAction.node_async(new EnhanceJokeQualityNode(clientBuilder)));

// 定义边:START → 生成笑话 → 评估笑话
stateGraph.addEdge(StateGraph.START, "生成笑话");
stateGraph.addEdge("生成笑话", "评估笑话");

// 条件分支:评估笑话 →优秀 → END
// →不够优秀 → 优化笑话 → END
stateGraph.addConditionalEdges(
"评估笑话",
AsyncEdgeAction.edge_async((OverAllState state) -> state.value("result", "优秀")),
// 返回值映射目标节点
Map.of(
"优秀", StateGraph.END,
"不够优秀", "优化笑话"
)
);
stateGraph.addEdge("优化笑话", StateGraph.END);

return stateGraph.compile();
}

@Bean("quickStartGraph")
public CompiledGraph quickStartGraph() throws GraphStateException {

// 状态值:input1、input2 都用 ReplaceStrategy(新值覆盖旧值)
KeyStrategyFactory keyStrategyFactory = new KeyStrategyFactory() {
@Override
public Map<String, KeyStrategy> apply() {
return Map.of("input1", new ReplaceStrategy(),
"input2", new ReplaceStrategy());
}
};

// 定义创建状态图stateGraph
StateGraph stateGraph = new StateGraph("quickStartGraph", keyStrategyFactory);

// 定义节点 node1:打印当前状态,返回 input1=1, input2=1
stateGraph.addNode("node1", node_async(new NodeAction() {
@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
log.info("node1 state: {}", state);
return Map.of("input1", 1, "input2", 1);
}
}));

// 定义node2:打印当前状态,返回 input1=2, input2=2
stateGraph.addNode("node2", node_async(new NodeAction() {
@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
log.info("node2 state: {}", state);
return Map.of("input1", 2, "input2", 2);
}
}));
// 定义边:START → node1 → node2 → END
stateGraph.addEdge(StateGraph.START, "node1");
stateGraph.addEdge("node1", "node2");
stateGraph.addEdge("node2", StateGraph.END);

// 编译状态图,交回 Spring 容器
CompiledGraph compiledGraph=stateGraph.compile();
return compiledGraph;
}

@Bean("simpleGraph")
public CompiledGraph simpleGraph(ChatClient.Builder clientBuilder) throws GraphStateException {

// 定义状态键的更新策略
KeyStrategyFactory keyStrategyFactory = () -> Map.of("word", new ReplaceStrategy());

// 创建状态图
StateGraph stateGraph = new StateGraph("simpleGraph", keyStrategyFactory);

// 添加节点
stateGraph.addNode("SentenceConstructionNode",
AsyncNodeAction.node_async(new SentenceConstructionNode(clientBuilder)));

stateGraph.addNode("TranslationNode",
AsyncNodeAction.node_async(new TranslationNode(clientBuilder)));

// 定义边 (执行顺序)
stateGraph.addEdge(StateGraph.START, "SentenceConstructionNode");
stateGraph.addEdge("SentenceConstructionNode", "TranslationNode");
stateGraph.addEdge("TranslationNode", StateGraph.END);

// 编译状态图,放入容器
return stateGraph.compile();
}
}




5、Node

 

package com.sb.zhipuai.node;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.PromptTemplate;
import java.util.Map;

/**
* @author Administrator评分节点
*/
public class LoopEvaluateJokesNode implements NodeAction {
private static final Logger log = LoggerFactory.getLogger(LoopEvaluateJokesNode.class);
private final ChatClient chatClient;
private final Integer targetScore;
private final Integer maxLoopCount;

public LoopEvaluateJokesNode(ChatClient.Builder builder, Integer targetScore, Integer maxLoopCount) {
this.chatClient = builder.build();
this.targetScore = targetScore;
this.maxLoopCount = maxLoopCount;
}

@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
// 从 state 中获取joke
String joke = state.value("joke", "");
//循环次数
Integer loopCount = state.value("loopCount", 1);
// 构造评分提示词:让模型输出0~10的数字
PromptTemplate promptTemplate = new PromptTemplate("你是一个笑话评分专家,能够对笑话进行评分,基于效果的搞笑程度给出0到10分的打分\n" +
"要求结果只返回最后的打分,不要其他内容。" +
"要评分的笑话::{joke}");
promptTemplate.add("joke", joke);
String prompt = promptTemplate.render();

// 调用模型
String content = chatClient.prompt()
.user(prompt)
.call()
.content();

// content转整数
Integer score = Integer.valueOf(content.trim());
log.info("joke: {}, score: {}, loopCount: {}", joke, score,loopCount);
//根据分数判断继续循环还是结束
String result = "loop";
if(score >= targetScore||loopCount>=maxLoopCount){
result = "break";
}
loopCount++;
// 返回结果存入state,key=result,loopCount
return Map.of("result", result,"loopCount",loopCount);
}
}



package com.sb.zhipuai.node;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.PromptTemplate;
import java.util.Map;

/**
* @author Administrator 造句节点
*/
public class SentenceConstructionNode implements NodeAction {

private final ChatClient chatClient;

public SentenceConstructionNode(ChatClient.Builder builder) {
// 构建 ChatClient 实例
this.chatClient = builder.build();
}

@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
// 从 state 中获取要造句的单词,如果没有则使用空字符串
String word = state.value("word", "");

PromptTemplate promptTemplate = new PromptTemplate("你是一个英语造句专家,能够基于给定的单词进行造句。" +
"要求只返回最终造好的句子,不要返回其他信息。给定的单词:{word}"
);
promptTemplate.add("word", word);
String prompt = promptTemplate.render();
String content = chatClient.prompt()
.user(prompt)
.call()
.content();

// 把句子存入 state,键名定义为 "sentence"
return Map.of("sentence", content);
}
}


package com.sb.zhipuai.node;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.PromptTemplate;

import java.util.Map;

// 其他 import 保持和你造句节点一样即可
// import org.springframework.ai.chat.client.ChatClient;
// import org.springframework.ai.chat.prompt.PromptTemplate;
// import com.sangeng.workflow.NodeAction; (假设的包名)
// import com.sangeng.workflow.OverallState; (假设的包名)

/**
* @author Administrator 翻译节点
*/
public class TranslationNode implements NodeAction {

private final ChatClient chatClient;

public TranslationNode(ChatClient.Builder builder) {
this.chatClient = builder.build();
}


@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
// 从 state 中获取要造句的单词,如果没有则使用空字符串
String sentence = state.value("sentence", "");

// 创建提示模板,定义AI翻译任务
PromptTemplate promptTemplate = new PromptTemplate("你是一个英语翻译专家,能够对句子进行翻译。" +
"要求只返回翻译的结果不要返回其他信息。要翻译的句子:{sentence}");

// 模板添加参数
promptTemplate.add("sentence", sentence);
String prompt = promptTemplate.render();

// 模型调用
String content = chatClient.prompt()
.user(prompt)
.call()
.content();

// 返回翻译结果,存入state
return Map.of("translation", content);
}
}
 
package com.sb.zhipuai.node;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.PromptTemplate;
import java.util.Map;


/**
* @author Administrator 生成笑话节点
*/
public class GenerateJokeNode implements NodeAction {
private final ChatClient chatClient;
public GenerateJokeNode(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
// 从 state 中获取topic
String topic = state.value("topic", "");

// PromptTemplate 渲染提示词
PromptTemplate promptTemplate = new PromptTemplate("你需要写一个关于指定主题的短笑话。要求返回的结果中只能包含笑话的内容" +
"主题:{topic}");
promptTemplate.add("topic", topic);
String prompt = promptTemplate.render();

//调用大模型
String content = chatClient.prompt()
.user(prompt)
.call()
.content();

// 存入state,键名定义为 "joke"
return Map.of("joke", content);
}
}

package com.sb.zhipuai.node;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.PromptTemplate;
import java.util.Map;

/**
* @author Administrator评分节点
*/
public class EvaluateJokesNode implements NodeAction {
private final ChatClient chatClient;

public EvaluateJokesNode(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
// 从 state 中获取joke
String joke = state.value("joke", "");

// 评分Prompt模板
PromptTemplate promptTemplate = new PromptTemplate("你是一个笑话评分专家,能够对笑话进行评分,基于效果的搞笑程度给出0到10分的打分。然后基于评分结果进行评价。如果大于等于3分评价:优秀 否则评价:不够优秀\n" +
"要求结果只返回最后的评价,不要其他内容。" +
"要评分的笑话::{joke}");
promptTemplate.add("joke", joke);
String prompt = promptTemplate.render();

//
String content = chatClient.prompt()
.user(prompt)
.call()
.content();

// 存入state,键名定义为 "result"
return Map.of("result", content.trim());
}



package com.sb.zhipuai.node;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.PromptTemplate;

import java.util.Map;

/**
* @author Administrator 优化笑话节点
*/
public class EnhanceJokeQualityNode implements NodeAction {
private final ChatClient chatClient;

public EnhanceJokeQualityNode(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
// 从 state 中获取joke
String joke = state.value("joke", "");

PromptTemplate promptTemplate = new PromptTemplate("你是一个笑话优化专家,你能够优化笑话,让它更加搞笑。" +
"只返回优化后的笑话,不要返回其他信息。要优化的笑话:{joke}");
promptTemplate.add("joke", joke);
String prompt = promptTemplate.render();

//调用大模型
String content = chatClient.prompt()
.user(prompt)
.call()
.content();

// 存入state,键名定义为 "newJoke"
return Map.of("newJoke", content.trim());
}
}






}



6、PlantUML状态图打印

image

 

image

 

 查看效果

http://www.plantuml.com/plantuml

image

 






7、http://localhost:18091/graph/saveGraph?msg=你好AA5

 

image

 会话id

http://localhost:18091/graph/saveGraph?msg=你好AA5&&conversationId=AA

image

 

image

 

posted on 2026-09-29 12:14  2026cn  阅读(8)  评论(0)    收藏  举报