提示词工程模式
基于全面的提示工程指南,我们将对即时工程技术进行实际应用。该指南涵盖了有效即时工程的理论、原则和模式, 并演示了如何使用 Spring AI ChatClient Fluent API 将这些概念转化为可运行的 Java 代码。
1,配置
配置部分概述了如何使用 Spring AI 设置和调整大型语言模型 (LLM)。它涵盖了如何根据用例选择合适的 LLM 提供程序,以及如何配置重要的生成参数,以控制模型输出的质量、样式和格式。
模型选择
为了快速进行工程设计,您需要先选择一个模型。Spring AI 支持多个 LLM 模型,让您无需更改应用程序代码即可切换模型 - 只需更新配置即可。只需添加所 选的启动依赖项即可spring-ai-starter-model-<MODEL-PROVIDER-NAME>。例如,以下是如何启用 Anthropic Claude API:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-anthropic</artifactId>
</dependency>
您可以像这样指定 LLM 模型名称:
.options(ChatOptions.builder()
.model("claude-3-7-sonnet-latest") // 使用 Anthropic 的 Claude 模型
.build())
模型输出配置
在深入研究即时工程技术之前,我们有必要了解如何配置 LLM 的输出行为。Spring AI 提供了多个配置选项,可让您通过 ChatOptions 构建器控制生成的各个方面。
所有配置都可以以编程方式应用,如下面的示例所示,或者在启动时通过 Spring 应用程序属性应用。

Temperature
Temperature 控制模型响应的随机性或“创造性”。
较低值(0.0-0.3):响应更确定、更集中。更适合事实类问题、分类问题或一致性至关重要的任务。
中等值(0.4-0.7):在确定性和创造性之间取得平衡。适用于一般用例。
值越高 (0.8-1.0):回复更具创意、多样性,且可能带来惊喜。更适合创意写作、头脑风暴或生成多样化选项。
.options(ChatOptions.builder()
.temperature(0.1) // 正确的输出
.build())
了解 Temperature 对于快速工程至关重要,因为不同的技术受益于不同的 Temperature 设置。
输出长度(MaxTokens)
该 maxTokens 参数限制了模型在响应中可以生成的标记(词片段)的数量。
低值(5-25):适用于单个单词、短语或 分类标签。
中等值(50-500):用于段落或简短解释。
高值(1000+):适用于长篇内容、故事或复杂的解释。
.options(ChatOptions.builder()
.maxTokens(250) // 中等长度的响应
.build())
设置适当的输出长度非常重要,以确保您获得完整的响应而没有不必要的冗长。
采样控制(Top-K 和 Top-P)
这些参数使您可以对生成过程中的令牌选择过程进行细粒度的控制。
Top-K:将 token 的选择范围限制为 K 个最有可能的后续 token。值越高(例如 40-50),多样性越好。
Top-P(核采样):从最小的标记集中动态选择,其累积概率超过 P。0.8-0.95 之类的值很常见。
.options(ChatOptions.builder()
.topK(40) // 仅考虑前 40 个 token
.topP(0.8) // 从覆盖 80% 概率质量的标记中抽样
.build())
这些采样控制与温度协同作用来形成响应特性。
结构化响应格式
除了纯文本响应(使用.content())之外,Spring AI 还可以轻松地使用.entity()方法将 LLM 响应直接映射到 Java 对象。
enum Sentiment {
POSITIVE, NEUTRAL, NEGATIVE
}
Sentiment result = chatClient.prompt("...")
.call()
.entity(Sentiment.class);
当与指示模型返回结构化数据的系统提示相结合时,此功能特别强大。
特定于模型的选项
Spring AI 不仅提供了跨不同 LLM 提供程序的一致接口 ChatOptions,还提供了特定于模型的选项类,用于公开特定于提供程序的功能和配置。这些特定于模型的选项允许您利用每个 LLM 提供程序的独特功能。
// 使用 OpenAI 特有的选项
OpenAiChatOptions openAiOptions = OpenAiChatOptions.builder()
.model("gpt-4o")
.temperature(0.2)
.frequencyPenalty(0.5) // OpenAI 特有参数:频率惩罚
.presencePenalty(0.3) // OpenAI 特有参数:存在惩罚
.responseFormat(new ResponseFormat("json_object")) // OpenAI 特有的 JSON 模式
.seed(42) // OpenAI 特有的参数:用于生成确定性结果
.build();
String result = chatClient.prompt("...")
.options(openAiOptions)
.call()
.content();
// 使用 Anthropic 特有的选项
AnthropicChatOptions anthropicOptions = AnthropicChatOptions.builder()
.model("claude-3-7-sonnet-latest")
.temperature(0.2)
.topK(40) // Anthropic 特有参数:用于控制采样多样性
.thinking(AnthropicApi.ThinkingType.ENABLED, 1000) // Anthropic 特有的“思考”配置
.build();
String result = chatClient.prompt("...")
.options(anthropicOptions)
.call()
.content();
每个模型提供商都有其自己的聊天选项实现(例如,OpenAiChatOptions、AnthropicChatOptions、MistralAiChatOptions)这些实现在公开提供商特定参数的同时,仍实现通用接口。这种方法让您可以灵活地使用可移植选项来实现跨提供商兼容性,或者在需要访问特定提供商的独特功能时使用特定于模型的选项。
请注意,使用特定于模型的选项时,您的代码将与该特定提供程序绑定,从而降低可移植性。您需要在访问特定于提供程序的高级功能与在应用程序中保持提供程序独立性之间进行权衡
2,Prompt 工程技术
2.1 零样本提示
零样本提示是指要求人工智能在不提供任何示例的情况下执行任务。这种方法测试模型从零开始理解和执行指令的能力。大型语言模型在海量文本语料库上进行训练,使其能够在没有明确演示的情况下理解“翻译”、“摘要”或“分类”等任务的含义。
零样本训练非常适合一些简单的任务,因为模型在训练过程中很可能已经见过类似的样本,而且您希望尽量缩短提示长度。然而,其性能可能会因任务复杂度和指令的制定方式而有所不同。
public void pt_zero_shot(ChatClient chatClient) {
enum Sentiment {
POSITIVE, NEUTRAL, NEGATIVE
}
Sentiment reviewSentiment = chatClient.prompt("""
Classify movie reviews as POSITIVE, NEUTRAL or NEGATIVE.
Review: "Her" is a disturbing study revealing the direction
humanity is headed if AI is allowed to keep evolving,
unchecked. I wish there were more movies like this masterpiece.
Sentiment:
""")
.options(ChatOptions.builder()
.model("claude-3-7-sonnet-latest")
.temperature(0.1)
.maxTokens(5)
.build())
.call()
.entity(Sentiment.class);
System.out.println("Output: " + reviewSentiment);
}
此示例展示了如何在不提供示例的情况下对电影评论情绪进行分类。请注意,为了获得更确定的结果,我们采用了较低的温度 (0.1),并且直接.entity(Sentiment.class)映射到 Java 枚举。
参考文献: Brown, TB 等人 (2020)。“语言模型是少样本学习器。”arXiv:2005.14165。https ://arxiv.org/abs/2005.14165
2.2 少样本提示
少样本提示为模型提供了一个或多个示例,以帮助指导其响应,这对于需要特定输出格式的任务特别有用。通过向模型展示所需输入-输出对的示例,它可以学习该模式并将其应用于新的输入,而无需显式更新参数。
单样本训练仅提供单个样本,当样本成本高昂或模式相对简单时非常有用。少样本训练则使用多个样本(通常为 3-5 个),以帮助模型更好地理解更复杂任务中的模式,或展示正确输出的不同变体。
public void pt_one_shot_few_shots(ChatClient chatClient) {
String pizzaOrder = chatClient.prompt("""
Parse a customer's pizza order into valid JSON
EXAMPLE 1:
I want a small pizza with cheese, tomato sauce, and pepperoni.
JSON Response:
{
"size": "small",
"type": "normal",
"ingredients": ["cheese", "tomato sauce", "pepperoni"]
}
EXAMPLE 2:
Can I get a large pizza with tomato sauce, basil and mozzarella.
JSON Response:
{
"size": "large",
"type": "normal",
"ingredients": ["tomato sauce", "basil", "mozzarella"]
}
Now, I would like a large pizza, with the first half cheese and mozzarella.
And the other tomato sauce, ham and pineapple.
""")
.options(ChatOptions.builder()
.model("claude-3-7-sonnet-latest")
.temperature(0.1)
.maxTokens(250)
.build())
.call()
.content();
}
对于需要特定格式、处理边缘情况,或在没有示例的情况下任务定义可能含糊不清的任务,小样本提示尤其有效。示例的质量和多样性会显著影响性能。
参考文献: Brown, TB 等人 (2020)。“语言模型是少样本学习器。”arXiv:2005.14165。https ://arxiv.org/abs/2005.14165
2.3 系统、情境和角色提示
System Prompting
System Prompting 设定了语言模型 的整体背景和目的,定义了模型应该做什么的“总体情况”。它为模型的响应建立了行为框架、约束条件和高级目标,并与具体的用户查询区分开来。
System Prompting 在整个对话过程中充当着持续的“使命”,允许您设置全局参数,例如输出格式、语气、道德界限或角色定义。与专注于特定任务的用户提示不同,System Prompting 框定了所有用户提示的解读方式。
public void pt_system_prompting_1(ChatClient chatClient) {
String movieReview = chatClient
.prompt()
.system("Classify movie reviews as positive, neutral or negative. Only return the label in uppercase.")
.user("""
Review: "Her" is a disturbing study revealing the direction
humanity is headed if AI is allowed to keep evolving,
unchecked. It's so disturbing I couldn't watch it.
Sentiment:
""")
.options(ChatOptions.builder()
.model("claude-3-7-sonnet-latest")
.temperature(1.0)
.topK(40)
.topP(0.8)
.maxTokens(5)
.build())
.call()
.content();
}
System Prompting 与 Spring AI 的实体映射功能结合使用时尤其强大:
record MovieReviews(Movie[] movie_reviews) {
enum Sentiment {
POSITIVE, NEUTRAL, NEGATIVE
}
record Movie(Sentiment sentiment, String name) {
}
}
MovieReviews movieReviews = chatClient
.prompt()
.system("""
Classify movie reviews as positive, neutral or negative. Return
valid JSON.
""")
.user("""
Review: "Her" is a disturbing study revealing the direction
humanity is headed if AI is allowed to keep evolving,
unchecked. It's so disturbing I couldn't watch it.
JSON Response:
""")
.call()
.entity(MovieReviews.class);
System Prompting 对于多轮对话尤其有价值,可确保跨多个查询的一致行为,并建立适用于所有响应的格式约束(如 JSON 输出)。
参考文献: OpenAI。(2022)。“系统消息”。https ://platform.openai.com/docs/guides/chat/introduction
Role Prompting
Role Prompting 会指示模型采用特定的角色或人物,这会影响其生成内容的方式。通过为模型分配特定的身份、专业知识或视角,您可以影响其响应的风格、语气、深度和框架。
Role Prompting 利用模型模拟不同专业领域和沟通风格的能力。常见 role 包括专家(例如,“您是一位经验丰富的数据科学家”)、专业人士(例如,“充当导游”)或风格人物(例如,“像莎士比亚一样解释”)。
public void pt_role_prompting_1(ChatClient chatClient) {
String travelSuggestions = chatClient
.prompt()
.system("""
I want you to act as a travel guide. I will write to you
about my location and you will suggest 3 places to visit near
me. In some cases, I will also give you the type of places I
will visit.
""")
.user("""
My suggestion: "I am in Amsterdam and I want to visit only museums."
Travel Suggestions:
""")
.call()
.content();
}
可以通过样式说明来增强 Role Prompting:
public void pt_role_prompting_2(ChatClient chatClient) {
String humorousTravelSuggestions = chatClient
.prompt()
.system("""
I want you to act as a travel guide. I will write to you about
my location and you will suggest 3 places to visit near me in
a humorous style.
""")
.user("""
My suggestion: "I am in Amsterdam and I want to visit only museums."
Travel Suggestions:
""")
.call()
.content();
}
这种技术对于专业领域知识特别有效,可以在响应中实现一致的语气,并与用户创建更具吸引力、个性化的互动。
参考文献: Shanahan, M. 等人 (2023)。“使用大型语言模型进行角色扮演。”arXiv:2305.16367。https ://arxiv.org/abs/2305.16367
Contextual Prompting
Contextual Prompting 通过传递情境参数为模型提供额外的背景信息。这项技术丰富了模型对具体情境的理解,使其能够提供更相关、更有针对性的响应,而不会扰乱主要指令。
通过提供上下文信息,您可以帮助模型理解与当前查询相关的特定领域、受众、约束或背景事实。这可以带来更准确、更相关、更恰当的响应。
public void pt_contextual_prompting(ChatClient chatClient) {
String articleSuggestions = chatClient
.prompt()
.user(u -> u.text("""
Suggest 3 topics to write an article about with a few lines of
description of what this article should contain.
Context: {context}
""")
.param("context", "You are writing for a blog about retro 80's arcade video games."))
.call()
.content();
}
Spring AI 使用 param() 方法注入上下文变量,使上下文提示更加清晰。当模型需要特定领域知识、根据特定受众或场景调整响应,以及确保响应符合特定约束或要求时,此技术尤为有用。
参考文献: Liu, P. 等 (2021)。“什么是 GPT-3 的良好上下文示例?”arXiv:2101.06804。https: //arxiv.org/abs/2101.06804