项目概述
Yang AI Learn 是一个基于 Spring Boot 3.5.11 和阿里云百炼平台的 AI 智能对话应用。该项目展示了如何将阿里云 DashScope AI Agent 集成到 Spring Boot 应用中,提供同步和流式两种 AI 对话交互方式。
技术架构
核心技术栈
- Spring Boot 3.5.11 - 应用框架
- Java 17 - 开发语言
- Spring AI Alibaba 1.0.0.2 - 阿里云 AI 集成组件
- DashScope Agent API - 阿里云百炼智能体服务
- Log4j2 - 日志框架
- Apache Commons Lang3 - 工具库
项目结构
java
yang-ai-learn/
├── src/main/java/com/yang/
│ ├── YangAiLearnApplication.java # 应用启动类
│ └── controller/
│ ├── AgentController.java # 同步调用控制器
│ └── AgentStreamController.java # 流式调用控制器
└── src/main/resources/
└── application.yaml # 配置文件
创建项目
从https://start.spring.io/快速创建一个空的Spring Boot项目

获取API Key并配置API Key到环境变量
获取地址:https://bailian.console.aliyun.com/cn-beijing/?tab=model#/api-key

核心功能
1. 同步对话接口 (AgentController)
接口地址 : GET /ai/agent/call
功能特点:
- 提供同步的 AI 对话能力
- 支持自定义消息输入(默认消息:"你好!")
- 返回完整的 AI 响应内容
- 记录文档引用(docReferences)和思考过程(thoughts)

实现要点:
- 使用
DashScopeAgent进行同步调用 - 通过
Prompt和DashScopeAgentOptions配置请求参数 - 解析响应中的
AssistantMessage获取 AI 回复 - 提取并记录元数据信息,包括文档引用和推理思路
2. 流式对话接口 (AgentStreamController)
接口地址 : GET /ai2/agent/stream
功能特点:
- 提供流式(Server-Sent Events)的 AI 对话能力
- 实时返回 AI 生成的内容片段
- 支持增量输出和思考过程展示
- 维护会话状态(sessionId)
实现要点:
- 使用 Reactor 的
Flux实现响应式流 - 配置
incrementalOutput和hasThoughts选项 - 通过
text/event-stream格式实时推送数据 - 支持会话管理,可追踪对话上下文

配置说明
项目通过 application.yaml 进行配置:
java
spring:
ai:
dashscope:
api-key: [百炼 API Key]
agent:
app-id: [大模型应用 ID]
关键配置项:
api-key: 阿里云百炼平台的 API 密钥app-id: 在百炼平台创建的智能体应用 ID
技术亮点
- 响应式编程: 使用 Spring WebFlux 的 Flux 实现流式响应,提升用户体验
- 日志管理: 采用 Log4j2 替代默认的 Logback,提供更灵活的日志配置
- 元数据处理: 完整解析 AI 响应的元数据,包括文档引用和推理过程
- 会话管理: 支持会话 ID 追踪,可实现多轮对话
- 依赖注入 : 通过构造函数注入
DashScopeAgentApi,符合 Spring 最佳实践
应用场景
- 智能客服系统
- 知识问答平台
- AI 助手集成
- 对话式应用开发
- AI 能力快速验证
项目特色
- 简洁的架构: 代码结构清晰,易于理解和扩展
- 双模式支持: 同时提供同步和异步两种调用方式,满足不同场景需求
- 完整的日志: 详细记录 AI 响应的各个环节,便于调试和监控
- 开箱即用: 配置简单,快速接入阿里云 AI 能力
总结
Yang AI Learn 是一个轻量级的 AI 集成示例项目,展示了如何在 Spring Boot 应用中快速集成阿里云百炼平台的智能体服务。项目代码简洁明了,适合作为学习 Spring AI 和阿里云 AI 服务集成的入门案例,也可以作为实际项目的基础框架进行扩展开发。
代码
pom
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 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.yang</groupId>
<artifactId>yang-ai-learn</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>yang-ai-learn</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>1.0.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yaml
XML
spring:
application:
name: yang-ai-learn
ai:
dashscope:
# 百炼API Key
api-key: sk-6ed40XXXXXXXXXXXXXXXXXXXXXXXX
agent:
# 大模型应用ID
app-id: 6ed40XXXXXXXXXXXXXXXXXXXXXXXX
AgentController(非流式调用)
java
package com.yang.controller;
import com.alibaba.cloud.ai.dashscope.agent.DashScopeAgent;
import com.alibaba.cloud.ai.dashscope.agent.DashScopeAgentOptions;
import com.alibaba.cloud.ai.dashscope.api.DashScopeAgentApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* AgentController
*
* @author By: yang<br>
* @Package: com.yang.controller <br>
* @CreateTime: 2026/3/13 15:13 <br>
* @Caution 注意:本内容仅限于本公司内部传阅,禁止外泄以及用于其他的商业目的 <br>
*/
@Slf4j
@RestController
@RequestMapping("/ai")
public class AgentController {
private DashScopeAgent agent;
@Value("${spring.ai.dashscope.agent.app-id}")
private String appId;
public AgentController(DashScopeAgentApi dashscopeAgentApi) {
this.agent = new DashScopeAgent(dashscopeAgentApi);
}
@GetMapping("/agent/call")
public String call(@RequestParam(value = "message",defaultValue = "你好!") String message) {
ChatResponse response = agent.call(new Prompt(message, DashScopeAgentOptions.builder().withAppId(appId).build()));
if (response == null || response.getResult() == null) {
return "响应为空";
}
AssistantMessage app_output = response.getResult().getOutput();
String content = app_output.getText();
DashScopeAgentApi.DashScopeAgentResponse.DashScopeAgentResponseOutput output = (DashScopeAgentApi.DashScopeAgentResponse.DashScopeAgentResponseOutput) app_output.getMetadata().get("output");
List<DashScopeAgentApi.DashScopeAgentResponse.DashScopeAgentResponseOutput.DashScopeAgentResponseOutputDocReference> docReferences = output.docReferences();
List<DashScopeAgentApi.DashScopeAgentResponse.DashScopeAgentResponseOutput.DashScopeAgentResponseOutputThoughts> thoughts = output.thoughts();
log.info("content:\n{}\n\n", content);
if (docReferences != null && !docReferences.isEmpty()) {
for (DashScopeAgentApi.DashScopeAgentResponse.DashScopeAgentResponseOutput.DashScopeAgentResponseOutputDocReference docReference : docReferences) {
log.info("{}\n\n", docReference);
}
}
if (thoughts != null && !thoughts.isEmpty()) {
for (DashScopeAgentApi.DashScopeAgentResponse.DashScopeAgentResponseOutput.DashScopeAgentResponseOutputThoughts thought : thoughts) {
log.info("{}\n\n", thought);
}
}
return content;
}
}
AgentStreamController**(流式调用)**
java
package com.yang.controller;
import com.alibaba.cloud.ai.dashscope.agent.DashScopeAgent;
import com.alibaba.cloud.ai.dashscope.agent.DashScopeAgentOptions;
import com.alibaba.cloud.ai.dashscope.api.DashScopeAgentApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.util.List;
/**
* AgentStreamController
*
* @author By: yang<br>
* @Package: com.yang.controller <br>
* @CreateTime: 2026/3/13 15:25 <br>
* @Caution 注意:本内容仅限于本公司内部传阅,禁止外泄以及用于其他的商业目的 <br>
*/
@Slf4j
@RestController
@RequestMapping("/ai2")
public class AgentStreamController {
private DashScopeAgent agent;
@Value("${spring.ai.dashscope.agent.app-id}")
private String appId;
public AgentStreamController(DashScopeAgentApi dashscopeAgentApi) {
this.agent = new DashScopeAgent(dashscopeAgentApi,
DashScopeAgentOptions.builder()
.withSessionId("current_session_id")
.withIncrementalOutput(true)
.withHasThoughts(true)
.build());
}
@GetMapping(value = "/agent/stream", produces = "text/event-stream")
public Flux<String> stream(@RequestParam(value = "message",
defaultValue = "你好") String message) {
return agent.stream(new Prompt(message, DashScopeAgentOptions.builder().withAppId(appId).build())).map(response -> {
if (response == null || response.getResult() == null) {
return "响应为空";
}
AssistantMessage app_output = response.getResult().getOutput();
String content = app_output.getText();
DashScopeAgentApi.DashScopeAgentResponse.DashScopeAgentResponseOutput output = (DashScopeAgentApi.DashScopeAgentResponse.DashScopeAgentResponseOutput) app_output.getMetadata().get("output");
List<DashScopeAgentApi.DashScopeAgentResponse.DashScopeAgentResponseOutput.DashScopeAgentResponseOutputDocReference> docReferences = output.docReferences();
List<DashScopeAgentApi.DashScopeAgentResponse.DashScopeAgentResponseOutput.DashScopeAgentResponseOutputThoughts> thoughts = output.thoughts();
log.info("content:\n{}\n\n", content);
return content;
});
}
}
YangAiLearnApplication(启动类)
java
package com.yang;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@Slf4j
@SpringBootApplication
public class YangAiLearnApplication {
public static void main(String[] args) {
SpringApplication.run(YangAiLearnApplication.class, args);
log.info("================= The project has been launched===========");
}
}
