使用 Spring AI 的 Prompt Engineering 技術

工程 | Christian Tzolov | 2025 年 4 月 14 日 | ...

這篇部落格文章演示了使用 Spring AI 的 Prompt Engineering 技術的實際實現。

本文中的示例和模式基於全面的 Prompt Engineering 指南,該指南涵蓋了有效 Prompt Engineering 的理論、原則和模式。

這篇部落格展示瞭如何使用 Spring AI 流暢的 ChatClient API 將這些概念轉化為可工作的 Java 程式碼。

為方便起見,示例的結構遵循原始指南中概述的相同模式和技術。

本文中使用的演示原始碼可在以下地址獲取:https://github.com/spring-projects/spring-ai-examples/tree/main/prompt-engineering/prompt-engineering-patterns

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>

以及一些連線屬性:spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY}

您可以像這樣指定特定的 LLM 模型名稱

.options(ChatOptions.builder()
        .model("claude-3-7-sonnet-latest")  // Use Anthropic's Claude model
        .build())

有關啟用和配置首選 AI 模型的詳細資訊,請參閱參考文件

LLM 輸出配置

在我們深入探討提示工程技術之前,瞭解如何配置 LLM 的輸出行為至關重要。Spring AI 提供了幾個配置選項,您可以透過 ChatOptions 構建器控制生成的各個方面。

所有配置都可以透過程式設計方式應用,如下面的示例所示,也可以透過 Spring 應用程式屬性在啟動時應用。

溫度

溫度控制模型響應的隨機性或“創造性”。

  • 較低值 (0.0-0.3):更具確定性、更集中的響應。更適用於事實性問題、分類或一致性至關重要的任務。
  • 中等值 (0.4-0.7):在確定性和創造性之間取得平衡。適用於一般用例。
  • 較高值 (0.8-1.0):更具創造性、多樣化且可能令人驚訝的響應。更適用於創意寫作、頭腦風暴或生成多樣化選項。
.options(ChatOptions.builder()
        .temperature(0.1)  // Very deterministic output
        .build())

理解溫度對於提示工程至關重要,因為不同的技術受益於不同的溫度設定。

輸出長度 (MaxTokens)

maxTokens 引數限制了模型在其響應中可以生成的令牌(詞片段)數量。

  • 低值 (5-25):用於單個詞、短語或分類標籤。
  • 中等值 (50-500):用於段落或簡短解釋。
  • 高值 (1000+):用於長篇內容、故事或複雜解釋。
.options(ChatOptions.builder()
        .maxTokens(250)  // Medium-length response
        .build())

設定適當的輸出長度對於確保您獲得完整響應而無不必要的冗長至關重要。

取樣控制 (Top-K 和 Top-P)

這些引數讓您可以對生成過程中的令牌選擇進行精細控制。

  • Top-K:將令牌選擇限制在前 K 個最可能的下一個令牌。較高的值(例如,40-50)會引入更多多樣性。
  • Top-P(核取樣):從累積機率超過 P 的最小令牌集合中動態選擇。常見值為 0.8-0.95。
.options(ChatOptions.builder()
        .topK(40)      // Consider only the top 40 tokens
        .topP(0.8)     // Sample from tokens that cover 80% of probability mass
        .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 提供商的獨特功能。

// Using OpenAI-specific options
OpenAiChatOptions openAiOptions = OpenAiChatOptions.builder()
        .model("gpt-4o")
        .temperature(0.2)
        .frequencyPenalty(0.5)      // OpenAI-specific parameter
        .presencePenalty(0.3)       // OpenAI-specific parameter
        .responseFormat(new ResponseFormat("json_object"))  // OpenAI-specific JSON mode
        .seed(42)                   // OpenAI-specific deterministic generation
        .build();

String result = chatClient.prompt("...")
        .options(openAiOptions)
        .call()
        .content();

// Using Anthropic-specific options
AnthropicChatOptions anthropicOptions = AnthropicChatOptions.builder()
        .model("claude-3-7-sonnet-latest")
        .temperature(0.2)
        .topK(40)                   // Anthropic-specific parameter
        .thinking(AnthropicApi.ThinkingType.ENABLED, 1000)  // Anthropic-specific thinking configuration
        .build();

String result = chatClient.prompt("...")
        .options(anthropicOptions)
        .call()
        .content();

每個模型提供商都有其自己的聊天選項實現(例如,OpenAiChatOptionsAnthropicChatOptionsMistralAiChatOptions),它們公開了提供商特定的引數,同時仍然實現了通用介面。這種方法使您能夠靈活地使用可移植選項以實現跨提供商相容性,或者在需要訪問特定提供商的獨特功能時使用模型特定選項。

請注意,當使用模型特定選項時,您的程式碼將與該特定提供商繫結,從而降低可移植性。這是在訪問高階提供商特定功能與在應用程式中保持提供商獨立性之間進行權衡。

2. 提示工程技術

以下每個部分都實現了指南中的特定提示工程技術。透過遵循“提示工程”指南和這些實現,您將徹底瞭解可用的提示工程技術,以及如何在生產 Java 應用程式中有效地實現它們。

2.1 零樣本提示

零樣本提示是指在不提供任何示例的情況下要求 AI 執行任務。這種方法測試模型從零開始理解和執行指令的能力。大型語言模型在龐大的文字語料庫上進行訓練,使它們能夠理解“翻譯”、“總結”或“分類”等任務的含義,而無需明確的演示。

零樣本非常適合模型在訓練期間可能見過類似示例的簡單任務,以及當您想要最小化提示長度時。但是,效能可能會因任務複雜性和指令 формули 方式而異。

// Implementation of Section 2.1: General prompting / zero shot (page 15)
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, T. B., et al. (2020). "Language Models are Few-Shot Learners." arXiv:2005.14165. https://arxiv.org/abs/2005.14165

2.2 單樣本和少樣本提示

少樣本提示為模型提供一個或多個示例以幫助指導其響應,這對於需要特定輸出格式的任務特別有用。透過向模型展示所需輸入-輸出對的示例,它可以學習模式並將其應用於新輸入,而無需顯式引數更新。

單樣本提供一個示例,當示例成本高昂或模式相對簡單時很有用。少樣本使用多個示例(通常為 3-5 個)來幫助模型更好地理解更復雜任務中的模式或說明正確輸出的不同變體。

// Implementation of Section 2.2: One-shot & few-shot (page 16)
public void pt_ones_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, T. B., et al. (2020). "Language Models are Few-Shot Learners." arXiv:2005.14165. https://arxiv.org/abs/2005.14165

2.3 系統、情境和角色提示

系統提示

系統提示為語言模型設定了總體上下文和目的,定義了模型應該做什麼的“大局”。它為模型的響應建立了行為框架、約束和高階目標,與特定的使用者查詢分開。

系統提示在整個對話過程中充當持久的“使命宣言”,允許您設定全域性引數,如輸出格式、語氣、道德邊界或角色定義。與側重於特定任務的使用者提示不同,系統提示框定了所有使用者提示應如何解釋。

// Implementation of Section 2.3.1: 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();
}

系統提示與 Spring AI 的實體對映功能結合使用時特別強大

// Implementation of Section 2.3.1: System prompting with JSON output
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);

系統提示對於多輪對話特別有價值,可確保在多個查詢中保持一致的行為,並用於建立適用於所有響應的 JSON 輸出等格式約束。

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

角色提示

角色提示指示模型採用特定的角色或個性,這會影響它生成內容的方式。透過為模型分配特定的身份、專業知識或視角,您可以影響其響應的風格、語氣、深度和框架。

角色提示利用了模型模擬不同專業領域和交流風格的能力。常見的角色包括專家(例如,“您是一位經驗豐富的資料科學家”)、專業人士(例如,“充當導遊”)或風格化角色(例如,“像莎士比亞一樣解釋”)。

// Implementation of Section 2.3.2: Role prompting
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();
}

角色提示可以透過風格指令來增強

// Implementation of Section 2.3.2: Role prompting with style instructions
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., et al. (2023). "Role-Play with Large Language Models." arXiv:2305.16367. https://arxiv.org/abs/2305.16367

情境提示

情境提示透過傳遞上下文引數向模型提供額外的背景資訊。這種技術豐富了模型對特定情況的理解,從而實現更相關和量身定製的響應,而不會使主要指令混亂。

透過提供上下文資訊,您可以幫助模型理解與當前查詢相關的特定領域、受眾、約束或背景事實。這會導致更準確、更相關且格式適當的響應。

// Implementation of Section 2.3.3: 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., et al. (2021). "What Makes Good In-Context Examples for GPT-3?" arXiv:2101.06804. https://arxiv.org/abs/2101.06804

2.4 回退提示

回退提示透過首先獲取背景知識將複雜的請求分解為更簡單的步驟。這種技術鼓勵模型首先“回退”到當前問題之外,考慮與問題相關的更廣泛的上下文、基本原理或一般知識,然後再解決特定查詢。

透過將複雜問題分解為更易於管理的元件,並首先建立基礎知識,模型可以對難題提供更準確的響應。

// Implementation of Section 2.4: Step-back prompting
public void pt_step_back_prompting(ChatClient.Builder chatClientBuilder) {
    // Set common options for the chat client
    var chatClient = chatClientBuilder
            .defaultOptions(ChatOptions.builder()
                    .model("claude-3-7-sonnet-latest")
                    .temperature(1.0)
                    .topK(40)
                    .topP(0.8)
                    .maxTokens(1024)
                    .build())
            .build();

    // First get high-level concepts
    String stepBack = chatClient
            .prompt("""
                    Based on popular first-person shooter action games, what are
                    5 fictional key settings that contribute to a challenging and
                    engaging level storyline in a first-person shooter video game?
                    """)
            .call()
            .content();

    // Then use those concepts in the main task
    String story = chatClient
            .prompt()
            .user(u -> u.text("""
                    Write a one paragraph storyline for a new level of a first-
                    person shooter video game that is challenging and engaging.

                    Context: {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 的工作原理是鼓勵模型在產生最終答案之前生成中間推理步驟,類似於人類解決複雜問題的方式。這使得模型的思維過程明確,並幫助它得出更準確的結論。

// Implementation of Section 2.5: Chain of Thought (CoT) - Zero-shot approach
public void pt_chain_of_thought_zero_shot(ChatClient chatClient) {
    String output = chatClient
            .prompt("""
                    When I was 3 years old, my partner was 3 times my age. Now,
                    I am 20 years old. How old is my partner?

                    Let's think step by step.
                    """)
            .call()
            .content();
}

// Implementation of Section 2.5: Chain of Thought (CoT) - Few-shot approach
public void pt_chain_of_thought_singleshot_fewshots(ChatClient chatClient) {
    String output = chatClient
            .prompt("""
                    Q: When my brother was 2 years old, I was double his age. Now
                    I am 40 years old. How old is my brother? Let's think step
                    by step.
                    A: When my brother was 2 years, I was 2 * 2 = 4 years old.
                    That's an age difference of 2 years and I am older. Now I am 40
                    years old, so my brother is 40 - 2 = 38 years old. The answer
                    is 38.
                    Q: When I was 3 years old, my partner was 3 times my age. Now,
                    I am 20 years old. How old is my partner? Let's think step
                    by step.
                    A:
                    """)
            .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 輸出的整合方法。

// Implementation of Section 2.6: Self-consistency
public void pt_self_consistency(ChatClient chatClient) {
    String email = """
            Hi,
            I have seen you use Wordpress for your website. A great open
            source content management system. I have used it in the past
            too. It comes with lots of great user plugins. And it's pretty
            easy to set up.
            I did notice a bug in the contact form, which happens when
            you select the name field. See the attached screenshot of me
            entering text in the name field. Notice the JavaScript alert
            box that I inv0k3d.
            But for the rest it's a great website. I enjoy reading it. Feel
            free to leave the bug in the website, because it gives me more
            interesting things to read.
            Cheers,
            Harry the Hacker.
            """;

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

    int importantCount = 0;
    int notImportantCount = 0;

    // Run the model 5 times with the same input
    for (int i = 0; i < 5; i++) {
        EmailClassification output = chatClient
                .prompt()
                .user(u -> u.text("""
                        Email: {email}
                        Classify the above email as IMPORTANT or NOT IMPORTANT. Let's
                        think step by step and explain why.
                        """)
                        .param("email", email))
                .options(ChatOptions.builder()
                        .temperature(1.0)  // Higher temperature for more variation
                        .build())
                .call()
                .entity(EmailClassification.class);

        // Count results
        if (output.classification() == EmailClassification.Classification.IMPORTANT) {
            importantCount++;
        } else {
            notImportantCount++;
        }
    }

    // Determine the final classification by majority vote
    String finalClassification = importantCount > notImportantCount ? 
            "IMPORTANT" : "NOT IMPORTANT";
}

自洽性對於高風險決策、複雜推理任務以及當您需要比單個響應更自信的答案時特別有價值。權衡是由於多次 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 示例

// Implementation of Section 2.7: Tree of Thoughts (ToT) - Game solving example
public void pt_tree_of_thoughts_game(ChatClient chatClient) {
    // Step 1: Generate multiple initial moves
    String initialMoves = chatClient
            .prompt("""
                    You are playing a game of chess. The board is in the starting position.
                    Generate 3 different possible opening moves. For each move:
                    1. Describe the move in algebraic notation
                    2. Explain the strategic thinking behind this move
                    3. Rate the move's strength from 1-10
                    """)
            .options(ChatOptions.builder()
                    .temperature(0.7)
                    .build())
            .call()
            .content();
    
    // Step 2: Evaluate and select the most promising move
    String bestMove = chatClient
            .prompt()
            .user(u -> u.text("""
                    Analyze these opening moves and select the strongest one:
                    {moves}
                    
                    Explain your reasoning step by step, considering:
                    1. Position control
                    2. Development potential
                    3. Long-term strategic advantage
                    
                    Then select the single best move.
                    """).param("moves", initialMoves))
            .call()
            .content();
    
    // Step 3: Explore future game states from the best move
    String gameProjection = chatClient
            .prompt()
            .user(u -> u.text("""
                    Based on this selected opening move:
                    {best_move}
                    
                    Project the next 3 moves for both players. For each potential branch:
                    1. Describe the move and counter-move
                    2. Evaluate the resulting position
                    3. Identify the most promising continuation
                    
                    Finally, determine the most advantageous sequence of moves.
                    """).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 提高自身效能的方法。

// Implementation of Section 2.8: Automatic Prompt Engineering
public void pt_automatic_prompt_engineering(ChatClient chatClient) {
    // Generate variants of the same request
    String orderVariants = chatClient
            .prompt("""
                    We have a band merchandise t-shirt webshop, and to train a
                    chatbot we need various ways to order: "One Metallica t-shirt
                    size S". Generate 10 variants, with the same semantics but keep
                    the same meaning.
                    """)
            .options(ChatOptions.builder()
                    .temperature(1.0)  // High temperature for creativity
                    .build())
            .call()
            .content();

    // Evaluate and select the best variant
    String output = chatClient
            .prompt()
            .user(u -> u.text("""
                    Please perform BLEU (Bilingual Evaluation Understudy) evaluation on the following variants:
                    ----
                    {variants}
                    ----

                    Select the instruction candidate with the highest evaluation score.
                    """).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)。

// Implementation of Section 2.9.1: Prompts for writing code
public void pt_code_prompting_writing_code(ChatClient chatClient) {
    String bashScript = chatClient
            .prompt("""
                    Write a code snippet in Bash, which asks for a folder name.
                    Then it takes the contents of the folder and renames all the
                    files inside by prepending the name draft to the file name.
                    """)
            .options(ChatOptions.builder()
                    .temperature(0.1)  // Low temperature for deterministic code
                    .build())
            .call()
            .content();
}

// Implementation of Section 2.9.2: Prompts for explaining code
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("""
                    Explain to me the below Bash code:
                    ```
                    {code}
                    ```
                    """).param("code", code))
            .call()
            .content();
}

// Implementation of Section 2.9.3: Prompts for translating code
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("""
                    Translate the below Bash code to a Python snippet:                        
                    {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 的提示工程指南

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有