002-Spring AI Alibaba Prompt 功能完整案例

本案例将引导您一步步构建一个 Spring Boot 应用,演示如何利用 Spring AI Alibaba 的 Prompt 模板功能,实现角色扮演和基于上下文的智能问答。

1. 案例目标

我们将创建一个包含两个核心功能的 Web 应用:

  1. AI 角色扮演 (/example/ai/roles):通过系统提示词模板,让 AI 扮演一个具有特定名字和声音风格的角色,并以该角色的口吻回答问题。
  2. 上下文问答 (/prompt/ai/stuff):根据请求参数,决定是否将一篇关于"冰壶"的维基百科文档作为上下文"填充"到提示词中,让 AI 基于该文档内容回答相关问题。

2. 技术栈与核心依赖

  • Spring Boot 3.x
  • Spring AI Alibaba (用于对接阿里云 DashScope 通义大模型)
  • Maven (项目构建工具)

pom.xml 中,你需要引入以下核心依赖:

复制代码
<dependencies>
    <!-- Spring AI Alibaba 核心启动器,集成 DashScope -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        <version>1.0.0-M2</version> <!-- 请使用最新版本 -->
    </dependency>
    <!-- Spring Web 用于构建 RESTful API -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
<!-- 添加 Spring Boot 和 Spring Cloud 的版本管理 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.3.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2023.0.1.2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

3. 项目配置

src/main/resources/application.yml 文件中,配置你的 DashScope API Key。

复制代码
spring:
  ai:
    dashscope:
      api-key: ${DASHSCOPE_API_KEY} # 建议使用环境变量,更安全
      # 可选:指定使用的模型,默认为 qwen-turbo
      chat:
        options:
          model: qwen-plus

重要提示 :请将 DASHSCOPE_API_KEY 环境变量设置为你从阿里云获取的有效 API Key。你也可以直接将其写在配置文件中,但这不推荐用于生产环境。

4. 准备 Prompt 模板文件

src/main/resources 目录下创建以下文件结构:

复制代码
src/main/resources/
├── docs/
│   └── wikipedia-curling.md
└── prompts/
    ├── system-message.st
    └── qa-prompt.st

4.1 docs/wikipedia-curling.md

这是我们将用作上下文的文档内容。

复制代码
# Curling
Curling is a sport in which players slide stones on a sheet of ice toward a target area which is segmented into four concentric circles. It is related to bowls, boules and shuffleboard. Two teams, each with four players, take turns sliding heavy, polished granite stones, also called rocks, across the ice curling sheet toward the house, a circular target marked on the ice. Each team has eight stones. The purpose is to accumulate the highest score for a game; points are scored for the stones resting closest to the centre of the house at the conclusion of each end, which is completed when both teams have thrown all of their stones. A game usually consists of eight or ten ends.
The curler can induce a curved path by causing the stone to slowly turn as it slides, and the path of the rock may be further influenced by two sweepers with brooms who accompany it as it slides down the sheet, using the brooms to alter the state of the ice in front of the stone. A great deal of strategy and teamwork goes into choosing the ideal path and placement of a stone for each situation, and the skills of the curlers determine how close to the desired result the stone will achieve. This gives curling its nickname of "chess on ice".

4.2 prompts/system-message.st

系统提示词模板,用于定义 AI 的角色。

复制代码
你是一个乐于助人的 AI 助手。你的名字是 {name},你的说话风格是 {voice}。
请始终保持这个角色设定与用户进行对话。

4.3 prompts/qa-prompt.st

问答提示词模板,用于注入上下文和问题。

复制代码
请根据提供的上下文信息来回答用户的问题。如果上下文中没有相关信息,请说你不知道。
上下文信息:
---
{context}
---
用户问题: {question}

5. 编写 Java 代码

5.1 RoleController.java

实现 AI 角色扮演功能。

复制代码
package com.example.demo.controller;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/example/ai")
public class RoleController {
    private final ChatClient chatClient;
    // 注入系统提示词模板文件
    @Value("classpath:/prompts/system-message.st")
    private Resource systemResource;
    // 构造函数注入 ChatClient
    public RoleController(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }
    /**
     * 生成角色扮演对话
     * @param message 用户消息
     * @param name AI 角色名字
     * @param voice AI 说话风格
     * @return 流式响应
     */
    @GetMapping("/roles")
    public Flux<String> generate(String message, String name, String voice) {
        // 1. 创建用户消息
        UserMessage userMessage = new UserMessage(message);
        // 2. 使用系统提示词模板并填充变量
        SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);
        Message systemMessage = systemPromptTemplate.createMessage(
                Map.of("name", name, "voice", voice)
        );
        // 3. 调用大模型,传入系统消息和用户消息
        return chatClient.prompt(new Prompt(List.of(systemMessage, userMessage)))
                .stream()
                .content();
    }
}

5.2 StuffController.java

实现基于上下文的问答功能。

复制代码
package com.example.demo.controller;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/prompt/ai")
public class StuffController {
    private final ChatClient chatClient;
    // 注入要填充的文档资源
    @Value("classpath:/docs/wikipedia-curling.md")
    private Resource docsToStuffResource;
    // 注入问答提示词模板
    @Value("classpath:/prompts/qa-prompt.st")
    private Resource qaPromptResource;
    public StuffController(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }
    /**
     * 根据上下文回答问题
     * @param message 用户问题
     * @param stuffit 是否填充上下文
     * @return 流式响应
     */
    @GetMapping(value = "/stuff")
    public Flux<String> completion(String message, boolean stuffit) {
        // 1. 创建提示词模板
        PromptTemplate promptTemplate = new PromptTemplate(qaPromptResource);
        Map<String, Object> map = new HashMap<>();
        map.put("question", message);
        // 2. 根据参数决定是否填充上下文信息
        if (stuffit) {
            map.put("context", docsToStuffResource);
        } else {
            map.put("context", ""); // 不填充时,传入空字符串
        }
        // 3. 创建最终的 Prompt 并调用模型
        return chatClient.prompt(promptTemplate.create(map))
                .stream()
                .content();
    }
}

6. 运行与测试

  1. 启动应用:运行你的 Spring Boot 主程序。
  2. 使用浏览器或 API 工具(如 Postman, curl)进行测试

测试 1:AI 角色扮演

访问以下 URL,让 AI 扮演一个名叫"阿尔法"、声音"沉稳而富有磁性"的助手,询问它今天天气如何。

复制代码
http://localhost:8080/example/ai/roles?message=今天天气怎么样?&name=阿尔法&voice=沉稳而富有磁性

预期响应(流式输出)

你好,我是阿尔法。关于今天的天气,我无法直接获取实时信息,建议您查看当地的天气预报应用。不过,无论天气如何,都希望您有愉快的一天。

测试 2:带上下文的问答

访问以下 URL,开启上下文填充,并提问"冰壶运动有几个队员?"。

复制代码
http://localhost:8080/prompt/ai/stuff?message=冰壶运动有几个队员?&stuffit=true

预期响应(流式输出)

根据提供的上下文信息,冰壶运动有两支队伍,每支队伍有四名队员。

测试 3:不带上下文的问答

访问相同的 URL,但将 stuffit 设为 false,再问同样的问题。

复制代码
http://localhost:8080/prompt/ai/stuff?message=冰壶运动有几个队员?&stuffit=false

预期响应(流式输出)

根据提供的上下文信息,我没有找到关于"冰壶运动有几个队员"的相关信息,所以我无法回答这个问题。

7. 实现思路与扩展建议

实现思路

本案例的核心思想是**"模板与数据分离"**。我们将固定的提示词结构(模板)与动态变化的变量(如角色名、上下文文档)分离开来。这使得:

  • 可维护性高 :修改提示词风格只需编辑 .st 文件,无需改动 Java 代码。
  • 复用性强:同一个模板可以用于不同的数据填充场景。
  • 功能强大:通过动态注入上下文,为构建检索增强生成(RAG)应用奠定了基础。

扩展建议

  • 多模板管理:可以设计一个更复杂的模板管理器,根据业务场景动态选择不同的模板。
  • 模板缓存:对于频繁使用的模板,可以增加缓存层,避免每次请求都从磁盘加载,提升性能。
  • A/B 测试:通过配置或请求头,动态切换不同版本的提示词模板,用于效果对比和优化。
  • 集成向量数据库 :将 StuffController 中的静态文档替换为从向量数据库(如 Milvus, Chroma)中检索到的相关文本片段,构建真正的 RAG 系统。
相关推荐
海边夕阳20066 小时前
【每天一个AI小知识】:什么是大语言模型(LLM)?
人工智能·深度学习·神经网络·机器学习·语言模型·自然语言处理·llm
算力魔方AIPC6 小时前
破解“竖排文本”魔咒:在 RTX 3060 上微调 PaddleOCR-VL 以识别日本漫画
人工智能
袖手蹲6 小时前
Arduino UNO Q 从 Arduino Cloud 远程控制闪烁 LED
人工智能·单片机·嵌入式硬件·电脑
老王头的笔记6 小时前
Spring支持的消费器模式,支持在当前事务提交、或回滚的前、后执行业务操作
java·windows·spring
doris6106 小时前
设备点检、保养、维修一站式解决方案
大数据·数据库·人工智能
北京耐用通信6 小时前
终结混合网络调试噩梦:耐达讯自动化实现EtherCAT对DeviceNet设备的直接读写
网络·人工智能·物联网·网络协议·自动化·信息与通信
BFT白芙堂6 小时前
Franka机械臂“举一反三”:LLM Trainer如何通过单次演示实现自动化数据生成与长程任务学习
人工智能·学习·机器学习·自动化·模型训练·具身智能·franka
三掌柜6666 小时前
2025三掌柜赠书活动第四十八期 Vibe Coding:AI编程时代的认知重构
人工智能
Li_7695326 小时前
Spring Cloud — SkyWalking(六)
java·后端·spring·spring cloud·skywalking
多则惑少则明7 小时前
AI测试、大模型测试(三)AI语音产品测试&AI测试边界
人工智能·语音识别·ai大模型测试