前面我们已经解锁了对话、图像、语音、视频等各种单点能力。但现实中的 AI 应用往往不是一个简单的“一问一答”,而是一连串有顺序、有条件的协作过程。今天,我们就来学习如何像搭积木一样,用 Spring AI Alibaba 的图式编排(Graph-based Orchestration)能力,把多个 AI 任务串联成一条自动化流水线。

想一想你在厨房里做一道复杂料理:切菜、焯水、爆炒、勾芡,每一步都有先后顺序,有些步骤还能同时进行。Spring AI Alibaba 借鉴了 LangGraph 的图编排思想,让我们能用 Java 代码定义一张“任务流程图”,每个节点负责一个具体的任务(可以是调用大模型、执行 Java 方法、甚至调用另一个子流程),节点之间通过边连接,数据以状态(State)的形式在节点间流转。今天我们会依次搞定链式工作流、并行化工作流和路由工作流,最后用一个智能客服的完整示例把它们组合在一起。

读完本篇,你将能够用一张图来管理复杂的 AI 业务流水线,而不再依赖一堆凌乱的 if-else 和方法调用。

一、痛点场景:单次 AI 调用不够用的时候

场景一:智能客服的完整流程

你做了一个客服机器人。用户问“我的订单怎么还没到?”,你的流程其实是:

  1. 用 AI 提取用户问题中的关键信息(订单号、意图)。
  2. 根据意图调用内部 API 查询物流状态。
  3. 把查询结果交给另一个 AI,生成一段有人情味的回复。

这中间涉及“理解 → 查询 → 生成”三步。如果每次都写一个巨大的 Prompt 试图一步到位,准确率和可控性会大打折扣,后期维护更是噩梦。

场景二:内容创作流水线

你要生成一篇技术博客:先让 AI 列出大纲,再根据大纲分段扩写,最后让另一个 AI 校对润色。如果能把这三个步骤定义成一个工作流,点一下按钮就自动跑完,效率会大大提升。

场景三:多模型协作

你可能想让 DeepSeek 做逻辑推理,百炼的 Qwen 做中文润色,最后用本地 Ollama 模型做总结。不同模型各司其职,需要一个“导演”来统一调度。

以上所有场景的核心诉求都是:任务编排。Spring AI Alibaba 提供了一套图式工作流引擎,让我们可以用 Java 代码直接定义任务节点和它们之间的流转关系,就像一个可视化的流程设计器,只不过是用代码来“画”的。

二、核心概念快览

在动手之前,先理清几个核心概念,它们是你理解后续代码的基石。

2.1 工作流图(StateGraph)

整个工作流在代码层面就是一张有向图,由节点(Node)和边(Edge)组成。Spring AI Alibaba 提供了 StateGraph 类来构建这张图。你可以把它想象成一个白板,你在上面画圆圈(节点)和箭头(边),最后启动一个“小火车”载着数据从头跑到尾。

2.2 节点(Node)

节点是具体执行任务的单元。每一个节点本质上就是一个函数,签名为 Function<State, State>,即接收当前状态,处理后返回更新后的状态。节点可以做的事情包括:

  • 调用大模型(如通义千问、DeepSeek)
  • 执行一段自定义 Java 逻辑(查数据库、调第三方 API)
  • 启动另一个子图(子工作流)

2.3 边(Edge)

边定义了节点之间的流转方向。一条边从节点 A 指向节点 B,表示“A 执行完后,把结果传给 B”。Spring AI Alibaba 支持两种边:

  • 普通边(addEdge):无条件地从 A 走向 B。
  • 条件边(addConditionalEdges):根据一个路由函数返回的字符串,选择下一个节点。

2.4 状态(State)

在整个工作流中流转的数据被称为状态(State)。它的默认实现是 Map<String, Object>,你可以往里面塞任意数据:用户输入、中间结果、最终答案等。所有节点共享同一个状态对象,但每个节点只能看到当前快照,并通过返回值来产生新的状态快照。

2.5 三种基础编排模式

模式 描述 适用场景
链式工作流 节点按固定顺序依次执行,上一个的输出作为下一个的输入 信息提取 → 处理 → 格式化输出
并行化工作流 多个节点同时执行,最后汇总结果 同时翻译成多种语言、同时检查代码的多个维度
路由工作流 根据条件判断走向不同的节点 按用户意图分类(投诉转人工,咨询自动回复)

三、环境准备

继续使用 Spring AI Alibaba 的项目,核心依赖仍然是 spring-ai-alibaba-starter-dashscope。工作流编排能力已经内置在该 starter 中,无需额外引入任何依赖。

如果你的项目还没有 Spring AI Alibaba,请参照第 8 篇搭建。下面是本篇文章需要确认的配置。

3.1 Maven 依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Spring AI Alibaba DashScope Starter(内置工作流引擎) -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        <version>1.1.2.0</version>  <!-- 请使用当前最新稳定版 -->
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.1.6</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

3.2 application.yml

spring:
  ai:
    dashscope:
      api-key: ${DASHSCOPE_API_KEY}
      chat:
        options:
          model: qwen-plus
          temperature: 0.7

logging:
  level:
    com.alibaba.cloud.ai.graph: DEBUG   # 开启工作流调试日志

确保环境变量 DASHSCOPE_API_KEY 已设置。

四、代码实战

我们将分三步构建:链式工作流 → 并行工作流 → 路由工作流,最后综合成一个智能客服工作流。所有代码都可以放在同一个配置类中,清晰明了。

4.1 创建工作流配置类

新建 WorkflowConfig.java,在这里集中定义各种工作流 Bean。

package com.example.demo.config;

import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.Graph;
import org.springframework.ai.chat.client.ChatClient;
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.StateGraph.START;

@Configuration
public class WorkflowConfig {

    private final ChatClient chatClient;

    public WorkflowConfig(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    // 后续在这里添加工作流 Bean
}

说明ChatClient 由 Spring AI Alibaba 自动配置创建,无需额外 Bean。

4.2 链式工作流:技术博客生成器

我们来实现一个“大纲生成 → 内容扩写 → 润色校对”的三步流水线。用户输入一个主题,最终得到一篇完整的博客。

节点定义

  • outline_node:根据主题生成大纲
  • expand_node:根据大纲逐段扩写
  • polish_node:对全文进行润色

WorkflowConfig 中添加链式工作流 Bean:

@Bean
public Graph blogChainGraph() {
    StateGraph<Map<String, Object>> graph = new StateGraph<>(Map.class);

    // 1. 定义节点
    graph.addNode("outline", this::generateOutline);
    graph.addNode("expand", this::expandContent);
    graph.addNode("polish", this::polishArticle);

    // 2. 连接边:START → outline → expand → polish → END
    graph.addEdge(START, "outline");
    graph.addEdge("outline", "expand");
    graph.addEdge("expand", "polish");
    graph.addEdge("polish", END);

    return graph.compile();
}

private Map<String, Object> generateOutline(Map<String, Object> state) {
    String topic = (String) state.get("topic");
    String outline = chatClient.prompt()
            .system("你是一个技术博主。请为主题生成一份详细的文章大纲,用数字列表表示,包含至少3个主要章节。")
            .user(topic)
            .call()
            .content();
    state.put("outline", outline);
    System.out.println("=== 大纲生成完成 ===");
    return state;
}

private Map<String, Object> expandContent(Map<String, Object> state) {
    String outline = (String) state.get("outline");
    String article = chatClient.prompt()
            .system("你是一个技术博主。请根据以下大纲写一篇完整的博客文章,每个章节都要详细展开,使用Markdown格式。")
            .user(outline)
            .call()
            .content();
    state.put("draft", article);
    System.out.println("=== 内容扩写完成 ===");
    return state;
}

private Map<String, Object> polishArticle(Map<String, Object> state) {
    String draft = (String) state.get("draft");
    String finalArticle = chatClient.prompt()
            .system("你是一个资深技术编辑。请对以下文章进行润色,修正语法错误,优化表达流畅度,确保逻辑清晰。直接输出润色后的完整文章。")
            .user(draft)
            .call()
            .content();
    state.put("final_article", finalArticle);
    System.out.println("=== 润色校对完成 ===");
    return state;
}

配套 Controller

package com.example.demo.controller;

import com.alibaba.cloud.ai.graph.Graph;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
public class WorkflowController {

    private final Graph blogChainGraph;

    public WorkflowController(@Qualifier("blogChainGraph") Graph blogChainGraph) {
        this.blogChainGraph = blogChainGraph;
    }

    @GetMapping("/workflow/blog")
    public String generateBlog(@RequestParam String topic) {
        Map<String, Object> initialState = new HashMap<>();
        initialState.put("topic", topic);

        Map<String, Object> finalState = blogChainGraph.invoke(initialState);
        return (String) finalState.get("final_article");
    }
}

测试

http://localhost:8080/workflow/blog?topic=Spring AI Alibaba 工作流入门

你将获得一篇结构清晰、文字流畅的技术博客。

4.3 并行工作流:多语言翻译

这个例子演示节点并行执行。用户输入一段中文,同时翻译成英文、日文、法文,最后汇总。

WorkflowConfig 中添加:

@Bean
public Graph parallelTranslationGraph() {
    StateGraph<Map<String, Object>> graph = new StateGraph<>(Map.class);

    graph.addNode("splitter", state -> state);  // 不做任何事,纯粹起点
    graph.addNode("translate_en", this::translateToEnglish);
    graph.addNode("translate_jp", this::translateToJapanese);
    graph.addNode("translate_fr", this::translateToFrench);
    graph.addNode("aggregator", state -> state); // 汇聚节点,结果已经在各并行节点写入state

    // 链式开始 → splitter,然后并行到三个翻译节点,最后汇聚
    graph.addEdge(START, "splitter");
    graph.addEdge("splitter", "translate_en");
    graph.addEdge("splitter", "translate_jp");
    graph.addEdge("splitter", "translate_fr");
    graph.addEdge("translate_en", "aggregator");
    graph.addEdge("translate_jp", "aggregator");
    graph.addEdge("translate_fr", "aggregator");
    graph.addEdge("aggregator", END);

    return graph.compile();
}

private Map<String, Object> translateToEnglish(Map<String, Object> state) {
    String text = (String) state.get("text");
    String en = chatClient.prompt().user("翻译成英文:" + text).call().content();
    state.put("english", en);
    return state;
}

private Map<String, Object> translateToJapanese(Map<String, Object> state) {
    String text = (String) state.get("text");
    String jp = chatClient.prompt().user("翻译成日文:" + text).call().content();
    state.put("japanese", jp);
    return state;
}

private Map<String, Object> translateToFrench(Map<String, Object> state) {
    String text = (String) state.get("text");
    String fr = chatClient.prompt().user("翻译成法文:" + text).call().content();
    state.put("french", fr);
    return state;
}

Controller 方法

private final Graph parallelTranslationGraph;

public WorkflowController(@Qualifier("blogChainGraph") Graph blogChainGraph,
                          @Qualifier("parallelTranslationGraph") Graph parallelTranslationGraph) {
    this.blogChainGraph = blogChainGraph;
    this.parallelTranslationGraph = parallelTranslationGraph;
}

@GetMapping("/workflow/translate")
public Map<String, String> parallelTranslate(@RequestParam String text) {
    Map<String, Object> initial = new HashMap<>();
    initial.put("text", text);
    Map<String, Object> result = parallelTranslationGraph.invoke(initial);

    Map<String, String> response = new HashMap<>();
    response.put("english", (String) result.get("english"));
    response.put("japanese", (String) result.get("japanese"));
    response.put("french", (String) result.get("french"));
    return response;
}

测试

http://localhost:8080/workflow/translate?text=今天天气真好

返回 JSON:

{
  "english": "The weather is really nice today.",
  "japanese": "今日は本当に天気がいいですね。",
  "french": "Il fait vraiment beau aujourd'hui."
}

三个翻译任务会并发执行,总耗时约等于最慢的那一个节点的时间。

4.4 路由工作流:根据意图分发

这个例子中,我们根据用户问题的意图,自动走向不同的处理节点。意图分为:查天气、算数学、讲笑话、默认回答。

WorkflowConfig 中添加:

@Bean
public Graph routingGraph() {
    StateGraph<Map<String, Object>> graph = new StateGraph<>(Map.class);

    graph.addNode("intent_analyzer", this::analyzeIntent);
    graph.addNode("weather_handler", this::weatherHandler);
    graph.addNode("math_handler", this::mathHandler);
    graph.addNode("joke_handler", this::jokeHandler);
    graph.addNode("fallback_handler", this::fallbackHandler);

    graph.addEdge(START, "intent_analyzer");
    // 条件边:根据analyzeIntent返回的路由键选择下一个节点
    graph.addConditionalEdges("intent_analyzer",
            this::routeByIntent,
            Map.of(
                    "weather", "weather_handler",
                    "math", "math_handler",
                    "joke", "joke_handler",
                    "unknown", "fallback_handler"
            ));
    // 所有处理节点都汇入 END
    graph.addEdge("weather_handler", END);
    graph.addEdge("math_handler", END);
    graph.addEdge("joke_handler", END);
    graph.addEdge("fallback_handler", END);

    return graph.compile();
}

private Map<String, Object> analyzeIntent(Map<String, Object> state) {
    String userInput = (String) state.get("user_input");
    String intent = chatClient.prompt()
            .system("分析用户意图,只返回一个词:weather(天气)、math(数学计算)、joke(笑话)、unknown(其他)。")
            .user(userInput)
            .call()
            .content().trim().toLowerCase();
    state.put("intent", intent);
    return state;
}

private String routeByIntent(Map<String, Object> state) {
    String intent = (String) state.getOrDefault("intent", "unknown");
    // 保证返回值在条件边的Map key中
    return List.of("weather", "math", "joke").contains(intent) ? intent : "unknown";
}

private Map<String, Object> weatherHandler(Map<String, Object> state) {
    String query = (String) state.get("user_input");
    String weather = "模拟天气结果:晴天,25°C"; // 此处可以调用真实天气API
    state.put("answer", "根据查询," + weather);
    return state;
}

private Map<String, Object> mathHandler(Map<String, Object> state) {
    String query = (String) state.get("user_input");
    String result = chatClient.prompt()
            .system("请解决以下数学问题,只输出最终结果。")
            .user(query)
            .call().content();
    state.put("answer", result);
    return state;
}

private Map<String, Object> jokeHandler(Map<String, Object> state) {
    String joke = chatClient.prompt()
            .system("讲一个简短的笑话。")
            .call().content();
    state.put("answer", joke);
    return state;
}

private Map<String, Object> fallbackHandler(Map<String, Object> state) {
    state.put("answer", "抱歉,我无法处理这个问题,请尝试询问天气、数学或笑话。");
    return state;
}

Controller

private final Graph routingGraph;

public WorkflowController(@Qualifier("blogChainGraph") Graph blogChainGraph,
                          @Qualifier("parallelTranslationGraph") Graph parallelTranslationGraph,
                          @Qualifier("routingGraph") Graph routingGraph) {
    this.blogChainGraph = blogChainGraph;
    this.parallelTranslationGraph = parallelTranslationGraph;
    this.routingGraph = routingGraph;
}

@GetMapping("/workflow/route")
public String route(@RequestParam String q) {
    Map<String, Object> initial = new HashMap<>();
    initial.put("user_input", q);
    Map<String, Object> finalState = routingGraph.invoke(initial);
    return (String) finalState.get("answer");
}

测试

  • http://localhost:8080/workflow/route?q=北京天气
  • http://localhost:8080/workflow/route?q=3.14 * 25 + 18
  • http://localhost:8080/workflow/route?q=讲个笑话
  • http://localhost:8080/workflow/route?q=你是谁

你会看到不同的意图走到了对应的处理节点。

4.5 综合案例:智能客服工作流

现在我们把链式、路由、并行组合成一个完整的智能客服流水线。流程如下:

  1. 意图分析(AI 节点):判断用户意图 —— 查订单、投诉、咨询。
  2. 信息提取(AI 节点):提取关键信息(订单号、投诉内容等)。
  3. 路由:根据意图分发给不同的处理节点。
    • 查订单 → 查询物流 API
    • 投诉 → 记录投诉并生成工单
    • 咨询 → 直接生成 FAQ 回复
  4. 并行节点:在生成最终回复的同时,执行两个任务:
    • 生成一段有人情味的回复(AI 节点)
    • 记录本次会话日志(模拟写数据库)
  5. 汇总:将回复和日志状态合并,输出最终结果。

我们将这个工作流定义为 customerServiceGraph

@Bean
public Graph customerServiceGraph() {
    StateGraph<Map<String, Object>> graph = new StateGraph<>(Map.class);

    // 节点定义
    graph.addNode("intent_analysis", this::csIntentAnalysis);
    graph.addNode("info_extraction", this::csInfoExtraction);
    graph.addNode("order_query", this::csOrderQuery);
    graph.addNode("complaint_handler", this::csComplaintHandler);
    graph.addNode("faq_handler", this::csFaqHandler);

    // 并行节点:生成回复、记录日志
    graph.addNode("response_gen", this::csGenerateResponse);
    graph.addNode("log_writer", this::csWriteLog);
    graph.addNode("aggregator", state -> state); // 汇聚节点

    // 边
    graph.addEdge(START, "intent_analysis");
    graph.addEdge("intent_analysis", "info_extraction");
    graph.addConditionalEdges("info_extraction",
            this::csRouteByIntent,
            Map.of(
                    "order", "order_query",
                    "complaint", "complaint_handler",
                    "faq", "faq_handler"
            ));

    // 处理完后并行执行 response_gen 和 log_writer
    graph.addEdge("order_query", "response_gen");
    graph.addEdge("order_query", "log_writer");
    graph.addEdge("complaint_handler", "response_gen");
    graph.addEdge("complaint_handler", "log_writer");
    graph.addEdge("faq_handler", "response_gen");
    graph.addEdge("faq_handler", "log_writer");

    // 汇聚到 aggregator,然后结束
    graph.addEdge("response_gen", "aggregator");
    graph.addEdge("log_writer", "aggregator");
    graph.addEdge("aggregator", END);

    return graph.compile();
}

// === 节点方法 ===

private Map<String, Object> csIntentAnalysis(Map<String, Object> state) {
    String input = (String) state.get("user_input");
    String intent = chatClient.prompt()
            .system("将用户意图分类为:order(查订单)、complaint(投诉)、faq(一般咨询),只返回一个词。")
            .user(input)
            .call().content().trim();
    state.put("intent", intent);
    return state;
}

private Map<String, Object> csInfoExtraction(Map<String, Object> state) {
    String input = (String) state.get("user_input");
    String info = chatClient.prompt()
            .system("提取用户消息中的关键信息,如订单号、投诉内容等,用简洁JSON格式输出。")
            .user(input)
            .call().content();
    state.put("extracted_info", info);
    return state;
}

private String csRouteByIntent(Map<String, Object> state) {
    return (String) state.getOrDefault("intent", "faq");
}

private Map<String, Object> csOrderQuery(Map<String, Object> state) {
    // 模拟查询物流
    state.put("order_result", "订单已发货,预计明天到达");
    return state;
}

private Map<String, Object> csComplaintHandler(Map<String, Object> state) {
    state.put("complaint_result", "投诉已记录,客服将在2小时内联系您");
    return state;
}

private Map<String, Object> csFaqHandler(Map<String, Object> state) {
    state.put("faq_result", "这是常见问题解答:...");
    return state;
}

private Map<String, Object> csGenerateResponse(Map<String, Object> state) {
    String intent = (String) state.get("intent");
    String context = state.containsKey("order_result") ?
            state.get("order_result").toString() :
            state.getOrDefault("complaint_result", state.getOrDefault("faq_result", "")).toString();
    String response = chatClient.prompt()
            .system("你是一个客服助手。根据处理结果生成一段礼貌、有帮助的回复。")
            .user("处理结果:" + context + "\n用户原话:" + state.get("user_input"))
            .call().content();
    state.put("final_reply", response);
    return state;
}

private Map<String, Object> csWriteLog(Map<String, Object> state) {
    // 模拟写日志到数据库
    System.out.println("日志记录:用户输入=" + state.get("user_input") + ", 意图=" + state.get("intent"));
    state.put("log_saved", true);
    return state;
}

Controller

@GetMapping("/workflow/customer-service")
public String customerService(@RequestParam String q) {
    Map<String, Object> initial = new HashMap<>();
    initial.put("user_input", q);
    Map<String, Object> finalState = customerServiceGraph.invoke(initial);
    return (String) finalState.get("final_reply");
}

测试

  • 查订单:/workflow/customer-service?q=订单123456到哪了
  • 投诉:/workflow/customer-service?q=我要投诉,产品有质量问题
  • 咨询:/workflow/customer-service?q=你们的工作时间是?

你会得到经过完整流水线处理后的专业客服回复,并且日志已“写入”。

五、运行与演示

启动应用,依次访问上述四个演示端点,观察控制台日志输出,你可以看到节点执行顺序、状态变化。

5.1 工作流调试技巧

application.yml 中开启 DEBUG 日志:

logging:
  level:
    com.alibaba.cloud.ai.graph: DEBUG

启动后调用接口,控制台会打印每个节点的输入状态、执行时间以及路由决策,非常方便定位问题。

5.2 状态快照与异常恢复

当前工作流执行过程中,如果某个节点抛出异常,整个图会终止,并抛出异常。如果你希望支持断点续跑,需要引入状态持久化机制(后续专门篇章讲解),目前版本中状态仅存在于内存中。

六、常见问题与避坑提示

问题一:节点忘记返回 state

这是最常见的新手错误。每个节点函数必须 return state;,如果你在函数内部修改了 state 但没有显式返回,下游节点拿不到修改。务必在每个节点末尾 return state;

问题二:条件边路由返回值不匹配

addConditionalEdges 中的 Map 的 key 必须与路由函数的返回值完全一致(区分大小写)。如果路由函数返回了一个不存在的 key,工作流会抛出 IllegalStateException。可以通过打印日志或调试确认返回值。

问题三:并行节点写入冲突

如果多个并行节点同时向 state 中写入同一个 key,后写入的值会覆盖前面的。因此并行节点应该写入互不重叠的 key,最后在汇聚节点合并。上面的并行翻译就是分别用 english, japanese, french

问题四:ChatClient 未自动配置导致空指针

Spring AI Alibaba 在引入了 dashscope starter 并且配置了 api-key 后会自动创建 ChatClient。如果报 No qualifying bean of type 'ChatClient',请检查 application.yml 中是否正确配置了 spring.ai.dashscope.api-key

问题五:状态中 key 值拼写错误

在节点间传递时,state 的 key 是字符串,没有任何编译期检查。前后节点使用的 key 不一致会导致取值时为 null。建议使用常量类统一管理 key 名,避免拼写错误。

问题六:大工作流导致内存或 Token 爆炸

如果你的工作流有十几个节点,每个节点都调用大模型,而且输入的 state 中携带大量历史数据,Token 会飞速增长。可以考虑对 state 进行瘦身,只保留当前任务所需的关键信息。

七、小结与下一步预告

本篇回顾

  • 理解了什么场景下需要工作流编排:多步骤、有分支、有并行的 AI 任务。
  • 掌握了 StateGraph 的基本构建方法:定义节点、连接边(普通边和条件边)、编译图、调用 invoke
  • 通过四个实战案例,完整覆盖了链式、并行、路由以及它们的组合。
  • 学会了工作流调试技巧和常见避坑点。

下一步预告

现在你的工作流已经可以跑起来了,但每次重启应用,执行中的状态都会丢失。如果工作流跑了半小时突然崩溃,重新开始将损失大量 Token 和时间。下一篇我们将学习 Spring AI Alibaba 工作流持久化,把工作流状态存入数据库或 Redis,实现断点续跑和历史回溯,让你的工作流真正达到生产级可用。

下一篇《Spring AI Alibaba 工作流持久化:图编排的状态存储与恢复》见。


本系列博客基于 Spring AI 1.1.6 和 Spring AI Alibaba 1.1.2.0 版本编写。图式编排 API 仍在快速演进中,部分 API 可能会有调整,请关注 Spring AI Alibaba 官方文档 获取最新版本信息。工作流实战中建议合理控制节点粒度和 Token 消耗,避免成本失控。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐