跳到主要内容Spring AI Alibaba 快速入门指南 | 极客日志JavaAIjava
Spring AI Alibaba 快速入门指南
综述由AI生成Spring AI Alibaba 快速入门指南涵盖环境配置、基础对话、提示词工程、Advisor 拦截、对话记忆、结构化输出、工具调用、MCP 协议、RAG 检索增强生成、AI Agent 及可观测性等内容。通过 Maven 依赖引入核心组件,配置 DashScope API Key 或本地 Ollama 模型。演示了 ChatClient 与 ChatModel 的流式与非流式调用方式,支持多模型动态切换。深入讲解了基于 MySQL 的对话记忆存储、自定义文档分割器与向量数据库结合的 RAG 实现流程。此外还包含 Tool Calling 动态注册、MCP 服务构建以及 Graph 状态图编排工作流的实践示例,为开发者提供从基础接入到复杂应用落地的完整技术路径。
机器人45 浏览 Spring AI Alibaba 快速入门指南
1. 环境准备
1.1 API Key 配置
访问 阿里云百炼平台 获取 API Key,并在 Windows 环境变量中配置:
AI_DASHSCOPE_API_KEY=your_api_key_here
配置完成后重启电脑使环境变量生效,可通过命令行验证:
echo %AI_DASHSCOPE_API_KEY%
1.2 Ollama 本地模型安装(可选)
Ollama 是一个用于在本地运行大型语言模型(LLM)的工具和平台。
Windows 安装步骤:
- 下载安装包:https://github.com/ollama/ollama/releases/download/v0.12.3/OllamaSetup.exe
验证安装:
ollama --version
自定义安装路径:
OllamaSetup.exe /DIR="D:\zhengqingya\soft\soft-dev\AI\LLM\Ollama"
配置环境变量(可选):
OLLAMA_MODELS=D:\zhengqingya\soft\soft-dev\AI\LLM\Ollama\models
常用 Ollama 命令:
ollama serve
ollama list
ollama pull <model_name>
ollama run <model_name>
ollama stop <model_name>
ollama rm <model_name>
ollama ps
2. 项目依赖配置
2.1 Maven 依赖
<properties>
<spring-boot.version>3.4.0</spring-boot.version>
<>1.0.0
1.0.0.3
org.springframework.boot
spring-boot-dependencies
${spring-boot.version}
pom
import
org.springframework.ai
spring-ai-bom
${spring-ai.version}
pom
import
com.alibaba.cloud.ai
spring-ai-alibaba-bom
${spring-ai-alibaba.version}
pom
import
com.alibaba.cloud.ai
spring-ai-alibaba-starter-dashscope
org.springframework.ai
spring-ai-starter-model-ollama
1.0.0
spring-ai.version
</spring-ai.version>
<spring-ai-alibaba.version>
</spring-ai-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>
</groupId>
<artifactId>
</artifactId>
<version>
</version>
<type>
</type>
<scope>
</scope>
</dependency>
<dependency>
<groupId>
</groupId>
<artifactId>
</artifactId>
<version>
</version>
<type>
</type>
<scope>
</scope>
</dependency>
<dependency>
<groupId>
</groupId>
<artifactId>
</artifactId>
<version>
</version>
<type>
</type>
<scope>
</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>
</groupId>
<artifactId>
</artifactId>
</dependency>
<dependency>
<groupId>
</groupId>
<artifactId>
</artifactId>
<version>
</version>
</dependency>
2.2 基础配置
application.yml 配置
server:
port: 8888
servlet:
encoding:
enabled: true
charset: utf-8
force: true
spring:
ai:
dashscope:
api-key: ${AI_DASHSCOPE_API_KEY}
ollama:
base-url: http://localhost:11434
chat:
model: deepseek-r1
3. 基础使用
3.1 简单对话示例
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RequiredArgsConstructor
@RestController
public class HelloWorldController {
private final ChatModel chatModel;
@GetMapping("/simple/chat")
public String simpleChat(@RequestParam String msg) {
return chatModel.call(msg);
}
@GetMapping("/stream/chat")
public Flux<String> streamChat(@RequestParam String msg) {
return chatModel.stream(msg);
}
}
3.2 ChatClient 使用
ChatClient 是更高层次的抽象,提供了简化的聊天接口和流式处理能力。
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RestController
public class ChatClientController {
private final ChatClient chatClient;
public ChatClientController(DashScopeChatModel dashScopeChatModel) {
chatClient = ChatClient.builder(dashScopeChatModel).build();
}
@GetMapping("/chat-client/simple/chat")
public String simpleChat(@RequestParam String msg) {
return chatClient.prompt().user(msg).call().content();
}
@GetMapping("/chat-client/stream/chat")
public Flux<String> streamChat(@RequestParam String msg) {
return chatClient.prompt().user(msg).stream().content();
}
}
3.3 多模型动态配置
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.google.common.collect.Maps;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.util.Map;
@RestController
@RequestMapping("/mutli-platform-model")
@Tag(name = "多模型动态配置")
public class MutliPlatformModelController {
private Map<String, ChatModel> STRATEGY = Maps.newHashMap();
public MutliPlatformModelController(DashScopeChatModel dashScopeChatModel, OllamaChatModel ollamaChatModel) {
STRATEGY.put("dashscope", dashScopeChatModel);
STRATEGY.put("ollama", ollamaChatModel);
}
@Operation(summary = "动态切换模型")
@GetMapping("/stream/chat")
public Flux<String> streamChat(@ModelAttribute MutliPlatformModelOptions options) {
ChatModel chatModel = STRATEGY.get(options.platform());
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultOptions(ChatOptions.builder()
.model(options.model())
.temperature(options.temperature())
.build()).build();
return chatClient.prompt().user(options.msg()).stream().content();
}
}
4. 提示词(Prompt)使用
4.1 四大角色
public enum MessageType {
USER("user"),
ASSISTANT("assistant"),
SYSTEM("system"),
TOOL("tool")
}
4.2 提示词模板
@RestController
@RequestMapping("/prompt")
@Tag(name = "提示词")
public class PromptController {
private ChatClient chatClient;
private ChatModel chatModel;
@Value("classpath:/prompt-template/tell-joke.txt")
private org.springframework.core.io.Resource promptTemplateRes;
public PromptController(DashScopeChatModel dashScopeChatModel) {
chatClient = ChatClient.builder(dashScopeChatModel).build();
chatModel = dashScopeChatModel;
}
private static final String DEFAULT_PROMPT = """
你是一位资深 Java 架构师,专注于企业级 Java 后端开发。
请严格按照以下规则回答:
1. 只回答 Java 及相关技术栈的问题;
2. 提供准确、专业的技术解答;
3. 对于非 Java 后端相关问题,请礼貌说明超出了专业范围。
""";
@GetMapping("/chat-client")
public String chatClient(@RequestParam String msg) {
return chatClient.prompt().system(DEFAULT_PROMPT).user(msg).call().content();
}
@GetMapping("/prompt-template")
public Flux<String> promptTemplate(@RequestParam String topic) {
PromptTemplate promptTemplate = new PromptTemplate("给我讲一个有关于{topic}的笑话");
Prompt prompt = promptTemplate.create(Map.of("topic", topic));
return chatModel.stream(prompt).map(chatResponse -> chatResponse.getResult().getOutput().getText());
}
}
5. Advisor 对话拦截
Advisor 主要用于拦截 ChatClient 的对话请求和响应,在对话过程中添加通用处理逻辑。
5.1 日志记录
@RestController
@RequestMapping("/advisor")
@Tag(name = "Advisor 对话拦截--日志记录")
public class AdvisorLogController {
private ChatClient chatClient;
public AdvisorLogController(DashScopeChatModel dashScopeChatModel) {
chatClient = ChatClient.builder(dashScopeChatModel).defaultAdvisors(new SimpleLoggerAdvisor()).build();
}
@GetMapping("/log")
public Flux<String> log(@RequestParam String msg) {
return chatClient.prompt().user(msg).stream().content();
}
}
5.2 敏感词拦截
@RestController
@RequestMapping("/advisor")
@Tag(name = "Advisor 对话拦截--敏感词拦截")
public class AdvisorSafeGuardController {
private ChatClient chatClient;
public AdvisorSafeGuardController(DashScopeChatModel dashScopeChatModel) {
chatClient = ChatClient.builder(dashScopeChatModel)
.defaultAdvisors(
new SimpleLoggerAdvisor(),
new SafeGuardAdvisor(Lists.newArrayList("敏感词","WC"),
"由于包含敏感内容,我无法对此进行回复。我们可以重新表述或讨论其他话题吗?",
1)).build();
}
@GetMapping("/safe-guard")
public Flux<String> safeGuard(@RequestParam String msg) {
return chatClient.prompt().user(msg).stream().content();
}
}
5.3 自定义拦截器
public class RewritePromptAdvisor implements BaseAdvisor {
private static final String REWRITE_TEXT = """
让我们仔细分析这个问题:
问题:{input_msg}
分析步骤:
1. 问题理解:这个问题在问什么?
2. 关键信息:有哪些重要的细节需要注意?
3. 回答构建:基于以上分析,给出准确详细的回答:
回答要求:
- 使用通俗易懂的语言
- 结合实际情况举例说明
- 如涉及技术内容,提供具体的操作步骤
- 返回 html 格式内容
""";
@Override
public ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) {
String contents = chatClientRequest.prompt().getContents();
String inputMsg = PromptTemplate.builder().template(REWRITE_TEXT).build().render(Map.of("input_msg", contents));
return chatClientRequest.mutate().prompt(Prompt.builder().content(inputMsg).build()).build();
}
@Override
public ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain) {
return chatClientResponse;
}
@Override
public int getOrder() {
return 0;
}
}
6. 对话记忆(Chat Memory)
6.1 MySQL 存储示例
依赖配置
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-memory-jdbc</artifactId>
<version>1.0.0.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
配置文件
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/spring-ai-alibaba-demo?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false
username: root
password: root
代码示例
@RestController
@RequestMapping("/chat-memory")
@Tag(name = "对话记忆")
public class ChatMemoryController {
private final ChatClient chatClient;
public ChatMemoryController(JdbcTemplate jdbcTemplate, DashScopeChatModel dashScopeChatModel) {
ChatMemoryRepository chatMemoryRepository = MysqlChatMemoryRepository.mysqlBuilder().jdbcTemplate(jdbcTemplate).build();
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
this.chatClient = ChatClient.builder(dashScopeChatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
.defaultAdvisors(new SimpleLoggerAdvisor())
.build();
}
@GetMapping("/chat/{id}")
public Flux<String> advisorChat(HttpServletResponse response, @PathVariable String id, @RequestParam String msg) {
response.setCharacterEncoding("UTF-8");
return this.chatClient.prompt(msg).advisors(a -> a.param(ChatMemory.CONVERSATION_ID, id)).stream().content();
}
}
7. 结构化输出
public record StructuredVO(String category, String question, String answer) {}
@RestController
@RequestMapping("/structured-output")
@Tag(name = "结构化输出")
public class StructuredOutputController {
private ChatClient chatClient;
public StructuredOutputController(DashScopeChatModel dashScopeChatModel) {
chatClient = ChatClient.builder(dashScopeChatModel).build();
}
@GetMapping("/test")
public StructuredVO structuredOutput() {
return chatClient.prompt()
.system("对问题分类并简要总结,并给出答案")
.user("这件商品的质量不好,我可以申请退货吗?")
.call()
.entity(StructuredVO.class);
}
}
8. 工具调用(Tool Calling)
允许 AI 模型调用外部工具和函数来执行特定任务。
8.1 定义工具
方法工具
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
@Service
public class TimeTools {
@Tool(description = "获取当前时间,默认时间格式:YYYY-MM-DD HH:mm:ss")
public String getCurrentTime(@ToolParam(description = "时间格式") String format) {
log.info("获取当前时间格式:{}", format);
return DateUtil.now();
}
}
函数工具
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Description;
import org.springframework.stereotype.Service;
import java.util.function.Function;
@Slf4j
@Service(value = "getWeather")
public class WeatherFunction implements Function<String, String> {
@Override
@Description("获取天气")
public String apply(@JsonPropertyDescription("城市") String city) {
log.info("获取{}天气", city);
return city + "天气:晴";
}
}
8.2 注册工具 & 调用
@RestController
@RequestMapping("/tool-calling")
@Tag(name = "工具调用")
public class ToolCallingController {
private ChatClient chatClient;
@Autowired
private TimeTools timeTools;
public ToolCallingController(DashScopeChatModel dashScopeChatModel) {
chatClient = ChatClient.builder(dashScopeChatModel).build();
}
@GetMapping("/time")
public Flux<String> time(@RequestParam String msg) {
return chatClient.prompt().user(msg).tools(timeTools).stream().content();
}
@GetMapping("/weather")
public Flux<String> weather(@RequestParam String msg) {
return chatClient.prompt().user(msg).toolNames(new String[]{"getWeather"}).stream().content();
}
}
8.3 动态注册工具
@RestController
@RequestMapping("/tool-calling")
@Tag(name = "工具调用 - 动态注册")
public class ToolCallingDynamicController {
private ChatClient chatClient;
@Autowired
private TimeTools timeTools;
public ToolCallingDynamicController(DashScopeChatModel dashScopeChatModel, TimeTools timeTools) {
chatClient = ChatClient.builder(dashScopeChatModel).build();
}
@GetMapping("/dynamic/{userId}")
public Flux<String> dynamic(@PathVariable Long userId, @RequestParam String msg) {
return chatClient.prompt().user(msg)
.toolCallbacks(getToolCallbacks(userId))
.stream().content();
}
private List<ToolCallback> getToolCallbacks(Long userId) {
List<ToolCallback> toolCallbacks = Lists.newArrayList();
if (userId != 1) {
return toolCallbacks;
}
Method method = ReflectionUtils.findMethod(TimeTools.class, "getCurrentTime", String.class);
if (method == null) {
throw new RuntimeException("Method not found");
}
String inputSchema = JsonSchemaGenerator.generateForMethodInput(method);
ToolCallback timeToolCallback = MethodToolCallback.builder()
.toolDefinition(ToolDefinition.builder()
.name("getCurrentTime")
.description("获取当前时间,默认时间格式:YYYY-MM-DD HH:mm:ss")
.inputSchema(inputSchema)
.build())
.toolMethod(method)
.toolObject(timeTools)
.build();
toolCallbacks.add(timeToolCallback);
return toolCallbacks;
}
@GetMapping("/dynamic2/{userId}")
public Flux<String> dynamic2(@PathVariable Long userId, @RequestParam String msg) {
String[] toolNames = userId == 1 ? new String[]{"getWeather"} : new String[0];
return chatClient.prompt().user(msg)
.toolNames(toolNames)
.stream().content();
}
}
9. MCP(Model Context Protocol)
MCP 是一种模型上下文协议,主要用于 AI 模型调用外部工具和函数。
9.1 传输方式
- STDIO(标准输入输出):通过标准输入输出流进行数据传输
- SSE(Server-Sent Events):基于 HTTP 的单向服务器推送技术
- Streamable HTTP:基于 HTTP 协议的流式传输
9.2 自定义 MCP 服务 - STDIO
服务端实现
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
spring:
main:
web-application-type: none
banner-mode: off
ai:
mcp:
server:
stdio: true
name: my-weather-server
version: 1.0.0
@Service
public class MyWeatherService {
@Tool(description = "获取天气")
public String getWeather(@ToolParam(description = "城市") String city) {
return city + "天气:雨";
}
}
@Bean
public ToolCallbackProvider weatherTools(MyWeatherService myWeatherService) {
return MethodToolCallbackProvider.builder().toolObjects(myWeatherService).build();
}
客户端接入
spring:
ai:
mcp:
client:
stdio:
servers-configuration: classpath:/mcp/mcp-servers-config.json
{
"mcpServers": {
"my-weather-server": {
"command": "java",
"args": [
"-Dspring.ai.mcp.server.stdio=true",
"-Dspring.main.web-application-type=none",
"-Dlogging.pattern.console=",
"-jar",
"D:\\path\\to\\your\\mcp-server.jar"
]
}
}
}
9.3 自定义 MCP 服务 - SSE
服务端实现
server:
port: 10088
spring:
main:
banner-mode: off
ai:
mcp:
server:
name: my-sse-server
version: 1.0.0
type: ASYNC
sse-endpoint: /sse
sse-message-endpoint: /mcp
capabilities:
tool: true
resource: true
prompt: true
completion: true
客户端接入
spring:
ai:
mcp:
client:
sse:
connections:
my-sse-server:
url: http://localhost:10088
10. RAG(Retrieval-Augmented Generation)
RAG 是一种结合检索和生成的技术架构,通过引入'外接知识库'让模型在回答问题前先查阅权威资料。
10.1 嵌入模型 (Embedding Model)
spring:
ai:
dashscope:
embedding:
options:
model: text-embedding-v4
dimensions: 64
@RestController
@RequestMapping("/rag")
@Tag(name = "RAG")
public class RagController {
private EmbeddingModel embeddingModel;
public RagController(DashScopeEmbeddingModel dashScopeEmbeddingModel) {
embeddingModel = dashScopeEmbeddingModel;
}
@GetMapping("/embedding")
public Object embedding(@RequestParam String msg) {
EmbeddingResponse embeddingResponse = this.embeddingModel.embedForResponse(List.of(msg));
return Map.of("embedding", embeddingResponse);
}
}
10.2 向量数据库
使用 SimpleVectorStore 轻量级向量数据库:
@RestController
@RequestMapping("/rag")
@Tag(name = "RAG")
public class RagController {
private VectorStore vectorStore;
public RagController(DashScopeEmbeddingModel dashScopeEmbeddingModel) {
vectorStore = SimpleVectorStore.builder(dashScopeEmbeddingModel).build();
}
@GetMapping("/vectorStore")
public Object vectorStore(@RequestParam String msg, @RequestParam int topK, @RequestParam double threshold) {
vectorStore.add(Lists.newArrayList(
Document.builder().text("LangChain 是一个用于开发由语言模型驱动的应用程序的框架。").build(),
Document.builder().text("Milvus 是一款开源向量数据库,专为大规模向量相似性搜索而设计。").build()
));
return vectorStore.similaritySearch(SearchRequest.builder().query(msg).topK(topK).similarityThreshold(threshold).build());
}
}
文本读取器
@Value("classpath:rag/pet.txt")
private Resource textRes;
@GetMapping("/text")
public Object text() {
TextReader textReader = new TextReader(textRes);
List<Document> documents = textReader.read();
return documents;
}
Markdown 读取器
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-markdown-document-reader</artifactId>
</dependency>
@Value("classpath:rag/iphone.md")
private Resource MdRes;
@GetMapping("/markdown")
public Object markdown() {
MarkdownDocumentReader markdownReader = new MarkdownDocumentReader(MdRes,
MarkdownDocumentReaderConfig.builder()
.withAdditionalMetadata("filename", MdRes.getFilename())
.withHorizontalRuleCreateDocument(false)
.withIncludeCodeBlock(false)
.withIncludeBlockquote(false)
.build());
List<Document> documents = markdownReader.read();
return documents;
}
10.4 文档分割器
TokenTextSplitter 是 RAG 应用中关键的文档预处理工具。
@GetMapping("/text")
public Object text() {
TextReader textReader = new TextReader(textRes);
List<Document> documents = textReader.read();
List<Document> splitDocs = new TokenTextSplitter(800, 350, 5, 10000, true).split(documents);
return splitDocs;
}
10.5 自定义文档分割器
public class RegulationDocumentSplitter extends TextSplitter {
public static Builder builder() {
return new Builder();
}
}
10.6 文档转换器
关键字提取
@GetMapping("/keyword")
public Object keyword() {
MarkdownDocumentReader markdownReader = new MarkdownDocumentReader(MdRes,
MarkdownDocumentReaderConfig.builder().withAdditionalMetadata("filename", MdRes.getFilename()).build());
List<Document> documents = markdownReader.read();
KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(chatModel, 3);
List<Document> enricherDocs = enricher.apply(documents);
return enricherDocs;
}
摘要生成
@GetMapping("/summary")
public Object summary() {
MarkdownDocumentReader markdownReader = new MarkdownDocumentReader(MdRes,
MarkdownDocumentReaderConfig.builder().withAdditionalMetadata("filename", MdRes.getFilename()).build());
List<Document> documents = markdownReader.read();
SummaryMetadataEnricher enricher = new SummaryMetadataEnricher(chatModel, List.of(SummaryMetadataEnricher.SummaryType.CURRENT, SummaryMetadataEnricher.SummaryType.NEXT),
"""请为以下文档内容生成摘要:
{context_str}
要求:
1. 摘要长度不超过 100 字
2. 突出关键信息
3. 保持原意不变
""", MetadataMode.ALL);
List<Document> enricherDocs = enricher.apply(documents);
return enricherDocs;
}
元数据过滤
@GetMapping("/metadata-filter")
public Object metadataFilter() {
MarkdownDocumentReader markdownReader = new MarkdownDocumentReader(MdRes,
MarkdownDocumentReaderConfig.builder().withAdditionalMetadata("filename", MdRes.getFilename()).build());
List<Document> documents = markdownReader.read();
KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(chatModel, 3);
List<Document> enricherDocs = enricher.apply(documents);
vectorStore.add(enricherDocs);
List<Document> result = vectorStore.similaritySearch(SearchRequest.builder()
.query("手机处理器")
.topK(3)
.filterExpression(new FilterExpressionBuilder().eq("filename", "phone.md").build())
.build());
return result;
}
10.7 检索增强生成
@RestController
@RequestMapping("/rag/retrieval-augmentation")
@Tag(name = "RAG-检索增强生成")
public class RagRetrievalAugmentationAdvisorController {
@Value("classpath:rag/iphone.md")
private Resource MdRes;
private ChatModel chatModel;
private ChatClient chatClient;
private VectorStore vectorStore;
public RagRetrievalAugmentationAdvisorController(DashScopeChatModel dashScopeChatModel, DashScopeEmbeddingModel dashScopeEmbeddingModel) {
chatModel = dashScopeChatModel;
chatClient = ChatClient.builder(dashScopeChatModel).defaultAdvisors(new SimpleLoggerAdvisor()).build();
vectorStore = SimpleVectorStore.builder(dashScopeEmbeddingModel).build();
}
@GetMapping("/chat")
public Flux<String> chat(@RequestParam String msg) {
MarkdownDocumentReader markdownReader = new MarkdownDocumentReader(MdRes,
MarkdownDocumentReaderConfig.builder().withAdditionalMetadata("filename", MdRes.getFilename()).build());
List<Document> documents = markdownReader.read();
vectorStore.add(documents);
Advisor advisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.similarityThreshold(0.5)
.topK(3)
.build())
.queryAugmenter(ContextualQueryAugmenter.builder()
.allowEmptyContext(false)
.emptyContextPromptTemplate(PromptTemplate.builder()
.template("用户查询位于知识库之外。礼貌地告知用户您无法回答。").build())
.build())
.queryTransformers(
RewriteQueryTransformer.builder()
.chatClientBuilder(ChatClient.builder(chatModel))
.targetSearchSystem("知识库")
.build(),
TranslationQueryTransformer.builder()
.chatClientBuilder(ChatClient.builder(chatModel))
.targetLanguage("中文")
.build())
.build();
return chatClient.prompt().user(msg).advisors(advisor).stream().content();
}
}
10.8 重排序
@RestController
@RequestMapping("/rag/rerank")
@Tag(name = "重排序")
public class RerankController {
private RerankModel rerankModel;
private ChatClient chatClient;
private VectorStore vectorStore;
public RerankController(DashScopeChatModel dashScopeChatModel, DashScopeEmbeddingModel dashScopeEmbeddingModel, DashScopeRerankModel dashScopeRerankModel) {
chatClient = ChatClient.builder(dashScopeChatModel).defaultAdvisors(new SimpleLoggerAdvisor()).build();
vectorStore = SimpleVectorStore.builder(dashScopeEmbeddingModel).build();
rerankModel = dashScopeRerankModel;
}
@GetMapping("/chat")
public Flux<String> chat(@RequestParam String msg) {
vectorStore.add(Lists.newArrayList(
Document.builder().text("iPhone18 基础价格:5999 元,税率:13%, 运费:0 元").build(),
Document.builder().text("iPhone20 基础价格:12999 元,税率:13%, 运费:50 元").build(),
Document.builder().text("iPhone10 基础价格:1299 元,税率:13%, 运费:0 元").build()
));
RetrievalRerankAdvisor rerankAdvisor = new RetrievalRerankAdvisor(vectorStore, rerankModel, SearchRequest.builder().topK(10).build());
return chatClient.prompt().user(msg).advisors(rerankAdvisor).stream().content();
}
}
10.9 幻觉评估
@RestController
@RequestMapping("/rag/fact-check")
@Tag(name = "RAG-幻觉评估")
public class RagFactCheckController {
private ChatModel chatModel;
public RagFactCheckController(DashScopeChatModel dashScopeChatModel) {
chatModel = dashScopeChatModel;
}
@GetMapping("/test")
public Object test() {
ArrayList<Document> documents = Lists.newArrayList(
Document.builder().text("iPhone18 基础价格:5999 元,税率:13%, 运费:0 元").build(),
Document.builder().text("iPhone20 基础价格:12999 元,税率:13%, 运费:50 元").build(),
Document.builder().text("iPhone10 基础价格:1299 元,税率:13%, 运费:0 元").build()
);
String aiRes = "iPhone20 6000 元";
FactCheckingEvaluator evaluator = new FactCheckingEvaluator(ChatClient.builder(chatModel));
EvaluationRequest evaluationRequest = new EvaluationRequest(documents, aiRes);
EvaluationResponse evaluationResponse = evaluator.evaluate(evaluationRequest);
return evaluationResponse;
}
}
11. AI Agent
AI Agent 是一种能够自主感知环境、做出决策并执行动作以实现特定目标的智能实体。
11.1 三种人机协同模式
| 模式名称 | 核心关系 (人类 : AI) | 特点与工作方式 | 典型场景 |
|---|
| 嵌入模式 (Embedded) | 我做你看 | 将 AI 能力作为功能模块嵌入现有产品 | 智能客服中的自动回复、推荐系统 |
| 副驾驶模式 (Copilot) | 我们一起做 | AI 作为实时协作的伙伴,提供建议和辅助 | GitHub Copilot 代码补全 |
| 智能体模式 (Agent) | 你做我看 | AI 拥有高度自主权,可独立规划、决策、执行复杂任务 | 自动交易系统、智能助手 |
11.2 AI Agent 的五大工作模式
- 提示链模式:将复杂任务拆解成一系列顺序执行的子任务
- 路由模式:根据输入内容特点,动态选择最合适的处理路径
- 并行化模式:同时启动多个 Agent 处理独立的子任务
- 协调者 - 工作者模式:模拟指挥体系,由协调者负责任务分解和调度
- 评估者 - 优化者模式:引入自我反思和优化的闭环
12. 可观测性
软件的可观测性是指通过系统输出(如日志、指标、跟踪等)来推断其内部状态的能力。
12.1 Zipkin 部署
12.2 Java 项目配置
依赖配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-tool-calling-weather</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
<version>1.5.0-M2</version>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
<version>3.4.3</version>
</dependency>
配置文件
spring:
ai:
dashscope:
api-key: ${AI_DASHSCOPE_API_KEY}
observations:
log-completion: true
log-prompt: true
chat:
client:
observations:
log-prompt: true
log-completion: true
include-error-logging: true
tools:
observability:
include-content: true
http:
client:
read-timeout: 60s
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
tracing:
sampling:
probability: 1.0
zipkin:
tracing:
endpoint: http://localhost:9411/api/v2/spans
13. Spring AI Alibaba Graph
Spring AI Alibaba Graph 是一个强大且直观的框架,能让你像搭积木一样,通过编排节点和流程来构建复杂的 AI 应用。
13.1 快速入门
依赖配置
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-graph-core</artifactId>
</dependency>
创建自定义节点
public class ExpanderNode implements NodeAction {
private final ChatClient chatClient;
public ExpanderNode(DashScopeChatModel chatModel) {
this.chatClient = ChatClient.builder(chatModel).build();
}
@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
String query = state.value("query", "");
String promptTemplate = "请为以下问题生成 3 个不同角度的变体问题:{query}";
String result = chatClient.prompt().user(u -> u.text(promptTemplate).param("query", query)).call().content();
List<String> queryVariants = Arrays.asList(result.split("\n"));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("expander_content", queryVariants);
return resultMap;
}
}
配置状态图
@Configuration
public class SimpleGraphConfiguration {
@SneakyThrows
@Bean
public StateGraph simpleGraph(DashScopeChatModel chatModel) {
KeyStrategyFactory keyStrategyFactory = () -> {
HashMap<String, KeyStrategy> strategies = new HashMap<>();
strategies.put("query", new ReplaceStrategy());
strategies.put("expander_content", new ReplaceStrategy());
return strategies;
};
StateGraph stateGraph = new StateGraph("问题扩展工作流", keyStrategyFactory)
.addNode("expander", AsyncNodeAction.node_async(new ExpanderNode(chatModel)))
.addEdge(StateGraph.START, "expander")
.addEdge("expander", StateGraph.END);
return stateGraph;
}
}
编译并运行工作流
@RestController
@RequestMapping("/graph")
@Tag(name = "Graph")
public class SimpleGraphController {
private final CompiledGraph compiledGraph;
public SimpleGraphController(@Qualifier("simpleGraph") StateGraph stateGraph) throws GraphStateException {
this.compiledGraph = stateGraph.compile();
}
@GetMapping("/expand")
public Map<String, Object> expandQuery(@RequestParam String query) throws GraphRunnerException {
Map<String, Object> initialState = Map.of("query", query);
Optional<OverAllState> result = compiledGraph.invoke(initialState);
return result.map(OverAllState::data).orElse(Map.of());
}
}
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online