掘金 人工智能 07月03日 14:03
Spring AI 实战指南:Prompt 工程基础
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了 Prompt 工程,这是一门通过精心设计的提示词与 AI 模型高效交互的艺术。文章介绍了搭建 Spring AI 项目,并详细阐述了 Prompt 的构成要素,包括指令、上下文、输入和输出格式。此外,文章还提供了动态 Prompt 模板设计,以及避免常见陷阱的实用建议,并通过构建智能客服系统的实战案例,展示了 Prompt 工程在实际项目中的应用。

💡 **Prompt 的核心组成部分**:一个完整的 Prompt 通常包含指令(告诉 AI做什么)、上下文(提供背景信息)、输入(具体数据或内容)和输出格式(指定结果的格式)。

⚙️ **动态 Prompt 模板设计**:Spring AI 提供了 PromptTemplate 类,允许根据不同输入动态生成 Prompt,例如通过模板填充城市和日期来查询天气信息,使 Prompt 更具灵活性。

⚠️ **避免常见的 Prompt 陷阱**:包括指令不明确、上下文信息不足和输出格式不明确。文章通过具体示例展示了如何改进 Prompt,确保 AI 能够理解并给出更准确的回答。

🤖 **智能客服 Prompt 系统实战**:文章提供了一个完整的智能客服系统的例子,展示了如何利用 Prompt 工程构建一个能够处理客户咨询、生成订单状态更新的系统。

🔑 **RESTful API 接口设计**:为了使 Prompt 服务更实用,文章还介绍了如何设计 RESTful API 接口,包括天气查询和客户服务,方便用户调用和集成。

Prompt 工程基础:与 AI 高效对话的艺术

我们已经成功搭建了第一个 Spring AI 应用,体验了与 AI 对话的奇妙感觉。今天,我们将深入探讨一个看似简单却极其重要的主题:Prompt 工程

如果你曾经与 ChatGPT 对话过,你可能会发现一个有趣的现象:同样的问题,用不同的方式表达,得到的答案质量可能天差地别。这就是 Prompt 工程的魅力所在——它不仅仅是一门技术,更是一门艺术。

2.1 环境准备与项目搭建

在开始学习 Prompt 工程之前,让我们先搭建一个完整的演示项目。本项目使用 DeepSeek AI 模型,它是一个高质量且成本友好的选择。

项目依赖配置

<?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.4.7</version>        <relativePath/>    </parent>    <groupId>com.example</groupId>    <artifactId>prompt-engineering-demo</artifactId>    <version>0.0.1-SNAPSHOT</version>    <name>prompt-engineering-demo</name>    <description>Spring AI Prompt Engineering Demo</description>    <properties>        <java.version>21</java.version>        <spring-ai.version>1.0.0</spring-ai.version>    </properties>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.ai</groupId>            <artifactId>spring-ai-starter-model-deepseek</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </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></project>

应用配置

src/main/resources/application.properties 中配置 DeepSeek API:

spring.application.name=prompt-engineering-demo# DeepSeek AI 配置spring.ai.deepseek.api-key=${DEEPSEEK_API_KEY}spring.ai.deepseek.chat.options.model=deepseek-chatspring.ai.deepseek.chat.options.temperature=0.7

重要提醒: 请通过环境变量设置你的 DeepSeek API Key:

export DEEPSEEK_API_KEY=your_deepseek_api_key_here

2.2 Prompt 的组成部分:理解 AI 的"语言"

在开始编写代码之前,让我们先理解 Prompt 的基本结构。一个完整的 Prompt 通常包含以下几个核心要素:

指令(Instructions)

这是 Prompt 的核心部分,告诉 AI 你想要它做什么。比如:

上下文(Context)

为 AI 提供必要的背景信息,帮助它更好地理解任务。比如:

输入(Input)

具体的数据或内容,让 AI 基于此进行处理。比如:

输出格式(Output Format)

指定你希望 AI 以什么样的格式返回结果。比如:

2.3 动态 Prompt 模板设计:让 AI 更灵活

在实际应用中,我们很少会使用静态的 Prompt。更多时候,我们需要根据不同的输入动态生成 Prompt。Spring AI 提供了强大的 PromptTemplate 类来帮助我们实现这一点。

让我们通过一个天气查询的例子来演示:

package com.example.promptengineering.service;import java.util.Map;import org.springframework.ai.chat.client.ChatClient;import org.springframework.ai.chat.prompt.PromptTemplate;import org.springframework.stereotype.Service;@Servicepublic class WeatherPromptService {    private final ChatClient chatClient;    public WeatherPromptService(ChatClient.Builder chatClientBuilder) {        this.chatClient = chatClientBuilder.build();    }    public String getWeatherInfo(String city, String date) {        // 定义 Prompt 模板        String promptTemplate = """            你是一位专业的天气预报员。请根据以下信息为用户提供天气建议:                        城市:{city}            日期:{date}                        请提供以下信息:            1. 天气状况描述            2. 温度范围            3. 出行建议            4. 着装建议                        请用友好的语气回答,就像在和朋友聊天一样。            """;        // 创建 PromptTemplate 实例        PromptTemplate template = new PromptTemplate(promptTemplate);                // 填充模板参数        String filledPrompt = template.render(Map.of(            "city", city,            "date", date        ));        // 调用 AI 模型        return chatClient.prompt()                .user(filledPrompt)                .call()                .content();    }}

代码解析:

    模板定义:我们使用文本块(Text Blocks)定义了一个包含占位符的 Prompt 模板参数绑定:使用 {city}{date} 作为占位符动态填充:通过 template.render() 方法,将实际的参数值填充到模板中AI 调用:将填充后的 Prompt 发送给 AI 模型

2.4 避免常见陷阱:让 AI 更听话

在 Prompt 工程中,有一些常见的陷阱需要我们特别注意:

陷阱 1:指令不明确

错误示例:

请帮我优化代码

正确示例:

请分析以下 Java 代码的性能问题,并提供具体的优化建议:1. 时间复杂度分析2. 内存使用优化3. 具体的代码改进方案代码:{code}
陷阱 2:上下文信息不足

错误示例:

请解释这段代码

正确示例:

你是一位资深的 Java 开发者,请为初学者解释以下 Spring Boot 代码的工作原理。请从以下几个方面进行解释:1. 注解的作用2. 方法的执行流程3. 相关的设计模式代码:{code}
陷阱 3:输出格式不明确

错误示例:

请列出这个项目的优点和缺点

正确示例:

请分析这个项目的优缺点,并按以下格式返回:**优点:**- 优点1- 优点2**缺点:**- 缺点1- 缺点2**改进建议:**- 建议1- 建议2

2.5 实战:构建一个智能客服 Prompt 系统

让我们通过一个完整的例子,来展示如何在实际项目中应用 Prompt 工程:

package com.example.promptengineering.service;import java.util.Map;import org.springframework.ai.chat.client.ChatClient;import org.springframework.ai.chat.prompt.PromptTemplate;import org.springframework.stereotype.Service;@Servicepublic class CustomerServicePromptService {    private final ChatClient chatClient;    public CustomerServicePromptService(ChatClient.Builder chatClientBuilder) {        this.chatClient = chatClientBuilder.build();    }    public String handleCustomerInquiry(String customerMessage, String customerName, String orderHistory) {        // 定义客服 Prompt 模板        String promptTemplate = "你是一位专业的客服代表,名字叫小明。请根据以下信息为客户提供帮助:\n\n" +                "客户姓名:{customerName}\n" +                "客户消息:{customerMessage}\n" +                "历史订单:{orderHistory}\n\n" +                "请遵循以下原则:\n" +                "1. 保持友好、耐心的态度\n" +                "2. 如果客户询问订单相关的问题,请参考历史订单信息\n" +                "3. 如果不确定的信息,请建议客户联系人工客服\n" +                "4. 回答要简洁明了,避免过于冗长\n" +                "5. 如果客户表达不满,要表示理解和歉意\n\n" +                "请以\"您好,{customerName}!\"开头,以\"还有什么可以帮您的吗?\"结尾。";        PromptTemplate template = new PromptTemplate(promptTemplate);                String filledPrompt = template.render(Map.of(            "customerName", customerName,            "customerMessage", customerMessage,            "orderHistory", orderHistory        ));        return chatClient.prompt()                .user(filledPrompt)                .call()                .content();    }    public String generateOrderStatusUpdate(String orderNumber, String status, String estimatedDelivery) {        String promptTemplate = "请生成一条订单状态更新的通知消息:\n\n" +                "订单号:{orderNumber}\n" +                "当前状态:{status}\n" +                "预计送达时间:{estimatedDelivery}\n\n" +                "要求:\n" +                "1. 语气要专业但友好\n" +                "2. 包含所有必要信息\n" +                "3. 如果状态是\"已发货\",要提醒客户注意查收\n" +                "4. 如果状态是\"配送中\",要提醒客户保持电话畅通\n" +                "5. 字数控制在 100 字以内";        PromptTemplate template = new PromptTemplate(promptTemplate);                String filledPrompt = template.render(Map.of(            "orderNumber", orderNumber,            "status", status,            "estimatedDelivery", estimatedDelivery        ));        return chatClient.prompt()                .user(filledPrompt)                .call()                .content();    }}

2.6 RESTful API 接口设计

为了让我们的 Prompt 服务更加实用,我们需要提供 RESTful API 接口:

package com.example.promptengineering.controller;import com.example.promptengineering.service.CustomerServicePromptService;import com.example.promptengineering.service.WeatherPromptService;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/api/prompt")public class PromptDemoController {    private final WeatherPromptService weatherPromptService;    private final CustomerServicePromptService customerServicePromptService;    public PromptDemoController(WeatherPromptService weatherPromptService,                               CustomerServicePromptService customerServicePromptService) {        this.weatherPromptService = weatherPromptService;        this.customerServicePromptService = customerServicePromptService;    }    @GetMapping("/weather")    public String getWeatherInfo(@RequestParam String city, @RequestParam String date) {        return weatherPromptService.getWeatherInfo(city, date);    }    @PostMapping("/customer-service")    public String handleCustomerInquiry(@RequestBody CustomerInquiryRequest request) {        return customerServicePromptService.handleCustomerInquiry(            request.customerMessage(),             request.customerName(),             request.orderHistory()        );    }    @PostMapping("/order-status")    public String generateOrderStatusUpdate(@RequestBody OrderStatusRequest request) {        return customerServicePromptService.generateOrderStatusUpdate(            request.orderNumber(),             request.status(),             request.estimatedDelivery()        );    }    public record CustomerInquiryRequest(String customerMessage, String customerName, String orderHistory) {}        public record OrderStatusRequest(String orderNumber, String status, String estimatedDelivery) {}}

2.7 API 使用示例

现在我们可以通过 HTTP 请求来测试我们的 Prompt 工程实现:

天气查询 API
curl "http://localhost:8080/api/prompt/weather?city=北京&date=2024-01-15"

响应示例:

您好!根据您查询的信息,北京在2024年1月15日的天气情况如下:1. 天气状况描述:晴天,空气质量良好2. 温度范围:-5°C 到 8°C3. 出行建议:天气晴朗,适合外出活动,但注意保暖4. 着装建议:建议穿着厚外套、围巾和手套,注意防寒保暖祝您出行愉快!
客服咨询 API
curl -X POST "http://localhost:8080/api/prompt/customer-service" \  -H "Content-Type: application/json" \  -d '{    "customerMessage": "我的订单什么时候能到?",    "customerName": "张三",    "orderHistory": "订单号:12345,状态:已发货,预计送达:2024-01-16"  }'
订单状态更新 API
curl -X POST "http://localhost:8080/api/prompt/order-status" \  -H "Content-Type: application/json" \  -d '{    "orderNumber": "12345",    "status": "已发货",    "estimatedDelivery": "2024-01-16"  }'

2.8 项目运行指南

    克隆项目
git clone https://github.com/yichuan4ai/spring-ai-examples.gitcd prompt-engineering-demo
    配置环境变量
export DEEPSEEK_API_KEY=your_deepseek_api_key_here
    运行应用
mvn spring-boot:run

或者使用提供的脚本:

chmod +x run.sh./run.sh

应用将在 http://localhost:8080 启动。

2.9 Prompt 工程的最佳实践

基于我的实践经验,我总结了一些 Prompt 工程的最佳实践:

1. 明确角色定位

始终为 AI 设定一个明确的角色,比如:

2. 提供具体示例

在 Prompt 中包含具体的示例,帮助 AI 更好地理解你的期望:

请按照以下格式回答问题:问题:什么是 Spring Boot?回答:Spring Boot 是一个基于 Spring 框架的快速开发工具,它简化了 Spring 应用的配置和部署过程。现在请回答:什么是 Spring AI?
3. 分步骤指导

对于复杂的任务,将其分解为多个步骤:

请按以下步骤分析这段代码:1. 首先,识别代码的主要功能2. 然后,分析可能存在的性能问题3. 最后,提供具体的优化建议
4. 设置约束条件

明确告诉 AI 什么可以做,什么不能做:

请回答以下问题,但请注意:- 不要提供具体的代码实现- 只提供概念性的解释- 如果涉及敏感信息,请说明无法提供

2.10 测试和优化你的 Prompt

Prompt 工程是一个迭代的过程,我们需要不断测试和优化:

@Servicepublic class PromptTestingService {    private final ChatClient chatClient;    public PromptTestingService(ChatClient.Builder chatClientBuilder) {        this.chatClient = chatClientBuilder.build();    }    public PromptTestResult testPrompt(String promptTemplate, Map<String, Object> parameters, String expectedOutput) {        PromptTemplate template = new PromptTemplate(promptTemplate);        String filledPrompt = template.render(parameters);                String actualOutput = chatClient.prompt()                .user(filledPrompt)                .call()                .content();        return new PromptTestResult(filledPrompt, actualOutput, expectedOutput);    }}public record PromptTestResult(String prompt, String actualOutput, String expectedOutput) {    public boolean isSuccessful() {        // 简单的相似度检查,实际项目中可以使用更复杂的算法        return actualOutput.contains(expectedOutput) || expectedOutput.contains(actualOutput);    }}

2.11 总结

Prompt 工程是 AI 应用开发中的一门重要技能。通过合理设计 Prompt,我们可以:

    提高 AI 回答的质量:明确的指令和上下文让 AI 更准确地理解我们的需求增强应用的灵活性:动态模板让我们可以根据不同情况生成合适的 Prompt降低开发成本:好的 Prompt 设计可以减少对 AI 模型的依赖,提高响应速度提升用户体验:专业的 Prompt 设计让 AI 的回答更加人性化和有用

在下一篇文章中,我们将深入探讨模型集成与调优,学习如何选择最适合你需求的 AI 模型,以及如何通过参数调优来获得更好的效果。

记住,Prompt 工程没有标准答案,关键是要根据你的具体需求不断实践和优化。就像编程一样,熟能生巧,多写多练,你就能掌握这门艺术。

如果你有任何问题或想法,欢迎在评论区与我交流。我们下期再见!


相关资源:

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Prompt 工程 Spring AI AI 对话 DeepSeek AI 智能客服
相关文章