Spring AI Alibaba 项目初始化:Maven依赖与YAML配置全解析

Spring AI Alibaba 项目初始化:Maven依赖与YAML配置全解析

导读:上一篇完成了第一个 Hello World,本文将系统性地讲解企业级 Spring AI Alibaba 项目的配置体系------从 BOM 版本对齐到多模型并存,从 Profile 环境隔离到三级 ChatOptions 覆盖机制。读完这篇,你可以直接拿配置模板进公司项目用。


一、为什么配置问题是最大的"时间黑洞"

我见过很多团队在接入 Spring AI Alibaba 时,代码写不了几行,先被依赖冲突折腾了半天:Spring AI 版本和 Alibaba 版本对不上,BOM 没引好,同时接多个模型时 Bean 名字冲突...

这些问题的根源不是技术难度,而是没有一套清晰的配置认知。本文的目标就是把这些"隐形坑"全部翻出来,给你一张可复用的配置地图。


二、BOM 依赖管理:版本对齐的核心手段

2.1 什么是 BOM,为什么需要它

BOM(Bill of Materials)是 Maven 的一种依赖管理机制,本质上是一个只包含 <dependencyManagement> 的特殊 POM。引入 BOM 后,该 BOM 管辖的所有依赖版本都由 BOM 统一决定,你无需在每个依赖上手动填写版本号。

Spring AI Alibaba 涉及的依赖模块较多(dashscope、milvus、redis、mcp 等),版本不一致极易引发运行时异常。BOM 是最优雅的解法。

2.2 完整 BOM 配置示例

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>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.5</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>ai-enterprise</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <java.version>17</java.version>
        <!-- Spring AI Alibaba 版本,与 spring-ai 1.1.2 对齐 -->
        <spring-ai-alibaba.version>1.1.2.2</spring-ai-alibaba.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- ① Spring AI Alibaba BOM:管理所有 com.alibaba.cloud.ai 子模块版本 -->
            <dependency>
                <groupId>com.alibaba.cloud.ai</groupId>
                <artifactId>spring-ai-alibaba-bom</artifactId>
                <version>${spring-ai-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- Web 支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- ② DashScope(通义千问)模型接入 -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- Spring Boot DevTools(可选,开发阶段热重载) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.3 多模型依赖配置

如果项目需要同时使用通义千问、OpenAI 以及本地 Ollama,依赖如下:

xml 复制代码
<!-- 通义千问(阿里云百炼) -->
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>

<!-- OpenAI(含 GPT-4 等) -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>

<!-- Ollama(本地模型,离线兜底用) -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>

注意 :同时引入多个模型 starter 时,Spring 容器里会存在多个 ChatModel Bean,需要使用 @Qualifier 或配置 primary 来指定默认使用哪个,后文会详细说明。

2.4 版本兼容性速查表

复制代码
+-------------------------+------------------+-------------------+
| Spring AI Alibaba       | Spring AI        | Spring Boot       |
+-------------------------+------------------+-------------------+
| 1.1.2.2(当前推荐)      | 1.1.2            | 3.3.x / 3.2.x    |
| 1.1.2.1(有已知 bug)    | 1.1.2            | 3.3.x / 3.2.x    |
| 1.0.0.3                 | 1.0.0            | 3.2.x            |
| 1.0.0-M5.1(旧里程碑)   | 1.0.0-M5         | 3.2.x            |
+-------------------------+------------------+-------------------+

三、YAML 配置体系:从单文件到企业分层

3.1 基础配置文件结构

对于 AI 配置,建议将其独立到专属文件,而非堆在主 application.yml 里:

复制代码
src/main/resources/
├── application.yml          # 公共配置(端口、应用名等)
├── application-ai.yml       # AI 相关配置(模型、参数等)
├── application-dev.yml      # 开发环境配置
└── application-prod.yml     # 生产环境配置

application.yml 主配置:

yaml 复制代码
spring:
  application:
    name: ai-enterprise
  profiles:
    # 默认激活 dev + ai 两个 profile
    active: dev,ai

server:
  port: 8080
  servlet:
    encoding:
      charset: UTF-8
      force: true

3.2 application-ai.yml:AI 专属配置

yaml 复制代码
# ==========================================
# Spring AI Alibaba 统一 AI 配置
# ==========================================
spring:
  ai:
    # ---- DashScope(通义千问)配置 ----
    dashscope:
      # API Key 通过环境变量注入,避免硬编码
      api-key: ${AI_DASHSCOPE_API_KEY}
      chat:
        options:
          # 默认模型(全局缺省值)
          model: qwen-turbo
          temperature: 0.7
          top-p: 0.8
          max-tokens: 2048
          # 是否启用增量流式输出(仅流式接口有效)
          incremental-output: true
      # Embedding 模型配置
      embedding:
        options:
          model: text-embedding-v3

    # ---- OpenAI 配置(如需接入) ----
    openai:
      api-key: ${OPENAI_API_KEY:}
      # 如使用代理或兼容接口,可修改 base-url
      base-url: https://api.openai.com
      chat:
        options:
          model: gpt-4o-mini
          temperature: 0.7

    # ---- Ollama 本地模型配置(离线兜底) ----
    ollama:
      base-url: http://localhost:11434
      chat:
        options:
          model: llama3.2
          temperature: 0.5

3.3 application-dev.yml:开发环境覆盖

yaml 复制代码
spring:
  ai:
    dashscope:
      # 开发环境可用测试 Key,降低成本
      api-key: ${AI_DASHSCOPE_API_KEY_DEV:${AI_DASHSCOPE_API_KEY}}
      chat:
        options:
          # 开发环境使用最便宜的模型
          model: qwen-turbo
          max-tokens: 1024

logging:
  level:
    com.alibaba.cloud.ai: DEBUG
    org.springframework.ai: DEBUG

3.4 application-prod.yml:生产环境覆盖

yaml 复制代码
spring:
  ai:
    dashscope:
      chat:
        options:
          # 生产环境用能力更强的模型
          model: qwen-plus
          max-tokens: 4096

logging:
  level:
    com.alibaba.cloud.ai: WARN
    org.springframework.ai: WARN

四、多模型并存:Bean 命名与注入策略

4.1 多 ChatModel 场景下的 Bean 冲突问题

当同时引入 DashScope 和 OpenAI 两个 starter,Spring 容器里会有两个 ChatModel 实现:DashScopeChatModelOpenAiChatModel。直接 @Autowired ChatModel 会报 NoUniqueBeanDefinitionException

解决方案有三种:

方案一:使用 @Qualifier 指定 Bean 名称(推荐)

java 复制代码
@Service
public class MultiModelService {

    private final ChatClient qwenClient;
    private final ChatClient openaiClient;

    public MultiModelService(
            // Spring AI Alibaba 注册的 Builder Bean 名称
            @Qualifier("dashscopeChatClientBuilder") ChatClient.Builder qwenBuilder,
            @Qualifier("openAiChatClientBuilder") ChatClient.Builder openaiBuilder) {

        this.qwenClient = qwenBuilder
                .defaultSystem("你是通义千问助手")
                .build();
        this.openaiClient = openaiBuilder
                .defaultSystem("You are a helpful assistant")
                .build();
    }

    public String askQwen(String question) {
        return qwenClient.prompt(question).call().content();
    }

    public String askOpenAI(String question) {
        return openaiClient.prompt(question).call().content();
    }
}

方案二:手动配置 @Primary 指定默认 Bean

java 复制代码
@Configuration
public class AiModelConfig {

    /**
     * 将 DashScope 设为默认 ChatModel
     * 其他地方 @Autowired ChatModel 时,优先注入此 Bean
     */
    @Bean
    @Primary
    public ChatClient defaultChatClient(
            @Qualifier("dashscopeChatModel") ChatModel dashScopeModel) {
        return ChatClient.builder(dashScopeModel)
                .defaultSystem("你是一个企业级智能助手")
                .build();
    }
}

方案三:基于 ChatModel 手动构建(最灵活)

java 复制代码
@Configuration
public class ChatClientConfig {

    @Bean("qwenChatClient")
    public ChatClient qwenChatClient(DashScopeChatModel dashScopeModel) {
        return ChatClient.builder(dashScopeModel)
                .defaultSystem("你是通义千问,由阿里云提供支持")
                .defaultOptions(DashScopeChatOptions.builder()
                        .withModel("qwen-max")
                        .withTemperature(0.7)
                        .build())
                .build();
    }

    @Bean("openaiChatClient")
    public ChatClient openaiChatClient(OpenAiChatModel openAiModel) {
        return ChatClient.builder(openAiModel)
                .defaultSystem("You are a helpful assistant powered by OpenAI")
                .build();
    }
}

4.2 DeepSeek-R1 接入配置

DeepSeek-R1 可通过兼容 OpenAI 接口的方式接入(百炼平台已上架 DeepSeek 模型):

yaml 复制代码
spring:
  ai:
    openai:
      # 使用阿里云百炼提供的 DeepSeek 兼容接口
      api-key: ${AI_DASHSCOPE_API_KEY}
      base-url: https://dashscope.aliyuncs.com/compatible-mode
      chat:
        options:
          model: deepseek-r1

对应的 Java 配置:

java 复制代码
@Bean("deepseekChatClient")
public ChatClient deepseekChatClient(
        @Qualifier("openAiChatModel") OpenAiChatModel openAiModel) {
    return ChatClient.builder(openAiModel)
            .defaultSystem("你是 DeepSeek-R1,擅长深度推理和分析")
            .build();
}

五、ChatOptions 三级覆盖机制详解

这是 Spring AI 体系中最容易被忽视但极其重要的特性,理解它能让你灵活控制每一次模型调用的行为。

5.1 三级结构示意

复制代码
Level 1:YAML 全局配置(优先级最低)
    spring.ai.dashscope.chat.options.temperature = 0.7
            |
            | (被 Level 2 覆盖)
            v
Level 2:ChatClient Builder 构建时的 defaultOptions
    ChatClient.builder(model)
        .defaultOptions(DashScopeChatOptions.builder()
            .withTemperature(0.8)  // 覆盖 YAML 的 0.7
            .build())
        .build()
            |
            | (被 Level 3 覆盖)
            v
Level 3:单次调用时的 .options(...)(优先级最高)
    chatClient.prompt(msg)
        .options(DashScopeChatOptions.builder()
            .withTemperature(1.2)  // 此次调用使用 1.2
            .build())
        .call()

5.2 实战:不同场景使用不同参数

java 复制代码
@Service
@RequiredArgsConstructor
public class SmartChatService {

    // 注入全局 ChatClient(使用 YAML 配置的默认参数)
    private final ChatClient chatClient;

    /**
     * 代码生成场景:低温度,输出稳定确定
     */
    public String generateCode(String requirement) {
        return chatClient.prompt()
                .system("你是一个资深 Java 开发工程师,只输出纯代码,不加解释")
                .user(requirement)
                .options(DashScopeChatOptions.builder()
                        .withModel("qwen-max")    // 用最强模型
                        .withTemperature(0.1)     // 极低温度,输出确定
                        .withMaxTokens(4096)      // 允许较长代码输出
                        .build())
                .call()
                .content();
    }

    /**
     * 创意写作场景:高温度,输出多样有趣
     */
    public String creativeWrite(String topic) {
        return chatClient.prompt()
                .system("你是一个充满创意的文案策划师")
                .user(topic)
                .options(DashScopeChatOptions.builder()
                        .withModel("qwen-plus")
                        .withTemperature(1.2)     // 高温度,充满创意
                        .withTopP(0.95)
                        .build())
                .call()
                .content();
    }

    /**
     * 数据抽取场景:极低温度,结构化输出
     */
    public String extractData(String rawText) {
        return chatClient.prompt()
                .system("从给定文本中提取结构化信息,以 JSON 格式输出")
                .user(rawText)
                .options(DashScopeChatOptions.builder()
                        .withTemperature(0.0)     // 零温度,完全确定性
                        .withModel("qwen-turbo")  // 简单任务用 turbo 节省成本
                        .build())
                .call()
                .content();
    }
}

六、ChatClient 单例设计与线程安全

6.1 为什么 ChatClient 要是单例

ChatClient 本身是无状态的------它不持有会话历史,不存储中间结果。每次调用都是完整的一次请求-响应循环。因此,将它作为单例注入是完全安全的,同时避免了反复创建对象的开销。

java 复制代码
@Configuration
public class ChatClientConfig {

    /**
     * 单例 ChatClient Bean
     * 多线程并发调用时不会互相干扰,因为每次 .prompt() 都创建独立的调用上下文
     */
    @Bean
    public ChatClient chatClient(ChatClient.Builder builder) {
        return builder
                .defaultSystem("你是企业级 AI 助手,回答简洁专业")
                .defaultAdvisors(new SimpleLoggerAdvisor())
                .build();
    }
}

6.2 Advisor 链式拦截器

Advisor 是 Spring AI 中的拦截器机制,类似于 AOP,可以在请求前后注入逻辑:

java 复制代码
@Bean
public ChatClient chatClientWithAdvisors(ChatClient.Builder builder) {
    return builder
            .defaultSystem("你是智能助手")
            // Advisor 按注册顺序执行
            // 1. 记忆增强:自动将历史消息附加到请求中
            .defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
            // 2. 日志追踪:记录每次请求和响应(开发阶段有用)
            .defaultAdvisors(new SimpleLoggerAdvisor())
            .build();
}

Advisor 执行流程:

复制代码
用户请求
    |
    v
[Advisor 1: 日志记录请求]
    |
    v
[Advisor 2: 注入记忆上下文]
    |
    v
[发送到 DashScope 模型]
    |
    v
[收到模型响应]
    |
    v
[Advisor 2: 保存响应到记忆]
    |
    v
[Advisor 1: 日志记录响应]
    |
    v
返回给用户

七、开发工具配置优化

7.1 IDEA 插件推荐

在 IDEA 中安装以下插件,提升 AI 应用开发体验:

  1. Spring Boot Assistant :YAML 配置自动补全,支持 spring.ai.* 属性提示;
  2. Lombok:Lombok 注解支持(必装);
  3. Maven Helper:依赖分析,快速发现版本冲突;
  4. HTTP Client:内置 HTTP 测试,替代 Postman 测试接口。

7.2 Spring Boot DevTools 热重载

DevTools 默认不会热重载已加载的类,但对 YAML 配置文件的修改可以生效。对于 AI 应用,有一点需要注意:

java 复制代码
// 不推荐:每次请求都 new ChatClient,无法享受 DevTools 热重载优势
@GetMapping("/chat")
public String chat(String msg) {
    ChatClient client = ChatClient.builder(chatModel).build(); // 不要这样做
    return client.prompt(msg).call().content();
}

// 推荐:注入单例 ChatClient,DevTools 修改配置后自动重载 Bean
@GetMapping("/chat")
public String chat(String msg) {
    return chatClient.prompt(msg).call().content(); // 正确姿势
}

7.3 配置文件加密(生产环境)

生产环境下,即便通过环境变量注入,API Key 也可能出现在容器启动日志中。推荐使用 Jasypt 加密:

xml 复制代码
<!-- pom.xml 添加 Jasypt -->
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>
yaml 复制代码
# application-prod.yml
spring:
  ai:
    dashscope:
      # ENC() 包裹加密后的值
      api-key: ENC(加密后的API-Key字符串)

jasypt:
  encryptor:
    # 加密密钥通过启动参数或环境变量传入,永远不要写在配置文件里
    password: ${JASYPT_ENCRYPTOR_PASSWORD}

八、Profile 隔离最佳实践

一个成熟的企业项目,开发、测试、预发、生产四套环境的 AI 配置通常差异很大:

复制代码
+----------+-------------+-----------+------------------+
| 环境      | 模型         | max-tokens | API Key 来源    |
+----------+-------------+-----------+------------------+
| dev      | qwen-turbo  | 1024       | 开发者个人 Key   |
| test     | qwen-turbo  | 2048       | 测试专用 Key     |
| staging  | qwen-plus   | 4096       | 预发 Key        |
| prod     | qwen-max    | 8192       | 生产 Key(加密) |
+----------+-------------+-----------+------------------+

启动时激活对应 Profile:

bash 复制代码
# 开发环境
java -jar app.jar --spring.profiles.active=dev,ai

# 生产环境
java -jar app.jar \
  --spring.profiles.active=prod,ai \
  --jasypt.encryptor.password=${JASYPT_PASSWORD}

九、完整配置参考模板

以下是一份可以直接复制使用的企业级配置模板:

yaml 复制代码
# =============================================
# application.yml(主配置)
# =============================================
spring:
  application:
    name: my-ai-app
  profiles:
    active: ${SPRING_PROFILES_ACTIVE:dev},ai

server:
  port: ${SERVER_PORT:8080}
  servlet:
    encoding:
      charset: UTF-8
      force: true

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: always
yaml 复制代码
# =============================================
# application-ai.yml(AI 专属配置)
# =============================================
spring:
  ai:
    dashscope:
      api-key: ${AI_DASHSCOPE_API_KEY}
      chat:
        options:
          model: ${AI_DASHSCOPE_MODEL:qwen-turbo}
          temperature: ${AI_TEMPERATURE:0.7}
          top-p: 0.8
          max-tokens: ${AI_MAX_TOKENS:2048}
          incremental-output: true
      embedding:
        options:
          model: text-embedding-v3

十、总结:配置管理要点速查

复制代码
1. BOM 引入
   → 统一版本,避免冲突
   → spring-ai-alibaba-bom 版本与 spring-ai 严格对应

2. Starter 选择(1.1版)
   → DashScope:spring-ai-alibaba-starter-dashscope
   → OpenAI:spring-ai-starter-model-openai
   → Ollama:spring-ai-starter-model-ollama

3. 多模型并存
   → @Qualifier 指定 Builder 名称
   → @Primary 指定默认 Bean
   → 手动 @Bean 配置各模型 ChatClient

4. 配置分层
   → application.yml(公共)
   → application-ai.yml(AI 专属)
   → application-{env}.yml(环境覆盖)

5. API Key 安全
   → 开发:环境变量
   → 生产:Jasypt 加密 + 启动参数传密钥

6. ChatOptions 优先级
   → Call 级 > Builder defaultOptions 级 > YAML 全局

下一篇将深入 ChatClient 的流式输出、Advisor 机制、多轮对话管理与异常治理策略,进入真正的业务实战场景。


参考资料

相关推荐
OpenCSG3 小时前
GLM-OCR:轻量级多模态OCR的技术突破
人工智能
ofoxcoding3 小时前
Qwen3.5 API 接入实测:和 GPT-4o 比到底差多少
人工智能·qwen3.5
摄影图3 小时前
智能汽车领域应用图素材 汽车AI研发转型
人工智能·科技·aigc
一只落魄的蜂鸟3 小时前
【2026年-11期】Where lies the future of humanity in the age of AI?
人工智能
IT阳晨。3 小时前
PyTorch深度学习实践
人工智能·pytorch·深度学习
老师用之于民3 小时前
【DAY29】嵌入式系统基础概念总结
人工智能
一水鉴天3 小时前
整体设计 定稿 的 整理 和完成20260320 之2:文档解析辅助工具编码实现手册 (豆包助手)
人工智能·架构·自动化
欧阳小猜3 小时前
Transformer革命:从序列建模到通用人工智能的架构突破
人工智能·架构·transformer
海兰3 小时前
【原理】OpenClaw插件系统深度解析
人工智能·插件·skill·openclaw