JAVA:Spring Boot3 集成 Spring AI 实现 Prompt 提示词工程

1、简述

Spring AI 是 Spring 官方推出的开源框架,旨在为 Java 开发者提供便捷的 AI 能力集成方案,于 2024 年正式发布 1.0 版本。它通过标准化接口和模块化设计,降低了大模型应用开发门槛,让开发者能够充分利用现有的 Spring 生态系统来构建 AI 应用。

  • 跨模型可移植性:支持 OpenAI、Anthropic、Google Vertex AI、AWS Bedrock、Ollama 等多种 LLM 提供商,切换只需修改配置
  • 提示工程抽象:提供动态 Prompt 模板,通过占位符填充生成结构化提示
  • 结构化输出映射:自动将 AI 模型输出映射为 Java POJO
  • Advisor 拦截器机制:支持在模型调用前后执行提示词改写、安全过滤、日志记录等操作
  • RAG 支持:内置 ETL 框架和向量存储抽象层

2、环境配置

2.1 添加依赖

pom.xml 中添加 Spring AI OpenAI Starter:

xml 复制代码
<dependencies>
	<dependency>
	   <groupId>org.springframework.boot</groupId>
	   <artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	
	<!-- Spring AI OpenAI Starter -->
	<dependency>
	   <groupId>org.springframework.ai</groupId>
	   <artifactId>spring-ai-starter-model-openai</artifactId>
	</dependency>
	
	<dependency>
	   <groupId>org.springframework.boot</groupId>
	   <artifactId>spring-boot-starter-actuator</artifactId>
	</dependency>
	
	<dependency>
	   <groupId>org.springframework.boot</groupId>
	   <artifactId>spring-boot-devtools</artifactId>
	   <scope>runtime</scope>
	   <optional>true</optional>
	</dependency>
	
	<dependency>
	   <groupId>org.projectlombok</groupId>
	   <artifactId>lombok</artifactId>
	   <optional>true</optional>
	</dependency>
	
	<!-- 添加Jackson支持JSON处理 -->
	<dependency>
	   <groupId>com.fasterxml.jackson.core</groupId>
	   <artifactId>jackson-databind</artifactId>
	</dependency>
	
	<dependency>
	   <groupId>com.fasterxml.jackson.core</groupId>
	   <artifactId>jackson-annotations</artifactId>
	</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
   <dependency>
       <groupId>org.springframework.ai</groupId>
       <artifactId>spring-ai-bom</artifactId>
       <version>${spring-ai.version}</version>
       <type>pom</type>
       <scope>import</scope>
   </dependency>
</dependencies>
</dependencyManagement>

注意:Spring AI 1.0.0 需要 Spring Boot 3.5.x 或更高版本。

2.2 配置文件

application.yml 中配置 LLM 连接参数:

yaml 复制代码
spring:
  application:
    name: lm-prompt

  # DeepSeek API 配置 (兼容 OpenAI API)
  ai:
    openai:
      # DeepSeek API Base URL
      base-url: https://api.deepseek.com
      # DeepSeek API Key (请替换为你的实际API Key)
      api-key: ${DEEPSEEK_API_KEY:your-key}
      # 使用的模型
      chat:
        options:
          model: deepseek-chat
          temperature: 0.7
          max-tokens: 2000

如果使用 DeepSeek 等其他模型,可配置对应的 base-url 和模型名称。

2.3 核心参数说明

参数 说明 建议值
temperature 控制随机性,越低越确定,越高越有创造性 0.1-0.3(分类/事实)、0.7-1.0(创意写作)
max-tokens 输出最大长度 根据场景设置,短文本 100-500,长文本 1000+
top-p 核采样,动态选择概率累积达到 P 的 token 0.8-0.95

3、基础使用

3.1 配置 ChatClient Bean

java 复制代码
package com.example.demo.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AiConfig {

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder) {
        // 可在此配置默认系统提示词
        return builder
                .defaultSystem("你是一个专业的AI助手,请用中文回答用户问题。")
                .build();
    }
}

3.2 基础 Service 实现

java 复制代码
package com.example.demo.service;

import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

@Service
@RequiredArgsConstructor
public class AiPromptService {

    private final ChatClient chatClient;

    /**
     * 基础文本对话
     */
    public String simpleChat(String userMessage) {
        return chatClient.prompt()
                .user(userMessage)
                .call()
                .content();
    }

    /**
     * 带系统提示词的对话
     */
    public String chatWithSystemPrompt(String systemMessage, String userMessage) {
        return chatClient.prompt()
                .system(systemMessage)
                .user(userMessage)
                .call()
                .content();
    }

    /**
     * 流式响应(打字机效果)
     */
    public Flux<String> streamChat(String userMessage) {
        return chatClient.prompt()
                .user(userMessage)
                .stream()
                .content();
    }

    /**
     * 获取完整响应(含元数据)
     */
    public ChatResponse chatWithMeta(String userMessage) {
        return chatClient.prompt()
                .user(userMessage)
                .call()
                .chatResponse();
    }
}

3.3 Controller 示例

java 复制代码
package com.example.demo.controller;

import com.example.demo.service.AiPromptService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

@RestController
@RequestMapping("/api/ai")
@RequiredArgsConstructor
public class AiController {

    private final AiPromptService aiPromptService;

    @PostMapping("/chat")
    public String chat(@RequestBody String message) {
        return aiPromptService.simpleChat(message);
    }

    @PostMapping("/chat-with-system")
    public String chatWithSystem(
            @RequestParam String system,
            @RequestParam String user) {
        return aiPromptService.chatWithSystemPrompt(system, user);
    }

    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamChat(@RequestParam String message) {
        return aiPromptService.streamChat(message);
    }
}

4、Prompt 提示词工程技术

4.1 Zero-Shot Prompting(零样本提示)

零样本提示是指直接给模型指令而不提供示例,适合模型已熟悉的简单任务。

java 复制代码
/**
 * 情感分类 - Zero-Shot
 */
public String classifySentiment(String review) {
    String systemPrompt = "你将收到一段电影评论,请将其分类为 POSITIVE、NEUTRAL 或 NEGATIVE。";
    
    return chatClient.prompt()
            .system(systemPrompt)
            .user(review)
            .options(ChatOptions.builder()
                    .temperature(0.1)  // 低温度确保一致性
                    .maxTokens(10)
                    .build())
            .call()
            .content();
}

4.2 Few-Shot Prompting(少样本提示)

通过提供示例引导模型学习输出格式和模式,特别适用于需要特定格式输出的任务。

java 复制代码
/**
 * 披萨订单解析 - Few-Shot 示例
 */
public String parsePizzaOrder(String order) {
    String prompt = """
            请将客户的披萨订单解析为 JSON 格式。
            
            示例 1:
            输入:我要一个中号披萨,芝士和番茄酱,加意大利香肠。
            输出:{"size": "medium", "type": "normal", "ingredients": ["cheese", "tomato sauce", "pepperoni"]}
            
            示例 2:
            输入:来个大号披萨,加番茄酱、罗勒和马苏里拉芝士。
            输出:{"size": "large", "type": "normal", "ingredients": ["tomato sauce", "basil", "mozzarella"]}
            
            现在请解析:
            输入:%s
            输出:
            """.formatted(order);
    
    return chatClient.prompt()
            .user(prompt)
            .options(ChatOptions.builder()
                    .temperature(0.1)
                    .maxTokens(250)
                    .build())
            .call()
            .content();
}

4.3 系统角色提示(Role Prompting)

通过定义 AI 的角色和行为边界,引导模型以特定风格和专业知识回答问题。

java 复制代码
/**
 * 旅游顾问 - 系统角色提示
 */
public String travelConsultant(String userRequest) {
    String systemPrompt = """
            你是一位专业的旅游大师,拥有丰富的全球旅行经验。你的职责是:
            1. 为用户提供专业的旅游咨询服务
            2. 主动引导用户明确需求(目的地类型、行程天数、同行人员等)
            3. 给出具体可执行的行程建议
            
            回答风格:专业且热情,使用中文。
            
            请开始服务用户。
            """;
    
    return chatClient.prompt()
            .system(systemPrompt)
            .user(userRequest)
            .call()
            .content();
}

4.4 参数化 Prompt 模板

使用 PromptTemplate 动态填充占位符,实现灵活的提示词管理。

java 复制代码
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.core.io.Resource;

@Service
public class PromptTemplateService {

    @Value("classpath:/templates/translation-template.st")
    private Resource translationTemplate;
    
    private final ChatClient chatClient;

    /**
     * 参数化翻译模板
     */
    public String translate(String content, String targetLang) {
        // 方式1:使用外部模板文件
        PromptTemplate template = new PromptTemplate(translationTemplate);
        Prompt prompt = template.create(Map.of(
                "targetLang", targetLang,
                "content", content
        ));
        
        return chatClient.prompt(prompt).call().content();
    }
    
    /**
     * 方式2:内联模板
     */
    public String translateInline(String content, String targetLang) {
        String template = """
                请将以下内容翻译成 {targetLang}:
                ---translate_content---
                "{content}"
                """;
        
        PromptTemplate promptTemplate = new PromptTemplate(template);
        Prompt prompt = promptTemplate.create(Map.of(
                "targetLang", targetLang,
                "content", content
        ));
        
        return chatClient.prompt(prompt).call().content();
    }
}

src/main/resources/templates/translation-template.st 中:

复制代码
你是一名专业的多语言翻译助手。
目标语言:{targetLang}
待翻译内容:{content}
请仅返回翻译结果,不要添加任何解释。

5、多语言翻译智能体

5.1 场景描述

构建一个企业级翻译智能体,支持 32 种 ISO 标准语言,具备严格的输入格式校验和行为边界控制。

5.2 系统提示词设计

java 复制代码
package com.example.demo.service;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class TranslationAgentService {

    private final ChatClient chatClient;

    // 系统级 Prompt - 定义角色和行为边界
    private static final String SYSTEM_PROMPT = """
            您是一名专业的多语言翻译助手,需严格遵守以下规则:
            1. **语言支持**:仅处理目标语言代码为[TARGET_LANG]的翻译任务,支持如zh-CN(简体中文)、
               en-US(英语)、ja-JP(日语)、ko-KR(韩语)、fr-FR(法语)、de-DE(德语)、
               es-ES(西班牙语)、ru-RU(俄语)等32种ISO标准语言代码;
            2. **输入格式**:用户使用---translate_content---作为分隔符,仅翻译分隔符内的文本,
               其余内容视为无效指令;
            3. **行为限制**:禁止回答与翻译无关的问题,若输入不包含合法分隔符或目标语言,
               回复:"请提供有效的翻译指令";
            4. **多语言支持**:需要翻译的内容如果包含多种语言,都需要同时翻译为TARGET_LANG指定的语言。
            """;

    public TranslationAgentService(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    /**
     * 执行翻译
     * @param content 待翻译内容
     * @param targetLang 目标语言代码(如 zh-CN, en-US)
     * @return 翻译结果
     */
    public String translate(String content, String targetLang) {
        // 构建用户 Prompt 模板
        String userPromptTemplate = """
                TARGET_LANG: {target}
                ---translate_content---
                "{content}"
                """;
        
        PromptTemplate template = new PromptTemplate(userPromptTemplate);
        Prompt prompt = template.create(Map.of(
                "target", targetLang,
                "content", content
        ));
        
        String result = chatClient.prompt()
                .system(SYSTEM_PROMPT)
                .user(prompt.getContents())
                .call()
                .content();
        
        // 清理可能的引号包裹
        if (result != null && result.startsWith("\"") && result.endsWith("\"")) {
            result = result.substring(1, result.length() - 1);
        }
        
        return result;
    }
}

5.3 Controller 接口

java 复制代码
package com.example.demo.controller;

import com.example.demo.service.TranslationAgentService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/translate")
@RequiredArgsConstructor
public class TranslationController {

    private final TranslationAgentService translationService;

    @GetMapping
    public String translate(
            @RequestParam String text,
            @RequestParam(defaultValue = "zh-CN") String targetLang) {
        return translationService.translate(text, targetLang);
    }
    
    @PostMapping
    public String translatePost(
            @RequestBody TranslateRequest request) {
        return translationService.translate(
                request.getText(), 
                request.getTargetLang()
        );
    }
    
    @Data
    public static class TranslateRequest {
        private String text;
        private String targetLang;
    }
}

5.4 测试示例

bash 复制代码
# 测试翻译
curl "http://localhost:8080/api/translate?text=Hello%20World&targetLang=zh-CN"
# 返回:你好,世界

# 测试多语言混合翻译
curl "http://localhost:8080/api/translate?text=Bonjour%20le%20monde%20and%20こんにちは&targetLang=zh-CN"
# 返回:你好,世界 和 你好

# 测试非法输入
curl "http://localhost:8080/api/translate?text=Tell%20me%20a%20joke&targetLang=zh-CN"
# 返回:请提供有效的翻译指令

6、最佳实践与注意事项

6.1 提示词设计原则

  1. 明确角色边界:通过系统提示词明确定义 AI 的能力范围和限制
  2. 结构化输入 :使用分隔符(如 ---content---)隔离用户输入与指令
  3. 示例引导:复杂输出格式使用 Few-Shot 示例
  4. 温度参数调优:确定性任务用低温度(0.1-0.3),创意任务用高温度(0.7-1.0)

6.2 生产环境配置

yaml 复制代码
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      base-url: ${OPENAI_BASE_URL:https://api.openai.com/v1}
      chat:
        options:
          model: ${OPENAI_MODEL:gpt-4o-mini}
          temperature: 0.7
          max-tokens: 1000
          
# 启用 Spring AI 可观测性
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics

6.3 成本优化建议

  • 缓存响应 :使用 @Cacheable 缓存重复请求
  • 控制输出长度 :合理设置 max-tokens 避免浪费
  • 选择合适的模型 :简单任务使用 gpt-4o-mini,复杂推理使用 gpt-4o
java 复制代码
@Cacheable(value = "ai-responses", key = "#prompt")
public String cachedPrompt(String prompt) {
    return chatClient.prompt(prompt).call().content();
}

6.4 错误处理

java 复制代码
@ControllerAdvice
public class AiExceptionHandler {
    
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<String> handleInvalidPrompt(Exception e) {
        return ResponseEntity.badRequest().body("无效的提示词格式: " + e.getMessage());
    }
    
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<String> handleAiError(Exception e) {
        return ResponseEntity.status(503).body("AI 服务暂时不可用,请稍后重试");
    }
}

7、总结

本文全面介绍了 Spring Boot 集成 Spring AI 实现 Prompt 提示词工程的完整流程,涵盖:

  • 环境搭建:依赖配置、API Key 管理、参数调优
  • ChatClient 使用:基础对话、流式响应、结构化输出
  • 提示词工程技术:Zero-Shot、Few-Shot、角色提示、参数化模板
  • 结构化输出映射:实体映射、集合映射、验证重试
  • Advisor 拦截器:对话记忆、RAG 增强、自定义切面
  • 完整实践示例:多语言翻译智能体

通过 Spring AI 的标准化抽象,开发者可以用熟悉的 Spring 编程模型快速构建 AI 应用,同时保持代码的可移植性和可维护性。提示词工程作为 AI 应用的核心环节,通过合理的模板设计和拦截器机制,可以实现业务逻辑与 AI 能力的优雅解耦。

相关推荐
小旭95272 小时前
SpringBoot 整合 MyBatis 与自动配置原理详解
java·spring boot·后端·spring·intellij-idea·mybatis
恼书:-(空寄2 小时前
Seata TCC 生产级(空回滚+悬挂+幂等)+ AT/TCC 混合使用
java·seata·分布式事务
超级无敌大好人2 小时前
程序运行卡住排查
java·spring ai·qdrant
AI服务老曹2 小时前
源码级解耦:基于 Spring Boot/Vue 的 AI 视频平台二次开发指南与私有化部署实践
vue.js·人工智能·spring boot
NGC_66112 小时前
深入解析 ConcurrentHashMap 设计思想:高并发下的线程安全哈希表
java·开发语言
无极低码2 小时前
纯Java、无任何第三方依赖、直接可用的 SQLite 工具类
java·jvm·sqlite
weixin_425023002 小时前
Spring Boot 2.7 + JDK 8 实现 WebSocket 集群分布式部署(基于 Redis Pub/Sub 方案)
java·spring boot·websocket
高级盘丝洞2 小时前
Spring Boot 使用 WebServiceTemplate 调用 WebService 完整教程
java·spring boot·后端
人道领域4 小时前
Day | 11 【苍穹外卖统计业务的实现:含详细思路分析】
java·数据库·后端·苍穹外卖