Spring AI 隐藏杀器:参数这样调,效果立竿见影
ztj100 2025-05-25 16:49 16 浏览 0 评论
前言
随着大语言模型(LLM)的飞速发展,如何有效地设计提示词(Prompt)成为了开发人员必须掌握的一项关键技能。Spring AI 框架为 Java 开发者提供了简洁而强大的 API,使提示工程技术的实现变得简单高效。本文将详细介绍如何使用 Spring AI 实现各种提示工程技巧,帮助您构建更智能、更可靠的 AI 应用程序。
文中的示例和模式基于全面的 提示工程指南,展示了如何将理论概念转化为实际可用的 Java 代码实现。
PIG AI新版来袭:一站式Java AI解决方案,六大能力全面升级!
1. 配置与初始化
在深入了解提示工程技术之前,我们先看看如何设置和调整 Spring AI 中的大语言模型配置。
选择 LLM 提供商
Spring AI 的优势之一是支持多种 LLM 提供商(如 OpenAI、Anthropic、Google Vertex AI、AWS Bedrock、Ollama 等),让您可以在不改变应用代码的情况下切换不同的模型提供商。只需添加所需的启动依赖 spring-ai-starter-model-<模型提供商名称> 即可。
例如,添加 Open AI 协议的支持:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
配置连接属性:
spring.ai.openai.api-key=sk-b30f6476fa9645ce8cf7e922073bf499
spring.ai.openai.chat.options.model=deepseek-chat
spring.ai.openai.base-url=https://api.deepseek.com/v1```
您可以指定具体的模型版本:
.options(ChatOptions.builder()
.model("deepseek-chat") // 请求过程中修改模型
.build())
LLM 输出配置
Spring AI 提供了多种配置选项,让您可以通过 ChatOptions 构建器控制模型输出的各个方面。
Temperature(温度)
Temperature 控制模型回答的随机性或 "创造性 ":
- o 较低值 (0.0-0.3):更确定性、更集中的回答,适合事实性问题和分类任务
- o 中等值 (0.4-0.7):在确定性和创造性之间取得平衡,适合一般用例
- o 较高值 (0.8-1.0):更具创造性、多样性和潜在的惊喜性,适合创意写作和头脑风暴
.options(ChatOptions.builder()
.temperature(0.1) // 非常确定性的输出
.build())
输出长度(MaxTokens)
maxTokens 参数限制模型在回答中可以生成的标记(词片段)数量:
- o 低值 (5-25):适合单个词、短语或分类标签
- o 中等值 (50-500):适合段落或简短解释
- o 高值 (1000+):适合长篇内容、故事或复杂解释
.options(ChatOptions.builder()
.maxTokens(250) // 中等长度回答
.build())
采样控制(Top-K 和 Top-P)
这些参数提供了对生成过程中标记选择的精细控制:
- o Top-K:将标记选择限制在 K 个最可能的下一个标记中
- o Top-P(核采样):动态选择累积概率超过 P 的最小标记集
.options(ChatOptions.builder()
.topK(40) // 只考虑前 40 个最可能的标记
.topP(0.8) // 从覆盖 80% 概率质量的标记中采样
.build())
结构化响应格式
除了使用 .content() 获取纯文本响应外,Spring AI 还提供了将 LLM 响应直接映射到 Java 对象的简便方法:
enum Sentiment {
POSITIVE, NEUTRAL, NEGATIVE
}
Sentiment result = chatClient.prompt("...")
.call()
.entity(Sentiment.class);
模型特定选项
虽然通用的 ChatOptions 提供了跨不同 LLM 提供商的一致接口,但 Spring AI 也提供了模型特定的选项类,以便访问提供商特有的功能:
// 使用 OpenAI 特定选项
OpenAiChatOptions openAiOptions = OpenAiChatOptions.builder()
.model("gpt-4o")
.temperature(0.2)
.responseFormat(new ResponseFormat("json_object")) // ollama 为 json_schema
.build();
2. 提示工程技术实战
2.1 零样本提示(Zero-Shot Prompting)
零样本提示是指在不提供任何示例的情况下要求 AI 执行任务,测试模型从零开始理解和执行指令的能力。
public voidpt_zero_shot_prompting(ChatClient chatClient) {
// 简单的零样本翻译
Stringtranslation= chatClient
.prompt("将以下英文文本翻译成中文:'Spring AI makes prompt engineering easy'")
.call()
.content();
// 零样本分类
Stringclassification= chatClient
.prompt("判断以下评论的情感是正面、中性还是负面:'这家餐厅的服务太差了,但是食物还不错 '")
.options(ChatOptions.builder()
.temperature(0.1) // 低温度,更确定性的回答
.build())
.call()
.content();
}
零样本提示适用于直接的任务,尤其是当模型在训练中可能已经见过类似示例时。优点是提示简短,但复杂任务的表现可能不稳定。
2.2 少样本提示(Few-Shot Prompting)
少样本提示通过提供几个示例来指导模型理解任务模式,尤其适用于需要特定格式或风格的任务。
public void pt_few_shot_prompting(ChatClient chatClient) {
String fewShotClassification = chatClient
.prompt("""
将以下产品评论分类为正面或负面:
评论:"这款手机太棒了,拍照效果非常好!"
分类:正面
评论:"送货慢,包装破损,很失望。"
分类:负面
评论:"使用一周后电池开始出现问题,不推荐购买。"
分类:
""")
.call()
.content();
}
少样本提示在需要一致性和特定输出格式的场景中特别有效,例如文本分类、实体提取和结构化数据生成。通过精心选择典型示例,可以显著提高模型性能。
2.3 思维链提示(Chain-of-Thought Prompting)
思维链提示技术鼓励模型逐步思考问题,特别适用于需要推理的复杂任务。
public voidpt_chain_of_thought_prompting(ChatClient chatClient) {
Stringsolution= chatClient
.prompt("""
小明有 5 个苹果,小红给了他 2 个苹果,然后他吃掉了 3 个,又送给了小华 1 个。
小明现在有多少个苹果?请一步一步思考。
""")
.call()
.content();
// 少样本思维链
StringfewShotCoT= chatClient
.prompt("""
问题:如果 8 个人分享 4 块比萨,每人可以得到多少块?
思考:总共有 4 块比萨,需要分给 8 个人。每块比萨分成 2 份,8 个人就需要 8 份。
4 块比萨可以分成 4 * 2 = 8 份。所以每个人可以得到 8/8 = 1 份,也就是半块比萨。
答案:1/2 块比萨
问题:火车以每小时 120 公里的速度行驶。2.5 小时后,火车行驶了多少公里?
思考:
""")
.call()
.content();
}
思维链提示通过展示模型的推理过程,不仅提高了解决复杂问题的准确性,还增强了答案的可解释性和可验证性。研究表明,这种方法在数学问题、逻辑推理和多步骤任务中特别有效。
2.4 自一致性提示(Self-Consistency Prompting)
自一致性提示技术通过生成多个独立解决方案并选择最常见答案来提高准确性,特别适用于关键决策场景。
public voidpt_self_consistency_prompting(ChatClient chatClient) {
// 使用思维链生成多个解决方案路径
List<String> solutions = newArrayList<>();
for (inti=0; i < 5; i++) {
Stringsolution= chatClient
.prompt("""
一个商店正在进行 "买 2 送 1" 的促销活动。如果每件商品原价 15 元,
买 7 件需要多少钱?请逐步思考。
""")
.options(ChatOptions.builder()
.temperature(0.7) // 较高温度增加多样性
.build())
.call()
.content();
solutions.add(solution);
}
// 选择最一致的答案
StringfinalSolution= chatClient
.prompt()
.user(u -> u.text("""
分析以下解决方案,选择最准确的一个:
{solutions}
""").param("solutions", String.join("\n---\n", solutions)))
.options(ChatOptions.builder()
.temperature(0.1) // 低温度保证确定性
.build())
.call()
.content();
}
自一致性提示在需要高准确性的场景中非常有价值,例如数学计算、代码生成和关键决策支持。通过综合多个思考路径,它能有效减少单一推理链中的错误积累。
2.5 思想树提示(Tree-of-Thoughts Prompting)
思想树提示是思维链的扩展,允许模型探索多个推理分支,适用于需要前瞻性思考的复杂问题。
public void pt_tree_of_thoughts_prompting(ChatClient chatClient) {
String solution = chatClient
.prompt("""
你正在玩数独游戏,需要填写 3x3 网格的最后一行。
已知数据:
第一行:1 5 9
第二行:6 7 3
第三行:? ? ?
请探索不同可能性,考虑每种选择带来的约束,找出符合数独规则的第三行数字组合。
""")
.call()
.content();
}
思想树提示在解决需要探索多种可能性的问题时尤为有效,例如游戏策略、复杂决策和算法设计。通过系统化地追踪不同解决路径,它可以找到更优的解决方案。
2.6 抽象提示(Abstractions in Prompting)
抽象提示技术鼓励模型首先 "退一步 ",从更高层次理解问题,然后再提供具体解决方案。
public void pt_abstractions_in_prompting(ChatClient chatClient) {
String solution = chatClient
.prompt("""
解决这个编程问题:实现一个函数,找出数组中所有和为特定值的数字对。
在回答之前,先思考这个问题的核心是什么,可以用什么算法解决,
有哪些边界情况需要考虑,然后再提供解决方案。
""")
.call()
.content();
}
抽象提示通过鼓励模型进行高层次思考,帮助解决复杂问题,特别适用于算法设计、系统架构和战略规划等需要全局视角的任务。
2.7 角色提示(Role Prompting)
角色提示让 AI 扮演特定角色,激发其基于角色背景知识的特定能力。
public voidpt_role_prompting(ChatClient chatClient) {
// 系统消息角色
StringroleWithSystem= chatClient
.prompt()
.system("你是一位经验丰富的 Java 开发专家,尤其擅长 Spring 框架 ")
.user("解释一下 Spring AOP 的原理和使用场景 ")
.call()
.content();
// 直接在用户提示中定义角色
StringroleInPrompt= chatClient
.prompt("""
作为一名资深数据库架构师,请评估将传统关系型数据库迁移到 NoSQL 数据库的优缺点,
特别是对于一个高流量的电子商务网站。考虑性能、可扩展性和一致性等方面。
""")
.call()
.content();
}
角色提示通过赋予模型特定 "身份 ",能够激发其在相关领域的专业知识,特别适用于需要特定专业背景、风格或视角的场景。通过精心设计角色,可以获得更专业、更多样化的回答。
2.8 自动提示工程(Automatic Prompt Engineering)
自动提示工程(APE)是一种元级别方法,使用 AI 来优化提示本身。
public voidpt_automatic_prompt_engineering(ChatClient chatClient) {
// 生成指令变体
StringorderVariants= chatClient
.prompt("""
我们有一个乐队周边 T 恤网店,为了训练聊天机器人,我们需要多种下单方式的表述:
"一件 S 码的 Metallica T 恤 "。请生成 10 个语义相同但表达不同的变体。
""")
.options(ChatOptions.builder()
.temperature(1.0) // 高温度增加创造性
.build())
.call()
.content();
// 评估并选择最佳变体
Stringoutput= chatClient
.prompt()
.user(u -> u.text("""
请对以下变体进行 BLEU (Bilingual Evaluation Understudy) 评估:
----
{variants}
----
选择评分最高的指令候选。
""").param("variants", orderVariants))
.call()
.content();
}
APE 在优化生产系统的提示、解决手动提示工程难以应对的挑战性任务,以及系统性地提高提示质量方面特别有价值。
2.9 代码提示(Code Prompting)
代码提示专门针对代码相关任务,利用 LLM 理解和生成编程语言的能力。
// 编写代码
publicvoidpt_code_prompting_writing_code(ChatClient chatClient) {
StringbashScript= chatClient
.prompt("""
用 Bash 编写一个脚本,询问用户输入文件夹名称,
然后将该文件夹中的所有文件重命名,在文件名前加上 "draft_" 前缀。
""")
.options(ChatOptions.builder()
.temperature(0.1) // 低温度保证确定性代码
.build())
.call()
.content();
}
// 解释代码
publicvoidpt_code_prompting_explaining_code(ChatClient chatClient) {
Stringcode="""
#!/bin/bash
echo "输入文件夹名称:"
read folder_name
if [ ! -d "$folder_name" ]; then
echo "文件夹不存在。"
exit 1
fi
files=( "$folder_name"/* )
for file in "${files[@]}"; do
new_file_name="draft_$(basename "$file")"
mv "$file" "$new_file_name"
done
echo "文件重命名成功。"
""";
Stringexplanation= chatClient
.prompt()
.user(u -> u.text("""
解释以下 Bash 代码的功能:
```
{code}
```
""").param("code", code))
.call()
.content();
}
// 翻译代码
publicvoidpt_code_prompting_translating_code(ChatClient chatClient) {
StringbashCode="""
#!/bin/bash
echo "输入文件夹名称:"
read folder_name
if [ ! -d "$folder_name" ]; then
echo "文件夹不存在。"
exit 1
fi
files=( "$folder_name"/* )
for file in "${files[@]}"; do
new_file_name="draft_$(basename "$file")"
mv "$file" "$new_file_name"
done
echo "文件重命名成功。"
""";
StringpythonCode= chatClient
.prompt()
.user(u -> u.text("""
将以下 Bash 代码翻译成 Python:
{code}
""").param("code", bashCode))
.call()
.content();
}
代码提示在自动代码文档生成、原型设计、学习编程概念和编程语言转换方面特别有价值。结合少样本提示或思维链等技术可以进一步提高效果。
结语
Spring AI 为实现各种提示工程技术提供了优雅的 Java API。通过结合这些技术与 Spring 强大的实体映射和流畅的 API,开发人员可以构建复杂而高效的 AI 应用程序。
最有效的方法往往是结合多种技术——例如,将系统提示与少样本示例结合,或将思维链与角色提示结合。Spring AI 灵活的 API 使这些组合变得直观且易于实现。
对于生产应用,请记住:
- 1. 测试不同参数(温度、top-k、top-p)下的提示效果
- 2. 考虑对关键决策使用自一致性技术
- 3. 利用 Spring AI 的实体映射实现类型安全的响应
- 4. 使用上下文提示提供应用程序特定知识
通过这些技术和 Spring AI 强大的抽象,您可以创建稳健的 AI 应用,提供一致且高质量的结果。
相关推荐
- 拒绝躺平,如何使用AOP的环绕通知实现分布式锁
-
如何在分布式环境下,像用synchronized关键字那样使用分布式锁。比如开发一个注解,叫@DistributionLock,作用于一个方法函数上,每次调方法前加锁,调完之后自动释放锁。可以利用Sp...
- 「解锁新姿势」 兄dei,你代码需要优化了
-
前言在我们平常开发过程中,由于项目时间紧张,代码可以用就好,往往会忽视代码的质量问题。甚至有些复制粘贴过来,不加以整理规范。往往导致项目后期难以维护,更别说后续接手项目的人。所以啊,我们要编写出优雅的...
- 消息队列核心面试点讲解(消息队列面试题)
-
Rocketmq消息不丢失一、前言RocketMQ可以理解成一个特殊的存储系统,这个存储系统特殊之处数据是一般只会被使用一次,这种情况下,如何保证这个被消费一次的消息不丢失是非常重要的。本文将分析Ro...
- 秒杀系统—4.第二版升级优化的技术文档二
-
大纲7.秒杀系统的秒杀活动服务实现...
- SpringBoot JPA动态查询与Specification详解:从基础到高级实战
-
一、JPA动态查询概述1.1什么是动态查询动态查询是指根据运行时条件构建的查询,与静态查询(如@Query注解或命名查询)相对。在业务系统中,80%的查询需求都是动态的,例如电商系统中的商品筛选、订...
- Java常用工具类技术文档(java常用工具类技术文档有哪些)
-
一、概述Java工具类(UtilityClasses)是封装了通用功能的静态方法集合,能够简化代码、提高开发效率。本文整理Java原生及常用第三方库(如ApacheCommons、GoogleG...
- Guava 之Joiner 拼接字符串和Map(字符串拼接join的用法)
-
Guave是一个强大的的工具集合,今天给大家介绍一下,常用的拼接字符串的方法,当然JDK也有方便的拼接字符串的方式,本文主要介绍guava的,可以对比使用基本的拼接的话可以如下操作...
- SpringBoot怎么整合Redis,监听Key过期事件?
-
一、修改Redis配置文件1、在Redis的安装目录2、找到redis.windows.conf文件,搜索“notify-keyspace-events”...
- 如何使用Python将多个excel文件数据快速汇总?
-
在数据分析和处理的过程中,Excel文件是我们经常会遇到的数据格式之一。本文将通过一个具体的示例,展示如何使用Python和Pandas库来读取、合并和处理多个Excel文件的数据,并最终生成一个包含...
- 利用Pandas高效处理百万级数据集,速度提升10倍的秘密武器
-
处理大规模数据集,尤其是百万级别的数据量,对效率的要求非常高。使用Pandas时,可以通过一些策略和技巧显著提高数据处理的速度。以下是一些关键的方法,帮助你使用Pandas高效地处理大型数据集,从而实...
- Python进阶-Day 25: 数据分析基础
-
目标:掌握Pandas和NumPy的基本操作,学习如何分析CSV数据集并生成报告。课程内容...
- Pandas 入门教程 - 第五课: 高级数据操作
-
在前几节课中,我们学习了如何使用Pandas进行数据操作和可视化。在这一课中,我们将进一步探索一些高级的数据操作技巧,包括数据透视、分组聚合、时间序列处理以及高级索引和切片。高级索引和切片...
- 原来这才是Pandas!(原来这才是薯片真正的吃法)
-
听到一些人说,Pandas语法太乱、太杂了,根本记不住。...
- python(pandas + numpy)数据分析的基础
-
数据NaN值排查,统计,排序...
- 利用Python进行数据分组/数据透视表
-
1.数据分组源数据表如下所示:1.1分组键是列名分组键是列名时直接将某一列或多列的列名传给groupby()方法,groupby()方法就会按照这一列或多列进行分组。按照一列进行分组...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)