Spring AI 作为 Java 生态的 AI 开发利器,极大降低了 AI 模型集成门槛,但在实际落地中,静态类型约束、语法繁琐等问题仍困扰着开发者:JDK 21+ 才支持的文字模板、AI 返回不确定性导致的类型适配难题、重复模板构建冗余等痛点,让"高效集成 AI"大打折扣。而 Groovy 凭借动态类型、灵活语法、无缝兼容 Java 的特性,恰好能精准破解这些痛点,让 Spring AI 开发更简洁、更灵活、更适配 AI 场景的不确定性。
一、前置准备
基于 Spring AI 1.1.0(最新稳定版本),Groovy 4.x 可无缝兼容,环境搭建仅需 3 步,比 Java 开发少去类型配置冗余。
1. 依赖配置(Maven 示例,Gradle 同理)
xml
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Spring Boot 父依赖,统一管理 Spring Boot 版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.8</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>groovy-spring-ai-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 统一管理 Spring AI 版本(等效 Gradle 的 dependencyManagement) -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Groovy 核心依赖(等效 Gradle 的 implementation) -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>4.0.29</version>
<type>pom</type>
</dependency>
<!-- Spring Boot 基础依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Spring AI OpenAI 组件 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai</artifactId>
</dependency>
<!-- 测试依赖(等效 Gradle 的 testImplementation) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Groovy 编译插件(Gradle 中 groovy 插件的等效实现) -->
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.13.1</version>
<executions>
<execution>
<goals>
<goal>compile</goal> <!-- 编译 Groovy 源码 -->
<goal>testCompile</goal> <!-- 编译 Groovy 测试源码 -->
</goals>
</execution>
</executions>
</plugin>
<!-- Spring Boot 打包插件(生成可执行 JAR) -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.GroovySpringAiApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
<!-- 配置 Java 版本(等效 Gradle 的 java 配置块) -->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
2. API Key 配置(application.groovy)
Groovy 配置文件支持动态逻辑,无需硬编码,比 YAML 更灵活:
groovy
// 读取环境变量,避免密钥泄露
spring.ai.openai.api-key = System.getenv("SPRING_AI_OPENAI_API_KEY")
spring.ai.openai.chat {
model = "gpt-3.5-turbo"
temperature = 0.6
max-tokens = 2048
}
3. 启动类(极简写法)
groovy
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
class GroovySpringAiApplication {
static void main(String[] args) {
SpringApplication.run(GroovySpringAiApplication, args)
}
}
二、核心痛点破解
痛点 1:Prompt 模板适配受限------Java 需 JDK 21+ 支持,Groovy 天生兼容
Java 中构建动态 Prompt 模板,需依赖 JDK 21 的文本块插值(STR."..."),低版本 JDK 只能用 String.format() 或字符串拼接,代码冗余且易出错;而 Groovy 原生支持字符串模板,无需依赖高版本 JDK,且语法更简洁。
Groovy 解决方案:动态字符串模板 + 闭包构建 Prompt
groovy
import org.springframework.ai.chat.ChatClient
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
@Service
class PromptService {
@Autowired
ChatClient chatClient
// 场景:构建带动态参数的 RAG 检索 Prompt
def ragPrompt(String userQuery, List<String> contextDocs) {
// 1. Groovy 字符串模板:直接嵌入变量和表达式,无需拼接
def systemPrompt = """
你是知识库助手,基于以下上下文回答用户问题:
${contextDocs.join("\n\n")}
规则:仅用上下文信息回答,不编造内容;回答简洁明了。
"""
// 2. 闭包快速构建结构化 Prompt(比 Java 链式调用更直观)
def response = chatClient.prompt {
system(systemPrompt)
user(userQuery)
}.call()
return response.content
}
}
优势对比:
| 特性 | Java(JDK < 21) | Groovy |
|---|---|---|
| 模板语法 | 需用 String.format(),占位符易混乱 |
直接 $变量 或 ${表达式},直观简洁 |
| 多行 Prompt | 需手动拼接 + 或文本块,格式易乱 |
三引号 """ 原生支持,保留换行和格式 |
| 低版本 JDK 兼容性 | 不支持文本插值,模板构建繁琐 | 全版本兼容,无需升级 JDK |
痛点 2:AI 返回不确定性------静态类型适配难,判定逻辑冗余
AI 模型返回结果存在两大不确定性:一是格式不确定(如有时返回 JSON、有时返回纯文本),二是内容不确定(如可选字段可能缺失)。Java 静态类型需提前定义实体类,一旦返回格式不符就会抛出解析异常;且判定返回类型需写大量 instanceof 或字符串匹配逻辑,代码臃肿。
Groovy 解决方案:动态类型 + 简洁判定逻辑
groovy
import org.springframework.ai.chat.ChatResponse
import groovy.json.JsonSlurper
@Service
class AiResponseService {
private final JsonSlurper jsonSlurper = new JsonSlurper()
// 处理 AI 动态返回(支持 JSON/纯文本两种格式)
def processDynamicResponse(ChatResponse response) {
def content = response.content.trim()
// 1. 动态判定返回格式(Groovy 简洁语法替代 Java 冗长逻辑)
if (content.startsWith("{") && content.endsWith("}")) {
// 2. 动态解析 JSON,无需实体类(适配字段缺失场景)
def json = jsonSlurper.parseText(content)
return [
type: "json",
data: json,
message: json.message ?: "默认提示" // 空值默认符,避免 NPE
]
} else {
// 3. 纯文本处理,动态提取关键信息
return [
type: "text",
data: content,
keywords: content.findAll(~/(Groovy|Spring AI|向量存储)/) // 正则快速提取
]
}
}
}
核心优势:
- 动态类型适配:无需定义
AiResponse实体类,用 Map 直接接收动态结果,字段缺失不会报错; - 空值安全处理:
json.message ?: "默认提示"替代 Javaif (json.getMessage() != null)判定; - 判定逻辑简化:正则匹配、字符串判断用一行代码完成,比 Java 少 50% 冗余。
痛点 3:重复模板与参数配置------Java 需多类封装,Groovy DSL 一键解决
Spring AI 开发中,不同场景(如 RAG、翻译、摘要)需重复构建相似 Prompt 模板,且模型参数(如 temperature、maxTokens)需灵活调整。Java 需创建多个模板类或 Builder 类,而 Groovy 可通过 DSL (领域特定语言)封装通用逻辑,实现"一键复用+动态配置"。
Groovy 解决方案:DSL 封装通用 Prompt 模板
groovy
@Service
class AiTemplateService {
@Autowired
ChatClient chatClient
// 定义 DSL:封装通用 Prompt 模板,支持动态参数配置
def aiCall(String templateType, Map params = [:]) {
// 通用参数默认值(Groovy 可选参数,无需重载)
def temp = params.temperature ?: 0.6
def maxTokens = params.maxTokens ?: 1024
// 模板路由(Groovy switch 支持区间、字符串匹配,比 Java 强大)
def (systemPrompt, userPrompt) = switch (templateType) {
case "summary":
def text = params.text
["你是文本摘要助手,总结需控制在 30 字内", "总结:$text"]
break
case "translate":
def text = params.text
def targetLang = params.targetLang ?: "中文"
["你是翻译助手,精准翻译为 $targetLang,无额外解释", "翻译:$text"]
break
case "rag":
def context = params.context
def query = params.query
["基于上下文回答:$context", query]
break
}
// 动态调整模型参数
def response = chatClient.prompt {
system(systemPrompt)
user(userPrompt)
options {
temperature(temp)
maxTokens(maxTokens)
}
}.call()
return response.content
}
}
使用示例:
less
// 1. 调用摘要模板
def summary = aiTemplateService.aiCall("summary", [text: "Groovy 是 Java 动态增强版,支持简洁语法和函数式编程"])
// 2. 调用翻译模板(指定目标语言和温度)
def translate = aiTemplateService.aiCall("translate", [text: "Spring AI is powerful", targetLang: "英文", temperature: 0.3])
优势 :用 DSL 封装重复逻辑,新增模板只需添加 case 分支,无需创建新类;参数支持默认值,调用更灵活,比 Java 减少 60% 模板代码。
痛点 4:向量存储文档处理繁琐------Java 循环冗余,Groovy 集合一键搞定
Spring AI 向量存储(如 Pinecone、Chroma)需将原始文本转为 Document 对象,Java 需通过 for 循环遍历、手动设置属性,代码冗余;且相似性查询结果处理需多步 Stream 操作,可读性差。
Groovy 解决方案:集合闭包 + 动态属性赋值
groovy
import org.springframework.ai.document.Document
import org.springframework.ai.pinecone.PineconeVectorStore
import org.springframework.beans.factory.annotation.Autowired
@Service
class VectorStoreService {
@Autowired
PineconeVectorStore vectorStore
// 批量添加文档到向量库(一行完成转换)
def batchAddDocs(List<String> texts, Map<String, String> commonMeta = [:]) {
// Groovy 集合 collect 闭包:替代 Java for 循环,快速转为 Document
def docs = texts.collect { text ->
new Document(
id: UUID.randomUUID().toString(),
content: text,
metadata: commonMeta + [createTime: new Date().format("yyyy-MM-dd HH:mm:ss")] // 元数据合并
)
}
vectorStore.add(docs)
return docs.size()
}
// 相似性查询 + 结果过滤
def searchSimilar(String query, int topK = 3) {
// 查询结果处理:过滤相似度低于 0.7 的文档
def results = vectorStore.similaritySearch(query, topK)
.findAll { it.metadata.similarityScore >= 0.7 } // 闭包过滤,比 Java Stream 简洁
.collect { doc ->
[
id: doc.id,
content: doc.content.take(100), // 截取前 100 字
score: doc.metadata.similarityScore
]
}
return results
}
}
三、实战落地:RAG 检索增强流程示例
结合以上痛点解决方案,实现一个"文档入库→相似检索→AI 回答"的完整 RAG 流程,体现 Groovy + Spring AI 的丝滑开发体验:
groovy
import org.springframework.boot.CommandLineRunner
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
class GroovySpringAiRagApplication implements CommandLineRunner {
@Autowired
VectorStoreService vectorStoreService
@Autowired
AiTemplateService aiTemplateService
static void main(String[] args) {
SpringApplication.run(GroovySpringAiRagApplication, args)
}
@Override
void run(String... args) throws Exception {
// 1. 准备知识库文档
def knowledgeDocs = [
"Groovy 支持动态类型,用 def 关键字声明变量,无需指定具体类型",
"Spring AI 1.0.0-M7 支持 OpenAI、Pinecone 等组件,需引入 spring-ai-bom 统一版本",
"Groovy 字符串模板支持 $变量 和 ${表达式},无需拼接字符串"
]
// 2. 批量添加文档到向量库
def docCount = vectorStoreService.batchAddDocs(knowledgeDocs, [source: "groovy-spring-ai-docs"])
println("成功入库 $docCount 条知识库文档")
// 3. 用户查询
def userQuery = "Groovy 如何简化 Spring AI 的 Prompt 构建?"
// 4. 相似检索(获取相关上下文)
def similarDocs = vectorStoreService.searchSimilar(userQuery)
def context = similarDocs.collect { it.content }.join("\n\n")
println("检索到相关文档:\n$context")
// 5. 调用 AI 生成回答(使用 RAG 模板)
def aiAnswer = aiTemplateService.aiCall("rag", [context: context, query: userQuery])
println("\nAI 回答:\n$aiAnswer")
}
}
运行结果:
ruby
成功入库 3 条知识库文档
检索到相关文档:
Groovy 字符串模板支持 $变量 和 ${表达式},无需拼接字符串
AI 回答:
Groovy 可通过字符串模板直接嵌入 $变量 或 ${表达式} 构建 Prompt,无需拼接;还能借助闭包快速构建结构化 Prompt(含 system 和 user 指令),比 Java 更简洁,且无需依赖高版本 JDK。
四、小结
对于 Java 开发者而言,Groovy 学习成本极低,且完全兼容 Spring AI 生态,无需重构现有代码即可无缝集成。无论是快速验证 AI 模型能力、搭建 RAG 检索系统,还是开发复杂多模型应用,Groovy + Spring AI 都能让 AI 开发从"繁琐适配"变为"丝滑落地",是 Java 生态下 AI 工程化的高效组合。