1. 项目概述:为什么现在要关注Spring AI Alibaba?

最近在跟几个做企业级应用的朋友聊天,发现大家不约而同地都在讨论一个话题:怎么把手头那些“笨重”的传统业务系统,变得能“听懂人话”、能“自己干活”。比如,一个内部的报销系统,能不能让员工直接说“帮我报销上周去上海的差旅费,发票在邮箱里”,系统就自动把票找出来、填好单子、走完审批流?又或者,一个客服工单系统,能不能在用户描述问题时,自动判断问题类型、关联历史记录、甚至直接给出解决方案草稿?

这些场景背后,其实都在指向同一个技术方向——智能体(Agent)。它不是简单调用一个大模型API生成一段文本,而是一个能感知环境、规划决策、调用工具、并持续学习的自主程序。而当我们把这种能力嵌入到以Java技术栈为主、运行在云上的庞大企业应用中时,挑战就来了:怎么把AI能力像Spring Bean一样优雅地注入?怎么管理复杂的提示词(Prompt)?怎么让AI稳定地调用我们已有的Java服务?

这恰恰是“使用Spring AI Alibaba构建智能体Agent”这个项目要解决的核心问题。它不是一个简单的框架介绍,而是一套针对阿里云生态和Spring技术体系的“企业级AI智能体落地方案”。简单说,它让你能用写Spring Boot应用的习惯,去构建和部署那些具备AI决策能力的业务模块。如果你正在为如何将大模型能力低成本、高效率、稳定可靠地集成到现有Java系统中而头疼,那这个技术组合值得你花时间深入了解。

2. 智能体(Agent)的核心架构与设计思想拆解

在开始敲代码之前,我们必须先统一思想:我们要建的到底是什么?很多人误以为接入了大模型API就是拥有了智能体,这就像认为给汽车装上了一个高级音响就等于拥有了自动驾驶一样。

2.1 从“工具调用”到“自主智能体”的演进

一个真正的智能体,其核心在于 自主决策与任务分解 能力。我们可以把它理解为一个优秀的项目负责人。当你(用户)提出一个模糊的需求(如“优化数据库性能”)时,一个简单的工具调用模型可能只会回复一段通用的优化建议文本。而一个智能体则会像项目经理一样,自主执行以下流程:

  1. 理解与澄清 :询问当前数据库类型、版本、主要慢查询特征等关键信息。
  2. 规划与分解 :将“优化性能”这个大目标,拆解为“分析慢日志”、“检查索引”、“评估硬件资源”等多个子任务。
  3. 执行与协调 :依次调用“日志分析工具”、“SQL执行计划工具”、“系统监控API”等具体工具来完成任务。
  4. 汇总与报告 :将各工具的执行结果整合,生成一份结构化的优化报告和建议。

Spring AI Alibaba提供的智能体框架,正是为了支持这种复杂的、链式的推理和执行过程而设计的。它不是一个单体功能,而是一个包含 推理引擎、工具管理、记忆模块、执行控制 的完整运行时环境。

2.2 Spring AI Alibaba智能体框架的核心组件

理解其组件,有助于我们在设计时做出正确选择。主要包含以下几层:

  • AI Model Abstraction (AI模型抽象层) :这是基础。它统一了不同大模型(如通义千问、ChatGPT、Claude等)的调用接口。无论底层用的是阿里云的灵积模型服务,还是其他兼容OpenAI API的服务,在Spring AI中你都可以通过一个统一的 ChatClient ChatModel 来交互。这带来了巨大的灵活性,避免业务代码和某个厂商的API强绑定。

  • Prompt Templating & Management (提示词模板与管理) :智能体的“思考逻辑”很大程度上由提示词决定。Spring AI提供了强大的提示词模板功能,支持将变量、上下文、工具描述动态注入到预设的模板中。更重要的是,它允许你将复杂的提示词定义为Spring Bean或存储在外部配置(如数据库、配置中心)中,实现热更新,而无需重启应用。

  • Tool Abstraction (工具抽象层) :这是智能体的“手和脚”。任何你想让AI调用的功能——查询数据库、调用内部RPC接口、发送邮件、执行一个Shell脚本——都需要被封装成一个 Tool 。Spring AI允许你将现有的Spring Bean(比如一个 @Service )通过注解轻松暴露为AI可调用的工具。这是将AI能力与现有业务系统融合的关键。

  • Agent Runtime (智能体运行时) :这是大脑和调度中心。它基于一个“推理-执行”循环工作:

    1. 接收用户输入和当前上下文(记忆)。
    2. 根据提示词,让大模型思考下一步该做什么(调用哪个工具,或者直接回复用户)。
    3. 解析大模型的输出,如果决定调用工具,则找到对应的 Tool 并执行。
    4. 将工具执行结果作为新的上下文,再次交给大模型进行下一步推理。
    5. 循环直至任务完成或达到终止条件。 Spring AI提供了如 ReActAgent ChainOfThoughtAgent 等多种经典的智能体实现,你可以根据任务复杂度选择。
  • Memory (记忆模块) :智能体需要有“短期记忆”来维持对话上下文,也需要“长期记忆”来学习历史经验。Spring AI提供了基于向量数据库(如阿里云DashVector)的长期记忆存储,以及基于会话的短期记忆管理,使得智能体能在多轮交互中保持连贯性。

设计心得 :不要试图一开始就构建一个“全能”的智能体。最好的实践是从一个核心、高频、边界清晰的业务场景切入,比如“智能数据查询助手”或“自动化故障诊断向导”,定义好它需要使用的3-5个关键工具,然后迭代优化。

3. 环境搭建与基础配置实战

理论清晰后,我们进入实战环节。假设我们要构建一个“内部IT支持智能体”,它能回答员工关于办公软件、网络、权限等常见问题,并在必要时自动创建工单。

3.1 项目初始化与依赖引入

首先,使用 Spring Initializr 创建一个标准的 Spring Boot 3.x 项目。在 pom.xml 中,关键依赖如下:

<dependencies>
    <!-- Spring AI 核心依赖 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-alibaba-ai-spring-boot-starter</artifactId>
        <version>0.8.1</version> <!-- 请使用最新稳定版 -->
    </dependency>
    <!-- Spring AI 智能体相关依赖 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-agent-spring-boot-starter</artifactId>
        <version>0.8.1</version>
    </dependency>
    <!-- 工具调用所需 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-tool-spring-boot-starter</artifactId>
        <version>0.8.1</version>
    </dependency>
    <!-- Web支持,用于提供API接口 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 配置处理器,便于提示词配置 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

这里重点说明版本选择:Spring AI 项目迭代较快,务必在 Spring AI 官方文档 Alibaba Spring AI GitHub 上核对与你的 Spring Boot 版本兼容的最新稳定版。盲目使用最新版本可能会遇到接口不兼容的问题。

3.2 阿里云灵积模型服务配置

Spring AI Alibaba 默认深度集成阿里云的灵积模型服务。你需要前往阿里云官网,开通“灵积”服务,并创建API Key。

application.yml 中进行配置:

spring:
  ai:
    alibaba-ai:
      # 阿里云灵积API访问密钥
      access-key-id: your-access-key-id
      access-key-secret: your-access-key-secret
      # 指定使用的模型,例如通义千问最新版
      chat-options:
        model: qwen-max
        temperature: 0.7 # 控制创造性,业务场景建议较低值(0.1-0.3),创意场景可调高
        max-tokens: 2000 # 单次回复最大长度
      # 连接与超时配置,生产环境必须调整
      client:
        connect-timeout: 10s
        read-timeout: 30s

关键配置解析:

  • model : 根据场景选择。 qwen-max 能力最强但成本较高; qwen-plus 性价比高,适合大多数业务场景; qwen-turbo 速度最快,适合简单交互。可以在阿里云控制台查看各模型的详细能力和计价。
  • temperature : 这是最重要的参数之一。值越高(接近1),回答越随机、有创意;值越低(接近0),回答越确定、保守。在需要稳定输出、执行指令的 工具调用场景,强烈建议设置为0.1或0.2 ,以减少模型“胡思乱想”导致工具调用失败的概率。
  • timeout : 网络超时至关重要。大模型推理可能需要数秒甚至更久,特别是处理长上下文时。务必根据实际模型响应时间和网络状况设置合理的超时,避免因超时导致线程阻塞。

3.3 定义第一个工具(Tool):工单创建工具

智能体的威力来自于工具。我们来定义一个创建IT工单的工具。

首先,创建一个工单服务(这可能是你已有的业务服务):

@Service
public class TicketService {
    public String createTicket(String title, String description, String requester, String category) {
        // 这里模拟调用实际的工单系统API或操作数据库
        log.info("创建工单:标题={}, 分类={}, 提交人={}", title, category, requester);
        // 假设返回工单号
        String ticketId = "TICKET-" + System.currentTimeMillis();
        return String.format("工单创建成功!工单号:%s。标题:%s。我们的工程师会尽快处理。", ticketId, title);
    }
}

然后,使用Spring AI的 @Tool 注解将其暴露给智能体:

@Component
public class ItSupportTools {
    @Autowired
    private TicketService ticketService;

    @Tool(name = "createSupportTicket", description = "为用户创建IT支持工单。当用户报告软件、硬件、网络或其他IT问题时使用。")
    public String createTicket(
            @ToolParam(description = "工单的简要标题,概括问题") String title,
            @ToolParam(description = "问题的详细描述,包括现象、发生时间等") String description,
            @ToolParam(description = "问题分类,例如:软件、硬件、网络、账号权限") String category) {
        // 在实际应用中,可以从安全上下文(如JWT)中获取当前用户
        String currentUser = "employee@company.com";
        return ticketService.createTicket(title, description, currentUser, category);
    }
}

工具定义要点:

  1. @Tool 注解 :标记一个方法为AI可调用的工具。 name 属性是工具的唯一标识, description 至关重要!大模型完全依赖这个描述来决定是否以及如何调用该工具。描述必须清晰、准确,说明工具的用途、适用场景和参数意义。
  2. @ToolParam 注解 :用于描述方法参数。同样,清晰的描述能帮助大模型更准确地理解需要从用户输入中提取什么信息来填充这个参数。
  3. 返回值 :工具方法的返回值应该是字符串格式,这个字符串会作为“工具执行结果”反馈给大模型,供其进行下一步推理。因此,返回的信息应简洁、结构化,便于AI理解。

避坑指南 :工具方法的参数尽量使用简单的Java类型(String, Integer, Boolean等)。复杂对象(如自定义DTO)需要大模型理解其结构,目前支持不够友好,容易导致调用失败。如果必须传递复杂数据,可以考虑将其序列化为JSON字符串作为单个String参数传入。

4. 构建并配置智能体(Agent)

有了工具,我们需要组装智能体的大脑。

4.1 定义智能体提示词(System Prompt)

提示词是智能体的“人格”和“工作说明书”。我们在 resources 目录下创建一个 prompts/it-support-agent.st 文件(Spring AI支持多种模板格式,这里用SimpleTemplate):

你是一个专业、友好、高效的IT支持助手,负责处理员工内部的IT问题。
你的名字叫“小智”。

你的核心职责:
1.  首先,尝试基于知识库直接解答用户关于办公软件、公司网络、系统权限等方面的常见问题。
2.  如果问题无法直接解决,或者用户明确要求,你需要使用工具来创建支持工单。
3.  创建工单时,必须向用户确认工单的标题、问题描述和分类。如果信息不足,要主动询问。

你必须遵守以下规则:
- 永远保持礼貌和耐心。
- 在创建工单前,必须向用户复述一遍工单信息并得到确认。
- 不要编造你不知道的信息。如果不知道,就承认并建议创建工单。
- 使用中文与用户交流。

你可以使用的工具:
{tools}

当前对话历史:
{history}

用户问题:{input}

请根据以上信息,思考并回复用户。如果需要使用工具,请严格按照工具要求的格式输出。

提示词设计技巧:

  • 角色设定 :开篇明确角色,能有效引导模型行为。
  • 职责边界 :清晰定义它能做什么、不能做什么,防止越界或“幻觉”。
  • 规则约束 :设定业务规则(如确认步骤),这是保证流程合规性的关键。
  • 变量注入 {tools} {history} {input} 是Spring AI会自动替换的占位符,分别对应可用工具描述、对话历史和当前用户输入。
  • 指令清晰 :最后给出明确的指令,告诉模型如何输出。

4.2 配置与组装智能体Bean

在Spring配置类中,我们将所有部件组装起来:

@Configuration
public class AgentConfiguration {
    @Value("classpath:/prompts/it-support-agent.st")
    private Resource systemPromptResource;

    @Bean
    public PromptTemplate itSupportAgentPromptTemplate() throws IOException {
        String promptText = StreamUtils.copyToString(systemPromptResource.getInputStream(), StandardCharsets.UTF_8);
        return new PromptTemplate(promptText);
    }

    @Bean
    public Agent itSupportAgent(ChatModel chatModel,
                                 PromptTemplate itSupportAgentPromptTemplate,
                                 ToolCallbackHandler toolCallbackHandler) {
        // 1. 创建工具执行器
        ToolExecutor toolExecutor = new DefaultToolExecutor(toolCallbackHandler);
        // 2. 构建智能体
        return Agent.builder()
                .chatModel(chatModel)
                .promptTemplate(itSupportAgentPromptTemplate)
                .toolExecutor(toolExecutor)
                .agentType(AgentType.CHAIN_OF_THOUGHT) // 使用思维链代理,适合需要多步推理的任务
                .maxIterations(5) // 防止无限循环,限制最大推理-执行轮数
                .build();
    }
}

配置解析:

  • AgentType.CHAIN_OF_THOUGHT :选择“思维链”代理。这种代理会在内部让模型展示其推理步骤(“我需要先问清问题类型...”),然后再决定行动,这使得它的决策过程更透明、更可靠,尤其适合需要逻辑判断的流程。
  • maxIterations(5) :这是一个 至关重要的安全阀 。智能体在复杂任务中可能会陷入“调用工具A -> 分析结果 -> 又调用工具A”的死循环。设置最大迭代次数可以强制终止,避免资源耗尽。
  • ToolCallbackHandler :这是Spring AI提供的一个标准组件,负责解析模型输出中的工具调用指令,并实际执行对应的 @Tool 方法。

4.3 创建API端点与测试

最后,我们创建一个简单的REST控制器来暴露智能体服务:

@RestController
@RequestMapping("/api/agent")
public class AgentController {
    @Autowired
    private Agent itSupportAgent;
    @Autowired
    private ChatMemory chatMemory; // 用于管理对话记忆

    @PostMapping("/chat")
    public String chat(@RequestParam String message, @RequestParam String sessionId) {
        // 1. 获取或创建当前会话的记忆
        Memory memory = chatMemory.get(sessionId).orElseGet(ChatMemory::create);
        // 2. 构建用户消息
        UserMessage userMessage = new UserMessage(message);
        // 3. 调用智能体处理
        AgentResponse response = itSupportAgent.call(userMessage, memory);
        // 4. 保存更新后的记忆
        chatMemory.put(sessionId, response.memory());
        // 5. 返回AI回复
        return response.output();
    }
}

现在,你可以启动应用,并使用Postman或curl进行测试:

curl -X POST "http://localhost:8080/api/agent/chat?sessionId=user123&message=我的Outlook客户端一直提示密码错误,登录不上去了,请帮我看看"

一个设计良好的智能体会先尝试询问“您是否确认密码输入正确?是否在其他设备可以登录?”,如果判断为账号问题,可能会建议“这可能是账号密码或权限问题,我为您创建一个‘账号权限’类别的工单,让工程师协助处理,可以吗?”。在获得用户确认后,它会自动调用 createSupportTicket 工具,并返回工单创建成功的消息。

5. 高级特性与生产级优化

基础功能跑通后,我们需要关注稳定性、性能和可观测性,以满足生产要求。

5.1 记忆(Memory)的持久化与向量检索

简单的对话记忆存储在内存中,重启即丢失。对于需要长期记忆(如记住用户偏好、历史问题)的场景,需要引入向量数据库。

以集成阿里云DashVector为例:

  1. 添加依赖
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-dashvector-store-spring-boot-starter</artifactId>
        <version>0.8.1</version>
    </dependency>
    
  2. 配置连接
    spring:
      ai:
        vectorstore:
          dashvector:
            api-key: your-dashvector-api-key
            endpoint: your-dashvector-endpoint
            namespace: it_support_agent # 命名空间,用于隔离不同应用的数据
    
  3. 使用向量记忆 :在配置Agent时,注入 VectorStoreMemory 代替简单的内存记忆。这样,每次对话的关键信息会被编码成向量存入DashVector。当用户提出新问题时,智能体会先从向量存储中检索语义最相关的历史片段,作为上下文注入提示词,从而实现“记住往事”的能力。

5.2 流式响应(Streaming)与前端集成

大模型生成内容需要时间,流式响应可以逐词返回结果,极大提升用户体验。Spring AI支持流式API。

修改控制器,返回 Flux<String> (Reactive) 或使用 SseEmitter

@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamChat(@RequestParam String message, @RequestParam String sessionId) {
    SseEmitter emitter = new SseEmitter(30_000L); // 超时时间
    // 异步处理流式响应
    itSupportAgent.stream(message, sessionId)
        .subscribe(
            chunk -> emitter.send(chunk),
            error -> emitter.completeWithError(error),
            emitter::complete
        );
    return emitter;
}

前端可以使用 EventSource API 来接收并实时显示这些数据块。

5.3 监控、日志与链路追踪

在生产环境中,必须对智能体的行为进行监控。

  • 结构化日志 :在工具方法、Agent调用关键点添加详细日志,记录输入、输出、耗时和异常。使用MDC(Mapped Diagnostic Context)注入 sessionId requestId ,便于串联整个调用链。
  • 指标监控 :利用Spring Actuator和Micrometer,暴露自定义指标,如:
    • agent.invocation.count :智能体调用次数。
    • agent.invocation.duration :调用耗时分布。
    • tool.invocation.count :各工具被调用的次数和成功率。
    • llm.token.usage :大模型Token消耗(可通过拦截 ChatClient 调用获取)。
  • 链路追踪 :将每次用户交互分配一个唯一Trace ID,贯穿从Web请求到AI模型调用再到工具执行的全链路,便于在出现问题时快速定位是网络超时、模型返回异常还是工具执行错误。

5.4 提示词工程优化与A/B测试

提示词的质量直接决定智能体的表现。不要指望一蹴而就。

  1. 外部化管理 :将提示词模板存储在数据库或Apollo/Nacos等配置中心。这样可以在不重启服务的情况下,动态修改提示词,进行热更新。
  2. 版本化与A/B测试 :为提示词设计版本号。可以通过在请求头中传递 Prompt-Version 或根据用户ID哈希分流,让不同用户使用不同版本的提示词,收集交互日志,对比分析哪个版本的提示词能带来更高的任务完成率或用户满意度。
  3. Few-Shot示例 :在提示词中嵌入几个高质量的输入输出示例(Few-Shot Learning),能极大地提升模型在特定任务上的表现。例如,在IT支持提示词里加入:“用户:‘打印机连不上’ -> 助手:‘请问打印机型号是什么?电脑上提示的具体错误信息是什么?’ -> 用户:‘HP LaserJet,提示找不到驱动程序’ -> 助手:‘这可能是驱动问题。我为您创建一个‘硬件-打印机’类别的工单,让工程师远程协助安装驱动,可以吗?’”

6. 常见问题排查与性能调优实录

在实际开发和运维中,你会遇到各种问题。以下是我踩过的一些坑和解决方案。

6.1 工具调用失败:参数映射错误

问题现象 :智能体决定调用工具,但日志显示工具调用失败,报错“参数类型不匹配”或“缺少必要参数”。

根因分析 :大模型没有从用户输入中正确提取出工具方法所需的参数。这通常是工具方法参数描述( @ToolParam )不够清晰,或者用户表达过于模糊。

解决方案

  1. 优化参数描述 :让描述更具体、包含示例。例如,将 description = "问题分类" 改为 description = "问题分类,必须是以下选项之一:'软件'、'硬件'、'网络'、'账号权限'、'其他'。如果无法确定,请询问用户。"
  2. 提供更详细的工具描述 :在 @Tool description 里,明确说明该工具在什么条件下使用,以及它期望的输入格式。
  3. 使用更强大的模型 :如果使用 qwen-turbo 等轻量模型遇到此问题,可以尝试切换到 qwen-plus qwen-max ,它们在理解指令和参数提取上通常更准确。
  4. 添加参数验证和默认值 :在工具方法内部,对传入的参数进行校验。如果参数为空或无效,返回一个友好的错误信息给大模型,让它重新提问或调整。

6.2 智能体陷入循环或执行无关操作

问题现象 :智能体在几步操作后,开始重复调用同一个工具,或者执行与用户问题完全无关的工具。

根因分析 :提示词中对智能体的约束不够强,或者 maxIterations 设置得过高,导致模型在不确定时“瞎猜”。

解决方案

  1. 强化提示词中的规则 :在System Prompt中明确加入停止条件。例如:“如果你已经创建了工单,或者明确告知用户无法解决并建议了下一步,那么任务就结束了,直接输出最终回复,不要再调用任何工具。”
  2. 降低 temperature :如前所述,在工具调用场景,将 temperature 降至0.1-0.3,减少模型的随机性。
  3. 合理设置 maxIterations :对于大多数任务,3-5轮迭代足够。如果超过这个数还没完成,很可能是陷入了混乱。
  4. 引入人工审核环节 :对于关键操作(如创建高优先级工单、执行数据删除),可以在工具逻辑中设计一个“人工确认”的步骤,例如发送一条待办消息到钉钉/飞书,由真人确认后再继续。

6.3 响应速度慢或超时

问题现象 :用户请求后需要等待很长时间才有响应,甚至超时。

根因分析

  1. 模型本身推理慢(特别是处理长上下文时)。
  2. 网络延迟高。
  3. 智能体进行了多轮复杂的工具调用(每个工具调用都可能涉及网络IO)。

解决方案

  1. 模型选型 :对实时性要求高的场景,优先选用 qwen-turbo 这类优化了速度的模型。
  2. 超时配置 :在 application.yml 中合理配置 read-timeout ,并确保服务端有重试或熔断机制。
  3. 优化上下文长度 :定期清理对话记忆( ChatMemory ),只保留最近几轮的关键对话。对于向量记忆,控制检索返回的片段数量和质量。
  4. 异步处理 :对于非实时任务,可以将用户请求放入消息队列(如RocketMQ),由后台的智能体异步处理,处理完成后通过WebSocket或消息推送通知用户。
  5. 工具性能优化 :确保 @Tool 方法本身是高效的。避免在工具方法内执行耗时的同步RPC调用或复杂计算,必要时将其异步化。

6.4 安全性考虑

问题 :用户输入可能包含恶意指令(Prompt Injection),诱导智能体执行未授权的工具或泄露敏感信息。

防护措施

  1. 输入过滤与净化 :在请求进入智能体前,对用户输入进行严格的校验和过滤,移除或转义可能被解释为系统指令的特殊字符或字符串。
  2. 工具权限控制 :不是所有 @Tool 都对所有用户开放。可以在工具方法内部集成权限校验逻辑,根据当前用户角色(从安全上下文获取)决定是否允许执行该操作。
  3. 输出审查 :对智能体的最终输出进行内容安全审核,可以利用阿里云的内容安全API,过滤不当言论。
  4. 沙箱环境 :对于执行代码、访问敏感系统的工具,考虑在安全的沙箱环境中运行。

构建企业级智能体是一个持续迭代的过程。从一个小而美的场景开始,聚焦于解决一个具体的业务痛点,通过Spring AI Alibaba提供的这套标准化、Spring风格的框架,你可以快速搭建出原型。然后,在真实用户反馈中不断优化你的提示词、工具设计和系统配置。记住,智能体不是要完全取代现有系统,而是作为一个强大的“胶水层”和“智能接口”,将人的自然语言指令转化为精准的系统操作,从而释放出更大的生产力。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐