Building Custom GenAI Tools via KSP Compiler Processing
To interface an AI agent with the real world, you must expose execution functions—commonly referred to as Tool Calling. Google ADK leverages Kotlin Symbol Processing (KSP) to automatically convert plain Kotlin functions into JSON schema payloads that LLMs understand at compile time.
The Danger of Manual Schema Definitions
In historical frameworks, developers had to manually write and map rigorous JSON schemas to explain native code function signatures to language models. If a parameter type shifted, the schema broke, introducing run-time exceptions. KSP removes this layer entirely by shifting schema generation to the compiler lifecycle.
Implementation: Writing an Auto-Generated Custom Tool
Let's build a type-safe tool using the @Tool annotation. This tool will run safely within our application framework to perform a mock data lookup or arithmetic validation.
package com.example.adkdemoapp.tools
import com.google.adk.kt.annotations.Tool
import com.google.adk.kt.annotations.ToolParam
class DeviceUtilityTools {
@Tool(
name = "calculate_system_efficiency",
description = "Computes real-time execution bounds based on current index input and hardware coefficient."
)
fun calculateEfficiency(
@ToolParam(description = "The baseline index value retrieved from local device storage.")
baseIndex: Double,
@ToolParam(description = "Coefficient scaler based on industrial configuration profile.")
coefficient: Int
): String {
// Deterministic, secure native code execution execution layer
val result = baseIndex * coefficient
return "Calculated system processing metric value is: $result%"
}
}
Compiling and Injecting the Tool
When you execute your project build (./gradlew assembleDebug), KSP processes the @Tool metadata hooks and compiles the structural configuration needed by the ADK engine under the hood. You then simply bind this to your agent profile:
// Attaching the compiled tool definition seamlessly
val systemAgent = LlmAgent(
name = "utility_agent",
model = Gemini(name = "gemini-2.5-flash", apiKey = BuildConfig.GEMINI_API_KEY),
tools = listOf(DeviceUtilityTools().toAdkTool()) // Auto-generated helper mapping extension
)