Koog 1.0 idioms, gotchas, and scaffolding skills for Kotlin agents on the JVM
91
89%
Does it follow best practices?
Impact
92%
1.73xAverage score across 47 eval scenarios
Advisory
Suggest reviewing before use
This skill is an action router — pick the step that matches the user's intent and execute only that step. Do not run other steps; do not parallelize.
Available actions:
responseProcessor (simpler — works with default singleRunStrategy)nodeLLMRequestStructured (graph DSL — required when the structured call sits inside a custom strategy)responseProcessorUse when the user just wants the agent's final answer to be a typed object and they're not authoring a custom strategy.
Define the output type with kotlinx.serialization:
import kotlinx.serialization.Serializable
@Serializable
data class TriageResult(
val classification: String,
val confidence: Double,
val suggestedAction: String,
)Pass a ResponseProcessor configured for the type to the factory:
val agent: AIAgent<String, TriageResult> = AIAgent(
promptExecutor = ...,
llmModel = ...,
systemPrompt = "Classify the GitHub issue and suggest an action.",
responseProcessor = jsonResponseProcessor<TriageResult>(),
)
val result: TriageResult = agent.run("Issue: app crashes on startup ...")The output type parameter on AIAgent<Input, Output> becomes the result of agent.run(...). Use this path when the strategy is singleRunStrategy() (the default).
Write the result to disk with explicit Path: labels (same convention as scaffold-agent). Do not respond with prose only.
Path: src/main/kotlin/com/example/Main.kt — the full agent construction with the responseProcessor parameter and the @Serializable output typePath: build.gradle.kts — the kotlinx-serialization plugin and dependency when not already presentCreate the files if they do not exist.
Finish here.
nodeLLMRequestStructured Inside a StrategyUse when the structured call lives inside a custom graph — e.g., one phase of a multi-step workflow produces a typed object that feeds the next phase.
Define the output type:
@Serializable
data class Classification(
val type: String,
val tags: List<String>,
)Use the structured node inside the strategy:
import ai.koog.agents.core.dsl.builder.strategy
val classifyStrategy = strategy<String, Classification>("classify-issue") {
val classify by nodeLLMRequestStructured<Classification>()
edge(nodeStart forwardTo classify)
edge(classify forwardTo nodeFinish)
}nodeLLMRequestStructured<T>() returns a Classification-typed value as the node output. The next edge's predicates/transforms operate on the typed value, not on raw Message.User.
Wire into the agent:
val agent: AIAgent<String, Classification> = AIAgent(
promptExecutor = ...,
llmModel = ...,
systemPrompt = "...",
strategy = classifyStrategy,
)The strategy's Output type parameter must match the structured node's type parameter and AIAgent's Output parameter. Mismatches surface as compile errors.
Write the strategy and the modified agent construction to disk with explicit Path: labels (same convention as scaffold-agent). Do not respond with prose only.
Path: src/main/kotlin/com/example/Strategy.kt — the strategy with the nodeLLMRequestStructured node and the @Serializable output typePath: src/main/kotlin/com/example/Main.kt — the agent construction passing strategy = ...Path: build.gradle.kts — the kotlinx-serialization plugin and dependency when not already presentCreate the files if they do not exist.
Finish here.
.gemini
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10
scenario-11
scenario-12
scenario-13
scenario-14
scenario-15
scenario-16
scenario-17
scenario-18
scenario-19
scenario-20
scenario-21
scenario-22
scenario-23
scenario-24
scenario-25
scenario-26
scenario-27
scenario-28
scenario-29
scenario-30
scenario-31
scenario-32
scenario-33
scenario-34
scenario-35
scenario-36
scenario-37
scenario-38
scenario-39
scenario-40
scenario-41
scenario-42
scenario-43
scenario-44
scenario-45
scenario-46
scenario-47
skills
add-observability
add-persistence
add-rag
add-structured-output
add-token-budgeting
add-tool
cache-llm-calls
define-prompt
domain-model-subtask-pipeline
references
enable-prompt-caching
handle-agent-events
manage-state
migrate-from-0-x
model-planner-subtasks
persist-chat-history
query-sql-from-agent
scaffold-agent
snapshot-and-restore
test-koog-agents
trace-agent-internals
use-attachments
use-functional-agent
use-llm-node-variants
use-planner
wire-a2a
wire-acp-server
wire-ktor-server
wire-mcp-server
wire-spring-boot