- 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,購買日期為2025年3月1日。根據資料,您的手錶仍在保固期內。建議您可以先嘗試使用我們官方指定的充電器和線進行充電,如果問題仍未解決,我們可以協助您安排維修服務。請問您需要我協助您預約維修嗎?
> 先不用了
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 產生