我向来对“整合大模型进 Java 应用”这件事持谨慎态度。在 GPT 火了之后,我们团队最初是用 HTTP 手动调 OpenAI 接口,把它当成一个 JSON API 用。但随着业务交互变复杂,我意识到:我们需要的是一个语义系统,而不是一个封装 prompt 的 util 类。
这时,Spring AI 出现了。
它不是框架革命,而是语义层和 Spring 编程模型之间的桥梁。你可以像写 Spring Boot Controller 那样调用大模型,像写 Bean 那样组织提示词和语义模板。
以下是我亲身踩过的坑与总结。
Spring AI 是什么?一句话版本
Spring AI 是 Spring 推出的 AI 集成框架,它封装了与 OpenAI、Azure、HuggingFace、Anthropic 等主流 LLM 提供商的连接逻辑,并基于 Spring 编程模型提供统一的:
- Prompt 模板机制
- Function 调用能力(Function calling)
- Embedding 向量搜索整合(如与 Redis、PGVector、Milvus 等)
- ChatMemory 管理
- RAG(检索增强生成)支持
第一步:快速跑通 OpenAI 接入
引入依赖(当前主流版本建议使用 0.8.1 或以上):
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>0.8.1</version>
</dependency>
application.yml 配置如下:
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai.com/v1
chat:
model: gpt-4
然后写个最基础的服务类:
@Service
public class AiAssistant {
private final OpenAiChatClient chatClient;
public AiAssistant(OpenAiChatClient chatClient) {
this.chatClient = chatClient;
}
public String ask(String question) {
ChatResponse response = chatClient.call(question);
return response.getResult().getOutput().getContent();
}
}
你会惊讶于它的“Spring 味儿”有多重 —— ChatClient 就像 RestTemplate
,但背后驱动的是 LLM。
第二步:PromptTemplate 的强大之处
Spring AI 真正让我惊艳的,是 PromptTemplate
和 PromptTemplateModel
。
举个例子,我们想做一个发票解析助手:
String template = """
你是一个发票专家,请从以下文本中提取字段:
{{text}}
返回格式:
{
"invoiceCode": "",
"invoiceNumber": "",
"amount": "",
"date": ""
}
""";
PromptTemplate promptTemplate = new PromptTemplate(template);
promptTemplate.add("text", ocrResult);
Prompt prompt = promptTemplate.create();
ChatResponse response = chatClient.call(prompt);
为什么说它强大?因为它把 prompt 当作模板文件处理,变量和代码解耦,可调试、可重构、可测试 —— 这比我们以前把 prompt 字符串硬编码在 Java 里强太多。
第三步:函数调用(Function Call)集成
Spring AI 支持大模型的函数调用(Function Calling)能力。你可以像注册 Spring Bean 一样注册 AI 能“调用”的 Java 方法:
@Component
public class InvoiceFunction {
@AiFunction
public String parseInvoice(@AiFunctionParameter(name = "text") String text) {
// 实际是把这个方法暴露给大模型,让它决定是否调用
return someService.extractInvoiceJson(text);
}
}
这意味着你可以让 LLM 成为业务流程中的“指挥员”,它不再只是吐字,而是能决定调用哪个函数、传什么参数。
第四步:向量检索 + Embedding(RAG 模式)
Spring AI 原生支持嵌入向量生成和搜索。以下是一个 Redis + Embedding 的组合示例:
- 首先配置 Redis 向量存储(需使用 Redis Stack):
spring:
ai:
vectorstore:
redis:
host: localhost
port: 6379
- 注入向量存储和 embedding 模型:
@Autowired
private VectorStore vectorStore;
@Autowired
private EmbeddingClient embeddingClient;
- 索引知识库:
EmbeddingResponse embedding = embeddingClient.embed("这是发票的开票代码含义说明…");
vectorStore.add(List.of(new Vector("invoice-001", embedding.getEmbedding(), metadata)));
- 在对话中执行 RAG 检索:
List<Document> docs = vectorStore.similaritySearch("什么是发票代码", 3);
String context = docs.stream().map(Document::getContent).collect(Collectors.joining("\n"));
- 拼接到 Prompt 中:
String prompt = "基于以下知识回答问题:\n" + context + "\n问题:什么是发票代码?";
这样你就完成了一个端到端的 RAG 系统,模型可以“读”你自己喂的文档。
项目实战技巧总结
- Prompt 模板一定要版本管理:我们用 YAML + Git 存储每个 PromptTemplate,避免代码污染和可追踪。
- 用注解暴露函数给大模型,是一种未来的编排模式:特别适合 Workflow 逻辑。
- LLM 的不可控性,需要用 ChatMemory 管住上下文:Spring AI 提供了
MemoryChatClient
封装 chat history,避免上下文漂移。 - 别忽视异常处理:OpenAI 接口 rate limit、timeout 经常发生,Spring AI 建议用
RetryTemplate
或自定义 fallback。
写在最后:Spring AI 更像一个“语言中间件”
Spring AI 不是大模型的封装器,而是让 Spring 应用具备“语言交互能力”的中间件。
它就像当年的 Spring Data,让我们用接口操作数据库;现在我们也可以用 Spring 风格操作语义接口。
你不再需要理解 token、role、chat-completion payload,只需要关注一件事:
“业务中哪块逻辑,可以更好地用语言来处理?”
从接口设计、代码结构,到 Prompt 管理和知识检索,Spring AI 都在逐渐成为一种“主流选型”。