📖 一、先从“用”开始,理解“它干了啥”
1. 想象一下:点外卖的流程
Spring AI 就像是“AI 服务外卖平台”:
// 你点外卖的代码(实际使用)
@Service
public class CustomerService {
// 这个就是 Spring AI 给你的“外卖小哥”
@Autowired
private ChatClient chatClient;
public String askAi(String question) {
// 点餐(问问题)
String answer = chatClient.call(question);
// 拿到外卖(AI 回答)
return answer;
}
}
你看,你就做了三件事:
- 有个“外卖小哥”(
ChatClient)在等你 - 告诉他“我要问什么”(调用
call方法) - 他给你“带回来答案”
完全不用管:
- 小哥骑什么车(HTTP 还是 gRPC)
- 去哪个餐厅(OpenAI 还是文心一言)
- 怎么付钱(API Key 怎么传)
- 路上堵不堵(网络连接、重试)
🏗️ 二、拆开“外卖小哥”看看里面有什么
1. 外卖小哥的“接单流程”
// 这是外卖小哥的“大脑”(简化版)
public class AiDeliveryGuy {
// 小哥的手机(联系餐厅用)
private Phone phone = new Phone();
// 小哥的钱包(付钱用)
private Wallet wallet = new Wallet();
// 接单流程
public String takeOrder(String customerQuestion) {
// 1. 先看看顾客要什么
System.out.println("顾客说:" + customerQuestion);
// 2. 查查要去哪家餐厅
String restaurant = decideRestaurant(customerQuestion);
// 3. 打电话给餐厅
String order = makeOrder(restaurant, customerQuestion);
// 4. 付钱
pay(restaurant, order);
// 5. 等餐厅做菜
String food = waitForFood(restaurant, order);
// 6. 拿回给顾客
return food;
}
private String decideRestaurant(String question) {
// 如果问题里有“中文”,去“文心一言”餐厅
if (question.contains("中文") || question.contains("中国")) {
return "wenxin";
}
// 否则默认去“OpenAI”餐厅
return "openai";
}
}
🔧 三、Spring AI 的“核心部件”
1. 最重要的“接口”——ChatClient
想象成“外卖APP里的点餐按钮”
// 这就是那个“点餐按钮”
public interface ChatClient {
// 点击按钮,传入问题
String call(String question);
// 高级功能:边等边看进度(流式)
void stream(String question, Consumer<String> onChunk);
}
这个接口的意义:
- 你只知道有个按钮能点
- 你不知道按钮后面是谁在做
- 可能是美团外卖,也可能是饿了么
- Spring AI 帮你“选最好用的那个”
2. 自动配置——Spring 的“智能管家”
想象成“你搬家后,管家自动布置好一切”
// Spring AI 的自动配置(简化版)
@Configuration
public class AiAutoConfig {
// 如果配置里有 openai 的 key,就创建 OpenAI 小哥
@Bean
@ConditionalOnProperty(name = "spring.ai.openai.api-key")
public ChatClient openAiGuy() {
System.out.println("老板,我雇了个 OpenAI 外卖小哥!");
return new OpenAiDeliveryGuy();
}
// 如果配置里有 wenxin 的 key,就创建文心一言小哥
@Bean
@ConditionalOnProperty(name = "spring.ai.wenxin.api-key")
public ChatClient wenxinGuy() {
System.out.println("老板,我雇了个文心一言外卖小哥!");
return new WenxinDeliveryGuy();
}
}
配置文件(application.yml):
spring:
ai:
openai:
api-key: sk-1234567890 # 有了这个,就雇 OpenAI 小哥
# wenxin:
# api-key: abcdefg # 注释掉,就不雇文心一言小哥
3. OpenAI 外卖小哥的真实工作
// OpenAI 外卖小哥的“工作手册”
public class OpenAiDeliveryGuy implements ChatClient {
private String apiKey; // 餐厅会员卡
private String baseUrl = "https://api.openai.com/v1"; // 餐厅地址
@Override
public String call(String question) {
// 1. 准备“点菜单”(JSON格式)
String orderForm = """
{
"model": "gpt-3.5-turbo",
"messages": [
{"role": "user", "content": "%s"}
],
"temperature": 0.7
}
""".formatted(question);
// 2. 打电话给餐厅(发HTTP请求)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/chat/completions"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + apiKey)
.POST(HttpRequest.BodyPublishers.ofString(orderForm))
.build();
// 3. 等待餐厅回复
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
// 4. 解析回复,取出“菜”(AI回答)
String responseJson = response.body();
// 假设 responseJson 是: {"choices":[{"message":{"content":"你好!"}}]}
String answer = parseAnswer(responseJson);
return answer;
}
private String parseAnswer(String json) {
// 简单解析JSON,实际用Jackson/Gson
int start = json.indexOf("\"content\":\"") + 11;
int end = json.indexOf("\"", start);
return json.substring(start, end);
}
}
🔄 四、完整流程动画演示
1. 场景:小明用 Spring AI 问天气
2. 代码级别的流程
// 这是实际 Spring AI 内部的大概流程
public class SpringAiMagic {
public String processQuestion(String question) {
// 第1步:找“外卖小哥”(ChatClient)
ChatClient deliveryGuy = findDeliveryGuy();
// 第2步:检查“小哥”的健康状况
if (!deliveryGuy.isHealthy()) {
// 小哥生病了,换个健康的
deliveryGuy = findBackupGuy();
}
// 第3步:记录“开始送餐时间”
long startTime = System.currentTimeMillis();
try {
// 第4步:小哥去送餐(调用AI)
String answer = deliveryGuy.call(question);
// 第5步:记录“送餐完成时间”
long endTime = System.currentTimeMillis();
System.out.println("送餐耗时:" + (endTime - startTime) + "ms");
return answer;
} catch (Exception e) {
// 第6步:如果出错了(比如餐厅关门)
System.out.println("送餐失败:" + e.getMessage());
// 尝试重试
return retryDelivery(question);
}
}
private ChatClient findDeliveryGuy() {
// 这里就是 Spring AI 的“智能”所在:
// 1. 查看配置文件
// 2. 查看类路径
// 3. 决定用哪个外卖平台
return new OpenAiDeliveryGuy(); // 假设配置了 OpenAI
}
}
🎯 五、Spring AI 的“智能”体现在哪?
1. 自动选择“最优外卖小哥”
// Spring AI 的“智能调度中心”
public class AiDispatcher {
private Map<String, ChatClient> deliveryGuys = new HashMap<>();
public AiDispatcher() {
// 注册所有可用的小哥
deliveryGuys.put("openai", new OpenAiDeliveryGuy());
deliveryGuys.put("wenxin", new WenxinDeliveryGuy());
deliveryGuys.put("azure", new AzureDeliveryGuy());
deliveryGuys.put("local", new LocalDeliveryGuy());
}
public ChatClient dispatch(String model) {
// 规则1:如果指定了模型,用对应的
if (model != null) {
if (model.contains("gpt")) return deliveryGuys.get("openai");
if (model.contains("ernie")) return deliveryGuys.get("wenxin");
}
// 规则2:看配置文件里启用了哪个
if (config.hasOpenAiKey()) return deliveryGuys.get("openai");
if (config.hasWenxinKey()) return deliveryGuys.get("wenxin");
// 规则3:都没配置,用本地的(如果有)
if (deliveryGuys.get("local") != null) {
return deliveryGuys.get("local");
}
throw new RuntimeException("一个外卖小哥都没雇!");
}
}
2. 自动处理“各种意外情况”
// Spring AI 的“应急预案”
public class EmergencyPlan {
public String askWithBackup(String question) {
try {
// 首选方案:OpenAI
return openAiGuy.call(question);
} catch (TooManyRequestsException e) {
// 情况1:OpenAI 说“太忙了,等会儿”
System.out.println("OpenAI 忙,换文心一言试试");
return wenxinGuy.call(question);
} catch (NetworkException e) {
// 情况2:网络不通
System.out.println("网络不通,用本地模型");
return localGuy.call(question);
} catch (AllFailedException e) {
// 情况3:全都挂了
return "抱歉,AI 服务暂时不可用,请稍后再试";
}
}
}
📦 六、Spring AI 的“工具箱”里还有什么?
1. 向量数据库(给 AI 加“记忆”)
// 想象成“AI 的笔记本”
public class AiNotebook {
private Map<String, String> memory = new HashMap<>();
public void teachAi(String topic, String knowledge) {
// 教 AI 知识
memory.put(topic, knowledge);
System.out.println("已教会 AI 关于:" + topic);
}
public String askWithMemory(String question) {
// 1. 先在“笔记本”里找答案
for (String topic : memory.keySet()) {
if (question.contains(topic)) {
System.out.println("从笔记本找到了答案!");
return memory.get(topic);
}
}
// 2. 笔记本里没有,问 AI
return chatClient.call(question);
}
}
2. 流式响应(“边做边吃”)
// 传统方式:等菜全做好再上
public String getFullAnswer(String question) {
// AI 要思考 10 秒才能给出完整答案
String fullAnswer = chatClient.call(question); // 等 10 秒
return fullAnswer; // 10 秒后一次返回
}
// 流式:上一道吃一道
public void getStreamAnswer(String question, Consumer<String> onChunk) {
// AI 边想边说
chatClient.stream(question, chunk -> {
// 每想到一点,就返回一点
onChunk.accept(chunk);
// 用户能先看到“今天”,然后看到“天气”,最后看到“晴朗”
});
}
🎪 七、实际项目中的“实战场景”
场景1:智能客服系统
@Service
public class CustomerServiceBot {
@Autowired
private ChatClient aiAssistant; // Spring AI 提供
// 传统客服的“知识库”
private Map<String, String> faq = Map.of(
"退货", "7天内可无理由退货",
"物流", "一般3-5天送达",
"客服电话", "400-123-4567"
);
public String answerCustomer(String question) {
// 1. 先看 FAQ 里有没有
for (String keyword : faq.keySet()) {
if (question.contains(keyword)) {
return faq.get(keyword);
}
}
// 2. FAQ 没有,问 AI
String prompt = """
你是客服助手,请用友好、专业的语气回答用户问题。
用户问题:%s
""".formatted(question);
return aiAssistant.call(prompt);
}
}
场景2:代码助手
@Service
public class CodeAssistant {
@Autowired
private ChatClient aiCoder;
public String explainCode(String code) {
String prompt = """
请解释这段代码是做什么的:
```java
%s
```
""".formatted(code);
return aiCoder.call(prompt);
}
public String fixBug(String error, String code) {
String prompt = """
遇到这个错误:%s
在代码中:%s
请帮我修复。
""".formatted(error, code);
return aiCoder.call(prompt);
}
}
🔧 八、自己动手“造轮子”(理解原理)
1. 最简化的 Spring AI 实现
// 第一步:定义“外卖小哥”接口
public interface SimpleAiClient {
String ask(String question);
}
// 第二步:实现“OpenAI 小哥”
@Component
@ConditionalOnProperty(name = "ai.provider", havingValue = "openai")
public class OpenAiClient implements SimpleAiClient {
@Value("${ai.openai.key}")
private String apiKey;
@Override
public String ask(String question) {
// 最简单的 HTTP 调用
String url = "https://api.openai.com/v1/chat/completions";
String json = String.format("""
{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "%s"}]
}
""", question);
// 发送请求,解析响应(省略细节)
return sendHttpRequest(url, json, apiKey);
}
}
// 第三步:自动配置
@Configuration
public class SimpleAiConfig {
@Bean
@ConditionalOnMissingBean
public SimpleAiClient aiClient() {
// 根据配置决定用哪个
String provider = environment.getProperty("ai.provider", "openai");
if ("openai".equals(provider)) {
return new OpenAiClient();
} else if ("mock".equals(provider)) {
return new MockAiClient(); // 测试用的假 AI
}
throw new IllegalStateException("不支持的 AI 提供商");
}
}
// 第四步:使用
@Service
public class MyService {
@Autowired
private SimpleAiClient aiClient; // 注入
public void doSomething() {
String answer = aiClient.ask("你好吗?");
System.out.println("AI 回答:" + answer);
}
}
📚 九、总结:Spring AI 到底做了什么?
用一句话总结:
Spring AI 把“调用各种 AI 服务”这件麻烦事,变成了“点外卖”一样简单。
具体来说:
| 你的烦恼 | Spring AI 的解决方案 |
|---|---|
| 每个 AI 服务 API 不一样 | 统一接口,你只用学一种 |
| HTTP 请求、JSON 解析好麻烦 | 框架帮你搞定 |
| 出错要重试、监控、日志 | 内置,开箱即用 |
| 换 AI 服务要改代码 | 改配置就行 |
| 要自己管理 API Key、连接池 | 自动管理 |
最后记住这个比喻:
ChatClient= 外卖小哥@Autowired= 小哥到你公司报到application.yml= 小哥的工作安排表call()方法 = 告诉小哥“去帮我买个饭”- Spring AI 框架 = 外卖平台(美团/饿了么)
你不需要知道:
- 小哥骑什么车
- 走哪条路
- 怎么跟餐厅沟通
- 怎么付钱
你只需要:
@Autowired
ChatClient 外卖小哥;
String 饭 = 外卖小哥.买饭("我要鱼香肉丝");
System.out.println("吃到了:" + 饭);
这就是 Spring AI 的核心思想:让复杂的事情变简单,让你专注于业务,而不是技术细节。
1356

被折叠的 条评论
为什么被折叠?



