当前位置: 首页 > news >正文

Spring AI Alibaba Graph使用案例多节点并行执行

1、pom.xml    

这里使用 1.0.0.3-SNAPSHOT。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-graph-example</artifactId><version>${revision}</version><relativePath>../pom.xml</relativePath></parent><groupId>com.alibaba.cloud.ai.graph</groupId><artifactId>parallel-node</artifactId><properties><spring-ai-alibaba.version>1.0.0.3-SNAPSHOT</spring-ai-alibaba.version></properties><dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-dashscope</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-autoconfigure-model-chat-client</artifactId></dependency><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-graph-core</artifactId><version>${spring-ai-alibaba.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies></project>

2、config

OverAllState 中存储的字段

  • query:用户的问题
  • expander_number:扩展的数量
  • expander_content:扩展的内容
  • translate_language:翻译的目标语言
  • translate_content:翻译的内容
  • collector_next_node:CollectorNode的下一个节点名
  • expand_status:扩展节点执行状态
  • translate_status: 翻译节点执行状态

定义DispatcherNode 、ExpanderNode、TranslateNode和CollectorNode

边的连接为:

"__START__" -down-> "dispatcher"
"dispatcher" -down-> "translator"
"dispatcher" -down-> "expander"
"translator" -down-> "collector"
"expander" -down-> "collector"
"collector" .down.> "condition1"
"condition1" .down.> "__END__"
'"collector" .down.> "__END__"
"condition1" .down.> "dispatcher"
'"collector" .down.> "dispatcher"

 3、ParallelNodeGraphConfiguration

/** Copyright 2025 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.alibaba.cloud.ai.graph.config;import com.alibaba.cloud.ai.graph.GraphRepresentation;
import com.alibaba.cloud.ai.graph.KeyStrategy;
import com.alibaba.cloud.ai.graph.KeyStrategyFactory;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.dispatcher.CollectorDispatcher;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import com.alibaba.cloud.ai.graph.node.CollectorNode;
import com.alibaba.cloud.ai.graph.node.DispatcherNode;
import com.alibaba.cloud.ai.graph.node.ExpanderNode;
import com.alibaba.cloud.ai.graph.node.TranslateNode;
import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.Map;import static com.alibaba.cloud.ai.graph.StateGraph.END;
import static com.alibaba.cloud.ai.graph.action.AsyncEdgeAction.edge_async;
import static com.alibaba.cloud.ai.graph.action.AsyncNodeAction.node_async;/*** @author sixiyida* @since 2025/6/27*/@Configuration
public class ParallelNodeGraphConfiguration {private static final Logger logger = LoggerFactory.getLogger(ParallelNodeGraphConfiguration.class);@Beanpublic StateGraph parallelNodeGraph(ChatClient.Builder chatClientBuilder) throws GraphStateException {KeyStrategyFactory keyStrategyFactory = () -> {HashMap<String, KeyStrategy> keyStrategyHashMap = new HashMap<>();// 用户输入keyStrategyHashMap.put("query", new ReplaceStrategy());keyStrategyHashMap.put("expander_number", new ReplaceStrategy());keyStrategyHashMap.put("expander_content", new ReplaceStrategy());keyStrategyHashMap.put("translate_language", new ReplaceStrategy());keyStrategyHashMap.put("translate_content", new ReplaceStrategy());keyStrategyHashMap.put("collector_next_node", new ReplaceStrategy());// 状态管理字段keyStrategyHashMap.put("expand_status", new ReplaceStrategy());keyStrategyHashMap.put("translate_status", new ReplaceStrategy());return keyStrategyHashMap;};StateGraph stateGraph = new StateGraph(keyStrategyFactory).addNode("dispatcher", node_async(new DispatcherNode())).addNode("translator", node_async(new TranslateNode(chatClientBuilder))).addNode("expander", node_async(new ExpanderNode(chatClientBuilder))).addNode("collector", node_async(new CollectorNode()))//开始节点 ---》 调度分发节点.addEdge(StateGraph.START, "dispatcher")// 并行边  翻译节点和扩展节点并行.addEdge("dispatcher", "translator").addEdge("dispatcher", "expander").addEdge("translator", "collector").addEdge("expander", "collector").addConditionalEdges("collector", edge_async(new CollectorDispatcher()),Map.of("dispatcher", "dispatcher", END, END));GraphRepresentation representation = stateGraph.getGraph(GraphRepresentation.Type.PLANTUML,"parallel translator and expander flow");logger.info("\n=== Parallel Translator and Expander UML Flow ===");logger.info(representation.content());logger.info("==================================\n");return stateGraph;}}

4、node 

DispatcherNode
/** Copyright 2025 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.alibaba.cloud.ai.graph.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 java.util.HashMap;
import java.util.Map;/*** @author sixiyida* @since 2025/6/27*/public class DispatcherNode implements NodeAction {private static final Logger logger = LoggerFactory.getLogger(DispatcherNode.class);@Overridepublic Map<String, Object> apply(OverAllState state) throws Exception {//调度分发节点logger.info("dispatcher node is running.");Map<String, Object> updated = new HashMap<>();//获取扩展expand节点的状态String expandStatus = state.value("expand_status", "");if (expandStatus.isEmpty()) {updated.put("expand_status", "assigned");logger.info("Set expand_status to assigned");} else {logger.info("expand_status already set to: {}", expandStatus);}//获取翻译 translate节点的状态String translateStatus = state.value("translate_status", "");if (translateStatus.isEmpty()) {updated.put("translate_status", "assigned");logger.info("Set translate_status to assigned");} else {logger.info("translate_status already set to: {}", translateStatus);}return updated;}
}

ExpanderNode
  • PromptTemplate DEFAULTPROMPTTEMPLATE:扩展文本的提示词
  • ChatClient chatClient:调用 AI 模型的 client 端
  • Integer NUMBER:默认扩展为 3 条相似问题

最后将 AI 模型的响应内容返回给给到字段 expander_content 中

/** Copyright 2025 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.alibaba.cloud.ai.graph.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;/*** @author sixiyida* @since 2025/6/27*/public class ExpanderNode implements NodeAction {private static final Logger logger = LoggerFactory.getLogger(ExpanderNode.class);private static final PromptTemplate DEFAULT_PROMPT_TEMPLATE = new PromptTemplate("You are an expert at information retrieval and search optimization.\nYour task is to generate {number} different versions of the given query.\n\nEach variant must cover different perspectives or aspects of the topic,\nwhile maintaining the core intent of the original query. The goal is to\nexpand the search space and improve the chances of finding relevant information.\n\nDo not explain your choices or add any other text.\nProvide the query variants separated by newlines.\n\nOriginal query: {query}\n\nQuery variants:\n");private final ChatClient chatClient;private final Integer NUMBER = 3;public ExpanderNode(ChatClient.Builder chatClientBuilder) {this.chatClient = chatClientBuilder.build();}@Overridepublic Map<String, Object> apply(OverAllState state) {logger.info("expander node is running.");//expand扩展节点 状态String expandStatus = state.value("expand_status", "");logger.info("Current expand_status: {}", expandStatus);if (!"assigned".equals(expandStatus)) {//如果不是 assigned已分配状态 代表是执行中processing 或者 已完成completedreturn Map.of();}String query = state.value("query", "");Integer expanderNumber = state.value("expander_number", this.NUMBER);logger.info("Calling LLM for expansion, setting status to processing");Flux<ChatResponse> chatResponseFlux = this.chatClient.prompt().user((user) -> user.text(DEFAULT_PROMPT_TEMPLATE.getTemplate()).param("number", expanderNumber).param("query", query)).stream().chatResponse();AsyncGenerator<? extends NodeOutput> generator = StreamingChatGenerator.builder().startingNode("expander_llm_stream").startingState(state).mapResult(response -> {String text = response.getResult().getOutput().getText();List<String> queryVariants = Arrays.asList(text.split("\n"));//设置expand扩展节点状态为completed已完成 并设置扩展内容expander_contentreturn Map.of("expander_content", queryVariants, "expand_status", "completed");}).build(chatResponseFlux);//设置expand扩展节点状态为processing 进行中 并设置扩展内容expander_contentreturn Map.of("expander_content", generator,"expand_status", "processing");}
}
TranslateNode
  • PromptTemplate DEFAULTPROMPTTEMPLATE:翻译文本的提示词
  • ChatClient chatClient:调用 AI 模型的 client 端
  • String TARGETLANGUAGE:默认翻译为英文

最后将 AI 模型的响应内容返回给给到字段 translate_content 中

/** Copyright 2025 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.alibaba.cloud.ai.graph.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;/*** @author sixiyida* @since 2025/6/27*/public class TranslateNode implements NodeAction {private static final Logger logger = LoggerFactory.getLogger(TranslateNode.class);private static final PromptTemplate DEFAULT_PROMPT_TEMPLATE = new PromptTemplate("Given a user query, translate it to {targetLanguage}.\nIf the query is already in {targetLanguage}, return it unchanged.\nIf you don't know the language of the query, return it unchanged.\nDo not add explanations nor any other text.\n\nOriginal query: {query}\n\nTranslated query:\n");private final ChatClient chatClient;private final String TARGET_LANGUAGE = "English";public TranslateNode(ChatClient.Builder chatClientBuilder) {this.chatClient = chatClientBuilder.build();}@Overridepublic Map<String, Object> apply(OverAllState state) {logger.info("translate node is running.");//获取 translate翻译节点的状态String translateStatus = state.value("translate_status", "");logger.info("Current translate_status: {}", translateStatus);if (!"assigned".equals(translateStatus)) {//如果不是 assigned已分配状态 代表是执行中processing 或者 已完成completedlogger.info("Translate status is not assigned, skipping LLM call");return Map.of();}String query = state.value("query", "");String targetLanguage = state.value("translate_language", TARGET_LANGUAGE);logger.info("Calling LLM for translation, setting status to processing");Flux<ChatResponse> chatResponseFlux = this.chatClient.prompt().user((user) -> user.text(DEFAULT_PROMPT_TEMPLATE.getTemplate()).param("targetLanguage", targetLanguage).param("query", query)).stream().chatResponse();AsyncGenerator<? extends NodeOutput> generator = StreamingChatGenerator.builder().startingNode("translate_llm_stream").startingState(state).mapResult(response -> {String text = response.getResult().getOutput().getText();List<String> queryVariants = Arrays.asList(text.split("\n"));//翻译节点的状态设置为 completed  并返回翻译内容return Map.of("translate_content", queryVariants, "translate_status", "completed");}).build(chatResponseFlux);//设置翻译节点为 processing 并设置 翻译内容return Map.of("translate_content", generator,"translate_status", "processing");}
}
CollectorNode
/** Copyright 2025 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.alibaba.cloud.ai.graph.node;import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import static com.alibaba.cloud.ai.graph.StateGraph.END;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.HashMap;
import java.util.Map;/*** @author sixiyida* @since 2025/6/27*/public class CollectorNode implements NodeAction {private static final Logger logger = LoggerFactory.getLogger(CollectorNode.class);private static final long TIME_SLEEP = 5000;@Overridepublic Map<String, Object> apply(OverAllState state) throws Exception {Thread.sleep(TIME_SLEEP);
//        合并扩展节点、翻译节点后的结果logger.info("collector node is running.");String nextStep = END;Map<String, Object> updated = new HashMap<>();if (!areAllExecutionResultsPresent(state)) {//翻译节点和扩展节点只要有一个未执行完成 下一步节点继续为分发调度节点nextStep = "dispatcher";}// 翻译节点和扩展节点都完成 下一节点为结束节点updated.put("collector_next_node", nextStep);logger.info("collector node -> {} node", nextStep);return updated;}public boolean areAllExecutionResultsPresent(OverAllState state) {//  翻译节点 和扩展节点都已执行完成并生成翻译内容和扩展内容return state.value("translate_content").isPresent() && state.value("expander_content").isPresent();}}
CollectorDispatcher
/** Copyright 2025 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.alibaba.cloud.ai.graph.dispatcher;import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.action.EdgeAction;/*** @author sixiyida* @since 2025/6/27*/public class CollectorDispatcher implements EdgeAction {@Overridepublic String apply(OverAllState state) throws Exception {//获取下个节点return (String) state.value("collector_next_node", StateGraph.END);}
} 
GraphProcess
/** Copyright 2025 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.alibaba.cloud.ai.graph.controller.GraphProcess;import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.NodeOutput;
import com.alibaba.cloud.ai.graph.async.AsyncGenerator;
import com.alibaba.cloud.ai.graph.streaming.StreamingOutput;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.codec.ServerSentEvent;
import reactor.core.publisher.Sinks;import java.util.Map;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** @author sixiyida* @since 2025/6/27*/public class GraphProcess {private static final Logger logger = LoggerFactory.getLogger(GraphProcess.class);private final ExecutorService executor = Executors.newSingleThreadExecutor();private CompiledGraph compiledGraph;public GraphProcess(CompiledGraph compiledGraph) {this.compiledGraph = compiledGraph;}public void processStream(AsyncGenerator<NodeOutput> generator, Sinks.Many<ServerSentEvent<String>> sink) {executor.submit(() -> {generator.forEachAsync(output -> {try {logger.info("output = {}", output);String nodeName = output.node();String content;if (output instanceof StreamingOutput streamingOutput) {content = JSON.toJSONString(Map.of(nodeName, streamingOutput.chunk()));} else {JSONObject nodeOutput = new JSONObject();nodeOutput.put("data", output.state().data());nodeOutput.put("node", nodeName);content = JSON.toJSONString(nodeOutput);}sink.tryEmitNext(ServerSentEvent.builder(content).build());} catch (Exception e) {throw new CompletionException(e);}}).thenAccept(v -> {// 正常完成sink.tryEmitComplete();}).exceptionally(e -> {sink.tryEmitError(e);return null;});});}
}

ParallelNodeGraphController
/** Copyright 2025 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.alibaba.cloud.ai.graph.controller;import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.NodeOutput;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.async.AsyncGenerator;
import com.alibaba.cloud.ai.graph.controller.GraphProcess.GraphProcess;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
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 reactor.core.publisher.Flux;
import reactor.core.publisher.Sinks;import java.util.HashMap;
import java.util.Map;/*** @author sixiyida* @since 2025/6/27*/@RestController
public class ParallelNodeGraphController {private static final Logger logger = LoggerFactory.getLogger(ParallelNodeGraphController.class);private final CompiledGraph compiledGraph;public ParallelNodeGraphController(@Qualifier("parallelNodeGraph")StateGraph stateGraph) throws GraphStateException {this.compiledGraph = stateGraph.compile();}@GetMapping(value = "/graph/stream/expand", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<ServerSentEvent<String>> expand(@RequestParam(value = "query", defaultValue = "你好,很高兴认识你,能简单介绍一下自己吗?", required = false) String query,@RequestParam(value = "expander_number", defaultValue = "3", required = false) Integer  expanderNumber,@RequestParam(value = "thread_id", defaultValue = "__default__", required = false) String threadId) throws GraphRunnerException {RunnableConfig runnableConfig = RunnableConfig.builder().threadId(threadId).build();Map<String, Object> objectMap = new HashMap<>();objectMap.put("query", query);objectMap.put("expander_number", expanderNumber);GraphProcess graphProcess = new GraphProcess(this.compiledGraph);Sinks.Many<ServerSentEvent<String>> sink = Sinks.many().unicast().onBackpressureBuffer();AsyncGenerator<NodeOutput> resultFuture = compiledGraph.stream(objectMap, runnableConfig);graphProcess.processStream(resultFuture, sink);return sink.asFlux().doOnCancel(() -> logger.info("Client disconnected from stream")).doOnError(e -> logger.error("Error occurred during streaming", e));}}

代码运行效果

http://127.0.0.1:8080/graph/stream/expand

http://www.lryc.cn/news/583476.html

相关文章:

  • Webpack、Vite配置技巧与CI/CD流程搭建全解析
  • CentOS7系统部署Node.js LTS V18.16.0
  • 【自动驾驶】经典LSS算法解析——深度估计
  • 佰力博科技与您浅谈低温介电材料特性及应用分析
  • 科技对生态保育的影响?
  • Oracle存储过程导出数据到Excel:全面实现方案详解
  • 专题一_双指针_三数之和
  • 【基础算法】贪心 (四) :区间问题
  • WIFI协议全解析04:从芯片角度看WiFi协议:ESP32/8266 支持了哪些?
  • SQL 视图与事务知识点详解及练习题
  • ARM汇编编程(AArch64架构)课程 - 第7章:SIMD与浮点运算
  • STIDGCN(时空交互动态图卷积网络)的原理,包括其核心模块的设计思路和工作机制 交通预测是智能交通系统中的一个重要任务
  • python+vue的企业产品订单管理系统
  • Redis:分组与设备在 Redis 中缓存存储设计
  • Redis-哨兵机制doctor环境搭建
  • CSS基础选择器、文本属性、引入方式及Chorme调试工具
  • Linux 测开:日志分析 + 定位 Bug
  • 【图像处理基石】如何检测到画面中的ppt并对其进行增强?
  • deepseek实战教程-第十篇deepseek对MCP协议支持
  • 计算机网络实验——网线的制作和测试
  • 7、整合前几篇插件列表
  • 云成本优化的核心原则与框架
  • Spring AI 本地 RAG 实战:用Redis、Chroma搭建离线知识问答系统
  • 【解决方法】ollama在powershell或者cmd运行时乱码报错
  • 网络安全之RCE分析与利用详情
  • 从零用java实现 小红书 springboot vue uniapp(13)模仿抖音视频切换
  • uniapp如何创建并使用组件?组件通过Props如何进行数据传递?
  • scp:上传大型数据集到实验室服务器
  • linux-用户和组
  • 家庭网络中的服务器怎么对外提供服务?