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 系统。
相关推荐
Francek Chen1 天前
【自然语言处理】应用04:自然语言推断与数据集
人工智能·pytorch·深度学习·神经网络·自然语言处理
硬核创业者1 天前
3个低门槛创业灵感
人工智能
冰西瓜6001 天前
从项目入手机器学习——鸢尾花分类
人工智能·机器学习·分类·数据挖掘
爱思德学术1 天前
中国计算机学会(CCF)推荐学术会议-C(人工智能):IJCNN 2026
人工智能·神经网络·机器学习
偶信科技1 天前
国产极细拖曳线列阵:16mm“水下之耳”如何撬动智慧海洋新蓝海?
人工智能·科技·偶信科技·海洋设备·极细拖曳线列阵
Java后端的Ai之路1 天前
【神经网络基础】-神经网络学习全过程(大白话版)
人工智能·深度学习·神经网络·学习
庚昀◟1 天前
用AI来“造AI”!Nexent部署本地智能体的沉浸式体验
人工智能·ai·nlp·持续部署
喜欢吃豆1 天前
OpenAI Realtime API 深度技术架构与实现指南——如何实现AI实时通话
人工智能·语言模型·架构·大模型
数据分析能量站1 天前
AI如何重塑个人生产力、组织架构和经济模式
人工智能
wscats1 天前
Markdown 编辑器技术调研
前端·人工智能·markdown