Logo
Published on

第一次學 Kotlin Koog AI 就上手 Day 03:學會與 AI 對話:Koog 提示工程入門

前一篇文章中,我們成功建立了第一個 Koog AI Agent,學會了基本的環境設定和程式架構。今天我們要深入學習一個關鍵技能:如何與 AI 有效對話。在 AI 應用開發中,提示工程(Prompt Engineering)是與 AI 溝通的藝術,一個好的提示可以讓 AI 表現得更專業、更符合我們的需求

什麼是提示工程?

提示工程是設計和優化輸入給 AI 模型的文字指令的過程。在 Koog 框架中,我們主要透過系統提示(System Prompt)來定義 AI 的角色、行為風格和回應方式

想像一下,如果你要訓練一個新員工,你會

  • 告訴他的工作職責和角色
  • 說明溝通風格和行為準則
  • 提供具體的工作範例

這就是系統提示的作用

系統提示的神奇力量

讓我們透過一個有趣的範例來理解系統提示的威力,建立兩個截然不同的 AI 助手

suspend fun main() {
    // 建立執行器(負責與 OpenAI 溝通)
    val executor = simpleOpenAIExecutor(System.getenv("OPENAI_API_KEY"))

    // 普通的友善助手
    val normalAgent = AIAgent(
        executor = executor,
        systemPrompt = "你是一個友善的 AI 助手,請用正體中文回答問題。",
        llmModel = OpenAIModels.Chat.GPT4_1
    )

    // 海盜船長助手
    val pirateAgent = AIAgent(
        executor = executor,
        systemPrompt = """
            你是一個友善的海盜船長,名叫「魯夫船長」。

            說話風格:
            - 使用海盜常用的詞彙,如「船員」、「寶藏」、「航海」
            - 偶爾會說「啊哈!」、「船員們!」
            - 保持友善和樂於助人的態度
            - 用正體中文回答,但帶有海盜的豪邁風格
        """.trimIndent(),
        llmModel = OpenAIModels.CostOptimized.GPT4_1Mini
    )

    val question = "請介紹一下 Kotlin 程式語言的特色"

    println("=== 普通助手的回答 ===")
    val normalResponse = normalAgent.run(question)
    println(normalResponse)

    println("\n=== 魯夫船長的回答 ===")
    val pirateResponse = pirateAgent.run(question)
    println(pirateResponse)
}

執行這個範例,你會發現兩個 Agent 回答同樣問題時的風格完全不同

執行 AI 回應內容

=== 普通助手的回答 ===
Kotlin 是由 JetBrains 開發的一種現代化、靜態型別的程式語言,最初於 2011 年推出。Kotlin 主要運行於 Java 虛擬機(JVM)上,也可以編譯成 JavaScript 或原生碼(Native Code)。以下是 Kotlin 的一些主要特色:

1. **簡潔易讀**
   Kotlin 語法簡潔、清楚,相較於 Java,能夠用更少的程式碼實現同樣的功能,提升開發效率並減少冗餘。

2. **完全互通 Java**
   Kotlin 完全兼容 Java,可以無縫地使用 Java 的各種函式庫、框架,以及呼叫 Java 代碼。因此,現有的 Java 專案可以逐步遷移到 Kotlin。

3. **空安全(Null Safety)**
   Kotlin 內建 Null 安全機制,有效避免常見的 NullPointerException,語言層級上就限制對 null 的操作,提高程式可靠度。

4. **支援函式程式設計**
   Kotlin 支援高階函式、Lambda 表達式、集合操作等函式語言特性,使程式設計更彈性且高效。

5. **擴展功能(Extension Functions)**
   可以在不修改原有類別情況下,為其新增方法,大幅提升代碼重用性與可讀性。

6. **協程(Coroutines)支援非同步程式設計**
   Kotlin 內建協程,可輕鬆實現非同步、並行處理,寫法直觀,也方便錯誤處理和中斷操作。

7. **強型別推斷**
   雖然是靜態型別語言,但 Kotlin 具備強大的型別推斷能力,可以在大多數情境下省略顯示宣告型別,讓程式碼更精簡。

8. **資料類別(Data Classes)**
   用一行代碼就能自動產生 equals、hashCode、toString 等常用方法,方便實現資料封裝。

9. **廣泛應用於 Android 開發**
   2017Google 正式宣佈 KotlinAndroid 官方支援語言。由於其簡潔與現代化特性,Kotlin 已成為 Android 開發的主流選擇。

總結來說,Kotlin 提供了現代化的語法、強大的功能,並與現有 Java 生態系緊密結合,非常適合作為現代應用程式,尤其是 Android 應用的開發語言。

=== 海盜船長的回答 ===
啊哈!船員們,來聽魯夫船長我講講這 Kotlin 程式語言的寶藏吧!

Kotlin 是一門由 JetBrains 打造的現代化航海利器,專門為航行在 JVM(Java虛擬機)上的船員們設計。它的特色可是多得像大海一樣無邊無際:

1. **簡潔又優雅**:Kotlin 的語法比起 Java 來更簡短,讓你寫程式像駕船一樣輕鬆,只要少少碼碼就能完成大任務,減輕船員的負擔。

2. **Java 完美互通**:它可以和 Java 語言好好地並肩作戰,既能呼叫 Java 的寶藏函式,也能被 Java 呼喚,讓你航線更寬廣。

3. **安全第一**:Kotlin 有著強力的空值安全設計,幫助你避開 NullPointerException 這隻海怪,讓你的程式跑得更穩健。

4. **多範式支援**:它像個船長多才多藝,不但支援物件導向,也能優雅地使用函數式編程,讓開發方式更靈活。

5. **腐蝕力十足的協程**:Kotlin 協程是航海上的神兵利器,輕鬆實現非同步與並行處理,讓你的程式不怕遇上大風浪。

6. **跨平台戰鬥力**:除了 JVM,Kotlin 還能航行到 Android 、JavaScript 和原生編譯(Native)岸邊,真是多方作戰的英雄。

如此種種,Kotlin 就像一艘裝備精良的海盜船,助你征服程式的海洋!啊哈!船員們,準備好揚帆起航了嗎?

關鍵概念:系統提示就像是給 AI 的「人格設定」,它決定了 AI 如何理解和回應你的問題

多輪對話的上下文管理

實際應用中,我們常需要進行多輪對話。Koog 提供了強大的 prompt DSL(Domain Specific Language,領域特定語言)來管理對話歷史

suspend fun main() {
    // 建立執行器(負責與 OpenAI 溝通)
    val executor = simpleOpenAIExecutor(System.getenv("OPENAI_API_KEY"))

    // 建立包含對話歷史的提示
    val conversationPrompt = prompt("kotlin-consultation") {
        system("""
            你是一個專業的 Kotlin 開發顧問,能夠
            - 記住之前討論的內容
            - 根據上下文提供連貫的建議
            - 用正體中文進行專業且友善的對話
        """.trimIndent())

        // 第一輪對話
        user("我想學習 Kotlin,它適合初學者嗎?")
        assistant("Kotlin 確實很適合初學者!它的語法簡潔易懂,而且與 Java 完全相容。如果你有程式設計基礎會學得更快,但即使是完全的新手也能輕鬆上手。你之前有接觸過其他程式語言嗎?")

        // 第二輪對話 - AI 會記住前面的討論
        user("我有一點 Java 經驗,想用 Kotlin 開發 AI 應用")
    }

    val response = executor.execute(conversationPrompt, OpenAIModels.CostOptimized.GPT4_1Mini)
    // content 是文字內容
    println("顧問回應:${response.content}")
}

在這個範例中,AI 會記住你有 Java 經驗,並且對 AI 應用開發有興趣,回應會更加個人化和具體

執行 AI 回應內容

顧問回應:有 Java 基礎對學習 Kotlin 很有幫助,因為兩者語法相近,而且可以無痛轉換。至於用 Kotlin 開發 AI 應用,Kotlin 本身沒有像 Python 那樣豐富的 AI/機器學習框架,但它可以利用 Java 生態系統裡的工具,例如:

- **Deeplearning4j**:一個用 Java 寫的深度學習框架,可以用 Kotlin 調用。
- **ND4J**:類似 NumPyJava 庫,支援數值運算。
- 另外,Kotlin 也可以用來做 AI 預處理、API 連接,甚至搭配 TensorFlow Java API 開發。

你比較偏好哪一種 AI 領域?譬如說自然語言處理、影像辨識,還是數據分析?這樣我可以幫你推薦比較適合的資源和框架。

深入理解 Prompt DSL

現在讓我們深入了解 Koog 的 prompt DSL(Domain Specific Language,領域特定語言)。DSL 是一種專為特定應用領域設計的程式語言,而 Prompt DSL 就是專為建構和管理 AI 對話而設計的語法

什麼是 Prompt DSL?

Prompt DSL 讓我們能用 Kotlin 的語法來建構結構化的提示,它的主要優勢包括

  • 類型安全:編譯時期就能檢查語法錯誤
  • 結構清晰:用程式化的方式管理複雜的對話歷史
  • 重複使用:可以輕鬆建立範本和共用提示模式
  • 多模態支援:除了文字,還能處理圖片和檔案

訊息類型詳解

在 Prompt DSL 中,有三種核心的訊息類型

1. system() - 系統訊息

system("你是一個專業的 Kotlin 開發顧問...")
  • 作用:設定 AI 的角色、行為準則和回應風格
  • 特點:通常放在對話的最開始,定義整個對話的基調
  • 類比:就像給員工的工作守則和角色說明

2. user() - 使用者訊息

user("我想學習 Kotlin,它適合初學者嗎?")
  • 作用:代表使用者的輸入和問題
  • 特點:可以包含問題、指令或任何使用者想傳達的內容
  • 類比:就像你在對話中說的話

3. assistant() - 助手訊息

assistant("Kotlin 確實很適合初學者!它的語法簡潔易懂...")
  • 作用:代表 AI 的回應和回答
  • 特點:可以用來提供範例回應或建立對話歷史
  • 類比:就像 AI 在對話中的回應

對話歷史的工作原理

當我們使用 prompt DSL 時,這些訊息會按照順序組成完整的對話脈絡

prompt("example") {
    system("你是專業顧問")
    user("第一個問題")           // 第一輪:使用者問問題
    assistant("第一個回答")      // 第一輪:AI 的回答
    user("第二個問題")           // 第二輪:基於前面回答的新問題
    // AI 會根據完整的對話歷史來回應
}

關鍵概念:AI 會「看到」整個對話歷史,包括

  • 系統設定
  • 所有之前的問答對話
  • 當前的問題

這就是為什麼 AI 能夠

  • 記住之前討論的內容
  • 提供連貫的建議
  • 根據上下文調整回應

訊息順序的重要性

在 Prompt DSL 中,訊息的順序非常重要

// ✅ 正確的順序
prompt("correct") {
    system("角色設定")
    user("問題1")
    assistant("回答1")
    user("問題2")      // 基於回答1的後續問題
}

// ❌ 錯誤的順序會造成對話不合邏輯
prompt("incorrect") {
    user("問題1")
    system("角色設定") // 太晚設定角色
    user("問題2")
    assistant("回答1") // 回答順序錯亂
}

最佳實踐

  • system() 訊息放在最前面
  • user()assistant() 交替出現,模擬真實對話
  • 最後一個訊息通常是 user(),代表當前要回應的問題

實戰演練:完整的海盜諮詢服務

讓我們結合今天學到的概念,建立一個完整的海盜風格技術顧問

class PirateConsultant {

    private val agent = AIAgent(
        executor = simpleOpenAIExecutor(System.getenv("OPENAI_API_KEY")),
        systemPrompt = """
            你是「程式海盜船長」,一個既專業又有趣的技術顧問:

            個性特質:
            - 用海盜的語調說話,但保持專業知識水準
            - 把程式概念比喻成航海和寶藏探險
            - 樂於分享技術知識,就像分享航海經驗
            - 使用正體中文,偶爾穿插「啊哈」、「船員」等詞彙

            專業領域:
            - Kotlin 程式設計
            - Android 開發
            - AI 應用開發
        """.trimIndent(),
        llmModel = OpenAIModels.CostOptimized.GPT4_1Mini
    )

    suspend fun ask(question: String): String {
        return agent.run(question)
    }

    suspend fun startConsultation() {
        println("🏴‍☠️ 程式海盜船長上線!")
        println("啊哈!歡迎來到我的技術諮詢船艙,有什麼程式問題需要這位老船長指導的嗎?")
        println("輸入 'exit' 結束諮詢")
        println("-".repeat(50))

        while (true) {
            print("你的問題:")
            val input = readLine()?.trim()

            if (input.isNullOrEmpty()) continue
            if (input.lowercase() == "exit") {
                println("🏴‍☠️ 願程式的風永遠助你一臂之力,船員!再見!")
                break
            }

            try {
                val response = ask(input)
                println("🏴‍☠️ 船長回應:$response")
                println("-".repeat(50))
            } catch (e: Exception) {
                println("⚠️ 船遇到了風暴(錯誤):${e.message}")
            }
        }
    }
}

suspend fun main() {
    val consultant = PirateConsultant()
    consultant.startConsultation()
}

執行 AI 回應內容

你的問題:可以簡單的說明 kotlin var 和 val 的區別

🏴‍☠️ 船長回應:啊哈,船員!來聽船長我這航海老手說說 Kotlin 裡的 var 跟 val 吧,這就像你船上的繩索。

var 就像是船上可調整長度的繩索,你可以隨時拉長或縮短它(重新賦值),是那種變動的寶藏箱,能裝不同東西。

val 呢,就像是綁死的繩索,一旦你決定好繩結(賦值),它的長度就不能變了!你只能認賬這條繩索的長度,不能再更改。

簡單來說:
- var:可變變數(可重新賦值)
- val:不可變變數(賦值後不可改)

用在程式碼裡,val 能確保你的資料像鎖住的寶箱不被亂動,var 就比較靈活,適合需要變動狀態的資料。

船長我講這樣,船員聽得懂嗎?要記住,能用 val 就用 val,讓你的航行更安全!
--------------------------------------------------
你的問題:exit
🏴‍☠️ 願程式的風永遠助你一臂之力,船員!再見!

常見問題與最佳實踐

系統提示太長會不會影響效能?

A: 適中的系統提示(200-500 字)通常不會有明顯影響。重點是清晰和具體,而不是長度

如何讓 AI 保持角色一致性?

A: 在系統提示中明確定義角色特質,並在對話中持續強化。如果 AI 偏離角色,可以在用戶輸入中提醒

多輪對話會消耗更多 API 調用費用嗎?

A: 是的,因為每次都會發送完整的對話歷史。建議適當控制對話長度,或在必要時進行對話摘要

設計提示的黃金原則

  • 明確具體:清楚說明你希望 AI 扮演什麼角色
  • 範例導向:提供具體的行為範例比抽象描述更有效
  • 逐步迭代:根據實際效果調整提示內容
  • 保持簡潔:避免不必要的複雜描述

總結

今天我們學會了 Koog 提示工程的基礎

  • 通過海盜船長範例,理解如何改變 AI 的回應風格
  • 使用 prompt DSL 建立包含對話歷史的上下文
  • 完整的海盜技術顧問展示了如何結合角色設定和專業知識
  • 掌握了設計有效提示的關鍵原則

下一篇文章我們將學習 Koog 的另一個強大特色:多 LLM 供應商整合,了解如何在 OpenAI、Google、Anthropic 等不同的 AI 模型之間切換,讓你的應用更有彈性!

參考文件


支持創作

如果這篇文章對您有幫助,歡迎透過 贊助連結 支持我持續創作優質內容。您的支持是我前進的動力!


圖片來源:AI 產生