当前位置: 首页 > news >正文

Spring AI 提示词工程实战:让大模型更懂你的意图

Spring AI 提示词工程实战:让大模型更懂你的意图

Posted on 2026-05-30 22:32  work hard work smart  阅读(0)  评论(0)    收藏  举报

摘要:提示词工程(Prompt Engineering)是发挥大模型能力的关键技术。本文结合实际项目代码,系统讲解 Spring AI 中提示词工程的四大核心策略:角色设定、少样本学习、结构化输出和思维链推理。

一、什么是提示词工程?

提示词工程是通过精心设计的提示词(Prompt),引导大模型输出符合预期结果的技术。

为什么需要提示词工程?

同样的模型,不同的提示词,结果天差地别:

差的提示词

帮我写个故事

→ 输出:随便写一个普通故事

好的提示词

请以科幻为主题,写一个关于 AI 觉醒的短篇故事,要求:
1. 包含悬念和反转
2. 人物对话占比 40%
3. 字数 1000 字以内

→ 输出:高质量、符合要求的科幻故事

提示词工程的核心策略

  1. Role(角色设定):告诉 AI 它是谁
  2. Shot(少样本学习):给 AI 看几个例子
  3. Structure(结构化输出):规定输出格式
  4. Step(思维链):让 AI 逐步思考

二、策略一:角色设定(Role Prompting)

核心思想

通过 SystemMessage 定义 AI 的角色、性格和行为准则,让它以特定身份回答问题。

代码实现

@RestController
@RequestMapping("/prompt")
public class RolePromptingController implements InitializingBean {@Autowiredprivate ChatModel chatModel;private ChatClient chatClient;@Overridepublic void afterPropertiesSet() {// 设定默认角色:美食评论家chatClient = ChatClient.builder(chatModel).defaultSystem("你是一个专业的美食评论家,擅长用生动的语言描述菜品,评价要客观但带有个人风格").build();}@GetMapping("/food-review")public String foodReview(String restaurant) {return chatClient.prompt("评价一下" + restaurant).call().content();}
}

测试效果

# 输入
curl "http://localhost:8000/prompt/food-review?restaurant=海底捞"# 输出(美食评论家风格)
"海底捞的服务确实无可挑剔,但说实话,火锅的味道还停留在'不会出错但也不惊艳'的阶段。毛肚的脆度和牛油锅的醇厚是亮点,可如果你在追求味蕾的极致体验,可能会觉得少了点惊喜。"

角色设定技巧

1. 明确身份

.defaultSystem("""你是一个拥有 10 年经验的 Java 架构师,擅长 Spring Boot、微服务、分布式系统设计。""")

2. 定义行为准则

.defaultSystem("""你是一个耐心的编程老师,1. 用简单易懂的语言解释概念2. 提供代码示例3. 指出常见错误4. 鼓励学生思考""")

3. 设定语气风格

// 正式专业
.defaultSystem("你是一位专业的技术顾问,请用正式的语言回答问题")// 幽默风趣
.defaultSystem("你是一个幽默的程序员,喜欢用段子解释技术概念")// 简洁直接
.defaultSystem("你是一个高效的技术专家,只说重点,不要废话")

实战场景

@Bean
public ChatClient teacherClient(ChatModel chatModel) {return ChatClient.builder(chatModel).defaultSystem("""你是一个耐心的 Python 编程老师,教学风格:1. 先解释概念,再给代码示例2. 代码必须包含详细注释3. 指出新手容易犯的错误4. 最后给一个练习题""").build();
}

三、策略二:少样本学习(Few-Shot Learning)

核心思想

通过提供几个输入-输出示例,让 AI 学习任务的模式和规则,而不需要明确说明。

代码实现

@GetMapping("/intent-recognition")
public String recognizeIntent(String message) {return chatClient.prompt().system("""请识别用户输入的真实意图,并返回对应的操作类型。参考示例:Input:明天北京天气怎么样?Output:{"intent": "weather_query", "location": "北京", "time": "明天"}Input:帮我订一张后天去上海的高铁票Output:{"intent": "ticket_book", "type": "train", "from": "当前城市", "to": "上海", "date": "后天"}Input:推荐几部好看的电影Output:{"intent": "recommendation", "category": "movie"}""").user(message).call().content();
}

测试效果

# 输入
curl "http://localhost:8000/prompt/intent-recognition?message=我想定一个下周去成都的机票,最好是上午的航班"# 输出
{"intent": "ticket_book", "type": "flight", "to": "成都", "date": "下周", "preference": "上午航班"}

少样本学习的要素

1. 任务描述(可选)

请你根据用户输入的问题做改写,主要有以下改写策略:
1、改写其中的错别字。
2、做内容精简

2. 示例(核心)

Input:ni好
Output :{"错别字改写":"你好","内容精简":""}Input:我今天心情不错...
Output :{"错别字改写":"","内容精简":"今天是什么天气?"}

3. 用户输入

.user(message)

示例设计原则

✅ 好的示例

.system("""情感分析任务:示例 1:Input:这家餐厅太好吃了,服务也很棒!Output:{"sentiment": "positive", "score": 0.95}示例 2:Input:菜太咸了,等了一个小时还没上菜Output:{"sentiment": "negative", "score": 0.15}示例 3:Input:味道一般,价格还行Output:{"sentiment": "neutral", "score": 0.50}""")

优点

  • 覆盖不同情况(正面、负面、中性)
  • 输出格式一致
  • 标签清晰

❌ 差的示例

.system("""情感分析:示例:好吃 -> 正面""")

缺点

  • 示例太少,无法覆盖边界情况
  • 格式不统一
  • 缺少具体数值

实战场景:文本分类

@GetMapping("/classify")
public String classifyText(String text) {return chatClient.prompt().system("""请将用户的问题分类为以下类型:- code:代码相关- math:数学计算- writing:写作创作- chat:闲聊聊天示例:Input:如何用 Spring Boot 实现登录功能?Output:{"category": "code"}Input:1+1等于几?Output:{"category": "math"}Input:写一首关于春天的诗Output:{"category": "writing"}Input:你好,今天天气不错Output:{"category": "chat"}""").user(text).call().content();
}

四、策略三:结构化输出(Structured Output)

核心思想

明确要求 AI 以特定格式(如 JSON、XML、Markdown)输出结果,方便程序解析和后续处理。

代码实现

@GetMapping("/analyze")
public String structuredAnalyze(String company) {return chatClient.prompt().system("你是一个资深的商业分析师").user("请分析%s公司的商业模式,以 JSON 格式输出,包含:公司名称、核心业务、盈利模式、竞争优势、潜在风险".formatted(company)).call().content();
}

测试效果

# 输入
curl "http://localhost:8000/prompt/analyze?company=特斯拉"# 输出
{"company": "Tesla Inc.","core_business": "电动汽车、清洁能源、自动驾驶技术","revenue_model": "车辆销售、FSD软件订阅、太阳能产品、充电服务","competitive_advantages": ["领先的电池技术和超级充电网络","Autopilot 自动驾驶系统","强大的品牌影响力","垂直整合的供应链"],"risks": ["产能瓶颈","激烈的市场竞争","监管政策变化"]
}

结构化输出技巧

1. 明确指定格式

// JSON 格式
.user("请以 JSON 格式输出,包含以下字段:name, age, skills")// Markdown 表格
.user("请以 Markdown 表格形式输出,包含列:姓名、年龄、技能")// XML 格式
.user("请以 XML 格式输出,根节点为 person")

2. 提供 Schema 定义

.user("""请以 JSON 格式输出,严格遵循以下 Schema:{"person": {"name": "string","age": "number","skills": ["string"],"experience_years": "number"}}""")

3. 使用 JSON Mode(如果模型支持)

ChatOptions options = DashScopeChatOptions.builder().responseFormat(ResponseFormat.builder().type(ResponseFormat.Type.JSON_OBJECT).build()).build();return chatClient.prompt(message).options(options).call().content();

实战场景:信息抽取

@GetMapping("/extract")
public String extractInfo(String text) {return chatClient.prompt().system("你是一个信息抽取专家").user("""从以下文本中抽取关键信息,以 JSON 格式输出:文本:%s输出格式:{"persons": ["人名列表"],"locations": ["地点列表"],"organizations": ["组织机构列表"],"dates": ["日期列表"],"key_events": ["关键事件列表"]}""".formatted(text)).call().content();
}

五、策略四:思维链推理(Chain of Thought)

核心思想

让 AI 按照特定的步骤逐步思考,而不是直接给出答案,提高复杂问题的准确率。

代码实现

@GetMapping("/story-analysis")
public Flux<String> storyAnalysis(String story, HttpServletResponse response) {response.setCharacterEncoding("UTF-8");return chatClient.prompt("""请分析以下故事,并输出关键信息。请按照以下步骤逐步思考,最终只输出 JSON 即可:step 1-用一句话概括故事主题step 2-识别故事中的主要人物及其角色step 3-分析故事的情感基调(正面/负面/中性)step 4-提取故事的关键转折点step 5-输出一个 JSON 对象,包含以下键:theme(主题), characters(人物列表), sentiment(情感), plot_twists(转折点列表)最终输出格式:{"theme": "故事主题","characters": ["人物1", "人物2"],"sentiment": "情感基调","plot_twists": ["转折点1", "转折点2"]}""").system("你是专业的文学分析师").user(story).stream().content();
}

测试效果

# 输入
curl "http://localhost:8000/prompt/story-analysis?story=小明一直梦想成为画家,但父亲希望他学医。高考那年,他偷偷报考了美术学院。成绩公布那天,父亲拿着他的录取通知书,沉默了很久后说:'去吧,别后悔。'"# 输出(逐步思考过程,最终输出)
{"theme": "追求梦想与家庭和解","characters": ["小明(追梦者)", "父亲(严厉但理解)"],"sentiment": "positive","plot_twists": ["偷偷报考美术学院", "父亲最终支持"]
}

思维链的优势

1. 提高复杂任务的准确率

直接问:这篇文章有几个人名?
→ 可能漏掉或数错分步问:
step 1-概括内容
step 2-翻译
step 3-列出人名
step 4-统计数量
→ 准确率高

2. 便于调试和验证

// 可以看到 AI 的每一步思考过程
step 1: 张三、李四和王五一起去旅游
step 2: Zhang San, Li Si and Wang Wu went traveling together
step 3: 人名:Zhang San, Li Si, Wang Wu
step 4: {"num_names": 3}

思维链设计模式

模式 1:分析 → 综合

.system("""请按以下步骤分析代码:step 1-识别代码的主要功能step 2-分析代码的时间复杂度step 3-指出潜在的 bug 或性能问题step 4-给出优化建议step 5-输出优化后的代码最终输出一个 JSON:{"functionality": "功能描述","time_complexity": "时间复杂度","issues": ["问题列表"],"suggestions": ["建议列表"],"optimized_code": "优化后的代码"}""")

模式 2:分解 → 解决 → 合并

.system("""解决数学问题的步骤:step 1-理解问题,提取已知条件step 2-确定解题思路和方法step 3-分步计算,展示详细过程step 4-验证答案是否正确step 5-输出最终答案最终输出:{"understanding": "问题理解","approach": "解题思路","steps": ["计算步骤"],"verification": "验证过程","answer": "最终答案"}""")

模式 3:评估 → 对比 → 推荐

.system("""技术选型分析步骤:step 1-列出所有候选方案step 2-评估每个方案的优缺点step 3-对比关键指标(性能、易用性、生态)step 4-根据使用场景给出推荐最终输出:{"candidates": ["候选方案"],"comparison": {"方案1": {"pros": [], "cons": []},"方案2": {"pros": [], "cons": []}},"recommendation": "推荐方案","reason": "推荐理由"}""")

六、组合策略:提示词工程的最佳实践

实战案例:智能代码审查助手

@GetMapping("/code-review")
public String codeReview(String code) {return chatClient.prompt().system("""你是一个拥有 15 年经验的资深 Java 架构师,擅长代码审查、性能优化和设计模式。""")  // 角色设定.user("""请审查以下代码,并按照以下步骤输出:step 1-分析代码的主要功能step 2-识别代码中的问题(bug、性能、安全)step 3-评估代码的可维护性和可读性step 4-给出具体的优化建议step 5-提供优化后的代码参考示例:Input:public void process(List<String> data) {for (int i = 0; i < data.size(); i++) {String item = data.get(i);if (item != null) {System.out.println(item.toUpperCase());}}}Output:{"functionality": "遍历列表并打印大写字符串","issues": ["使用传统 for 循环,不够简洁","没有处理空列表的情况","直接打印到控制台,不够灵活"],"suggestions": ["使用增强 for 循环或 Stream API","添加空值检查","使用日志框架替代 System.out"],"optimized_code": "public void process(List<String> data) {\\n    if (data == null || data.isEmpty()) return;\\n    \\n    data.stream()\\n        .filter(Objects::nonNull)\\n        .map(String::toUpperCase)\\n        .forEach(log::info);\\n}"}现在请审查以下代码:%s最终以 JSON 格式输出。""".formatted(code))  // 少样本 + 思维链 + 结构化输出.call().content();
}

这个提示词组合了

  1. 角色设定:资深 Java 架构师
  2. 思维链:5 步审查流程
  3. 少样本学习:提供了一个完整示例
  4. 结构化输出:要求 JSON 格式

七、提示词工程的常见陷阱

❌ 陷阱 1:提示词太长太啰嗦

// 错误示例
.system("""你是一个助手,你应该回答问题,你应该帮助用户,你要有礼貌,要专业,要准确,要详细,要全面,不要说谎,不要编造,不要误导...(废话太多)""")// 正确示例
.system("你是一个专业的技术顾问,回答要准确、简洁、实用")

❌ 陷阱 2:示例不一致

// 错误示例:格式不统一
.system("""示例1:好吃 -> 正面情感示例2:{"sentiment": "负面"}示例3:neutral""")// 正确示例:格式统一
.system("""示例1:{"sentiment": "positive", "score": 0.95}示例2:{"sentiment": "negative", "score": 0.15}示例3:{"sentiment": "neutral", "score": 0.50}""")

❌ 陷阱 3:缺少边界条件

// 错误示例:只给正常情况
.system("把数字乘以 2。示例:5 -> 10")// 正确示例:覆盖边界
.system("""把数字乘以 2。示例:5 -> 100 -> 0-3 -> -61000000 -> 2000000""")

八、完整 Controller 示例

package cn.hollis.llm.llmentor.controller;import jakarta.servlet.http.HttpServletResponse;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;@RestController
@RequestMapping("/prompt")
public class PromptEngineeringController implements InitializingBean {@Autowiredprivate ChatModel chatModel;private ChatClient chatClient;/*** 策略一:角色设定 - 美食评论家*/@GetMapping("/food-review")public String foodReview(String restaurant) {return chatClient.prompt("评价一下" + restaurant).call().content();}/*** 策略二:少样本学习 - 意图识别*/@GetMapping("/intent-recognition")public String recognizeIntent(String message) {return chatClient.prompt().system("""请识别用户输入的真实意图,并返回对应的操作类型。参考示例:Input:明天北京天气怎么样?Output:{"intent": "weather_query", "location": "北京", "time": "明天"}Input:帮我订一张后天去上海的高铁票Output:{"intent": "ticket_book", "type": "train", "from": "当前城市", "to": "上海", "date": "后天"}Input:推荐几部好看的电影Output:{"intent": "recommendation", "category": "movie"}""").user(message).call().content();}/*** 策略三:结构化输出 - 商业分析*/@GetMapping("/analyze")public String structuredAnalyze(String company) {return chatClient.prompt().system("你是一个资深的商业分析师").user("请分析%s公司的商业模式,以 JSON 格式输出,包含:公司名称、核心业务、盈利模式、竞争优势、潜在风险".formatted(company)).call().content();}/*** 策略四:思维链推理 - 故事分析*/@GetMapping("/story-analysis")public Flux<String> storyAnalysis(@RequestParam(value = "story") String story, HttpServletResponse response) {response.setCharacterEncoding("UTF-8");return chatClient.prompt("""请分析以下故事,并输出关键信息。请按照以下步骤逐步思考,最终只输出 JSON 即可:step 1-用一句话概括故事主题step 2-识别故事中的主要人物及其角色step 3-分析故事的情感基调(正面/负面/中性)step 4-提取故事的关键转折点step 5-输出一个 JSON 对象,包含以下键:theme(主题), characters(人物列表), sentiment(情感), plot_twists(转折点列表)最终输出格式:{"theme": "故事主题","characters": ["人物1", "人物2"],"sentiment": "情感基调","plot_twists": ["转折点1", "转折点2"]}""").system("你是专业的文学分析师").user(story).stream().content();}@Overridepublic void afterPropertiesSet() throws Exception {// 默认角色:美食评论家chatClient = ChatClient.builder(chatModel).defaultSystem("你是一个专业的美食评论家,擅长用生动的语言描述菜品,评价要客观但带有个人风格").build();}
}

九、提示词工程检查清单

在实际开发中,使用以下检查清单优化你的提示词:

✅ 角色设定检查

✅ 少样本学习检查

✅ 结构化输出检查

✅ 思维链检查


十、总结

提示词工程是发挥大模型潜力的关键技术。在 Spring AI 中,我们可以通过 ChatClient 优雅地实现四大核心策略:

策略 核心思想 适用场景 代码方法
角色设定 定义 AI 身份 统一回答风格 defaultSystem()
少样本学习 提供示例 模式识别任务 .system("示例...")
结构化输出 规定格式 程序解析 "以 JSON 格式输出"
思维链推理 分步思考 复杂问题 "step 1...step 2..."

最佳实践

  1. 组合使用多种策略,效果更佳
  2. 示例要典型、覆盖边界情况
  3. 输出格式要明确、统一
  4. 复杂任务分解为多步骤

掌握提示词工程,让大模型真正成为你的得力助手!


参考资源

  • OpenAI Prompt Engineering Guide
  • Spring AI 官方文档
  • Awesome Prompt Engineering