Step 2 of 5
Tool declarations, parameter schemas, registering tools, tool-calling loop
Tool calling — สอน agent ใช้เครื่องมือ: weather, calculator, search
A tool is a Kotlin function the LLM can call. Without tools, the agent can only talk. With tools, it can read weather, run math, query a database, or call any API.
Koog exposes functions as tools with two annotations:
@Tool — marks the function as callable by the LLM@LLMDescription("...") — tells the LLM what the function and each parameter meanDiagram: The tool-calling loop. The LLM sees the tool descriptions, decides to call one, the agent runs it, and feeds the result back.
Loading diagram...
Put related tools in a class that implements ToolSet. The class can hold state (like an HTTP client or a database connection).
class AssistantTools : ToolSet {
@Tool
@LLMDescription("Get the current weather for a city")
fun getWeather(
@LLMDescription("City name, e.g. 'Tokyo'") city: String
): String {
// In real code, call a weather API here
return "The weather in $city is sunny and 22C."
}
@Tool
@LLMDescription("Calculate a math result from two numbers and an operator")
fun calculate(
@LLMDescription("First number") a: Double,
@LLMDescription("Operator: +, -, *, or /") op: String,
@LLMDescription("Second number") b: Double
): String {
val result = when (op) {
"+" -> a + b
"-" -> a - b
"*" -> a * b
"/" -> if (b != 0.0) a / b else return "Error: divide by zero"
else -> return "Error: unknown operator '$op'"
}
return "Result: $result"
}
}
Notes:
String, Int, Boolean) so the LLM sends correct values@LLMDescriptionString so the LLM can read the resultPass the tool set into a ToolRegistry and give it to the agent:
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
val apiKey = System.getenv("OPENAI_API_KEY") ?: error("Set OPENAI_API_KEY")
val agent = AIAgent(
promptExecutor = simpleOpenAIExecutor(apiKey),
llmModel = OpenAIModels.Chat.GPT4o,
systemPrompt = "You are a helpful assistant. Use tools to answer.",
toolRegistry = ToolRegistry {
tools(AssistantTools())
}
)
println(agent.run("What is 12 times 7, and what is the weather in Tokyo?"))
}
Koog runs the loop for you. The LLM chooses which tool to call, Koog runs it, then asks the LLM again. To see each call, add an event handler:
val agent = AIAgent(
promptExecutor = simpleOpenAIExecutor(apiKey),
llmModel = OpenAIModels.Chat.GPT4o,
toolRegistry = ToolRegistry { tools(AssistantTools()) }
) {
handleEvents {
onToolCallStarting { ctx ->
println("-> calling ${ctx.toolName}(${ctx.toolArgs})")
}
}
}
Expected output:
-> calling calculate({"a":12.0,"op":"*","b":7.0})
-> calling getWeather({"city":"Tokyo"})
12 times 7 is 84.0. The weather in Tokyo is sunny and 22C.
The LLM picked both tools, in the order it reasoned about them.
getWeather, sendEmail, searchDocssendEmail(to: String, subject: String, body: String) tool that prints the email instead of sending it.