1. 什么是 Agent?为什么需要 Spring AI?

在深入了解代码之前,我们先弄清楚一个概念:Agent 到底是什么?

简单来说,Agent 是一种能够自主调用工具、多步推理并完成复杂任务的 AI 应用形态。它和普通的“一问一答”聊天机器人最大的区别在于:

  • 普通聊天机器人:你问它答,只依赖模型自身知识;
  • Agent:模型可以调用外部工具(如搜索网页、查询数据库、调用本地函数),并根据工具返回的结果继续推理,直到完成任务。

Spring AI 是 Spring 官方推出的 AI 应用开发框架。它的核心价值在于:

  1. 统一的 AI 接口抽象:一套 API 适配 OpenAI、Ollama、通义千问、智谱等多种大模型;
  2. 原生支持 Agent 与 Tool Calling:把 Spring 的 Bean 轻松变成模型可调用的工具;
  3. 融入 Spring 生态:自动配置、依赖注入、可观测性等都和 Spring Boot 无缝集成。

下面我们就从零开始,搭建一个真正能调用工具、能“干活”的 Spring AI Agent。


2. 环境准备与项目初始化

在开始编码前,请准备好以下环境:

环境版本要求说明
JDK17 及以上Spring Boot 3.x 要求 JDK 17+
Maven3.6+用于构建项目
IDE任意推荐 IntelliJ IDEA
大模型 API KeyOpenAI / 通义千问 / Ollama 等本教程以 OpenAI 兼容接口为例

2.1 创建 Spring Boot 项目

可以通过 Spring Initializr 创建项目,也可以使用 IDEA 新建 Spring Boot 项目。这里推荐手动创建一个最简 Maven 项目,便于你理解每一处配置。

首先创建 pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.5</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>spring-ai-agent-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-ai-agent-demo</name>
    <description>我的第一个 Spring AI Agent</description>

    <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.0.0-M3</spring-ai.version>
    </properties>

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

        <!-- Spring AI OpenAI 支持,如果你用其他模型请选择对应 starter -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

说明:Spring AI 目前仍在快速迭代中,1.0.0-M3 是里程碑版本。实际使用时请根据官方文档选择最新稳定版本。如果你使用的是 Ollama 本地模型,只需把 spring-ai-openai-spring-boot-starter 换成 spring-ai-ollama-spring-boot-starter。


3. 添加配置并连接大模型

创建主启动类:

package com.example.agentdemo;

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

@SpringBootApplication
public class AgentDemoApplication {

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

随后在 src/main/resources/application.yml 中配置模型连接信息:

spring:
  application:
    name: spring-ai-agent-demo
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      base-url: https://api.openai.com
      chat:
        options:
          model: gpt-4o-mini
          temperature: 0.7

如果你使用的是国内兼容 OpenAI 协议的模型服务,只需要修改 base-url 和 api-key 即可,例如:

spring:
  ai:
    openai:
      api-key: ${DASHSCOPE_API_KEY}
      base-url: https://dashscope.aliyuncs.com/compatible-mode
      chat:
        options:
          model: qwen-plus

这样配置完成后,Spring AI 就会自动创建 ChatModel Bean,供后续使用。


4. 定义你的第一个工具(Tool)

Agent 的能力来自工具。在 Spring AI 中,把一个普通 Java 方法变成模型可调用的工具非常简单:只需要在方法上添加 @Tool 注解。

下面我们定义两个实用工具:查询天气 和 数学计算。

4.1 创建天气服务工具

package com.example.agentdemo.tool;

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

@Service
public class WeatherTool {

    @Tool(description = "根据城市名称查询该城市当前的天气情况")
    public String getWeather(
            @ToolParam(description = "要查询天气的城市名称,例如:北京") String city) {
        // 这里模拟查询天气,实际项目中可以替换为调用第三方天气 API
        return city + "当前天气晴朗,气温 22 摄氏度,空气质量良好。";
    }

    @Tool(description = "计算两个浮点数的加减乘除结果")
    public double calculate(
            @ToolParam(description = "第一个数字") double a,
            @ToolParam(description = "第二个数字") double b,
            @ToolParam(description = "运算类型:add 表示加,subtract 表示减," +
                    "multiply 表示乘,divide 表示除") String operation) {
        return switch (operation) {
            case "add" -> a + b;
            case "subtract" -> a - b;
            case "multiply" -> a * b;
            case "divide" -> {
                if (b == 0) {
                    throw new IllegalArgumentException("除数不能为 0");
                }
                yield a / b;
            }
            default -> throw new IllegalArgumentException("不支持的运算类型:" + operation);
        };
    }
}

要点解释:

  • @Tool(description = "..."):这个描述非常重要,模型会根据描述判断“什么时候该调用这个工具”。描述越清晰,调用越准确;
  • @ToolParam(description = "..."):参数描述同样关键,它帮助模型正确填充参数;
  • 方法本身可以是任意业务逻辑,Agent 只关心方法的签名和返回值。

5. 创建 Agent 并注入工具

接下来创建 Agent。Spring AI 提供了 ChatClient 作为统一入口,我们可以通过 Builder 模式把工具注册进去。

5.1 编写 Agent 服务类

package com.example.agentdemo.service;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.stereotype.Service;

@Service
public class AgentService {

    private final ChatClient chatClient;

    public AgentService(ChatModel chatModel, WeatherTool weatherTool) {
        this.chatClient = ChatClient.builder(chatModel)
                // 注册工具:这里可以连续注册多个工具
                .defaultTools(weatherTool)
                // 添加日志 Advisor,便于观察 Agent 的调用链路
                .defaultAdvisors(new SimpleLoggerAdvisor())
                .build();
    }

    public String chat(String userMessage) {
        return this.chatClient.prompt()
                .system("你是一个乐于助人的智能助手。遇到需要查询天气或计算的任务时," +
                        "请优先使用提供的工具,并根据工具返回结果如实回答。")
                .user(userMessage)
                .call()
                .content();
    }
}

5.2 核心代码解析

  1. ChatClient.builder(chatModel):以注入的 ChatModel 为基础构建客户端;
  2. .defaultTools(weatherTool):把包含 @Tool 方法的 Bean 注册为 Agent 可用工具。Spring AI 会自动扫描被 @Tool 注解的方法并生成模型可识别的工具描述;
  3. .defaultAdvisors(new SimpleLoggerAdvisor()):添加简易日志,方便在控制台观察模型的每次工具调用;
  4. .call().content():发送请求并返回最终文本结果。

6. 添加 Controller 并启动调试

为了让 Agent 可以被访问,我们添加一个简单的 REST 接口:

package com.example.agentdemo.controller;

import com.example.agentdemo.service.AgentService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AgentController {

    private final AgentService agentService;

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

    @GetMapping("/chat")
    public String chat(@RequestParam String message) {
        return agentService.chat(message);
    }
}

启动项目后,打开浏览器或使用 curl 测试:

curl "http://localhost:8080/chat?message=北京现在天气怎么样?"

控制台会输出类似以下的工具调用日志:

>>> system: 你是一个乐于助人的智能助手...
>>> user: 北京现在天气怎么样?
>>> function: getWeather(city=北京)
>>> function result: 北京当前天气晴朗,气温 22 摄氏度...
>>> assistant: 根据查询结果,北京当前天气晴朗,气温 22 摄氏度,空气质量良好。

再测试一个需要多步推理的例子:

curl "http://localhost:8080/chat?message=如果明天北京气温下降 10 度,大概是多少度?"

这个请求会先触发天气查询工具,再触发数学计算工具,体现 Agent 的多步工具调用能力。


7. 进阶:让 Agent 具备记忆能力

默认情况下,Agent 是不带记忆的,每次请求都是独立会话。我们可以通过 MessageChatMemoryAdvisor 轻松加上对话记忆。

7.1 注入记忆组件

首先确保项目中已有内存聊天记忆依赖(Spring AI 自带,无需额外依赖),然后修改 AgentService:

package com.example.agentdemo.service;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.stereotype.Service;

@Service
public class AgentService {

    private final ChatClient chatClient;

    public AgentService(ChatModel chatModel, WeatherTool weatherTool) {
        this.chatClient = ChatClient.builder(chatModel)
                .defaultTools(weatherTool)
                .defaultAdvisors(
                        // 关键:加上内存记忆 Advisor
                        new MessageChatMemoryAdvisor(new InMemoryChatMemory()),
                        new SimpleLoggerAdvisor()
                )
                .build();
    }

    public String chat(String conversationId, String userMessage) {
        return this.chatClient.prompt()
                .system("你是一个乐于助人的智能助手。遇到需要查询天气或计算的任务时," +
                        "请优先使用提供的工具,并根据工具返回结果如实回答。")
                .user(userMessage)
                // 使用会话 ID 区分不同用户/会话
                .advisors(a -> a.param("chat_memory_conversation_id", conversationId))
                .call()
                .content();
    }
}

同时修改 Controller 接收会话 ID:

@GetMapping("/chat")
public String chat(@RequestParam String message,
                   @RequestParam(defaultValue = "default") String sessionId) {
    return agentService.chat(sessionId, message);
}

现在 Agent 就能记住同一会话中的上下文了。例如:

# 第一轮
curl "http://localhost:8080/chat?sessionId=user001&message=我叫小明,帮我查一下北京的天气"

# 第二轮:模型会记得你叫小明
curl "http://localhost:8080/chat?sessionId=user001&message=我刚刚问的是哪个城市?"

注意:InMemoryChatMemory 只适合开发和测试环境。生产环境建议使用 CassandraChatMemoryRepository、JdbcChatMemoryRepository 或 Redis 等方式持久化记忆。


8. 常见问题与排错

问题现象可能原因解决方案
启动报 api-key 相关错误环境变量未设置在 IDEA 运行配置或终端 export OPENAI_API_KEY
模型不调用工具工具描述不清晰优化 @Tool 和 @ToolParam 的 description
工具返回后模型“答非所问”系统提示词不够明确在 system 提示中强调“基于工具结果回答”
连接超时网络问题或 base-url 不正确检查代理和 base-url 配置
JDK 版本报错使用了 JDK 8 或 11升级到 JDK 17+

9. 总结与下一步

通过这篇文章,你应该已经完成了一个最小但完整的 Spring AI Agent:

  1. 创建了 Spring Boot 项目并引入 Spring AI 依赖;
  2. 配置了大模型连接信息;
  3. 用 @Tool 注解定义了天气查询和数学计算工具;
  4. 通过 ChatClient 构建 Agent 并注册工具;
  5. 添加了 REST 接口并成功验证多步工具调用;
  6. 使用 MessageChatMemoryAdvisor 为 Agent 添加了会话记忆。

下一步你可以尝试:

  • 接入真实业务工具,例如订单查询、数据库操作、文件处理;
  • 使用 QuestionAnswerAdvisor 结合向量数据库实现 RAG Agent;
  • 通过 Spring AI 的 ToolCallingManager 管理更复杂的工具调用场景;
  • 部署到生产环境并配置持久化会话记忆与可观测性。

Spring AI 让 Java 开发者构建 Agent 的门槛大大降低。希望这篇文章能帮你迈出第一步,祝你玩得开心!

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐