Spring AI Alibaba Agent Framework 从入门到实战

Spring AI Alibaba Agent Framework 从入门到实战

本文基于 Spring AI Alibaba 1.1.2.0,从零开始搭建一个基于 ReAct 模式的智能 Agent,涵盖核心概念、API 详解、完整代码示例及常见问题排查。


一、Agent Framework 是什么?

Spring AI Alibaba Agent Framework 是在 Graph 引擎之上构建的高级抽象,它封装了 ReAct(Reasoning + Acting)循环,让开发者能够快速创建具有推理和工具调用能力的智能 Agent。

1.1 ReAct 模式

ReAct 是一种将推理和行动相结合的 Agent 范式:

阶段 说明
思考(Reasoning) Agent 分析当前情况,决定下一步做什么
行动(Acting) 执行工具调用或生成最终答案
观察(Observation) 接收工具执行的结果
迭代 基于观察结果继续思考和行动,直到完成任务

这个循环使 Agent 能够:

  • 将复杂问题分解为多个步骤
  • 动态调整策略基于中间结果
  • 处理需要多次工具调用的任务
  • 在不确定的环境中做出决策

1.2 ReactAgent 工作原理

ReactAgent 基于 Graph 运行时构建,在以下节点间移动:

  • Model Node:调用 LLM 进行推理和决策
  • Tool Node:执行工具调用
  • Hook Nodes:在关键位置插入自定义逻辑

二、核心 API 详解

2.1 Model(模型配置)

Model 是 Agent 的推理引擎。使用 ChatModel 实例配置。

java 复制代码
DashScopeApi dashScopeApi = DashScopeApi.builder()
        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
        .build();

ChatModel chatModel = DashScopeChatModel.builder()
        .dashScopeApi(dashScopeApi)
        .defaultOptions(DashScopeChatOptions.builder()
                .withModel("deepseek-v4-flash")
                .withTemperature(0.7)
                .withMaxToken(2000)
                .build())
        .build();

2.2 Tools(工具定义)

工具赋予 Agent 执行操作的能力。使用 @Tool 注解定义。

java 复制代码
@Component
public class AgentTools {
    @Tool(description = "获取指定城市的当前天气信息")
    public String getWeather(@ToolParam(description = "城市名称") String city) {
        // 实现逻辑
        return "北京:晴,25°C";
    }
}

2.3 工具注册方式

ReactAgent.builder() 中,正确注册工具的方式是使用 .tools(ToolCallback...)

java 复制代码
ToolCallback[] toolCallbacks = MethodToolCallbackProvider.builder()
        .toolObjects(agentTools)
        .build()
        .getToolCallbacks();

ReactAgent agent = ReactAgent.builder()
        .name("assistant_agent")
        .model(chatModel)
        .tools(toolCallbacks)  // 传入 ToolCallback 数组
        .build();

2.4 System Prompt

System Prompt 塑造 Agent 的行为方式。

java 复制代码
ReactAgent agent = ReactAgent.builder()
        .name("my_agent")
        .model(chatModel)
        .systemPrompt("""
                你是一个智能助手,可以帮助用户完成各种任务。
                你有以下能力:
                1. 查询城市天气
                2. 获取当前时间
                3. 进行数学计算
                
                请根据用户的问题,选择合适的工具来解决问题。
                """)
        .build();

2.5 调用 Agent

java 复制代码
// 基础调用
AssistantMessage response = agent.call("北京今天天气怎么样?");
System.out.println(response.getText());

2.6 Memory(记忆)

使用 MemorySaver 维护对话上下文。

java 复制代码
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;
import com.alibaba.cloud.ai.graph.RunnableConfig;

ReactAgent agent = ReactAgent.builder()
        .name("chat_agent")
        .model(chatModel)
        .saver(new MemorySaver())
        .build();

// 使用 threadId 维护对话上下文
RunnableConfig config = RunnableConfig.builder()
        .threadId("user_123")
        .build();

agent.call("我叫张三", config);
agent.call("我叫什么名字?", config);  // 输出: "你叫张三"

2.7 迭代控制

使用 ModelCallLimitHook 限制 Agent 的迭代次数,防止无限循环。

java 复制代码
import com.alibaba.cloud.ai.graph.agent.hook.modelcalllimit.ModelCallLimitHook;

ReactAgent agent = ReactAgent.builder()
        .name("my_agent")
        .model(chatModel)
        .hooks(ModelCallLimitHook.builder().runLimit(5).build())
        .build();

注:

博客:

https://blog.csdn.net/badao_liumang_qizhi

三、环境搭建

3.1 依赖配置(pom.xml)

xml 复制代码
<properties>
    <java.version>17</java.version>
    <spring-ai-alibaba.version>1.1.2.0</spring-ai-alibaba.version>
    <jackson.version>2.16.2</jackson.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Agent Framework 核心 -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-agent-framework</artifactId>
        <version>${spring-ai-alibaba.version}</version>
    </dependency>

    <!-- DashScope 模型接入 -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        <version>${spring-ai-alibaba.version}</version>
    </dependency>
</dependencies>

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
    </repository>
</repositories>

3.2 配置文件(application.yml)

yaml 复制代码
server:
  port: 885

spring:
  ai:
    dashscope:
      api-key: ${DASHSCOPE_API_KEY}   # 从环境变量读取
      chat:
        options:
          model: deepseek-v4-flash     # 或 qwen-max

logging:
  level:
    com.alibaba.cloud.ai: debug

四、完整代码示例

4.1 工具类定义

java 复制代码
package com.badao.ai.tools;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

@Component
public class AgentTools {

    @Tool(description = "获取指定城市的当前天气信息")
    public String getWeather(@ToolParam(description = "城市名称,如:北京、上海") String city) {
        Map<String, String> weatherData = new HashMap<>();
        weatherData.put("北京", "晴,25°C,湿度45%");
        weatherData.put("上海", "多云,28°C,湿度60%");
        weatherData.put("杭州", "小雨,22°C,湿度75%");
        weatherData.put("深圳", "晴,30°C,湿度50%");
        return weatherData.getOrDefault(city, city + "的天气信息暂不可用");
    }

    @Tool(description = "获取当前日期和时间")
    public String getCurrentTime() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    @Tool(description = "计算两个数字的和")
    public double add(@ToolParam(description = "第一个数字") double a,
                      @ToolParam(description = "第二个数字") double b) {
        return a + b;
    }
}

4.2 Agent 配置类

java 复制代码
package com.badao.ai.config;

import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.agent.hook.modelcalllimit.ModelCallLimitHook;
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;
import com.badao.ai.tools.AgentTools;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AgentConfig {

    @Value("${spring.ai.dashscope.api-key}")
    private String apiKey;

    @Bean
    public ChatModel chatModel() {
        DashScopeApi dashScopeApi = DashScopeApi.builder()
                .apiKey(apiKey)
                .build();

        return DashScopeChatModel.builder()
                .dashScopeApi(dashScopeApi)
                .defaultOptions(DashScopeChatOptions.builder()
                        .withModel("deepseek-v4-flash")
                        .withTemperature(0.7)
                        .withMaxToken(2000)
                        .build())
                .build();
    }

    @Bean
    public ReactAgent assistantAgent(ChatModel chatModel, AgentTools agentTools) {
        // 将 @Tool 注解的对象转换为 ToolCallback 数组
        ToolCallback[] toolCallbacks = MethodToolCallbackProvider.builder()
                .toolObjects(agentTools)
                .build()
                .getToolCallbacks();

        return ReactAgent.builder()
                .name("assistant_agent")
                .model(chatModel)
                .tools(toolCallbacks)  // 传入 ToolCallback 数组
                .systemPrompt("""
                        你是一个智能助手,可以帮助用户完成各种任务。
                        你有以下能力:
                        1. 查询城市天气
                        2. 获取当前时间
                        3. 进行数学计算
                        
                        请根据用户的问题,选择合适的工具来解决问题。
                        """)
                .hooks(ModelCallLimitHook.builder().runLimit(5).build())
                .saver(new MemorySaver())
                .build();
    }
}

4.3 Service 层

java 复制代码
package com.badao.ai.service;

import com.alibaba.cloud.ai.graph.RunnableConfig;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Service
public class AgentService {

    private final ReactAgent agent;

    public AgentService(ReactAgent agent) {
        this.agent = agent;
    }

    public String chat(String userMessage) throws GraphRunnerException {
        AssistantMessage response = agent.call(userMessage);
        return response.getText();
    }

    public String chatWithMemory(String userMessage, String sessionId) throws GraphRunnerException {
        RunnableConfig config = RunnableConfig.builder()
                .threadId(sessionId)
                .build();
        AssistantMessage response = agent.call(userMessage, config);
        return response.getText();
    }
}

4.4 Controller 层

java 复制代码
package com.badao.ai.controller;

import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import com.badao.ai.service.AgentService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import java.util.Map;
import java.util.UUID;

@RestController
@RequestMapping("/api/agent")
public class AgentController {

    private static final Logger log = LoggerFactory.getLogger(AgentController.class);

    private final AgentService agentService;

    public AgentController(AgentService agentService) {
        this.agentService = agentService;
    }

    @PostMapping("/chat")
    public Map<String, Object> chat(@RequestBody Map<String, String> request) {
        String message = request.get("message");
        try {
            String response = agentService.chat(message);
            return Map.of("success", true, "response", response);
        } catch (GraphRunnerException e) {
            log.error("Agent 执行失败", e);
            return Map.of("success", false, "error", "Agent 执行失败: " + e.getMessage());
        }
    }

    @PostMapping("/chat/session")
    public Map<String, Object> chatWithSession(@RequestBody Map<String, String> request) {
        String message = request.get("message");
        String sessionId = request.getOrDefault("sessionId", UUID.randomUUID().toString());
        try {
            String response = agentService.chatWithMemory(message, sessionId);
            return Map.of("success", true, "sessionId", sessionId, "response", response);
        } catch (GraphRunnerException e) {
            log.error("Agent 执行失败", e);
            return Map.of("success", false, "error", "Agent 执行失败: " + e.getMessage());
        }
    }
}

4.5 启动类

java 复制代码
package com.badao.ai;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringAiDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringAiDemoApplication.class, args);
    }
}

五、测试与验证

5.1 测试命令

bash 复制代码
# 基础对话
curl -X POST http://localhost:885/api/agent/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "北京今天天气怎么样?"}'

# 带会话记忆的对话
curl -X POST http://localhost:885/api/agent/chat/session \
  -H "Content-Type: application/json" \
  -d '{"message": "我叫张三", "sessionId": "test-001"}'

curl -X POST http://localhost:885/api/agent/chat/session \
  -H "Content-Type: application/json" \
  -d '{"message": "我叫什么名字?", "sessionId": "test-001"}'

5.2 预期输出

json 复制代码
{
  "success": true,
  "response": "北京今天的天气是晴,25°C,湿度45%。"
}

测试记忆功能:

六、常见问题与解决方案

6.1 GraphRunnerException 未处理

错误Unhandled exception: com.alibaba.cloud.ai.graph.exception.GraphRunnerException

原因agent.call() 方法声明抛出受检异常,调用方必须处理。

解决方案

在 Service 方法上声明抛出,由 Controller 统一捕获处理:

java 复制代码
public String chat(String userMessage) throws GraphRunnerException {
    AssistantMessage response = agent.call(userMessage);
    return response.getText();
}

或在 Service 内部捕获并转换为运行时异常:

java 复制代码
public String chat(String userMessage) {
    try {
        AssistantMessage response = agent.call(userMessage);
        return response.getText();
    } catch (GraphRunnerException e) {
        throw new RuntimeException("Agent 执行失败", e);
    }
}

6.2 工具注册方法不正确

错误Cannot resolve method 'tools(AgentTools)'Cannot resolve method 'methodTools(AgentTools)'

原因ReactAgent.builder() 的正确工具注册方式是 .tools(ToolCallback...)

解决方案

java 复制代码
// 使用 MethodToolCallbackProvider 转换
ToolCallback[] toolCallbacks = MethodToolCallbackProvider.builder()
        .toolObjects(agentTools)
        .build()
        .getToolCallbacks();

return ReactAgent.builder()
        .name("assistant_agent")
        .model(chatModel)
        .tools(toolCallbacks)  // 传入 ToolCallback 数组
        .build();

6.3 Agent 无限循环

问题:Agent 不断调用工具而不产生最终答案,消耗大量 Token。

解决方案 :使用 ModelCallLimitHook 限制迭代次数。

java 复制代码
ReactAgent agent = ReactAgent.builder()
        .name("my_agent")
        .model(chatModel)
        .hooks(ModelCallLimitHook.builder().runLimit(5).build())
        .build();

6.4 工具调用失败

问题:工具执行时抛出异常,导致 Agent 中断。

解决方案:在工具方法中添加 try-catch,返回友好的错误信息。

java 复制代码
@Tool(description = "获取天气")
public String getWeather(String city) {
    try {
        // 调用外部 API
        return weatherApi.get(city);
    } catch (Exception e) {
        return "获取天气信息失败,请稍后重试。";
    }
}

6.5 多轮对话上下文丢失

问题:后续请求无法记住之前的对话内容。

解决方案 :使用 MemorySaverthreadId

java 复制代码
// 创建 Agent 时配置 MemorySaver
.saver(new MemorySaver())

// 调用时传入 threadId
RunnableConfig config = RunnableConfig.builder()
        .threadId("user_123")
        .build();
agent.call(userMessage, config);

6.6 导入包路径错误

常见包路径对照表

正确导入路径
ReactAgent com.alibaba.cloud.ai.graph.agent.ReactAgent
MemorySaver com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver
RunnableConfig com.alibaba.cloud.ai.graph.RunnableConfig
GraphRunnerException com.alibaba.cloud.ai.graph.exception.GraphRunnerException
ModelCallLimitHook com.alibaba.cloud.ai.graph.agent.hook.modelcalllimit.ModelCallLimitHook
ToolCallback org.springframework.ai.tool.ToolCallback
MethodToolCallbackProvider org.springframework.ai.tool.method.MethodToolCallbackProvider

七、总结

通过本文,你完整学习了 Spring AI Alibaba Agent Framework 的:

知识点 核心内容
ReAct 模式 Reasoning + Acting 循环
ReactAgent 基于 Graph 的 Agent 实现
Model 配置 ChatModel + ChatOptions
Tool 定义 @Tool 注解声明式定义
Tool 注册 MethodToolCallbackProvider → ToolCallback\[\]
System Prompt 塑造 Agent 行为
Memory MemorySaver + threadId
迭代控制 ModelCallLimitHook
异常处理 GraphRunnerException 统一处理

你可以基于这个完整的示例,进一步扩展 Agent 的能力,例如接入更多工具、实现多 Agent 协作、或集成 RAG 等高级功能。


📎 参考资源:Spring AI Alibaba GitHub | 官方文档