本文中將闡述下 AI 流程編排框架和 Spring AI Alibaba Graph 以及如何使用。
1. Agent 智能體
結合 Google 和 Authropic 對 Agent 的定義:Agent 的定義為:智能體(Agent)是能夠獨立運行,感知和理解現實世界并使用工具來實現最終目標的應用程序。
從架構上,可以將 Agent 分為兩類:
- Workflows 系統:人類干預做整體決策,LLMs 作為 workflows 鏈路的節點。
- 具有明確語義的系統,預先定義好 workflows 流程;
- LLMs 通過各個 Node 節點對 Workflows 路徑編排來達到最終效果。
- 智能體系統(Agents):LLMs 作為大腦決策,自驅動完成任務。
- LLMs 自己編排和規劃工具調用;
- 適用于模型驅動決策的場景。
以上兩種架構都在 Spring AI Alibaba 項目中有體現:一是 JManus 系統。二是基于 spring ai alibaba graph 構建的 DeepResearch 系統。
1. AI 智能體框架介紹
在過去一年中,AI Infra 快速發展,涌現了一系列以 LangChain 為代碼的 AI 應用開發框架,到最基礎的應用開發框架到智能體編排,AI 應用觀測等。此章節中主要介紹下 AI 應用的智能體編排框架。
1.1 Microsoft AutoGen
Github 地址:https://github.com/microsoft/autogen
由微軟開源的智能體開發框架:AutoGen 是一個用于創建可自主行動或與人類協同工作的多智能體 AI 應用程序的框架。
1.2 LangGraph
Github 地址:https://github.com/langchain-ai/langgraph
以 LangGraph 為基礎,使用圖結構的 AI 應用編排框架。由 LangChain 社區開發,社區活躍。
1.3 CrewAI
Github 地址:https://github.com/crewAIInc/crewAI
CrewAI 是一個精簡、快速的 Python 框架,完全從零構建,完全獨立于 LangChain 或其他代理框架。它為開發人員提供了高級的簡潔性和精確的底層控制,非常適合創建適合任何場景的自主 AI 代理。
2. Spring AI Alibaba Graph
Github 地址:https://github.com/alibaba/spring-ai-alibaba/tree/main/spring-ai-alibaba-graph
Spring AI Alibaba Graph 是一款面向 Java 開發者的工作流、多智能體框架,用于構建由多個 AI 模型或步驟組成的復雜應用。通過圖結構的定義,來描述智能體中的狀態流轉邏輯。
框架核心包括:StateGraph(狀態圖,用于定義節點和邊)、Node(節點,封裝具體操作或模型調用)、Edge(邊,表示節點間的跳轉關系)以及 OverAllState(全局狀態,貫穿流程共享數據)
2.1 快速入門
Demo 地址:https://github.com/deigmata-paideias/deigmata-paideias/tree/main/ai/exmaple/spring-ai-alibaba-graph-demo
pom.xml
<dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-dashscope</artifactId></dependency><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-graph-core</artifactId><version>1.0.0.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId></dependency>
</dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>3.4.5</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-bom</artifactId><version>1.0.0.2</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>
application.yml
server:port: 8081spring:ai:dashscope:api-key: ${AI_DASHSCOPE_API_KEY}
Config
import com.alibaba.cloud.ai.graph.GraphRepresentation;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.OverAllStateFactory;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.action.EdgeAction;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import com.alibaba.cloud.ai.graph.node.QuestionClassifierNode;
import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy;
import indi.yuluo.graph.customnode.RecordingNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.List;
import java.util.Map;import static com.alibaba.cloud.ai.graph.StateGraph.END;
import static com.alibaba.cloud.ai.graph.StateGraph.START;
import static com.alibaba.cloud.ai.graph.action.AsyncEdgeAction.edge_async;
import static com.alibaba.cloud.ai.graph.action.AsyncNodeAction.node_async;/*** Graph Demo:首先判斷評價正負,其次細分負面問題,最后輸出處理方案。** @author yuluo* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>*/@Configuration
public class GraphAutoConfiguration {private static final Logger logger = LoggerFactory.getLogger(GraphAutoConfiguration.class);/*** 定義一個工作流 StateGraph Bean.*/@Beanpublic StateGraph workflowGraph(ChatClient.Builder builder) throws GraphStateException {// LLMs BeanChatClient chatClient = builder.defaultAdvisors(new SimpleLoggerAdvisor()).build();// 定義一個 OverAllStateFactory,用于在每次執行工作流時創建初始的全局狀態對象。通過注冊若干 Key 及其更新策略來管理上下文數據// 注冊三個狀態 key 分別為// 1. input:用戶輸入的文本// 2. classifier_output:分類器的輸出結果// 3. solution:最終輸出結論// 使用 ReplaceStrategy(每次寫入替換舊值)策略處理上下文狀態對象中的數據,用于在節點中傳遞數據OverAllStateFactory stateFactory = () -> {OverAllState state = new OverAllState();state.registerKeyAndStrategy("input", new ReplaceStrategy());state.registerKeyAndStrategy("classifier_output", new ReplaceStrategy());state.registerKeyAndStrategy("solution", new ReplaceStrategy());return state;};// 創建 workflows 節點// 使用 Graph 框架預定義的 QuestionClassifierNode 來處理文本分類任務// 評價正負分類節點QuestionClassifierNode feedbackClassifier = QuestionClassifierNode.builder().chatClient(chatClient).inputTextKey("input").categories(List.of("positive feedback", "negative feedback")).classificationInstructions(List.of("Try to understand the user's feeling when he/she is giving the feedback.")).build();// 負面評價具體問題分類節點QuestionClassifierNode specificQuestionClassifier = QuestionClassifierNode.builder().chatClient(chatClient).inputTextKey("input").categories(List.of("after-sale service", "transportation", "product quality", "others")).classificationInstructions(List.of("What kind of service or help the customer is trying to get from us? Classify the question based on your understanding.")).build();// 編排 Node 節點,使用 StateGraph 的 API,將上述節點加入圖中,并設置節點間的跳轉關系// 首先將節點注冊到圖,并使用 node_async(...) 將每個 NodeAction 包裝為異步節點執行(提高吞吐或防止阻塞,具體實現框架已封裝)StateGraph stateGraph = new StateGraph("Consumer Service Workflow Demo", stateFactory)// 定義節點.addNode("feedback_classifier", node_async(feedbackClassifier)).addNode("specific_question_classifier", node_async(specificQuestionClassifier)).addNode("recorder", node_async(new RecordingNode()))// 定義邊(流程順序).addEdge(START, "feedback_classifier").addConditionalEdges("feedback_classifier",edge_async(new FeedbackQuestionDispatcher()),Map.of("positive", "recorder", "negative", "specific_question_classifier")).addConditionalEdges("specific_question_classifier",edge_async(new SpecificQuestionDispatcher()),Map.of("after-sale", "recorder", "transportation", "recorder", "quality", "recorder", "others","recorder"))// 圖的結束節點.addEdge("recorder", END);GraphRepresentation graphRepresentation = stateGraph.getGraph(GraphRepresentation.Type.PLANTUML,"workflow graph");System.out.println("\n\n");System.out.println(graphRepresentation.content());System.out.println("\n\n");return stateGraph;}public static class FeedbackQuestionDispatcher implements EdgeAction {@Overridepublic String apply(OverAllState state) {String classifierOutput = (String) state.value("classifier_output").orElse("");logger.info("classifierOutput: {}", classifierOutput);if (classifierOutput.contains("positive")) {return "positive";}return "negative";}}public static class SpecificQuestionDispatcher implements EdgeAction {@Overridepublic String apply(OverAllState state) {String classifierOutput = (String) state.value("classifier_output").orElse("");logger.info("classifierOutput: {}", classifierOutput);Map<String, String> classifierMap = new HashMap<>();classifierMap.put("after-sale", "after-sale");classifierMap.put("quality", "quality");classifierMap.put("transportation", "transportation");for (Map.Entry<String, String> entry : classifierMap.entrySet()) {if (classifierOutput.contains(entry.getKey())) {return entry.getValue();}}return "others";}}}
自定義 RecordingNode 節點
public class RecordingNode implements NodeAction {private static final Logger logger = LoggerFactory.getLogger(RecordingNode.class);@Overridepublic Map<String, Object> apply(OverAllState state) {String feedback = (String) state.value("classifier_output").get();Map<String, Object> updatedState = new HashMap<>();if (feedback.contains("positive")) {logger.info("Received positive feedback: {}", feedback);updatedState.put("solution", "Praise, no action taken.");}else {logger.info("Received negative feedback: {}", feedback);updatedState.put("solution", feedback);}return updatedState;}}
Controller
@RestController
@RequestMapping("/graph/demo")
public class GraphController {private final CompiledGraph compiledGraph;public GraphController(@Qualifier("workflowGraph") StateGraph stateGraph) throws GraphStateException {this.compiledGraph = stateGraph.compile();}@GetMapping("/chat")public String simpleChat(@RequestParam("query") String query) {return compiledGraph.invoke(Map.of("input", query)).flatMap(input -> input.value("solution")).get().toString();}}
2.2 訪問測試
### 正面
GET http://localhost:8081/graph/demo/chat?query="This product is excellent, I love it!"# Praise, no action taken.### 負面 1
GET http://localhost:8081/graph/demo/chat?query="這東西真垃圾啊,天吶,太難用了!"# ```json
# {"keywords": ["東西", "垃圾", "難用"], "category_name": "product quality"}
# ```### 負面 2
GET http://localhost:8081/graph/demo/chat?query="The product broke after one day, very disappointed."# ```json
# {"keywords": ["product", "broke", "one day", "disappointed"], "category_name": "product quality"}
# ```
3. 參考資料
- Google Agent 白皮書:https://www.kaggle.com/whitepaper-agents
- Authropic Agent:https://www.anthropic.com/engineering/building-effective-agents
- IBM Agents 智能體編排: https://www.ibm.com/cn-zh/think/topics/ai-agent-orchestration
- Spring AI Alibaba Graph:https://github.com/alibaba/spring-ai-alibaba/blob/main/spring-ai-alibaba-graph/README-zh.md