- Published on
第一次學 Kotlin Koog AI 就上手 Day 15:洞察 AI 內心:掌握 Agent 的事件與生命週期
在前一篇文章中,我們學習了 Koog 的記憶體系統,讓 Agent 具備持久化記憶能力。今天我們將探討 Koog 的事件處理機制,這是了解和監控 Agent 執行過程的重要工具
想像一下,如果我們能夠觀察 AI Agent 的「內心世界」,就像醫生透過心電圖監控病人的心跳一樣。事件處理系統就是我們的「AI 心電圖」,讓我們能夠即時掌握 Agent 在做什麼、進展如何,以及是否遇到問題
為什麼需要事件處理?
在開發 AI 應用時,我們常常會遇到這些問題
- 黑盒子問題:Agent 在執行時發生了什麼?
- 除錯困難:出錯時很難找到問題所在
- 效能監控:不知道 Agent 的回應速度如何
- 用戶體驗:無法了解用戶等待的原因
事件處理系統就是解決這些問題的關鍵。它讓我們能夠「看見」Agent 的執行過程,就像在程式中加入 println
一樣簡單,但功能更強大
三個關鍵事件
在 Koog 框架中,有三個最重要的事件需要我們掌握。注意:事件處理需要使用 install(EventHandler)
功能
onBeforeAgentStarted - Agent 啟動事件
當 Agent 開始執行任務時觸發,就像是打開燈泡的那一刻
install(EventHandler) {
onBeforeAgentStarted { eventContext ->
println("Agent 開始工作了!")
println("Agent ID:${eventContext.agent.id}")
println("使用策略:${eventContext.strategy.name}")
println("開始時間:${java.time.LocalDateTime.now()}")
}
}
onToolCall - 工具調用事件
當 Agent 開始使用工具(如搜尋、計算、API 調用)時觸發
install(EventHandler) {
onToolCall { eventContext ->
println("工具 ${eventContext.tool.name} 開始執行")
println("輸入參數:${eventContext.toolArgs}")
println("執行 ID:${eventContext.runId}")
}
}
onAgentRunError - 錯誤處理事件
當執行過程中發生錯誤時觸發,是除錯的重要線索
install(EventHandler) {
onAgentRunError { eventContext ->
println("發生錯誤:${eventContext.throwable.message}")
println("錯誤類型:${eventContext.throwable.javaClass.simpleName}")
println("Agent ID:${eventContext.agentId}")
// 可以選擇性地記錄詳細的堆疊追蹤
eventContext.throwable.printStackTrace()
}
}
客服機器人範例
讓我們透過一個簡單的客服機器人來看看如何使用這些事件
class EventCustomerServiceBot {
fun createBot(): AIAgent<String, String> {
return AIAgent(
executor = simpleOpenAIExecutor(ApiKeyManager.openAIApiKey!!),
systemPrompt = """
你是一個友善的客服助手,專門協助客戶解決問題
請用親切的語氣回應,並盡量提供有用的資訊
使用正體中文回應
""".trimIndent(),
llmModel = OpenAIModels.CostOptimized.GPT4_1Mini
) {
// 安裝事件處理功能
install(EventHandler) {
// 當客服機器人開始工作時
onBeforeAgentStarted { eventContext ->
val currentTime = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
println("=".repeat(50))
println("客服機器人已啟動")
println("開始時間:$currentTime")
println("Agent ID:${eventContext.agent.id}")
println("使用策略:${eventContext.strategy.name}")
println("執行 ID:${eventContext.runId}")
println("=".repeat(50))
}
// 當開始使用工具時(比如查詢資料庫、搜尋資訊等)
onToolCall { eventContext ->
println("工具開始執行:")
println(" 工具名稱:${eventContext.tool.name}")
println(" 輸入參數:${eventContext.toolArgs}")
println(" 執行 ID:${eventContext.runId}")
println("-".repeat(30))
}
// 當工具執行完成並有結果時
onToolCallResult { eventContext ->
println("工具執行完成:")
println(" 工具名稱:${eventContext.tool.name}")
// 顯示工具執行的簡要結果
val resultPreview = when {
eventContext.result.toString().length <= 100 -> eventContext.result.toString()
else -> "${eventContext.result.toString().take(97)}..."
}
println(" 執行結果:$resultPreview")
println("-".repeat(30))
}
// 當 Agent 執行完成時
onAgentFinished { eventContext ->
println("客服機器人執行完成")
println(" Agent ID:${eventContext.agentId}")
println(" 執行 ID:${eventContext.runId}")
println("=".repeat(50))
}
// 當發生錯誤時
onAgentRunError { eventContext ->
println("客服系統發生問題:")
println(" 錯誤訊息:${eventContext.throwable.message}")
println(" Agent ID:${eventContext.agentId}")
println(" 發生時間:${LocalDateTime.now()}")
// 根據錯誤類型提供不同的處理建議
when {
eventContext.throwable.message?.contains("timeout") == true ->
println(" 建議:網路連線可能不穩定,請稍後再試")
eventContext.throwable.message?.contains("quota") == true ->
println(" 建議:API 配額可能已用完,請檢查帳戶狀態")
else ->
println(" 建議:請檢查設定或聯繫技術支援")
}
println("=".repeat(50))
}
}
}
}
}
實際使用範例
suspend fun main() {
// 建立客服機器人
val bot = CustomerServiceBot().createBot(apiKey)
// 模擬客戶對話
val customerQuestions = listOf(
"你好,請問你們的營業時間是什麼時候?",
"運費是怎麼計算的?"
)
customerQuestions.forEach { question ->
println("客戶問題:$question")
try {
val response = bot.run(question)
println("客服回應:$response")
} catch (e: Exception) {
println("處理失敗:${e.message}")
}
println("\n" + "=".repeat(60) + "\n")
}
}
執行 AI 回應內容
客戶問題:你好,請問你們的營業時間是什麼時候?
==================================================
客服機器人已啟動
開始時間:2025-08-15 16:07:45
Agent ID:e503114c-9d6f-4a04-b5f2-e6f40f3ff380
使用策略:single_run
執行 ID:85c5d609-f781-421f-b795-9242b608b5d3
==================================================
客服機器人執行完成
Agent ID:e503114c-9d6f-4a04-b5f2-e6f40f3ff380
執行 ID:85c5d609-f781-421f-b795-9242b608b5d3
==================================================
客服回應:您好!感謝您的詢問。我們的營業時間是週一到週五,上午9點到下午6點,週末及國定假日休息。如果您有任何其他問題,隨時歡迎告訴我喔!祝您有美好的一天!
============================================================
客戶問題:運費是怎麼計算的?
==================================================
客服機器人已啟動
開始時間:2025-08-15 16:07:47
Agent ID:e503114c-9d6f-4a04-b5f2-e6f40f3ff380
使用策略:single_run
執行 ID:f0a73e3f-d11e-409c-9c83-581e33b6c753
==================================================
客服機器人執行完成
Agent ID:e503114c-9d6f-4a04-b5f2-e6f40f3ff380
執行 ID:f0a73e3f-d11e-409c-9c83-581e33b6c753
==================================================
客服回應:您好!關於運費的計算方式,通常會根據以下幾個因素來決定:
1. **配送地點**:寄送的地址距離您的所在地越遠,運費通常會越高。
2. **包裹重量與尺寸**:重量較重或體積較大的包裹,運費會比較貴。
3. **運送方式**:例如標準快遞、加急快遞、國際運送等,不同方式費用也會不同。
4. **促銷活動或免運門檻**:有時候店家會提供滿額免運或優惠折扣。
如果您方便的話,可以提供您所在的地區和想購買的商品資訊,我可以幫您查詢更詳細的運費標準喔!祝您購物愉快!😊
============================================================
進階使用技巧
計算處理時間
install(EventHandler) {
// 記錄開始時間
var startTime = 0L
onBeforeAgentStarted { eventContext ->
startTime = System.currentTimeMillis()
println("開始處理客戶問題...")
println("執行 ID:${eventContext.runId}")
}
onAgentFinished { eventContext ->
val duration = System.currentTimeMillis() - startTime
println("處理完成,耗時:${duration}ms")
println("執行 ID:${eventContext.runId}")
}
}
統計工具使用次數
install(EventHandler) {
val toolUsageCount = mutableMapOf<String, Int>()
onToolCall { eventContext ->
// 統計工具使用次數
toolUsageCount[eventContext.tool.name] =
toolUsageCount.getOrDefault(eventContext.tool.name, 0) + 1
println("${eventContext.tool.name} 已使用 ${toolUsageCount[eventContext.tool.name]} 次")
}
}
支援多個事件處理器
install(EventHandler) {
// 可以為同一個事件註冊多個處理器
onBeforeAgentStarted { eventContext ->
println("第一個處理器:Agent 開始執行")
}
onBeforeAgentStarted { eventContext ->
println("第二個處理器:記錄開始時間")
}
}
簡單的錯誤提示機制
install(EventHandler) {
var errorCount = 0
onAgentRunError { eventContext ->
errorCount++
println("第 $errorCount 次錯誤:")
if (errorCount >= 3) {
println("連續錯誤過多,建議檢查系統狀態")
}
}
}
疑難排解
事件沒有觸發
解決方法:在 Agent 建立時安裝 EventHandler
功能
val agent = AIAgent(...) {
install(EventHandler) { // 確保有安裝 EventHandler
onBeforeAgentStarted { eventContext -> ... }
}
}
使用了過時的 API
可能原因:使用了被標記為 Deprecated 的屬性賦值方式
解決方法:改用新的方法呼叫方式
// 舊的方式(已棄用)
install(EventHandler) {
onToolCall = { stage, tool, toolArgs -> ... }
}
// 新的方式(推薦)
install(EventHandler) {
onToolCall { eventContext -> ... }
}
輸出太多資訊
解決方法:加入條件判斷,只在需要時輸出
install(EventHandler) {
val isDebugMode = System.getenv("DEBUG") == "true"
onToolCall { eventContext ->
if (isDebugMode) {
println("工具:${eventContext.tool.name}")
}
}
}
效能影響
解決方法:保持事件處理邏輯簡單
install(EventHandler) {
// 避免在事件中做複雜的運算
onBeforeAgentStarted { eventContext ->
heavyDatabaseOperation() // 不建議
}
// 保持簡單快速
onBeforeAgentStarted { eventContext ->
println("Agent started: ${eventContext.agent.id}")
}
}
總結
今天我們學習了 Koog 框架中的事件處理機制
- 新的事件 API:使用
install(EventHandler)
安裝事件處理功能 - 三個核心事件:
onBeforeAgentStarted
、onToolCall
、onAgentRunError
- Context 物件:透過 eventContext 存取豐富的事件資訊
- 實際應用:透過智能客服機器人了解事件的實際用途
- 進階功能:支援多個事件處理器、完整的事件生命週期
- 除錯技巧:使用事件來找出問題和優化效能
完整的事件類型清單
除了上述三個關鍵事件,Koog 還提供了更多事件類型供進階使用
Agent 生命週期事件
onBeforeAgentStarted
- Agent 啟動前onAgentFinished
- Agent 執行完成onAgentRunError
- Agent 執行發生錯誤
策略執行事件
onStrategyStarted
- 策略開始執行onStrategyFinished
- 策略執行完成
節點執行事件
onBeforeNode
- 節點執行前onAfterNode
- 節點執行後
LLM 呼叫事件
onBeforeLLMCall
- LLM 呼叫前onAfterLLMCall
- LLM 呼叫後
工具相關事件
onToolCall
- 工具開始執行onToolCallResult
- 工具執行完成並有結果onToolCallFailure
- 工具執行失敗onToolValidationError
- 工具參數驗證錯誤
這些事件提供了完整的監控能力,讓你能夠追蹤 Agent 執行的每個階段
事件處理就像是給 Agent 裝上了「儀表板」,讓我們能夠清楚看到它的運作狀況。透過這些豐富的事件類型,你可以建立一個全面監控、可除錯的 AI 應用
在下一篇文章中,我們將學習 Koog 的策略模式與工作流程設計,了解如何建立更複雜的 Agent 執行邏輯
參考資料
支持創作
如果這篇文章對您有幫助,歡迎透過 贊助連結 支持我持續創作優質內容。您的支持是我前進的動力!
圖片來源:AI 產生