Spring AI Alibaba 图式编排:用工作流驱动复杂 AI 任务
前面我们已经解锁了对话、图像、语音、视频等各种单点能力。但现实中的 AI 应用往往不是一个简单的“一问一答”,而是一连串有顺序、有条件的协作过程。今天,我们就来学习如何像搭积木一样,用 Spring AI Alibaba 的图式编排(Graph-based Orchestration)能力,把多个 AI 任务串联成一条自动化流水线。
想一想你在厨房里做一道复杂料理:切菜、焯水、爆炒、勾芡,每一步都有先后顺序,有些步骤还能同时进行。Spring AI Alibaba 借鉴了 LangGraph 的图编排思想,让我们能用 Java 代码定义一张“任务流程图”,每个节点负责一个具体的任务(可以是调用大模型、执行 Java 方法、甚至调用另一个子流程),节点之间通过边连接,数据以状态(State)的形式在节点间流转。今天我们会依次搞定链式工作流、并行化工作流和路由工作流,最后用一个智能客服的完整示例把它们组合在一起。
读完本篇,你将能够用一张图来管理复杂的 AI 业务流水线,而不再依赖一堆凌乱的 if-else 和方法调用。
一、痛点场景:单次 AI 调用不够用的时候
场景一:智能客服的完整流程
你做了一个客服机器人。用户问“我的订单怎么还没到?”,你的流程其实是:
- 用 AI 提取用户问题中的关键信息(订单号、意图)。
- 根据意图调用内部 API 查询物流状态。
- 把查询结果交给另一个 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 + 18http://localhost:8080/workflow/route?q=讲个笑话http://localhost:8080/workflow/route?q=你是谁
你会看到不同的意图走到了对应的处理节点。
4.5 综合案例:智能客服工作流
现在我们把链式、路由、并行组合成一个完整的智能客服流水线。流程如下:
- 意图分析(AI 节点):判断用户意图 —— 查订单、投诉、咨询。
- 信息提取(AI 节点):提取关键信息(订单号、投诉内容等)。
- 路由:根据意图分发给不同的处理节点。
- 查订单 → 查询物流 API
- 投诉 → 记录投诉并生成工单
- 咨询 → 直接生成 FAQ 回复
- 并行节点:在生成最终回复的同时,执行两个任务:
- 生成一段有人情味的回复(AI 节点)
- 记录本次会话日志(模拟写数据库)
- 汇总:将回复和日志状态合并,输出最终结果。
我们将这个工作流定义为 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 消耗,避免成本失控。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)