- Published on
第一次學 Kotlin Koog AI 就上手 Day 05:賦予 AI 動手能力:工具系統入門
在前一篇文章中,我們學習了如何整合多個 LLM 供應商,能夠靈活選擇最適合的模型 (供應商)。但到目前為止,我們的 Agent 只能進行對話,還無法執行具體的操作。今天我們將學習 Koog 框架的工具系統基礎,讓 AI Agent 具備實際的操作能力
什麼是工具系統?
在 AI Agent 的世界中,工具(Tool) 是連接 AI 思維與現實世界的橋樑。就像人類使用計算機、電話、筆記本來完成各種任務一樣,AI Agent 也需要工具來執行具體操作
Koog 的工具系統設計理念很簡單
讓 AI Agent 能夠安全且可控地執行實際操作
為什麼需要工具系統?
- 擴展能力:讓 AI 能執行計算、查詢資料等實用功能
- 保持安全:所有操作都通過明確定義的介面執行
- 易於控制:開發者可以精確控制 Agent 能做什麼
- 提升價值:讓 AI 從「聊天機器人」變成「實用助手」
工具系統與 Function Calling 的關係
如果你有使用其他 AI 開發框架的經驗,你可能會發現 Koog 的「工具(Tool)」概念似曾相識。沒錯!Koog 的工具系統本質上就是 LLM Function Calling 的實作
在不同的語言和框架中,這個概念有著不同的名稱
框架/語言 | 名稱 | 描述 |
---|---|---|
Koog (Kotlin) | Tool | 使用 SimpleTool 或註解方式定義 |
OpenAI API | Function Calling | 直接定義 JSON Schema |
LangChain (Python) | Tool | 使用裝飾器或繼承 BaseTool |
AutoGen | Function Calling | 註冊 Python 函數 |
Semantic Kernel (C#) | Plugin/Function | 使用屬性標註方法 |
核心概念都相同:讓 LLM 能夠呼叫預先定義的函數來執行具體操作,並將結果整合到對話流程中
Koog 的優勢在於
- 類型安全:Kotlin 的靜態類型檢查
- 結構化:清晰的工具定義架構
- 靈活性:支援 Class-based 和 Annotation-based 兩種方式
- 整合性:與 Kotlin 生態系統無縫整合
Koog 內建工具介紹
Koog 框架提供了三個基本的內建工具,讓我們先了解這些工具的基本用法
SayToUser:向使用者說話
SayToUser
工具讓 Agent 能夠主動向使用者輸出訊息
suspend fun main() {
// 註冊工具
val toolRegistry = ToolRegistry {
tool(SayToUser)
}
val agent = AIAgent(
executor = simpleOpenAIExecutor(System.getenv("OPENAI_API_KEY")),
systemPrompt = "你是友善的 AI 助手,請使用 SayToUser 工具與使用者對話",
toolRegistry = toolRegistry,
llmModel = OpenAIModels.CostOptimized.GPT4_1Mini
)
agent.run("你好!")
}
執行 AI 回應內容
Agent says: 你好!很高興見到你,有什麼我可以幫助你的嗎?
AskUser:向使用者提問
AskUser
工具讓 Agent 能夠主動詢問使用者問題
suspend fun main() {
// 註冊工具
val toolRegistry = ToolRegistry {
tool(SayToUser)
tool(AskUser)
}
val agent = AIAgent(
executor = simpleOpenAIExecutor(System.getenv("OPENAI_API_KEY")),
// systemPrompt = "請使用 AskUser 詢問使用者的姓名,然後用 SayToUser 打招呼。",
systemPrompt = "請先詢問使用者的姓名,然後在跟使用者打招呼。",
toolRegistry = toolRegistry,
llmModel = OpenAIModels.CostOptimized.GPT4_1Mini
)
agent.run("你好!")
}
實測,有沒有在
system prompt
裡寫明使用工具
,得到的結果都是一樣的
執行 AI 回應內容
您好!請問您的姓名是?
Cash
Agent says: 您好,Cash!很高興見到您,有什麼我可以幫助您的嗎?
ExitTool:結束對話
ExitTool
工具讓 Agent 能夠優雅地結束對話
suspend fun main() {
// 註冊工具
val toolRegistry = ToolRegistry {
tool(SayToUser)
tool(AskUser)
tool(ExitTool)
}
val agent = AIAgent(
executor = simpleOpenAIExecutor(System.getenv("OPENAI_API_KEY")),
// systemPrompt = "請使用 AskUser 詢問使用者的姓名,然後用 SayToUser 打招呼。",
systemPrompt = "請先詢問使用者的姓名,然後在跟使用者打招呼。",
toolRegistry = toolRegistry,
llmModel = OpenAIModels.CostOptimized.GPT4_1Mini
)
agent.run("你好!")
}
執行 AI 回應內容
你好!請問您的姓名是?
> Cash
Agent says: Cash,您好!很高興認識您。請問有什麼我可以幫助您的嗎?
請問您今天想聊些什麼,或者有什麼需要幫忙的?
> 沒有
自定義工具開發 (Class-based)
內建工具雖然實用,但真正的威力在於開發自定義工具。Koog 提供了 SimpleTool
抽象類,讓我們能夠輕鬆建立自己的工具
SimpleTool 基礎結構
每個自定義工具都需要四個基本要素
- 參數類別:定義工具接受的參數
- 參數序列化器:處理參數的序列化
- 工具描述:告訴 LLM 如何使用這個工具
- 執行邏輯:工具的實際功能
序列化設定
先確認 build.gradle.kts
中是否已加入 serializtion
plugin
plugins {
kotlin("jvm") version "2.2.0"
// 確認有加上相關的序列化插件
kotlin("plugin.serialization") version "2.2.0"
}
建立 SimpleTool 加法工具
object AddTool : SimpleTool<AddTool.Args>() {
// 1. 定義參數類別
@Serializable
data class Args(val number1: Int, val number2: Int) : ToolArgs
// 2. 設定序列化器
override val argsSerializer = Args.serializer()
// 3. 定義工具描述
override val descriptor = ToolDescriptor(
name = "add_numbers",
description = "將兩個數字相加",
requiredParameters = listOf(
ToolParameterDescriptor(
name = "number1",
description = "第一個數字",
type = ToolParameterType.Integer
),
ToolParameterDescriptor(
name = "number2",
description = "第二個數字",
type = ToolParameterType.Integer
)
)
)
// 4. 實作執行邏輯
override suspend fun doExecute(args: Args): String {
return try {
val result = args.number1 + args.number2
"計算結果:${args.number1} + ${args.number2} = $result"
} catch (e: Exception) {
"計算錯誤:${e.message}"
}
}
}
使用 SimpleTool 工具
suspend fun main() {
// 註冊工具
val toolRegistry = ToolRegistry {
tool(SayToUser)
tool(AddTool)
}
val agent = AIAgent(
executor = simpleOpenAIExecutor(System.getenv("OPENAI_API_KEY")),
systemPrompt = """
你是一個數學助手。當使用者需要計算兩個數字相加時:
1. 使用 add_numbers 工具進行計算
2. 使用 SayToUser 工具告訴使用者結果
請用友善的正體中文回應
""".trimIndent(),
toolRegistry = toolRegistry,
llmModel = OpenAIModels.CostOptimized.GPT4_1Mini
)
// 測試加法功能
agent.run("請幫我計算 15 + 27")
}
執行這個程式時,AI Agent 會
- 識別使用者想要計算 15 + 27
- 透過
doExecute
來計算結果
我覺得這裡和其它語言的 tool 方式不太一樣,不用明確的實作工具的方法,而是實作
doExecute
,所以程式碼裡面可以沒有addNumbers
函數
- 使用
SayToUser
工具告訴使用者答案是 42
執行 AI 回應內容
Agent says: 15 加 27 的結果是 42。
自定義工具開發 (Annotation-based)
除了 Class-based 的方式,Koog 還提供了更簡潔的 Annotation-based 工具開發方式。這種方法使用註解來自動生成工具描述,讓開發者能夠以更宣告式的方式建立工具
什麼是 Annotation-based 工具?
Annotation-based 工具提供了一種宣告式的方式來將函數公開為 LLM 可用的工具。透過使用註解,我們可以將現有的函數轉換為 LLM 可使用的工具,而無需手動實作工具描述
核心註解介紹
@Tool
:標記函數為可供 LLM 使用的工具@LLMDescription
:為工具、參數提供描述資訊
建立 ToolSet
首先,我們需要建立一個繼承 ToolSet
的類別
@LLMDescription("數學計算工具集")
class MathToolSet : ToolSet {
@Tool
@LLMDescription("將兩個數字相加")
fun addNumbers(
@LLMDescription("第一個數字")
number1: Int,
@LLMDescription("第二個數字")
number2: Int
): String {
return try {
val result = number1 + number2
"計算結果:$number1 + $number2 = $result"
} catch (e: Exception) {
"計算錯誤:${e.message}"
}
}
}
使用 Annotation-based 工具
suspend fun main() {
// 註冊工具集
val toolRegistry = ToolRegistry {
tool(SayToUser)
// 使用 tools 方法註冊
tools(MathToolSet())
}
val agent = AIAgent(
executor = simpleOpenAIExecutor(System.getenv("OPENAI_API_KEY")),
systemPrompt = """
你是一個數學助手。當使用者需要計算兩個數字相加時:
1. 使用 addNumbers 工具進行計算
2. 使用 SayToUser 工具告訴使用者結果
請用友善的正體中文回應
""".trimIndent(),
toolRegistry = toolRegistry,
llmModel = OpenAIModels.CostOptimized.GPT4_1Mini
)
// 測試加法功能
agent.run("請幫我計算 25 + 17")
}
執行 AI 回應內容
Agent says: 25 加 17 的結果是 42。
與 Class-based 方式的比較
特性 | Class-based | Annotation-based |
---|---|---|
語法複雜度 | 較複雜,需要實作多個部分 | 較簡潔,使用註解即可 |
參數定義 | 需要定義 Args 類別和序列化器 | 直接在函數參數上使用註解 |
工具描述 | 手動定義 ToolDescriptor | 自動從註解生成 |
適用場景 | 複雜工具,需要精細控制 | 簡單工具,快速開發 |
進階功能:多工具組合
一個 ToolSet 可以包含多個工具
@LLMDescription("數學計算工具集")
class MathToolSet : ToolSet {
@Tool
@LLMDescription("將兩個數字相加")
fun addNumbers(
@LLMDescription("第一個數字")
number1: Int,
@LLMDescription("第二個數字")
number2: Int
): String {
return try {
val result = number1 + number2
"計算結果:$number1 + $number2 = $result"
} catch (e: Exception) {
"計算錯誤:${e.message}"
}
}
@Tool
@LLMDescription("將兩個數字相乘")
fun multiplyNumbers(
@LLMDescription("第一個數字")
number1: Int,
@LLMDescription("第二個數字")
number2: Int
): String {
return try {
val result = number1 * number2
"乘法結果:$number1 × $number2 = $result"
} catch (e: Exception) {
"計算錯誤:${e.message}"
}
}
@Tool
@LLMDescription("檢查數字是否為質數")
fun isPrime(
@LLMDescription("要檢查的數字")
number: Int
): String {
if (number <= 1) return "$number 不是質數"
for (i in 2..sqrt(number.toDouble()).toInt()) {
if (number % i == 0) return "$number 不是質數"
}
return "$number 是質數"
}
}
suspend fun main() {
// 註冊工具集
val toolRegistry = ToolRegistry {
tool(SayToUser)
// 使用 tools 方法註冊
tools(MathToolSet())
}
val agent = AIAgent(
executor = simpleOpenAIExecutor(System.getenv("OPENAI_API_KEY")),
systemPrompt = """
你是一個數學助手。你有一些數學工具可以使用
請用友善的正體中文回應
""".trimIndent(),
// systemPrompt = """
// 你是一個數學助手。你有一些數學工具可以使用:
// 1. 將兩個數字相加 - addNumbers
// 2. 將兩個數字相乘 - multiplyNumbers
// 3. 檢查數字是否為質數 - isPrime
// 當使用者有相關的數學問題時,請選擇相對應的工具來處理和回應
// 請用友善的正體中文回應
// """.trimIndent(),
toolRegistry = toolRegistry,
// llmModel = OpenAIModels.CostOptimized.GPT4_1Mini
llmModel = OpenAIModels.CostOptimized.GPT4_1
)
// 測試加法功能
agent.run("請幫我計算 25 + 17")
// 測試乘法功能
agent.run("請幫我計算 4 * 5")
// 測試質數功能
agent.run("請問一下 5 是不是質數")
}
這裡我試了 4.1 mini 好幾次,都沒有辦法順利執行,就算是把工具描述的很清楚也是一樣,最後改用 4.1 就可以成功執行
如果有遇到工具沒有辦法順序執行的,可以嘗試換一個 (更聰明的) 模型試試看
執行 AI 回應內容
Agent says: 25 + 17 的答案是 42。
Agent says: 4 × 5 = 20
Agent says: 5 是質數,因為它只有 1 和自己可以整除。
選擇建議
使用 Class-based
- 需要複雜的參數驗證
- 工具邏輯較為複雜
- 需要精細控制工具行為
使用 Annotation-based
- 快速原型開發
- 工具邏輯相對簡單
- 偏好宣告式的程式設計風格
- 需要將現有函數快速轉換為工具
工具開發基本原則
保持簡單
每個工具都應該專注於一個明確的任務
// ✅ 好的設計:功能明確
object AddTool : SimpleTool<AddTool.Args>() {
// 只做加法運算
}
// ❌ 避免的設計:功能過於複雜
object MathTool : SimpleTool<MathTool.Args>() {
// 同時處理加減乘除、三角函數、統計等
}
明確的參數描述
讓 LLM 能夠正確理解如何使用工具
ToolParameterDescriptor(
name = "number1",
description = "第一個數字", // 清楚說明參數用途
type = ToolParameterType.Integer
)
基本錯誤處理
提供有意義的錯誤訊息
override suspend fun doExecute(args: Args): String {
return try {
// 執行工具邏輯
performOperation(args)
} catch (e: Exception) {
"操作失敗:${e.message}"
}
}
總結
今天我們學習了 Koog 工具系統的基礎概念
- 讓 AI Agent 從「聊天機器人」變成「實用助手」
- SayToUser、AskUser、ExitTool 三個基本工具
- 使用 Class-based - SimpleTool 建立結構化的自定義工具
- 使用 Annotation-based 註解快速建立簡潔的工具
- 基本原則:保持簡單、明確描述、適當錯誤處理
下一篇文章中,我們將學習如何調校 AI Agent 的行為參數,讓它更符合我們的需求
參考資料
支持創作
如果這篇文章對您有幫助,歡迎透過 贊助連結 支持我持續創作優質內容。您的支持是我前進的動力!
圖片來源:AI 產生