Logo
Published on

第一次學 Kotlin Koog AI 就上手 Day 16:策略路由:根據問題類型選擇最適合的 Agent

在前面的文章中,我們已經學習了快取機制(Day 13)和記憶體系統(Day 14),並在上一篇文章學習了事件處理與生命週期管理。今天我們將學習一個實用技巧:如何使用規則型分流讓系統自動判斷問題的複雜度,並選擇最適合的處理方式。簡單問題快速回應,複雜問題深度支援

策略路由的核心理念

為什麼需要不同的處理方式?

想像一下日常生活中的情景:當有人問你「現在幾點?」時,你會快速回答;但當有人問「我的電腦無法開機,怎麼辦?」時,你會仔細了解問題並提供詳細的解決步驟

在 AI 客服系統中,我們也需要同樣的分流機制

簡單問題 → 快速回應

  • 營業時間、價格資訊
  • 直接、準確、一次解決

複雜問題 → 深度支援

  • 技術問題、投訴處理、多步驟操作
  • 互動式問答、使用工具、記住上下文

這樣做的好處

  • 提升效率:簡單問題得到即時回應
  • 節省資源:不為簡單問題啟動複雜機制
  • 更好體驗:複雜問題獲得專業的深度支援
  • 成本控制:按需分配運算資源

實作 QueryRouter:策略路由的核心

讓我們來建立一個 QueryRouter,它能自動判斷問題的複雜度並選擇最適合的處理方式

/**
 * QueryRouter - 策略路由的核心類別
 * 根據問題類型自動選擇最適合的 Agent
 */
class QueryRouter {

    // 快速回應 Agent - 單次執行策略
    private val quickAgent = AIAgent(
        executor = simpleOpenAIExecutor(openAIKey),
        strategy = singleRunStrategy(),        // 簡單問題用單次執行
        systemPrompt = """
            你是一個高效客服助手,專門處理簡單查詢
            回答要直接、準確、簡潔
            使用正體中文回答
        """.trimIndent(),
        llmModel = OpenAIModels.CostOptimized.GPT4_1Mini
    )

    // 深度支援 Agent - 聊天對話策略
    private val deepAgent = AIAgent(
        executor = simpleOpenAIExecutor(openAIKey),
        strategy = chatAgentStrategy(),              // 複雜問題用對話策略
        systemPrompt = """
            你是一個專業的技術支援專家,能處理複雜問題
            可以與客戶多輪互動,深入了解問題並提供詳細解決方案
            使用正體中文回答
        """.trimIndent(),
        llmModel = OpenAIModels.CostOptimized.GPT4_1Mini,
        toolRegistry = ToolRegistry {
            // 可以主動向用戶說話
            tool(SayToUser)
            // 可以詢問更多資訊
            tool(AskUser)
        }
    )

    /**
     * 核心功能:判斷問題是否複雜
     * 這是基於規則的簡單分類邏輯
     *
     * 您可以根據需求調整:
     * - 增加或修改關鍵字清單
     * - 調整長度閾值(目前是 50 字)
     * - 加入其他判斷條件(如:包含特定符號、多個句子等)
     */
    private fun isComplexQuery(query: String): Boolean {
        // 複雜問題的關鍵字
        val complexKeywords = listOf(
            "分析", "比較", "問題", "故障", "無法",
            "不滿意", "投訴", "退款", "協助", "解決"
        )

        // 檢查是否包含複雜關鍵字
        val hasComplexKeywords = complexKeywords.any { query.contains(it) }

        // 長問題通常更複雜
        val isLongQuery = query.length > 50

        return hasComplexKeywords || isLongQuery
    }

    /**
     * 處理客戶查詢的主方法
     */
    suspend fun handleQuery(query: String): QueryResult {
        return try {
            val startTime = System.currentTimeMillis()

            // 這裡就是策略路由的關鍵!
            val result = if (isComplexQuery(query)) {
                println("識別為複雜問題,使用深度支援 Agent")
                deepAgent.run(query)
            } else {
                println("識別為簡單問題,使用快速回應 Agent")
                quickAgent.run(query)
            }

            val processingTime = System.currentTimeMillis() - startTime

            QueryResult(
                answer = result,
                isComplex = isComplexQuery(query),
                processingTimeMs = processingTime
            )

        } catch (e: Exception) {
            println("處理問題時發生錯誤: ${e.message}")
            QueryResult(
                answer = "抱歉,系統暫時無法處理您的問題。請稍後再試",
                isComplex = false,
                processingTimeMs = 0,
                error = e.message
            )
        }
    }
}

// 結果資料類別
data class QueryResult(
    val answer: String,
    val isComplex: Boolean,
    val processingTimeMs: Long,
    val error: String? = null
)

實際測試範例

讓我們來測試一下 QueryRouter 的策略路由效果

suspend fun main() {
    val router = QueryRouter()

    println("QueryRouter 策略路由測試")
    println("=".repeat(50))

    // 測試案例
    val testQueries = listOf(
        "你們的營業時間是什麼?",                 // 簡單問題
        "我的產品無法正常運作,需要協助解決",        // 複雜問題
    )

    testQueries.forEachIndexed { index, query ->
        println("\n測試 ${index + 1}: $query")

        val result = router.handleQuery(query)

        val strategyName = if (result.isComplex) "深度支援" else "快速回應"

        println("選擇策略: $strategyName")
        println("處理時間: ${result.processingTimeMs}ms")
        println("AI 回應: ${result.answer}")

        if (index < testQueries.size - 1) {
            println("=".repeat(50))
        }
    }

    println("\n測試完成!策略路由成功運作")
}

執行 AI 回應內容

🚀 QueryRouter 策略路由測試
==================================================

測試 1: 你們的營業時間是什麼?
識別為簡單問題,使用快速回應 Agent
選擇策略: 快速回應
處理時間: 1048ms
AI 回應: 我們的營業時間是週一至週五,上午9點到下午6點。
==================================================

測試 2: 我的產品無法正常運作,需要協助解決
識別為複雜問題,使用深度支援 Agent
您好,請問您的產品是什麼類型?能否描述一下具體的問題或錯誤現象?這樣我可以更精準地幫助您解決問題。
> 我的智慧手錶有問題,無法開機
了解您的智慧手錶無法開機。請問您之前是否有看到任何異常情況,例如電量過低、曾經進行過更新、或是有摔落或進水的情況?另外,您是否嘗試過充電,或長按電源鍵一段時間?
> 都沒有
謝謝您的回覆。接下來我們可以嘗試以下步驟:
1. 請確認充電器和充電線是否正常運作,可以嘗試用其他相容的充電器或線。
2. 將手錶連接充電器,至少充電15分鐘後,再長按電源鍵10秒以上,看看是否可以開機。
3. 如果還是無法開機,請問您的手錶型號和購買時間?方便我判斷是否在保固期內安排後續維修。
> 好的
請提供您的智慧手錶型號和購買日期,這樣我可以幫您確認保固狀況並提供下一步的維修建議。
> a1001,2025/03/01
Agent says: 您的智慧手錶型號為A1001,購買日期為202531日。根據資料,您的手錶仍在保固期內。建議您可以先嘗試使用我們官方指定的充電器和線進行充電,如果問題仍未解決,我們可以協助您安排維修服務。請問您需要我協助您預約維修嗎?
> 先不用了
Agent says: 好的,如果您之後需要任何協助或想要預約維修,隨時告訴我。我會隨時為您服務,祝您有美好的一天!
選擇策略: 深度支援
處理時間: 82966ms

測試完成!策略路由成功運作

核心技術解析

isComplexQuery 函數的設計

QueryRouter 的核心就是 isComplexQuery 函數,它使用兩個簡單但有效的指標

  • 關鍵字匹配:檢查是否包含複雜問題的關鍵字
  • 文字長度:較長的問題通常意味著更複雜的情境

重要提醒:這個判斷邏輯完全可以根據您的業務需求調整!您可以

  • 修改關鍵字清單以符合您的應用場景
  • 調整長度閾值(目前設定為 50 字)
  • 加入更多判斷條件,如特定格式、問號數量等
private fun isComplexQuery(query: String): Boolean {
    val complexKeywords = listOf(
        "分析", "比較", "問題", "故障", "無法",
        "不滿意", "投訴", "退款", "協助", "解決"
    )

    val hasComplexKeywords = complexKeywords.any { query.contains(it) }
    val isLongQuery = query.length > 50

    return hasComplexKeywords || isLongQuery
}

兩種 Agent 的差異

特性快速回應 Agent深度支援 Agent
策略simpleSingleRunStrategy()chatAgentStrategy()
工具SayToUser, AskUser
適用場景簡單查詢複雜問題

實際效益與優勢

使用 QueryRouter 帶來的具體改善

效能提升

  • 簡單問題:有效減少平均回應時間
  • 複雜問題:雖然處理時間較長,但提供更準確的解答
  • 策略路由:避免資源浪費,提升整體系統效率

用戶體驗改善

  • 快速回應:簡單問題立即得到答案
  • 專業支援:複雜問題獲得深度分析和多輪互動
  • 個人化服務:系統能根據問題特性調整回應方式

開發維護性

  • 程式碼簡潔:邏輯清晰,易於理解和維護
  • 擴展性強:可以輕鬆調整關鍵字或增加新的判斷條件
  • 整合友善:可以無縫整合到現有系統中

進階思考:從規則到智慧

目前方案的特點

我們實作的 QueryRouter 使用簡單的規則判斷,這種方式

優點

  • 簡單直觀、執行快速、易於調整
  • 可控性高,不會出現意外的分類結果
  • 適合快速原型開發和測試

限制

  • 規則需要手動定義,可能無法涵蓋所有情況
  • 難以處理語意相似但用詞不同的問題
  • 需要持續維護和更新關鍵字清單

官方的進階方案

Koog 框架提供了更強大的 Custom Strategy Graphs,它能夠

  • 建立複雜的策略圖:使用節點和邊來定義複雜的流程控制
  • 支援並行執行:可以同時執行多個工具或判斷
  • 條件分支:根據不同條件動態選擇執行路徑
  • 歷史壓縮:有效管理長對話的上下文

在接下來的文章中,我們會探索更進階的概念 這些進階技術將展示如何建立更複雜、更靈活的處理流程

總結

今天我們學習了策略路由的核心概念,並實作了一個簡單而有效的 QueryRouter

核心學習成果

  • 規則型分流:學會建立基於關鍵字和長度的問題分類邏輯
  • 策略選擇:根據問題特性自動選擇最適合的 Agent 配置
  • 彈性設計:理解如何根據業務需求調整判斷條件
  • 技術進階:了解從規則到智慧分流的演進路徑

在下一篇文章中,我們將學習 Koog 的流式處理與即時回應功能,探討如何為用戶提供更流暢的互動體驗

參考資料


支持創作

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


圖片來源:AI 產生