Logo
Published on

第一次學 Kotlin Koog AI 就上手 Day 22:策略圖基礎:構建多階段 AI 工作流程

在前面的文章中,我們學習了快取機制、記憶體系統、事件處理和策略路由等功能。今天我們要深入學習 Koog 框架的核心概念之一:策略圖(Strategy Graph),這是建構複雜 AI 工作流程的基礎

什麼是策略圖?

從簡單到複雜的演進

還記得我們之前使用的簡單策略嗎?

// 簡單的單次執行策略
val agent = AIAgent(
    executor = simpleOpenAIExecutor(ApiKeyManager.openAIApiKey!!),
    strategy = singleRunStrategy(), // 簡單策略
    systemPrompt = "你是一個客服助手"
)

這種策略適合處理簡單的問答,但當我們需要處理複雜的業務邏輯時,就需要更強大的工具——策略圖 (Strategy Graph)

策略圖的核心概念

策略圖就像是一張藍圖,描述 AI Agent 如何一步步處理複雜任務

  • 節點(Node):代表一個具體的處理步驟
  • 邊(Edge):連接節點,控制執行流程
  • 條件(Condition):決定何時從一個節點跳到另一個節點

想像一下,如果 AI Agent 是一個工廠,策略圖就是生產線的設計圖,每個節點是一個工作站,邊是輸送帶,條件是品質檢查點

策略圖的核心組件

Strategy:頂層容器

val strategy = strategy<String, String>("strategy_name") {
    // 在這裡定義節點和邊
}
  • 泛型參數<輸入類型, 輸出類型>
  • 名稱:策略的識別名稱
  • 區塊:定義整個工作流程的地方

Node:執行單元

節點是策略圖的基本執行單位,每個節點負責一個特定的任務

val processNode by node<String, String>("process_data") { input ->
    // 處理輸入資料
    val result = "處理後的資料:$input"
    result // 返回處理結果
}

Edge:流程控制

邊定義了節點之間的連接關係

// 基本連接
edge(nodeA forwardTo nodeB)

// 條件連接
edge(nodeA forwardTo nodeB onCondition { output ->
    output.length > 10
})

// 轉換輸出
edge(nodeA forwardTo nodeB transformed { output ->
    output.uppercase()
})

特殊節點:nodeStart 和 nodeFinish

每個策略圖都有兩個特殊節點

  • nodeStart:策略圖的起點
  • nodeFinish:策略圖的終點

多階段資料處理流程

讓我們建立一個實際的範例,展示如何使用策略圖處理電商訂單

訂單處理流程圖

flowchart TD
    A[開始] --> B[驗證訂單節點]
    B --> C{驗證結果}
    C -->|驗證通過| D[計算價格節點]
    C -->|驗證失敗| E[錯誤處理節點]
    D --> F[生成確認節點]
    F --> G[結束]
    E --> G[結束]

    style A fill:#e1f5fe
    style B fill:#f3e5f5
    style C fill:#fff3e0
    style D fill:#f3e5f5
    style E fill:#ffebee
    style F fill:#f3e5f5
    style G fill:#e8f5e8

這個流程圖展示了策略圖中各個節點之間的關係

  • 驗證節點:檢查訂單資料的完整性
  • 條件分支:根據驗證結果決定後續流程
  • 成功路徑:驗證通過 → 計算價格 → 生成確認
  • 失敗路徑:驗證失敗 → 錯誤處理 → 結束
class OrderProcessingAgent {

    private val agent = AIAgent(
        executor = simpleOpenAIExecutor(ApiKeyManager.openAIApiKey!!),
        systemPrompt = "你是一個專業的訂單處理助手",
        llmModel = OpenAIModels.CostOptimized.GPT4_1Mini,
        // 使用自訂策略圖
        strategy = createOrderProcessingStrategy()
    )

    private fun createOrderProcessingStrategy() = strategy<String, String>("order_processing") {

        // 節點一:驗證訂單資料
        val validateOrderNode by node<String, String>("validate_order") { orderData ->
            println("🔍 正在驗證訂單資料...")

            // 模擬訂單驗證邏輯
            val lines = orderData.split("\n")
            val hasCustomerInfo = lines.any { it.contains("客戶:") }
            val hasProductInfo = lines.any { it.contains("商品:") }
            val hasAmount = lines.any { it.contains("金額:") }

            when {
                !hasCustomerInfo -> "錯誤:缺少客戶資訊"
                !hasProductInfo -> "錯誤:缺少商品資訊"
                !hasAmount -> "錯誤:缺少金額資訊"
                else -> {
                    println("✅ 訂單驗證通過")
                    "驗證通過:$orderData"
                }
            }
        }

        // 節點二:計算價格
        val calculatePriceNode by node<String, String>("calculate_price") { validatedOrder ->
            println("💰 正在計算訂單價格...")

            // 從訂單中提取金額
            val amountLine = validatedOrder.split("\n")
                .find { it.contains("金額:") }

            val amount = amountLine?.substringAfter("金額:")?.trim()?.toDoubleOrNull() ?: 0.0
            val tax = amount * 0.05 // 5% 稅金
            val total = amount + tax

            val result = "$validatedOrder\n稅金:$tax\n總計:$total"
            println("✅ 價格計算完成,總計:$total")
            result
        }

        // 節點三:生成訂單確認
        val generateConfirmationNode by node<String, String>("generate_confirmation") { orderWithPrice ->
            println("📝 正在生成訂單確認...")

            val confirmation = """
                📋 訂單確認書
                ================
                $orderWithPrice
                ================
                狀態:已確認
                確認時間:${java.time.LocalDateTime.now()}
            """.trimIndent()

            println("✅ 訂單確認書生成完成")
            confirmation
        }

        // 節點四:錯誤處理
        val handleErrorNode by node<String, String>("handle_error") { errorMessage ->
            println("❌ 處理訂單錯誤")

            """
                ⚠️ 訂單處理失敗
                錯誤原因:$errorMessage
                請檢查訂單資料並重新提交
            """.trimIndent()
        }

        // 定義執行流程
        edge(nodeStart forwardTo validateOrderNode)

        // 驗證成功 -> 計算價格
        edge(validateOrderNode forwardTo calculatePriceNode onCondition { result ->
            result.startsWith("驗證通過")
        })

        // 驗證失敗 -> 錯誤處理
        edge(validateOrderNode forwardTo handleErrorNode onCondition { result ->
            result.startsWith("錯誤")
        })

        // 計算價格 -> 生成確認
        edge(calculatePriceNode forwardTo generateConfirmationNode)

        // 所有路徑最終都到達結束點
        edge(generateConfirmationNode forwardTo nodeFinish)
        edge(handleErrorNode forwardTo nodeFinish)
    }

    suspend fun processOrder(orderData: String): String {
        return agent.run(orderData)
    }
}

雖然看起來程式碼很複雜,但是把每個 node 拆開來看,然後了解 edge 的流程走向,其實不會很複雜

多階段資料使用範例

suspend fun main() {
    val processor = OrderProcessingAgent()

    println("=== 訂單處理策略圖演示 ===\n")

    // 測試正常訂單
    val validOrder = """
        客戶:張小明
        商品:筆記型電腦
        金額:50000
    """.trimIndent()

    println("📝 處理正常訂單:")
    try {
        val result = processor.processOrder(validOrder)
        println("\n🎯 處理結果:")
        println(result)
    } catch (e: Exception) {
        println("❌ 處理失敗:${e.message}")
    }

    println("\n" + "=".repeat(50) + "\n")

    // 測試異常訂單
    val invalidOrder = """
        客戶:李小華
        商品:智慧型手機
        // 缺少金額資訊
    """.trimIndent()

    println("📝 處理異常訂單:")
    try {
        val result = processor.processOrder(invalidOrder)
        println("\n🎯 處理結果:")
        println(result)
    } catch (e: Exception) {
        println("❌ 處理失敗:${e.message}")
    }
}

執行 AI 回應內容

=== 訂單處理策略圖演示 ===

📝 處理正常訂單:
🔍 正在驗證訂單資料...
✅ 訂單驗證通過
💰 正在計算訂單價格...
✅ 價格計算完成,總計:52500.0
📝 正在生成訂單確認...
✅ 訂單確認書生成完成

🎯 處理結果:
                📋 訂單確認書
                ================
                驗證通過:客戶:張小明
商品:筆記型電腦
金額:50000
稅金:2500.0
總計:52500.0
                ================
                狀態:已確認
                確認時間:2025-08-17T17:31:42.787342

==================================================

📝 處理異常訂單:
🔍 正在驗證訂單資料...
❌ 處理訂單錯誤

🎯 處理結果:
⚠️ 訂單處理失敗
錯誤原因:錯誤:缺少金額資訊
請檢查訂單資料並重新提交

策略圖的優勢

清晰的邏輯結構

每個節點職責單一,邊界清楚,整個流程一目了然

靈活的條件控制

透過條件邊,可以實現複雜的業務邏輯分流

易於測試和維護

每個節點可以獨立測試,便於除錯和修改

可重用性

節點可以在不同的策略圖中重複使用

與簡單策略的比較

特性簡單策略策略圖
複雜度
靈活性有限極高
條件控制困難簡單
錯誤處理基本完善
可維護性一般優秀
學習成本中等

最佳實踐建議

節點設計原則

  • 單一職責:每個節點只做一件事
  • 明確命名:節點名稱要能表達其功能
  • 錯誤處理:考慮異常情況的處理路徑

流程設計技巧

  • 起始檢查:在流程開始時驗證輸入
  • 分流清楚:條件判斷要明確,避免模糊
  • 統一出口:盡量讓所有路徑都經過 nodeFinish

偵錯和測試

  • 添加日誌:在關鍵節點添加日誌輸出
  • 分段測試:先測試個別節點,再測試整個流程
  • 邊界測試:測試各種輸入情況

總結

今天我們學習了 Koog 框架策略圖的基礎概念

  • 策略圖架構:Strategy、Node、Edge 的組成關係
  • 節點設計:如何創建具有單一職責的處理單元
  • 流程控制:使用條件邊實現複雜的業務邏輯
  • 實際應用:透過訂單處理範例理解完整流程

策略圖是構建複雜 AI 應用的重要基礎,它讓我們能夠以結構化的方式設計和管理複雜的工作流程

下一篇文章我們將深入學習進階節點操作,包括 LLM 互動節點和工具執行節點,讓策略圖能夠與外部系統進行更豐富的互動

參考資源


支持創作

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


圖片來源:AI 產生