01-第一个AI程序
教程代码:https://github.com/mszlu521/spring-ai-alibaba
教程制作:码神之路(https://www.mszlu.com/docs/ai/msai/01.html)
AI Agent实战教程:https://www.mszlu.com/docs/ai/msai/01.html
- 提供Go和Java版本,目前Go版本已经完结
1. 现代AI Agent架构的演进
现代AI系统的起点是大语言模型(LLM)。它的本质是一个通过海量文本训练得到的"概率预测机器":基于前文语境,预测下一个最可能出现的token。这种机制赋予了它惊人的语言理解和逻辑推理能力,但也带来了根本性的局限:模型是"静态"的——训练完成后知识就定格在某一时间点,且只能进行"文本进、文本出"的运算,无法直接操作外部世界。
当我们要求AI完成"查询今日股价并分析"这类任务时,矛盾就显现了:模型"想得出"分析思路,但"做不到"实时查询。这正是Tool Calling(工具调用) 机制出现的原点。
1.1.1 Tool Calling:打破模型的"封闭牢笼"
Tool Calling解决的核心问题是:如何让大模型从"纸上谈兵"转向"动手实践"。
其实现逻辑非常巧妙:我们不再只是向模型提问,而是同时告诉它"我为你准备了哪些工具"(如股票API、计算器、搜索引擎),并用结构化格式(如JSON Schema)描述每个工具的用途和参数。当大模型推理时,它会判断当前任务是否需要外部工具——如果需要,它不是直接回答问题,而是输出一段调用指令(例如:"我需要调用get_stock_price,参数ticker为AAPL")。系统接收到这个指令后,实际执行工具,并将结果再次注入上下文,让模型基于真实数据给出最终回答。
这就像给一位智者配上了手脚:他仍然是决策者,但可以通过工具触达物理世界。然而,随着工具数量的增加,新的痛苦诞生了——每个API的接口格式、认证方式、错误处理都各不相同。开发者需要为每个工具写大量的适配代码,这催生了标准化需求。
1.1.2 MCP:工具世界的"通用插座"
MCP(Model Context Protocol) 的出现,本质上是为了解决工具生态的碎片化问题。
在没有MCP之前,如果你开发了一个让AI操作Photoshop的工具,你需要为ChatGPT、Claude、Gemini分别开发不同的插件适配层。MCP借鉴了USB接口的理念:它定义了一套标准协议,规定工具如何描述自己的能力(Schema)、如何建立安全连接、如何传输上下文。任何支持MCP的AI应用,都能即插即用地使用任何支持MCP的工具,无需重复开发。
这极大地扩展了AI的行动边界——从本地文件系统到企业数据库,从邮件客户端到云服务,AI Agent获得了一个标准化的"数字四肢"。
1.1.3 RAG:为模型接上"外部大脑"
由于大模型是静态的,所以当它在面对未知问题时,它倾向于"自信地编造"而非坦诚不知。当企业试图将AI应用于需要准确事实的场景(如医疗咨询、法律分析)时,就成为了致命的缺陷。
这正是 RAG(Retrieval-Augmented Generation,检索增强生成) 技术诞生的背景。
RAG解决的核心问题是:如何让大模型在不重新训练的情况下,获取训练数据之外的准确知识?
其工作原理类似于"开卷考试":当用户提问时,系统首先通过嵌入模型(Embedding Model) 将问题转化为向量,在向量数据库中检索语义相关的文档片段(这些文档可以是企业内部的最新规章制度、刚发布的论文、或实时更新的产品手册)。检索到的内容被注入到Prompt的上下文中,作为"参考资料"呈现给大模型,模型基于此进行生成回答。
这带来了三重革命性价值:
- 知识时效性:无需重新训练模型,只需更新外部知识库,AI就能"学会"新信息;
- 可解释性:答案可以标注来源出处,解决了"黑盒"信任问题;
- 成本效益:相比微调(Fine-tuning)整个大模型,维护向量数据库的成本几乎可以忽略不计。
然而,RAG的本质仍然是**"被动检索、主动回答"——它让模型从"背诵者"变成了"查阅者",但仍局限于文本生成。当任务需要主动操作外部系统**(如发送邮件、预订酒店、执行代码)时,仍旧需要Tool Calling的技术支持。
1.1.3 Agent Skills:程序性知识的"可移植容器"
当我们解决了RAG(知识检索)和Tool Calling(工具使用)后,AI系统面临一个新的隐性痛点:模型虽然能查资料、调工具,但缺乏"做事的方法论"——即程序性知识(Procedural Knowledge)。
举个例子:模型可能知道Python语法(显性知识),也知道如何调用数据库API(工具能力),但它不知道"你们公司特定的代码审查流程是什么步骤"、"数据分析报告的标准模板是什么格式"、"遇到异常时应该按什么顺序排查"。这些组织特定的、流程性的、最佳实践类的知识,无法通过RAG的简单文本检索获得,也无法通过MCP的工具接口传递。
Agent Skills 正是为了解决**"agent缺乏完成任务所需的上下文和程序性知识"**而生。它由Anthropic提出并开源,核心定义是:Skills是包含指令、脚本和资源的文件夹,作为可移植、版本控制的包存在。
1.1.3.1 与MCP、Tool Calling的关系
需要明确区分这三个概念的不同抽象层级:
- Tool Calling(工具调用):解决**"能不能做"的问题,是模型与外部系统的实时交互机制**;
- MCP(Model Context Protocol):解决**"如何连接"的问题,是工具接口的标准化协议**;
- Agent Skills(Skills标准):解决**"知道怎么做"的问题,是程序性知识的封装与交付格式**。
三者的协作关系是:Agent Skills提供了**"操作手册"**(知道应该按什么步骤、用什么标准来做),当执行到具体步骤需要调用外部工具时,通过MCP协议发现可用工具,再通过Tool Calling机制实际执行。
例如,一个"安全漏洞分析"Skill会包含分析流程、检查清单、报告模板(程序性知识);当需要查询漏洞数据库时,它指示模型通过MCP协议连接的CVE查询工具(标准化接口),实际执行Tool Calling获取数据(实时交互)。
1.1.4 Multi-Agent:从"通才"到"专家团队"
然而,当任务复杂度达到一定程度(例如"开发一款APP"),单一Agent的局限性暴露无遗:它既要做架构设计,又要写代码,还要做UI设计,容易顾此失彼。这就好比让一个人同时扮演产品经理、程序员和设计师,效率和质量都难以保证。
Multi-Agent System(多智能体系统) 的出现,是为了解决单一Agent的能力过载问题,借鉴了人类社会分工协作的智慧。
在这种架构中,我们不再追求一个"万能Agent",而是构建Agent Team(智能体团队):研究Agent专精于信息搜集,分析师Agent专精于数据处理,程序员Agent专精于代码生成。每个Agent拥有自己的Skill集合、系统提示词和记忆空间。
1.1.5 A2A协议:Agent之间的"通用语言"
但新的问题随之而来:这些Agent可能运行在不同的框架或者是服务中,使用不同的通信格式,它们如何"听懂"彼此?这就像让说中文的研究员和说法语的程序员协作,必须有翻译机制。
A2A(Agent-to-Agent)协议 正是为了解决异构Agent之间的互操作性而生。它定义了Agent发现、能力广播、任务委托、状态同步、安全认证等标准。基于A2A,一个用Python编写的数据分析Agent可以无缝调用另一个用Java开发的图表生成Agent,就像互联网上的HTTP协议让不同服务器能够通信一样。
1.1.6 ReAct与工作流:串联一切的思考与编排
在这一切的背后,ReAct(Reasoning + Acting) 模式提供了认知层面的串联逻辑。它描述了Agent如何工作:不是一次性得出答案,而是通过"思考→行动→观察→再思考"的循环逐步逼近目标。
ReAct强制要求大模型以显式的结构化格式输出这个思维过程:
- Thought(思考):基于当前上下文,模型显式写出推理过程("我需要先获取Q3的销售数据才能分析趋势,我应该调用sales_query工具");
- Action(行动):基于上述思考,输出结构化的工具调用指令(
{"tool": "sales_query", "params": {"quarter": "Q3"}}); - Observation(观察):系统执行工具,将结果(如"Q3销售额同比下降15%")重新注入上下文;
- Reflection(反思/调整):模型基于新的观察,决定下一步("数据确认了下降趋势,现在需要调用competitor_analysis工具查看竞品动态")。
这种显式的思维链(Chain-of-Thought) 带来了三重革命性改进:
- 可解释性:我们不再看到模型的"直觉反应",而是能完整阅读它的"心路历程",知道它为什么调用某个工具;
- 错误自纠:当工具返回异常或空结果时,模型可以在Reflection步骤识别"这个查询没有返回有效数据,我需要调整参数重试",而不是继续瞎猜;
- 幻觉抑制:通过强制"先思考再行动",模型必须基于逻辑推导而非统计概率做决定,大幅减少了"为了调用工具而调用工具"的随机性行为。
ReAct本质上定义了单Agent的认知节奏——它让每个决策步骤都变得透明、可追溯、可调试。
1.1.7 Workflow:驯服AI不确定性的"确定性编排"
当AI执行长周期、多步骤的复杂任务时,AI的不确定性成为了最后一道障碍。
ReAct的核心是"让模型自己决定下一步做什么"——这带来了灵活性,但也带来了不可控性:同样的输入,模型这次可能先查知识库再分析,下次可能直接瞎编;遇到复杂分支,模型可能陷入循环或跳过关键步骤;更糟糕的是,企业无法审计和复现模型的决策路径,因为每次ReAct循环的"思维链"都是现场生成的。
工作流平台正是解决如何既利用AI能力,又确保业务流程的确定性、可重复性、可视化可控这一核心矛盾。
其本质是一种**预定义管道(Pre-defined Pipeline)**架构:
节点化封装:把AI关在可控的"笼子"里 工作流将AI能力拆解为可视化节点:开始节点、LLM节点、知识库节点(RAG)、工具节点、条件分支节点、循环节点、代码执行节点、结束节点。每个节点的输入、输出、Prompt模板、温度参数、超时限制都是人类预先配置的。
- 这与ReAct的"自由思考"截然相反——在工作流中,LLM节点不是"自主决定调用什么工具",而是**"人类指定它在这个步骤必须做什么事"。例如:第一步必须是"意图识别节点"(用低温度参数确保分类稳定),第二步根据意图分支到不同的知识库检索节点,第三步是"答案生成节点"(用高温度参数生成友好回复)。AI的随机性被限制在节点内部**,而节点之间的流转是确定性的代码逻辑。
流程固化:消除累积误差 ReAct的风险在于"一步错步步错"——如果早期的Observation被误解,后续推理会基于错误前提螺旋下滑。而工作流通过显式分支解决这个问题:人类预设"如果知识库检索结果为空,则走'兜底回复'分支;如果置信度低于0.7,则走人工审核分支"。这些条件判断是硬编码的,不依赖模型的"反思"能力,从而确保异常路径被显式处理,而非依赖模型的"自觉性"。
3. 解决AI不确定性的工程化手段 工作流通过以下机制驯服不确定性:
输入输出标准化:每个节点定义严格的JSON Schema,确保上游节点的输出能被下游节点正确解析,避免模型"自由发挥"格式导致下游崩溃;
版本控制与A/B测试:工作流可以保存版本、灰度发布,让业务流程的变更可审计、可回滚,而ReAct的"思维"是临时的、不可版本化的;
人工介入点的刚性插入:在关键节点(如转账确认、内容发布)强制插入"人类审核节点",流程在此暂停并等待外部信号,而不是依赖模型自己决定"要不要问人类";
知识库与LLM的解耦:通过显式的"知识库节点"将RAG过程可视化,人类可以清楚看到"哪些上下文被注入了",而不是像ReAct那样由模型隐式决定检索时机。
在这些技术的加持下,现在已经全面进入了AI Agent时代
2. 什么是 Spring AI Alibaba?
网址:https://java2ai.com/
Spring AI Alibaba 是一个 面向 Java 生态的企业级 AI Agent 开发框架。作为 Agent 框架,它提供了构建生产级 Agent 所需的完整技术栈:
- 上下文管理
- 记忆管理
- Tool Calling机制
- 模型管理
- 多智能体
- 工作流
- RAG
- A2A
- MCP
- Agent Skills
- 等等
3. 环境准备
- Java环境:JDK 17 或更高版本。
- Maven:Maven 3.6 或更高版本。
- AI API Key:
- 访问 阿里云百炼
- 登录阿里云账号(没有就注册一个)
- 进入「模型广场」,点击「API-KEY 管理」
- 创建一个新的 API Key
- 复制保存这个 Key(格式像
sk-xxxxxxxxxxxx) - 注意:key不要泄露给别人
4. 创建第一个项目
4.1 使用Spring Initializr初始化项目


4.2 添加 Spring AI Alibaba 依赖
修改pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<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.5.11</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.mszlu.ai</groupId>
<artifactId>alibaba</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-ai-alibaba</name>
<description>spring-ai-alibaba</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>21</java.version>
<!-- Spring AI Alibaba 版本 -->
<spring-ai-alibaba.version>1.1.2.2</spring-ai-alibaba.version>
<!-- Spring AI 版本 -->
<spring-ai.version>1.1.2</spring-ai.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI Alibaba 核心框架 -->
<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>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
4.3 配置 API Key
注意:IDEA不能实时同步系统环境变量,配置环境变量后,需要重启IDEA使环境变量生效
配置环境变量:
软件地址:https://github.com/mszlu521/devToolsBox

spring:
application:
name: spring-ai-alibaba
ai:
dashscope:
# 你的阿里云 DashScope API Key,这里配置环境变量
api-key: ${AI_DASHSCOPE_API_KEY:default-key}
chat:
options:
model: qwen3-max
# 日志级别
logging:
level:
com.alibaba.cloud.ai: DEBUG
2
3
4
5
6
7
8
9
10
11
12
13
14
在 IDEA 中运行的话,可以直接在 Run Configuration 里设置环境变量
5. 编写第一个 AI 程序
5.1 创建 AI 服务
package com.mszlu.ai.alibaba.service;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* AI 对话服务
*
* 这是你的第一个 AI 服务,它可以和 AI 模型对话!
*/
@Service
public class ChatService {
/**
* ChatModel 就是 AI 模型的"遥控器"
* Spring Boot 会自动注入配置好的模型
*/
private final ChatModel chatModel;
public ChatService(ChatModel chatModel) {
this.chatModel = chatModel;
}
/**
* 最简单的对话方式
*
* @param userInput 用户说的话
* @return AI 的回复
*/
public String simpleChat(String userInput) {
// 直接调用,传入字符串,返回字符串
return chatModel.call(userInput);
}
/**
* 更完整的对话方式
*
* @param userInput 用户说的话
* @return AI 的回复(包含更多元信息)
*/
public String advancedChat(String userInput) {
// 1. 创建用户消息
UserMessage userMessage = new UserMessage(userInput);
SystemMessage systemMessage = new SystemMessage("You are a helpful assistant.");
// 2. 创建 Prompt
Prompt prompt = new Prompt(systemMessage, userMessage);
// 3. 调用模型
ChatResponse response = chatModel.call(prompt);
// 4. 获取 AI 的回复内容
return response.getResult().getOutput().getText();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
5.2 创建 REST API
package com.mszlu.ai.alibaba.controller;
import com.mszlu.ai.alibaba.service.ChatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* AI 对话接口
*
* 通过 HTTP 请求和 AI 对话
*/
@RestController
@RequestMapping("/api/chat")
public class ChatController {
private final ChatService chatService;
public ChatController(ChatService chatService) {
this.chatService = chatService;
}
/**
* 简单对话接口
*
* 使用方法:
* POST http://localhost:8080/api/chat/simple
* Body: {"message": "你好,请介绍一下自己"}
*/
@PostMapping("/simple")
public Map<String, String> simpleChat(@RequestBody Map<String, String> request) {
String userMessage = request.get("message");
String aiResponse = chatService.simpleChat(userMessage);
return Map.of(
"user", userMessage,
"ai", aiResponse
);
}
/**
* GET 方式对话(方便浏览器测试)
*
* 使用方法:
* http://localhost:8080/api/chat/ask?message=你好
*/
@GetMapping("/ask")
public Map<String, String> ask(@RequestParam String message) {
String aiResponse = chatService.simpleChat(message);
return Map.of(
"user", message,
"ai", aiResponse
);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
6. 启动测试
运行SpringAiAlibabaApplication:

简单点,我们使用浏览器进行测试:
http://localhost:8080/api/chat/ask?message=你好,请用一句话介绍Spring AI Alibaba

🎉 恭喜!你已经成功运行了第一个 AI 程序!
7. 代码解析
让我们理解一下刚才写的代码:
用户请求 ──► ChatController ──► ChatService ──► ChatModel ──► AI模型
│ │ │
└──── 返回 JSON ◄────┴── 返回文字 ◄─┘
2
3
| 组件 | 作用 |
|---|---|
ChatController | 接收 HTTP 请求 |
ChatService | 业务逻辑处理 |
ChatModel | 调用 AI 模型 |
| AI 模型 | 生成回复 |
ChatModel是 Spring AI Alibaba 的核心接口,它:
- 封装了不同 AI 模型的调用细节
- 提供统一的调用方式
- 自动处理连接、认证、重试等
8. 课后练习
- 修改提示词:让 AI 以"诗人"的身份回答问题
- 添加新接口:实现一个 GET 接口,返回 AI 对任意话题的简短总结
- 错误处理:给 ChatService 添加 try-catch,处理 API 调用失败的情况
