Spring AI Alibaba + LangGraph 工作流编排
Spring AI Alibaba + LangGraph 工作流编排实战
Spring AI Alibaba 是阿里巴巴基于 Spring AI 构建的企业级扩展,原生集成通义千问(Qwen)系列模型,并引入 LangGraph 实现有状态、可循环的 AI 工作流编排。这是 2026 年阿里、蚂蚁、字节等大厂 Java AI 岗位的高频考点。
一、什么是 Spring AI Alibaba
Spring AI Alibaba 并非对 Spring AI 的简单封装,而是阿里巴巴结合云原生实践深度定制的 AI 应用框架:
核心特性:
| 特性 | 说明 |
|---|---|
| Qwen 全系列支持 | qwen-turbo / qwen-plus / qwen-max / qwen-vl(多模态)等 |
| LangGraph 集成 | StateGraph 有状态工作流,支持条件路由、循环、Human-in-the-loop |
| 阿里云生态 | OSS、TableStore(向量存储)、百炼平台无缝接入 |
| 国内合规 | 数据不出境,符合金融/政务行业合规要求 |
二、环境搭建
2.1 Maven 依赖
<properties>
<spring-ai-alibaba.version>1.0.0-M6.1</spring-ai-alibaba.version>
<spring-boot.version>3.3.5</spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<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>
<dependencies>
<!-- Spring AI Alibaba 核心(含 DashScope + LangGraph) -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-core</artifactId>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- LangGraph 状态图(可选独立引入) -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-graph-core</artifactId>
</dependency>
</dependencies>2.2 application.yml 配置
spring:
ai:
dashscope:
# 从阿里云百炼平台获取:https://bailian.console.aliyun.com/
api-key: ${DASHSCOPE_API_KEY:sk-your-api-key}
chat:
options:
model: qwen-plus # 推荐:平衡性能与成本
temperature: 0.7
top-p: 0.8
max-tokens: 2048
embedding:
options:
model: text-embedding-v3 # 通义千问 Embedding 模型获取 API Key: 登录 阿里云百炼,进入"API-KEY 管理"创建 Key,新用户有免费 Token 额度。
三、LangGraph 核心概念
LangGraph 将 AI 工作流抽象为有向图:
关键概念说明:
| 概念 | Java 类型 | 说明 |
|---|---|---|
StateGraph | StateGraph<S> | 工作流定义,S 是状态类型 |
Node | NodeAction<S> 函数式接口 | 节点执行逻辑,接收状态,返回更新后的状态 |
Edge | addEdge(from, to) | 无条件边,执行完 from 后跳到 to |
ConditionalEdge | addConditionalEdges(...) | 条件边,根据状态字段决定下一个节点 |
State | 自定义 POJO / Map | 节点间共享的数据容器 |
Interrupt | NodeInterruptException | 暂停工作流,等待人工输入 |
四、示例一:基础 Qwen 模型集成
最简单的集成方式,直接使用 ChatClient。
代码实现
package com.example.ai.controller;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
@RestController
@RequestMapping("/api/v1/qwen")
public class QwenChatController {
private final ChatClient chatClient;
// Spring AI Alibaba 自动装配 DashScope ChatModel
public QwenChatController(ChatClient.Builder builder) {
this.chatClient = builder
.defaultSystem("你是通义千问,阿里巴巴研发的 AI 助手,回答简洁专业。")
.build();
}
// 同步调用
@PostMapping("/chat")
public String chat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
// 流式调用(SSE)
@GetMapping(value = "/stream", produces = "text/event-stream")
public Flux<String> stream(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
}测试命令
# 同步调用
curl -X POST "http://localhost:8080/api/v1/qwen/chat" \
-d "message=用一句话解释微服务架构"
# 流式调用
curl -N "http://localhost:8080/api/v1/qwen/stream?message=介绍一下通义千问的特点"预期输出
微服务架构将单体应用拆分为多个独立部署、松耦合的小服务,
每个服务负责单一业务功能,通过 API 通信,可独立开发、部署和扩展。五、示例二:简单 StateGraph(两节点流水线)
用 LangGraph 实现:输入 → 分析节点 → 总结节点 → 输出。
状态类定义
package com.example.ai.graph;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class AnalysisState {
private String userInput; // 用户原始输入
private String analysisResult; // 分析节点输出
private String summaryResult; // 总结节点输出
private String error; // 错误信息(节点失败时设置)
}StateGraph 构建
package com.example.ai.graph;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.GraphRunConfig;
import com.alibaba.cloud.ai.graph.node.NodeAction;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SimpleGraphConfig {
@Bean
public StateGraph<AnalysisState> simpleAnalysisGraph(ChatClient.Builder builder) {
ChatClient chatClient = builder.build();
// 节点 1:分析节点 —— 对输入内容做深度分析
NodeAction<AnalysisState> analyzeNode = state -> {
String analysis = chatClient.prompt()
.system("你是一个技术分析专家,对用户输入进行要点提炼和技术分析。")
.user("请分析以下内容的技术要点:\n" + state.getUserInput())
.call()
.content();
return state.setAnalysisResult(analysis);
};
// 节点 2:总结节点 —— 将分析结果提炼为行动建议
NodeAction<AnalysisState> summarizeNode = state -> {
String summary = chatClient.prompt()
.system("你是一个简洁的技术顾问,将分析报告提炼为 3 条行动建议。")
.user("基于以下分析,给出 3 条具体建议:\n" + state.getAnalysisResult())
.call()
.content();
return state.setSummaryResult(summary);
};
// 构建有向图
return StateGraph.<AnalysisState>builder()
.addNode("analyze", analyzeNode) // 注册分析节点
.addNode("summarize", summarizeNode) // 注册总结节点
.addEdge(StateGraph.START, "analyze") // START → 分析节点
.addEdge("analyze", "summarize") // 分析节点 → 总结节点
.addEdge("summarize", StateGraph.END) // 总结节点 → END
.build();
}
}Controller 层
@PostMapping("/simple-graph")
public Map<String, String> runSimpleGraph(@RequestParam String input) {
AnalysisState initialState = new AnalysisState().setUserInput(input);
AnalysisState result = simpleAnalysisGraph
.compile()
.invoke(initialState, GraphRunConfig.builder().build());
return Map.of(
"analysis", result.getAnalysisResult(),
"summary", result.getSummaryResult()
);
}工作流图
测试命令
curl -X POST "http://localhost:8080/api/v1/graph/simple-graph" \
-d "input=我们的订单系统每天有10万订单,MySQL 单表数据量已超过5000万,查询越来越慢"预期输出
{
"analysis": "技术要点:\n1. 大数据量问题:5000万行已超过 MySQL 单表推荐上限...\n2. 查询性能瓶颈:索引效率下降,全表扫描风险...\n3. 数据增长趋势:按 10 万/天,约 1.5 年翻倍...",
"summary": "行动建议:\n1. 短期:优化索引,对冷数据归档分离热温冷三层存储\n2. 中期:实施分库分表(ShardingSphere),按 order_id 取模分 16 张表\n3. 长期:引入 TiDB 或 OceanBase,实现分布式数据库平滑迁移"
}六、示例三:条件路由(基于用户意图分类)
根据用户意图动态决定处理路径,是 Agent 工作流的核心模式。
状态类
@Data
@Accessors(chain = true)
public class RouterState {
private String userInput;
private String intent; // 意图分类结果:TECH / BUSINESS / UNKNOWN
private String response;
}条件路由 StateGraph
@Bean
public StateGraph<RouterState> routerGraph(ChatClient.Builder builder) {
ChatClient chatClient = builder.build();
// 意图分类节点
NodeAction<RouterState> classifyNode = state -> {
String intent = chatClient.prompt()
.system("""
你是一个意图分类器,只能回复以下三个词之一,不要有任何其他内容:
- TECH:技术问题(编程、架构、数据库、算法等)
- BUSINESS:业务问题(需求、流程、商业模式等)
- UNKNOWN:无法判断或不相关问题
""")
.user("对以下输入进行意图分类:" + state.getUserInput())
.call()
.content()
.trim()
.toUpperCase();
return state.setIntent(intent);
};
// 技术问题处理节点
NodeAction<RouterState> techNode = state -> {
String response = chatClient.prompt()
.system("你是资深 Java 架构师,提供专业技术解决方案,包含代码示例。")
.user(state.getUserInput())
.call()
.content();
return state.setResponse("[技术专家] " + response);
};
// 业务问题处理节点
NodeAction<RouterState> businessNode = state -> {
String response = chatClient.prompt()
.system("你是产品经理和业务分析师,从商业价值角度分析问题,给出方案建议。")
.user(state.getUserInput())
.call()
.content();
return state.setResponse("[业务顾问] " + response);
};
// 兜底节点
NodeAction<RouterState> fallbackNode = state ->
state.setResponse("抱歉,无法识别您的问题类型,请描述得更具体一些。");
// 条件路由函数:根据 intent 字段决定下一个节点
return StateGraph.<RouterState>builder()
.addNode("classify", classifyNode)
.addNode("tech_handler", techNode)
.addNode("business_handler", businessNode)
.addNode("fallback", fallbackNode)
.addEdge(StateGraph.START, "classify")
// 条件边:classify 节点后根据 intent 路由
.addConditionalEdges(
"classify",
state -> state.getIntent(), // 条件函数:返回路由 key
Map.of(
"TECH", "tech_handler",
"BUSINESS", "business_handler",
"UNKNOWN", "fallback"
)
)
.addEdge("tech_handler", StateGraph.END)
.addEdge("business_handler", StateGraph.END)
.addEdge("fallback", StateGraph.END)
.build();
}工作流图
测试命令
# 触发 TECH 路由
curl -X POST "http://localhost:8080/api/v1/graph/router" \
-d "input=如何用Redis实现分布式锁?"
# 触发 BUSINESS 路由
curl -X POST "http://localhost:8080/api/v1/graph/router" \
-d "input=我们的电商平台用户留存率下降,怎么改善?"七、示例四:多 Agent 工作流(研究→写作→审核流水线)
三个 Agent 串联工作,模拟内容生产流水线。这是面试中考查 Agent 架构设计的核心场景。
状态类
@Data
@Accessors(chain = true)
public class ContentPipelineState {
private String topic; // 用户指定的写作主题
private String researchResult; // 研究 Agent 输出:背景资料
private String draftContent; // 写作 Agent 输出:初稿
private String reviewFeedback; // 审核 Agent 输出:审核意见
private String finalContent; // 最终定稿内容
private int revisionCount; // 修改轮次(防止无限循环)
private boolean approved; // 是否通过审核
}多 Agent StateGraph
@Bean
public StateGraph<ContentPipelineState> contentPipelineGraph(ChatClient.Builder builder) {
ChatClient chatClient = builder.build();
// Agent 1:研究 Agent —— 收集主题相关背景知识
NodeAction<ContentPipelineState> researchAgent = state -> {
String research = chatClient.prompt()
.system("""
你是专业研究员,负责为写作提供准确的背景资料。
输出格式:
【核心概念】(2-3 个关键点)
【技术细节】(重要的技术事实和数据)
【最佳实践】(行业公认的实践案例)
""")
.user("请研究以下主题,收集写作所需的背景知识:" + state.getTopic())
.call()
.content();
return state.setResearchResult(research);
};
// Agent 2:写作 Agent —— 基于研究结果生成内容
NodeAction<ContentPipelineState> writerAgent = state -> {
String context = state.getRevisionCount() > 0
? "上一版审核意见:\n" + state.getReviewFeedback() + "\n\n请修改改进。\n"
: "";
String draft = chatClient.prompt()
.system("你是技术写作专家,能将研究资料转化为清晰易懂的技术文章。")
.user(context + "基于以下研究资料,为主题【" + state.getTopic() + "】撰写技术文章:\n\n"
+ state.getResearchResult())
.call()
.content();
return state.setDraftContent(draft);
};
// Agent 3:审核 Agent —— 检查内容质量并给出通过/修改意见
NodeAction<ContentPipelineState> reviewerAgent = state -> {
String review = chatClient.prompt()
.system("""
你是严格的技术内容审核专家。按以下标准评审文章:
1. 技术准确性(最重要)
2. 逻辑清晰度
3. 代码示例质量(如有)
4. 结构完整性
最后必须给出明确结论:
- 如果文章质量良好,以"【通过】"开头
- 如果需要修改,以"【需要修改】"开头,并列出具体问题
""")
.user("请审核以下技术文章:\n\n" + state.getDraftContent())
.call()
.content();
boolean approved = review.startsWith("【通过】");
return state
.setReviewFeedback(review)
.setApproved(approved)
.setFinalContent(approved ? state.getDraftContent() : null);
};
// 处理修改请求(更新修改轮次)
NodeAction<ContentPipelineState> revisionNode = state ->
state.setRevisionCount(state.getRevisionCount() + 1);
return StateGraph.<ContentPipelineState>builder()
.addNode("research", researchAgent)
.addNode("write", writerAgent)
.addNode("review", reviewerAgent)
.addNode("revise", revisionNode)
.addEdge(StateGraph.START, "research")
.addEdge("research", "write")
.addEdge("write", "review")
// 审核后的条件路由:通过则结束,否则修改(最多 2 轮)
.addConditionalEdges(
"review",
state -> {
if (state.isApproved()) return "approved";
if (state.getRevisionCount() >= 2) return "max_revision";
return "needs_revision";
},
Map.of(
"approved", StateGraph.END,
"needs_revision", "revise",
"max_revision", StateGraph.END // 超出修改次数,强制结束
)
)
.addEdge("revise", "write") // 修改后重新写作(形成循环)
.build();
}工作流图(含循环)
测试命令
curl -X POST "http://localhost:8080/api/v1/graph/content-pipeline" \
-d "topic=Java虚拟线程与传统线程池的性能对比"时序图
八、示例五:Human-in-the-Loop(人工干预节点)
Human-in-the-loop 允许工作流在关键节点暂停,等待人工确认后继续。这是生产环境 AI 工作流的安全保障机制。
状态类
@Data
@Accessors(chain = true)
public class ApprovalState {
private String taskDescription; // 待执行的任务描述
private String executionPlan; // AI 生成的执行计划
private String humanDecision; // 人工决策:APPROVE / REJECT
private String humanComment; // 人工备注
private String executionResult; // 执行结果(仅审批通过后有值)
}带人工审批的 StateGraph
@Bean
public StateGraph<ApprovalState> approvalWorkflow(ChatClient.Builder builder) {
ChatClient chatClient = builder.build();
// 节点 1:规划节点 —— AI 生成执行计划
NodeAction<ApprovalState> planNode = state -> {
String plan = chatClient.prompt()
.system("你是技术架构师,为运维任务制定详细可执行的操作计划,必须列出每步的风险和回滚方案。")
.user("请为以下任务制定执行计划:" + state.getTaskDescription())
.call()
.content();
return state.setExecutionPlan(plan);
};
// 节点 2:人工审批节点 —— 抛出中断异常,暂停工作流
NodeAction<ApprovalState> humanApprovalNode = state -> {
// NodeInterruptException 会暂停图的执行
// 框架将当前 state 序列化保存,等待外部调用 resume()
throw new com.alibaba.cloud.ai.graph.NodeInterruptException(
"等待人工审批",
state // 将当前状态随中断传出,方便前端展示
);
};
// 节点 3:执行节点 —— 仅在审批通过后运行
NodeAction<ApprovalState> executeNode = state -> {
if (!"APPROVE".equals(state.getHumanDecision())) {
return state.setExecutionResult("任务已被拒绝,原因:" + state.getHumanComment());
}
String result = chatClient.prompt()
.system("你是运维执行机器人,按照批准的计划逐步执行,实时汇报每步结果。")
.user("执行以下已批准的计划:\n" + state.getExecutionPlan())
.call()
.content();
return state.setExecutionResult(result);
};
// 条件边:根据人工决策路由
return StateGraph.<ApprovalState>builder()
.addNode("plan", planNode)
.addNode("human_approval", humanApprovalNode)
.addNode("execute", executeNode)
.addEdge(StateGraph.START, "plan")
.addEdge("plan", "human_approval")
.addConditionalEdges(
"human_approval",
state -> "APPROVE".equals(state.getHumanDecision()) ? "approved" : "rejected",
Map.of(
"approved", "execute",
"rejected", StateGraph.END
)
)
.addEdge("execute", StateGraph.END)
.build();
}审批 API Controller
@RestController
@RequestMapping("/api/v1/approval")
@RequiredArgsConstructor
public class ApprovalController {
private final StateGraph<ApprovalState> approvalWorkflow;
// 存储暂停中的工作流实例(生产环境用 Redis 持久化)
private final Map<String, CompiledGraph.ResumePoint<ApprovalState>>
pendingApprovals = new ConcurrentHashMap<>();
// 提交任务,工作流运行到审批节点自动暂停
@PostMapping("/submit")
public Map<String, Object> submitTask(@RequestParam String taskDescription) {
String taskId = UUID.randomUUID().toString();
ApprovalState initialState = new ApprovalState()
.setTaskDescription(taskDescription);
try {
approvalWorkflow.compile().invoke(initialState,
GraphRunConfig.builder().build());
} catch (NodeInterruptException e) {
// 捕获中断,保存 resume point
ApprovalState pausedState = (ApprovalState) e.getState();
pendingApprovals.put(taskId, e.getResumePoint());
return Map.of(
"taskId", taskId,
"status", "PENDING_APPROVAL",
"executionPlan", pausedState.getExecutionPlan(),
"message", "任务已生成执行计划,等待人工审批"
);
}
return Map.of("status", "COMPLETED");
}
// 人工审批接口
@PostMapping("/decide/{taskId}")
public Map<String, Object> decide(
@PathVariable String taskId,
@RequestParam String decision, // APPROVE 或 REJECT
@RequestParam(required = false) String comment
) {
var resumePoint = pendingApprovals.remove(taskId);
if (resumePoint == null) {
return Map.of("error", "任务不存在或已处理");
}
// 更新状态,注入人工决策
ApprovalState updatedState = resumePoint.getState()
.setHumanDecision(decision.toUpperCase())
.setHumanComment(comment);
// 恢复工作流执行
ApprovalState finalState = resumePoint.resume(updatedState);
return Map.of(
"taskId", taskId,
"decision", decision,
"result", finalState.getExecutionResult()
);
}
}工作流图
测试命令
# 第一步:提交任务
TASK_RESP=$(curl -s -X POST "http://localhost:8080/api/v1/approval/submit" \
-d "taskDescription=将生产环境 MySQL 从 5.7 升级到 8.0")
echo $TASK_RESP
TASK_ID=$(echo $TASK_RESP | jq -r '.taskId')
# 第二步:查看 AI 生成的执行计划(在审批前)
echo "执行计划:$(echo $TASK_RESP | jq -r '.executionPlan')"
# 第三步:人工审批(批准)
curl -X POST "http://localhost:8080/api/v1/approval/decide/$TASK_ID" \
-d "decision=APPROVE" \
-d "comment=计划完整,已确认备份,批准执行"
# 或者拒绝
curl -X POST "http://localhost:8080/api/v1/approval/decide/$TASK_ID" \
-d "decision=REJECT" \
-d "comment=需要先在测试环境验证,请重新规划"九、状态管理:节点间如何传递数据
状态(State)是 LangGraph 工作流的核心机制,所有节点通过共享同一个状态对象通信。
设计原则
状态设计最佳实践
// 1. 使用 Lombok @Accessors(chain=true) 实现流式 API
@Data
@Accessors(chain = true)
public class WorkflowState {
// 输入字段(只在入口节点设置)
private final String originalInput;
// 中间状态字段(各节点依次填充)
private String processedData;
private List<String> collectedResults = new ArrayList<>();
// 控制字段(用于条件路由)
private String currentStep;
private int retryCount;
private boolean hasError;
private String errorMessage;
// 输出字段(最终结果)
private String finalOutput;
}
// 2. 节点返回新状态(不修改原状态)
NodeAction<WorkflowState> safeNode = state -> {
// 正确:使用 Lombok setter 返回更新后的实例
return state.setProcessedData("处理结果");
// 不推荐:直接修改传入对象(虽然 Java 默认是引用传递,但与框架期望不符)
// state.processedData = "处理结果";
// return state;
};
// 3. 错误处理:在 State 中记录错误而非抛异常(除 NodeInterruptException 外)
NodeAction<WorkflowState> robustNode = state -> {
try {
String result = callExternalApi(state.getOriginalInput());
return state.setProcessedData(result);
} catch (Exception e) {
// 记录错误到 State,让后续节点或条件路由处理
return state
.setHasError(true)
.setErrorMessage("外部 API 调用失败:" + e.getMessage());
}
};生产环境状态持久化
// 将 State 序列化到 Redis,实现工作流跨 JVM 实例恢复
@Component
public class RedisStateStore {
private final RedisTemplate<String, String> redis;
private final ObjectMapper objectMapper;
public void save(String workflowId, Object state) {
try {
String json = objectMapper.writeValueAsString(state);
redis.opsForValue().set(
"workflow:state:" + workflowId,
json,
Duration.ofHours(24) // 24 小时过期
);
} catch (JsonProcessingException e) {
throw new RuntimeException("状态序列化失败", e);
}
}
public <T> T load(String workflowId, Class<T> stateClass) {
String json = redis.opsForValue().get("workflow:state:" + workflowId);
if (json == null) return null;
try {
return objectMapper.readValue(json, stateClass);
} catch (JsonProcessingException e) {
throw new RuntimeException("状态反序列化失败", e);
}
}
}十、面试高频问题汇总
Q1:Spring AI Alibaba 与 Spring AI 的关系是什么?
答:Spring AI Alibaba 是 Spring AI 的官方扩展实现,不是 fork。Spring AI 定义接口标准(ChatModel、EmbeddingModel、VectorStore),Spring AI Alibaba 提供基于 DashScope(通义千问 API)的具体实现。同时,Spring AI Alibaba 扩展了 Spring AI 没有的能力,比如 LangGraph 工作流引擎、阿里云 OSS 文档加载、百炼平台集成等。
Q2:LangGraph 的 StateGraph 和普通的责任链模式有什么区别?
答:责任链是线性的,节点按顺序传递请求,不支持分支和循环。StateGraph 是有向图,支持:①条件分支(addConditionalEdges,根据 State 决定下一个节点);②循环(节点可以指回前面的节点,实现多轮迭代);③并行执行(同一层次的节点可以并发执行);④中断恢复(NodeInterruptException + resume)。这使 StateGraph 天然适合复杂 Agent 工作流。
Q3:Human-in-the-loop 中工作流暂停后,JVM 重启了怎么办?
答:这是生产环境必须解决的问题。解决方案:① 捕获 NodeInterruptException 时,将暂停状态(包括 State 和 resume 所需的 checkpoint)序列化到 Redis 或数据库;② JVM 重启后,从持久化存储恢复 State;③ 调用 StateGraph.compile().invokeFromCheckpoint(checkpoint, updatedState) 从断点继续执行。Spring AI Alibaba 的 LangGraph 实现支持 Checkpoint 机制,对应 Python LangGraph 的 Persistence 概念。
Q4:多 Agent 工作流如何防止无限循环?
答:三种手段:①在 State 中设置 maxIterations 计数器,每轮递增,条件路由中检查是否超限;②设置工作流级别的超时(GraphRunConfig.builder().timeout(Duration.ofMinutes(5)).build());③审核 Agent 的评审标准要明确可达(避免 LLM 永远输出"需要修改")。示例四中用 revisionCount >= 2 作为强制退出条件即是此思路。
Q5:通义千问哪个模型适合工作流场景?
答:按场景选择:
qwen-turbo:速度最快,适合工作流中的意图分类、简单判断节点(低延迟优先)qwen-plus:性能与成本均衡,适合大多数工作流节点(推荐默认选择)qwen-max:能力最强,适合需要深度推理的关键节点(如代码生成、复杂分析)qwen-long:超长上下文(最高 1M tokens),适合 RAG 场景注入大量文档片段
工作流实践:在同一个 StateGraph 中,不同节点可以使用不同模型,在 NodeAction 中分别构建不同配置的 ChatClient 即可实现成本与质量的精细化控制。
本文代码基于 Spring AI Alibaba 1.0.0-M6.x + Spring Boot 3.3.x,框架 API 可能随正式版迭代更新,请参考 官方文档 核实最新 API。
