YangeIT大约 5 分钟

1. Spring AI 是什么

Spring AI is an application framework for AI engineering.
Spring AI is an application framework for AI engineering.

官方地址 :https://spring.io/projects/spring-aiopen in new window

Spring AI 可以理解为:

用 Spring Boot 的开发方式去接入大模型,并把提示词、对话、工具调用、RAG、结构化输出等能力封装成更适合 Java 后端开发的 API。

如果不用 Spring AI,我们通常要手写很多内容:

  1. 自己拼接 HTTP 请求去调用模型接口。
  2. 自己维护消息上下文。
  3. 自己定义工具调用协议。
  4. 自己处理模型调用前后的对象转换。

用了 Spring AI 后:

  1. 通过 Starter 引入模型能力。
  2. ChatClient 发起对话。
  3. @Tool 把 Java 方法暴露给模型。
  4. 用 Spring Bean、配置文件、Service、Controller 的方式组织 AI 功能。

这就非常适合我们这种已有 Spring Boot 项目,要把 AI 能力嵌入业务系统的场景。

Spring AI Alibaba 是构建 Agent 智能体应用最简单的方式,只需不到 10 行代码就可以构建您的智能体应用。 笔记地址:https://java2ai.com/docs/overviewopen in new window


2. 当前项目做了什么 AI 功能

当前项目做的是:

“养老院专属客服机器人”

它支持以下业务能力:

  1. 房型查询
  2. 护理项目查询
  3. 护理项目详情查询
  4. 老人信息查询
  5. 我的预约查询
  6. 新增预约
  7. 取消预约
  8. 养老院政策咨询
  9. 多轮对话
  10. 会话历史清空

也就是说,这不是一个只会闲聊的机器人,而是一个:

能调业务工具、能读数据库、能做业务操作、能受权限控制的 AI 客服。

image
image

3. Spring AI 入门案例

在完成智能客服之前,我们先写一个SpringAI的入门案例

  1. 导入依赖
  2. 配置密钥
  3. 编写Controller
  4. 测试

ReactAgent = 遵循 ReAct 推理 + 行动循环范式 的 AI 智能体,是 Spring AI Alibaba Agent 框架的默认核心实现类。作用:让大模型不再只能纯文字聊天,可以自主思考要不要调用工具、调用哪个工具、循环多轮执行,直到把复杂任务做完。

核心痛点:

  1. 普通 ChatClient 只能一问一答:
  2. 查实时天气、查数据库、调用业务接口、计算数据,模型做不到;
  3. 容易编造不存在的数据(AI 幻觉)。

ReactAgent 靠闭环迭代解决以上问题。👈

https://java2ai.com/docs/quick-startopen in new window

3.1 依赖

一个最基础的聊天项目,最少要有:

<dependencies>
<!-- Spring AI Alibaba Agent Framework -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-agent-framework</artifactId>
<version>1.1.2.0</version>
</dependency>

<!-- DashScope ChatModel 支持(如果使用其他模型,请跳转 Spring AI 文档选择对应的 starter) -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>1.1.2.0</version>
</dependency>
</dependencies>

3.2 配置

key申请地址:https://bailian.console.aliyun.com/cn-beijing?tab=model#/api-keyopen in new window

最基础配置:

spring:
  ai:
    dashscope:
      api-key: sk-0b68751a0e064970xxxxxxxxxx
      chat:
        options:
          model: qwen-plus
          temperature: 0.2

说明:

  1. api-key 是大模型密钥。
  2. model 指定模型。
  3. temperature 越低越稳定,越高越发散。

3.3 最简单 Controller

@RestController
public class DemoAiController {

    private final ChatClient chatClient;

    public DemoAiController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping("/ai/demo")
    public String demo(String message) {
        return chatClient.prompt() // 开始构造一次请求
                .user(message) // 添加用户消息
                .call()// 调用模型
                .content();// 取出文本
    }
}

打开浏览器,输入:http://localhost:9995/ai/demo?message=你是谁?open in new window

输出:👇

你好!我是通义千问(Qwen),阿里巴巴集团旗下的超大规模语言模型。我可以回答问题、创作文字,比如写故事、写公文、写邮件、写剧本、逻辑推理、编程等等,还能表达观点,玩游戏等。如果你有任何问题或需要帮助,欢迎随时告诉我!😊

3.4 入门案例的局限

这个案例虽然能跑,但有很多问题:

  1. 没有系统提示词
  2. 没有多轮对话
  3. 没有工具调用
  4. 不能查数据库
  5. 不能做预约操作
  6. 不能控制用户权限

所以真实业务系统不会停留在这一步。


4. 当前项目如何设计

设计成“Controller + AiService + ToolService + ConversationService”

因为业务型 AI 项目不能只靠一个 Controller 写到底。

当前项目分层逻辑是:

  1. CustomerServiceAiController 作用:暴露 HTTP 接口,接收前端请求。
  2. CustomerServiceAiService 作用:负责编排整个 AI 对话过程。
  3. CustomerServiceConversationService 作用:负责会话历史的保存、截断、清空。
  4. CustomerServiceToolService 作用:把“查房型、查项目、查老人、查预约、增删预约、查政策”这些能力暴露成模型可调用的工具。

这样拆分的好处:

  1. 职责清晰
  2. 便于测试
  3. 便于扩展新工具
  4. AI 能力和普通业务能力边界清晰

4.2 关键对象说明

  1. ChatClient 它是对话入口。
  2. Prompt 它是请求构造器,表示开始构造一次请求。
  3. system(...) 系统消息。作用: 定义模型身份,定义行为规则, 约束输出风格,限制乱回答
  4. user(...) 用户消息。作用:当前时间,会话编号,历史对话,用户本轮问题
  5. tools(...) 把 Java 方法暴露给模型,让模型在需要时主动调用这些方法。
  6. toolContext(...) 给工具传递隐式上下文信息,这些信息不会直接暴露给大模型。这样模型即使不知道用户真实 ID,工具方法仍然能拿到 userId 去做权限校验和数据隔离。
  7. call().content() 调用模型,并取出模型回复内容。

可以把它理解为:

前端问题 -> AI 编排 -> 工具调用 -> 数据库/业务 -> 回到模型 -> 最终答案

4.3 房型查询,老人查询

  String answer = chatClient.prompt()
                .system(properties.getSystemPrompt()) // 系统提示词
                .user(userPrompt)// 用户消息
                .tools(toolService)// 工具
                .toolContext(toolContext)// 上下文
                .call()// 调用模型
                .content();// 取出文本