提示工程模式

基于全面的 提示工程指南 的提示工程技术实践实现。 该指南涵盖了提示工程的理论、原则和模式,而这里我们将展示如何使用 Spring AI 的流畅 ChatClient API 将这些概念转化为可用的 Java 代码。 本文使用的演示源代码可在以下地址获取:提示工程模式示例

1. 配置

配置部分概述了如何使用 Spring AI 设置和调整大型语言模型(LLM)。 它涵盖了为您的用例选择合适的 LLM 提供商,以及配置控制模型输出质量、风格和格式的重要生成参数。

LLM 提供商选择

对于提示工程,您将从选择模型开始。 Spring AI 支持 多个 LLM 提供商(如 OpenAI、Anthropic、Google Vertex AI、AWS Bedrock、Ollama 等),让您无需更改应用程序代码即可切换提供商 - 只需更新配置即可。 只需添加选定的启动器依赖项 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 输出配置

chat options flow

在我们深入探讨提示工程技术之前,了解如何配置 LLM 的输出行为至关重要。Spring AI 提供了多个配置选项,让您可以通过 ChatOptions 构建器控制生成的各个方面。

所有配置都可以通过下面示例中演示的程序方式应用,或在启动时通过 Spring 应用程序属性应用。

温度

温度控制模型响应的随机性或"创造性"。

  • 较低的值(0.0-0.3):更确定性的、集中的响应。更适合事实性问题、分类或一致性至关重要的任务。

  • 中等值(0.4-0.7):在确定性和创造性之间取得平衡。适合一般用例。

  • 较高的值(0.8-1.0):更具创造性、多样性和潜在惊喜的响应。更适合创意写作、头脑风暴或生成多样化选项。

.options(ChatOptions.builder()
        .temperature(0.1)  // 非常确定性的输出
        .build())

理解温度对于提示工程至关重要,因为不同的技术受益于不同的温度设置。

输出长度(MaxTokens)

maxTokens 参数限制了模型在其响应中可以生成的标记(词片段)数量。

  • 低值(5-25):用于单词、短语或分类标签。

  • 中等值(50-500):用于段落或简短解释。

  • 高值(1000+):用于长格式内容、故事或复杂解释。

.options(ChatOptions.builder()
        .maxTokens(250)  // 中等长度响应
        .build())

设置适当的输出长度对于确保获得完整响应而不产生不必要的冗长很重要。

采样控制(Top-K 和 Top-P)

这些参数让您能够对生成过程中的标记选择进行精细控制。

  • Top-K:将标记选择限制为 K 个最可能的下一个标记。较高的值(例如 40-50)引入更多多样性。

  • Top-P(核采样):动态选择累积概率超过 P 的最小标记集。常用值如 0.8-0.95。

.options(ChatOptions.builder()
        .topK(40)      // 仅考虑前 40 个标记
        .topP(0.8)     // 从覆盖 80% 概率质量的标记中采样
        .build())

这些采样控制与温度配合使用,共同塑造响应特征。

结构化响应格式

除了纯文本响应(使用 .content())外,Spring AI 还使用 .entity() 方法使 LLM 响应直接映射到 Java 对象变得简单。

enum Sentiment {
    POSITIVE, NEUTRAL, NEGATIVE
}

Sentiment result = chatClient.prompt("...")
        .call()
        .entity(Sentiment.class);

当与指示模型返回结构化数据的系统提示结合使用时,此功能特别强大。

模型特定选项

虽然可移植的 ChatOptions 为不同的 LLM 提供商提供了一致的接口,但 Spring AI 还提供了模型特定的选项类,这些类暴露了提供商特定的功能和配置。这些模型特定的选项允许您利用每个 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();

每个模型提供商都有自己的聊天选项实现(例如 OpenAiChatOptionsAnthropicChatOptionsMistralAiChatOptions),这些实现暴露提供商特定的参数,同时仍然实现通用接口。这种方法让您可以在需要跨提供商兼容性时使用可移植选项,或在需要访问特定提供商的独特功能时使用模型特定选项。

请注意,使用模型特定选项时,您的代码会与该特定提供商绑定,降低了可移植性。这是在访问高级提供商特定功能与在应用程序中保持提供商独立性之间的权衡。

2. 提示工程技术

下面的每个部分都实现了指南中的特定提示工程技术。 通过同时遵循"提示工程"指南和这些实现,您将全面了解不仅有哪些提示工程技术可用,而且如何在生产 Java 应用程序中有效实现它们。

2.1 零样本提示

零样本提示涉及要求 AI 执行任务而不提供任何示例。这种方法测试模型从零开始理解和执行指令的能力。大型语言模型在大量文本语料库上训练,使它们能够理解"翻译"、"总结"或"分类"等任务,而无需明确的演示。

零样本适用于模型在训练期间可能看到过类似示例的简单任务,以及当您想要最小化提示长度时。但是,性能可能会根据任务复杂性和指令表述的好坏而变化。

// 实现第 2.1 节:通用提示/零样本(第 15 页)
public void pt_zero_shot(ChatClient chatClient) {
    enum Sentiment {
        POSITIVE, NEUTRAL, NEGATIVE
    }

    Sentiment reviewSentiment = chatClient.prompt("""
            将电影评论分类为 POSITIVE、NEUTRAL 或 NEGATIVE。
            评论:"Her"是一部揭示如果人工智能继续不受控制地发展,人类将走向何方的令人不安的研究。
            我希望有更多像这样的杰作。
            情感:
            """)
            .options(ChatOptions.builder()
                    .model("claude-3-7-sonnet-latest")
                    .temperature(0.1)
                    .maxTokens(5)
                    .build())
            .call()
            .entity(Sentiment.class);

    System.out.println("输出:" + reviewSentiment);
}

这个例子展示了如何在不提供示例的情况下对电影评论情感进行分类。注意低温度(0.1)以获得更确定性的结果,以及直接 .entity(Sentiment.class) 映射到 Java 枚举。

参考: Brown, T. B., et al. (2020). "Language Models are Few-Shot Learners." arXiv:2005.14165. https://arxiv.org/abs/2005.14165

2.2 单样本和少样本提示

少样本提示为模型提供一个或多个示例来帮助指导其响应,对于需要特定输出格式的任务特别有用。通过向模型展示所需输入-输出对的示例,它可以在不进行显式参数更新的情况下学习模式并将其应用于新输入。

单样本提供一个示例,这在示例成本高昂或模式相对简单时很有用。少样本使用多个示例(通常为 3-5 个)来帮助模型更好地理解更复杂任务中的模式,或说明正确输出的不同变体。

// 实现第 2.2 节:单样本和少样本(第 16 页)
public void pt_one_shot_few_shots(ChatClient chatClient) {
    String pizzaOrder = chatClient.prompt("""
            将客户的披萨订单解析为有效的 JSON

            示例 1:
            我想要一个小披萨,加奶酪、番茄酱和意大利辣香肠。
            JSON 响应:
            ```
            {
                "size": "small",
                "type": "normal",
                "ingredients": ["cheese", "tomato sauce", "pepperoni"]
            }
            ```

            示例 2:
            我能要一个大披萨,加番茄酱、罗勒和马苏里拉奶酪吗。
            JSON 响应:
            ```
            {
                "size": "large",
                "type": "normal",
                "ingredients": ["tomato sauce", "basil", "mozzarella"]
            }
            ```

            现在,我想要一个大披萨,前半部分加奶酪和马苏里拉奶酪。
            后半部分加番茄酱、火腿和菠萝。
            """)
            .options(ChatOptions.builder()
                    .model("claude-3-7-sonnet-latest")
                    .temperature(0.1)
                    .maxTokens(250)
                    .build())
            .call()
            .content();
}

少样本提示对于需要特定格式、处理边缘情况或任务定义在没有示例的情况下可能模糊的任务特别有效。示例的质量和多样性会显著影响性能。

参考: Brown, T. B., et al. (2020). "Language Models are Few-Shot Learners." arXiv:2005.14165. https://arxiv.org/abs/2005.14165

2.3 系统、上下文和角色提示

系统提示

系统提示为语言模型设置整体上下文和目的,定义模型应该做什么的"大图景"。它建立行为框架、约束和模型响应的高级目标,与特定用户查询分开。

系统提示在整个对话中作为持久的"使命宣言",允许您设置全局参数,如输出格式、语气、道德界限或角色定义。与关注特定任务的用户提示不同,系统提示框定了应如何解释所有用户提示。

// 实现第 2.3.1 节:系统提示
public void pt_system_prompting_1(ChatClient chatClient) {
    String movieReview = chatClient
            .prompt()
            .system("将电影评论分类为积极、中性或消极。仅返回大写的标签。")
            .user("""
                    评论:"Her"是一部揭示如果人工智能继续不受控制地发展,人类将走向何方的令人不安的研究。
                    它太令人不安了,我无法观看。

                    情感:
                    """)
            .options(ChatOptions.builder()
                    .model("claude-3-7-sonnet-latest")
                    .temperature(1.0)
                    .topK(40)
                    .topP(0.8)
                    .maxTokens(5)
                    .build())
            .call()
            .content();
}

系统提示在与 Spring AI 的实体映射功能结合使用时特别强大:

// 实现第 2.3.1 节:带 JSON 输出的系统提示
record MovieReviews(Movie[] movie_reviews) {
    enum Sentiment {
        POSITIVE, NEUTRAL, NEGATIVE
    }

    record Movie(Sentiment sentiment, String name) {
    }
}

MovieReviews movieReviews = chatClient
        .prompt()
        .system("""
                将电影评论分类为积极、中性或消极。返回有效的 JSON。
                """)
        .user("""
                评论:"Her"是一部揭示如果人工智能继续不受控制地发展,人类将走向何方的令人不安的研究。
                它太令人不安了,我无法观看。

                JSON 响应:
                """)
        .call()
        .entity(MovieReviews.class);

系统提示对于多轮对话特别有价值,确保跨多个查询的一致行为,以及建立格式约束(如应适用于所有响应的 JSON 输出)。

参考: OpenAI. (2022). "System Message." https://platform.openai.com/docs/guides/chat/introduction

角色提示

角色提示指示模型采用特定角色或角色,这会影响其生成内容的方式。通过为模型分配特定的身份、专业知识或视角,您可以影响其响应的风格、语气、深度和框架。

角色提示利用模型模拟不同专业领域和沟通风格的能力。常见角色包括专家(例如,"你是一位经验丰富的数据科学家")、专业人士(例如,"扮演旅行指南")或风格角色(例如,"像莎士比亚一样解释")。

// 实现第 2.3.2 节:角色提示
public void pt_role_prompting_1(ChatClient chatClient) {
    String travelSuggestions = chatClient
            .prompt()
            .system("""
                    我希望你扮演旅行指南。我会告诉你我的位置,你会建议我附近的 3 个地方。
                    在某些情况下,我也会告诉你我要访问的地方类型。
                    """)
            .user("""
                    我的建议:"我在阿姆斯特丹,我只想参观博物馆。"
                    旅行建议:
                    """)
            .call()
            .content();
}

角色提示可以通过风格说明增强:

// 实现第 2.3.2 节:带风格说明的角色提示
public void pt_role_prompting_2(ChatClient chatClient) {
    String humorousTravelSuggestions = chatClient
            .prompt()
            .system("""
                    我希望你扮演旅行指南。我会告诉你我的位置,你会以幽默的风格建议我附近的 3 个地方。
                    """)
            .user("""
                    我的建议:"我在阿姆斯特丹,我只想参观博物馆。"
                    旅行建议:
                    """)
            .call()
            .content();
}

这种技术对于专业领域知识、在响应中实现一致的语气以及创建更具吸引力的个性化用户交互特别有效。

参考: Shanahan, M., et al. (2023). "Role-Play with Large Language Models." arXiv:2305.16367. https://arxiv.org/abs/2305.16367

上下文提示

上下文提示通过传递上下文参数为模型提供额外的背景信息。这种技术丰富了模型对特定情况的理解,使其能够提供更相关和定制的响应,而不会使主要指令变得混乱。

通过提供上下文信息,您帮助模型理解与当前查询相关的特定领域、受众、约束或背景事实。这导致更准确、相关和适当框架的响应。

// 实现第 2.3.3 节:上下文提示
public void pt_contextual_prompting(ChatClient chatClient) {
    String articleSuggestions = chatClient
            .prompt()
            .user(u -> u.text("""
                    建议 3 个文章主题,并附带几行描述说明这篇文章应该包含什么内容。

                    上下文:{context}
                    """)
                    .param("context", "你正在为一个关于 80 年代复古街机游戏的博客写作。"))
            .call()
            .content();
}

Spring AI 通过 param() 方法注入上下文变量,使上下文提示变得清晰。这种技术对于模型需要特定领域知识、适应特定受众或场景的响应,以及确保响应符合特定约束或要求时特别有价值。

参考: Liu, P., et al. (2021). "What Makes Good In-Context Examples for GPT-3?" arXiv:2101.06804. https://arxiv.org/abs/2101.06804

2.4 退步提示

退步提示通过首先获取背景知识将复杂请求分解为更简单的步骤。这种技术鼓励模型先从即时问题中"退步",考虑与问题相关的更广泛背景、基本原则或一般知识,然后再解决具体查询。

通过将复杂问题分解为更易于管理的组件并首先建立基础知识,模型可以为困难问题提供更准确的响应。

// 实现第 2.4 节:退步提示
public void pt_step_back_prompting(ChatClient.Builder chatClientBuilder) {
    // 为聊天客户端设置通用选项
    var chatClient = chatClientBuilder
            .defaultOptions(ChatOptions.builder()
                    .model("claude-3-7-sonnet-latest")
                    .temperature(1.0)
                    .topK(40)
                    .topP(0.8)
                    .maxTokens(1024)
                    .build())
            .build();

    // 首先获取高级概念
    String stepBack = chatClient
            .prompt("""
                    基于流行的第一人称射击动作游戏,在第一人称射击视频游戏中,
                    哪些 5 个虚构的关键设置有助于创造具有挑战性和吸引力的关卡故事情节?
                    """)
            .call()
            .content();

    // 然后在主要任务中使用这些概念
    String story = chatClient
            .prompt()
            .user(u -> u.text("""
                    为一个具有挑战性和吸引力的第一人称射击视频游戏的新关卡写一段故事情节。

                    上下文:{step-back}
                    """)
                    .param("step-back", stepBack))
            .call()
            .content();
}

退步提示对于复杂推理任务、需要专业领域知识的问题,以及当您想要更全面和深思熟虑的响应而不是即时答案时特别有效。

参考: Zheng, Z., et al. (2023). "Take a Step Back: Evoking Reasoning via Abstraction in Large Language Models." arXiv:2310.06117. https://arxiv.org/abs/2310.06117

2.5 思维链(CoT)

思维链提示鼓励模型通过逐步推理来解决问题,这提高了复杂推理任务的准确性。通过明确要求模型展示其工作或通过逻辑步骤思考问题,您可以显著提高需要多步推理的任务的性能。

CoT 通过鼓励模型在产生最终答案之前生成中间推理步骤来工作,类似于人类解决复杂问题的方式。这使模型的思维过程变得明确,并帮助它得出更准确的结论。

// 实现第 2.5 节:思维链(CoT)- 零样本方法
public void pt_chain_of_thought_zero_shot(ChatClient chatClient) {
    String output = chatClient
            .prompt("""
                    当我 3 岁时,我的伴侣的年龄是我的 3 倍。现在,我 20 岁了。
                    我的伴侣多大了?

                    让我们一步一步思考。
                    """)
            .call()
            .content();
}

// 实现第 2.5 节:思维链(CoT)- 少样本方法
public void pt_chain_of_thought_singleshot_fewshots(ChatClient chatClient) {
    String output = chatClient
            .prompt("""
                    问:当我弟弟 2 岁时,我的年龄是他的两倍。现在我 40 岁了。
                    我弟弟多大了?让我们一步一步思考。
                    答:当我弟弟 2 岁时,我 2 * 2 = 4 岁。年龄差是 2 岁,我更大。
                    现在我 40 岁了,所以我弟弟是 40 - 2 = 38 岁。答案是 38。

                    问:当我 3 岁时,我的伴侣的年龄是我的 3 倍。现在我 20 岁了。
                    我的伴侣多大了?让我们一步一步思考。
                    答:
                    """)
            .call()
            .content();
}

关键短语"让我们一步一步思考"触发模型展示其推理过程。CoT 对于数学问题、逻辑推理任务和任何需要多步推理的问题特别有价值。它通过使中间推理明确来帮助减少错误。

参考: Wei, J., et al. (2022). "Chain-of-Thought Prompting Elicits Reasoning in Large Language Models." arXiv:2201.11903. https://arxiv.org/abs/2201.11903

2.6 自一致性

自一致性涉及多次运行模型并聚合结果以获得更可靠的答案。这种技术通过为同一问题采样不同的推理路径并通过多数投票选择最一致的答案,解决了 LLM 输出的可变性问题。

通过使用不同的温度或采样设置生成多个推理路径,然后聚合最终答案,自一致性提高了复杂推理任务的准确性。它本质上是一种 LLM 输出的集成方法。

// 实现第 2.6 节:自一致性
public void pt_self_consistency(ChatClient chatClient) {
    String email = """
            你好,
            我看到你使用 Wordpress 做网站。这是一个很棒的开源内容管理系统。
            我过去也使用过它。它有很多很棒的用户插件。而且设置起来相当容易。
            我确实注意到联系表单中有一个错误,当你选择名字字段时就会发生。
            看我附加的截图,我在名字字段中输入文本。注意我触发的 JavaScript 警告框。
            但除此之外,这是一个很棒的网站。我很喜欢阅读它。你可以把错误留在网站上,
            因为它让我有更多有趣的东西可读。
            祝好,
            黑客哈利。
            """;

    record EmailClassification(Classification classification, String reasoning) {
        enum Classification {
            IMPORTANT, NOT_IMPORTANT
        }
    }

    int importantCount = 0;
    int notImportantCount = 0;

    // 使用相同输入运行模型 5 次
    for (int i = 0; i < 5; i++) {
        EmailClassification output = chatClient
                .prompt()
                .user(u -> u.text("""
                        邮件:{email}
                        将上述邮件分类为重要或不重要。让我们一步一步思考并解释原因。
                        """)
                        .param("email", email))
                .options(ChatOptions.builder()
                        .temperature(1.0)  // 更高的温度以获得更多变化
                        .build())
                .call()
                .entity(EmailClassification.class);

        // 统计结果
        if (output.classification() == EmailClassification.Classification.IMPORTANT) {
            importantCount++;
        } else {
            notImportantCount++;
        }
    }

    // 通过多数投票确定最终分类
    String finalClassification = importantCount > notImportantCount ?
            "重要" : "不重要";
}

自一致性对于高风险决策、复杂推理任务以及当您需要比单个响应更自信的答案时特别有价值。权衡是增加了计算成本和延迟,因为需要多次 API 调用。

参考: Wang, X., et al. (2022). "Self-Consistency Improves Chain of Thought Reasoning in Language Models." arXiv:2203.11171. https://arxiv.org/abs/2203.11171

2.7 思维树(ToT)

思维树(ToT)是一种高级推理框架,通过同时探索多个推理路径来扩展思维链。它将问题解决视为搜索过程,模型生成不同的中间步骤,评估它们的潜力,并探索最有希望的路径。

这种技术对于具有多种可能方法的复杂问题或解决方案需要探索各种替代方案才能找到最佳路径时特别强大。

原始的"提示工程"指南没有提供 ToT 的实现示例,可能是因为其复杂性。下面是一个展示核心概念的简化示例。

游戏解决 ToT 示例:

// 实现第 2.7 节:思维树(ToT)- 游戏解决示例
public void pt_tree_of_thoughts_game(ChatClient chatClient) {
    // 步骤 1:生成多个初始移动
    String initialMoves = chatClient
            .prompt("""
                    你正在下国际象棋。棋盘处于起始位置。
                    生成 3 个不同的可能开局移动。对于每个移动:
                    1. 用代数记谱法描述移动
                    2. 解释这个移动背后的战略思考
                    3. 从 1-10 评分这个移动的强度
                    """)
            .options(ChatOptions.builder()
                    .temperature(0.7)
                    .build())
            .call()
            .content();

    // 步骤 2:评估并选择最有希望的移动
    String bestMove = chatClient
            .prompt()
            .user(u -> u.text("""
                    分析这些开局移动并选择最强的一个:
                    {moves}

                    一步一步解释你的推理,考虑:
                    1. 位置控制
                    2. 发展潜力
                    3. 长期战略优势

                    然后选择单个最佳移动。
                    """).param("moves", initialMoves))
            .call()
            .content();

    // 步骤 3:从最佳移动探索未来游戏状态
    String gameProjection = chatClient
            .prompt()
            .user(u -> u.text("""
                    基于这个选定的开局移动:
                    {best_move}

                    预测双方接下来的 3 步。对于每个潜在分支:
                    1. 描述移动和反移动
                    2. 评估结果位置
                    3. 确定最有希望的延续

                    最后,确定最有利的移动序列。
                    """).param("best_move", bestMove))
            .call()
            .content();
}

参考: Yao, S., et al. (2023). "Tree of Thoughts: Deliberate Problem Solving with Large Language Models." arXiv:2305.10601. https://arxiv.org/abs/2305.10601

2.8 自动提示工程

自动提示工程使用 AI 生成和评估替代提示。这种元技术利用语言模型本身来创建、改进和基准测试不同的提示变体,以找到特定任务的最佳表述。

通过系统地生成和评估提示变体,APE 可以找到比手动工程更有效的提示,特别是对于复杂任务。这是一种使用 AI 来改进其自身性能的方法。

// 实现第 2.8 节:自动提示工程
public void pt_automatic_prompt_engineering(ChatClient chatClient) {
    // 生成相同请求的变体
    String orderVariants = chatClient
            .prompt("""
                    我们有一个乐队周边 T 恤网店,为了训练聊天机器人,我们需要各种订购方式:
                    "一件 Metallica T 恤,尺码 S"。生成 10 个变体,保持相同的语义但保持相同的含义。
                    """)
            .options(ChatOptions.builder()
                    .temperature(1.0)  // 高温度以获得创造性
                    .build())
            .call()
            .content();

    // 评估并选择最佳变体
    String output = chatClient
            .prompt()
            .user(u -> u.text("""
                    请对以下变体进行 BLEU(双语评估研究)评估:
                    ----
                    {variants}
                    ----

                    选择评估分数最高的指令候选。
                    """).param("variants", orderVariants))
            .call()
            .content();
}

APE 对于优化生产系统的提示、解决手动提示工程已达到其极限的具有挑战性的任务,以及系统地大规模改进提示质量特别有价值。

参考: Zhou, Y., et al. (2022). "Large Language Models Are Human-Level Prompt Engineers." arXiv:2211.01910. https://arxiv.org/abs/2211.01910

2.9 代码提示

代码提示是指用于代码相关任务的专门技术。这些技术利用 LLM 理解和生成编程语言的能力,使它们能够编写新代码、解释现有代码、调试问题以及在语言之间进行翻译。

有效的代码提示通常涉及清晰的规范、适当的上下文(库、框架、风格指南),有时还需要类似代码的示例。温度设置往往较低(0.1-0.3)以获得更确定性的输出。

// 实现第 2.9.1 节:编写代码的提示
public void pt_code_prompting_writing_code(ChatClient chatClient) {
    String bashScript = chatClient
            .prompt("""
                    用 Bash 写一个代码片段,它要求输入一个文件夹名称。
                    然后它获取文件夹的内容并重命名其中的所有文件,在文件名前添加 draft 前缀。
                    """)
            .options(ChatOptions.builder()
                    .temperature(0.1)  // 低温度以获得确定性代码
                    .build())
            .call()
            .content();
}

// 实现第 2.9.2 节:解释代码的提示
public void pt_code_prompting_explaining_code(ChatClient chatClient) {
    String code = """
            #!/bin/bash
            echo "Enter the folder name: "
            read folder_name
            if [ ! -d "$folder_name" ]; then
            echo "Folder does not exist."
            exit 1
            fi
            files=( "$folder_name"/* )
            for file in "${files[@]}"; do
            new_file_name="draft_$(basename "$file")"
            mv "$file" "$new_file_name"
            done
            echo "Files renamed successfully."
            """;

    String explanation = chatClient
            .prompt()
            .user(u -> u.text("""
                    向我解释下面的 Bash 代码:
                    ```
                    {code}
                    ```
                    """).param("code", code))
            .call()
            .content();
}

// 实现第 2.9.3 节:翻译代码的提示
public void pt_code_prompting_translating_code(ChatClient chatClient) {
    String bashCode = """
            #!/bin/bash
            echo "Enter the folder name: "
            read folder_name
            if [ ! -d "$folder_name" ]; then
            echo "Folder does not exist."
            exit 1
            fi
            files=( "$folder_name"/* )
            for file in "${files[@]}"; do
            new_file_name="draft_$(basename "$file")"
            mv "$file" "$new_file_name"
            done
            echo "Files renamed successfully."
            """;

    String pythonCode = chatClient
            .prompt()
            .user(u -> u.text("""
                    将下面的 Bash 代码翻译成 Python 片段:
                    {code}
                    """).param("code", bashCode))
            .call()
            .content();
}

代码提示对于自动代码文档、原型设计、学习编程概念以及在编程语言之间进行翻译特别有价值。通过与少样本提示或思维链等技术结合使用,可以进一步提高其有效性。

参考: Chen, M., et al. (2021). "Evaluating Large Language Models Trained on Code." arXiv:2107.03374. https://arxiv.org/abs/2107.03374

结论

Spring AI 为实现所有主要提示工程技术提供了一个优雅的 Java API。通过将这些技术与 Spring 强大的实体映射和流畅 API 结合使用,开发人员可以使用清晰、可维护的代码构建复杂的 AI 驱动应用程序。

最有效的方法通常涉及组合多种技术 - 例如,将系统提示与少样本示例结合使用,或将思维链与角色提示结合使用。Spring AI 的灵活 API 使这些组合易于实现。

对于生产应用程序,请记住:

  1. 使用不同参数(温度、top-k、top-p)测试提示

  2. 考虑对关键决策使用自一致性

  3. 利用 Spring AI 的实体映射获得类型安全的响应

  4. 使用上下文提示提供应用程序特定的知识

通过这些技术和 Spring AI 强大的抽象,您可以创建健壮的 AI 驱动应用程序,提供一致、高质量的结果。

参考文献

  1. Brown, T. B., et al. (2020). "Language Models are Few-Shot Learners." arXiv:2005.14165.

  2. Wei, J., et al. (2022). "Chain-of-Thought Prompting Elicits Reasoning in Large Language Models." arXiv:2201.11903.

  3. Wang, X., et al. (2022). "Self-Consistency Improves Chain of Thought Reasoning in Language Models." arXiv:2203.11171.

  4. Yao, S., et al. (2023). "Tree of Thoughts: Deliberate Problem Solving with Large Language Models." arXiv:2305.10601.

  5. Zhou, Y., et al. (2022). "Large Language Models Are Human-Level Prompt Engineers." arXiv:2211.01910.

  6. Zheng, Z., et al. (2023). "Take a Step Back: Evoking Reasoning via Abstraction in Large Language Models." arXiv:2310.06117.

  7. Liu, P., et al. (2021). "What Makes Good In-Context Examples for GPT-3?" arXiv:2101.06804.

  8. Shanahan, M., et al. (2023). "Role-Play with Large Language Models." arXiv:2305.16367.

  9. Chen, M., et al. (2021). "Evaluating Large Language Models Trained on Code." arXiv:2107.03374.

  10. Spring AI 文档

  11. ChatClient API 参考

  12. Google 的提示工程指南