Posts Tagged ‘StrategyDSL’
[VoxxedDaysAmsterdam2026] Building AI Agents on the JVM: A Practical Exploration with Koog in Kotlin
Lecturer
Anton Arhipov is a Developer Advocate at JetBrains, where he engages with developers and shares insights on Kotlin, IntelliJ IDEA, and related technologies. He frequently speaks at conferences and contributes to JetBrains initiatives around AI tooling and agent frameworks.
Abstract
Anton Arhipov’s session at Voxxed Days Amsterdam 2026 introduces the construction of AI agents directly on the JVM using Koog, a lightweight Kotlin-native framework developed at JetBrains. Rather than relying on Python-based solutions, the talk demonstrates building tool-using LLM agents in Kotlin, emphasizing seamless integration with existing JVM products and domain models. Through live coding and detailed examination of core concepts—including communication with language models, tool registration, interaction loops, and the distinctive graph-based strategy DSL—participants gain insight into creating robust, reproducible agent workflows. The presentation culminates in a coding agent example that generates, compiles, and tests small programs, highlighting both opportunities and challenges when working with local and remote LLMs.
Why Build AI Agents on the JVM? Context and Motivations
The emergence of large language models has spurred interest in autonomous AI agents capable of tool use and iterative reasoning. While Python has historically dominated this space, Anton argues that language choice should serve the embedding context. For JVM-based products such as IntelliJ IDEA, TeamCity, or YouTrack, implementing agents in Python introduces significant overhead: external process management, serialization costs, and duplication of domain models. A native JVM solution reuses existing infrastructure, types, and libraries, improving efficiency and maintainability.
Koog originated from internal JetBrains efforts to embed agents into their tools. The framework’s tech lead documented the transition from Python to Kotlin, sparking discussions around perceived “skill issues” versus genuine architectural advantages. Anton stresses that the decision prioritizes integration over language fashion.
Fundamentals of Agent Architecture and the Interaction Loop
At a high level, an AI agent comprises an environment, a strategy (or “brain”), model providers, and user interaction. The workflow begins with a user request. The agent forwards a prompt to an LLM via a prompt executor (supporting OpenAI, Google, Ollama, and others). The model may respond with:
- An assistant message (plain text, terminating the loop), or
- A tool call, prompting the agent to invoke registered tools, feed results back to the LLM, and iterate until an assistant message appears.
This forms the agentic loop. Koog models agents as simple classes with a tools registry, configurable strategy, prompt, model selection, iteration limits, and a prompt executor. Predefined models and capability checks (e.g., tool calling support) simplify setup.
Anton demonstrates a basic happy-path agent that writes a Kotlin program (initially a “Hello World,” later a Snake game using Java Swing). Early iterations reveal the need for tools: file system operations, shell execution via Gradle, and careful prompting to enforce compilation and verification steps. Live runs expose humorous LLM behaviors, such as generating wrapper files or hallucinating results, underscoring the importance of robust system prompts, validation, and verification.
Tool Integration, Local Models, and Observed Challenges
Tools in Koog can be registered via a registry or supplied as annotated functions with descriptions for better LLM guidance. The session explores interactions with local models (e.g., small Mistral variants via Ollama) versus remote APIs. Local models offer speed and privacy but exhibit unreliability in tool calling—hallucinating results, ignoring descriptions, or fabricating outputs when tool results appear implausible (such as unrealistic temperature values in Kelvin).
Examples illustrate how insufficient tool descriptors or conflicting instructions lead to unexpected behavior. Anton shows cases where models call tools multiple times, reject their own outputs, or produce inconsistent results across runs, even with identical prompts. These observations highlight that reliable tool calling remains critical for effective agents and often requires significant prompt engineering and workflow safeguards.
The Strategy DSL: Graph-Based Control for Determinism and Reproducibility
A standout feature of Koog is its strategy DSL, which models agent behavior as a reproducible graph rather than a purely LLM-driven loop. The default strategy handles basic LLM calls and tool invocation, but custom strategies allow sophisticated workflows.
Nodes represent actions (e.g., calling the LLM, processing tool results), while edges use predicates or conditions (e.g., “if tool call, proceed to execution node”). Graphs support sequencing, branching, and chaining multiple strategies—such as enforcing a planning stage before implementation and verification. Type safety in Kotlin ensures nodes and edges compose correctly, with the compiler assisting in workflow construction.
Anton walks through building a simple parsing-and-increment graph, then extends the concept to more realistic scenarios involving structured outputs for plans. By validating plans against domain models and potentially generating dynamic sub-strategies, developers introduce determinism into otherwise stochastic LLM processes. Structured outputs improve reliability when deserializing LLM responses into typed objects like plan items.
This graph approach distinguishes Koog from many other frameworks, enabling complex, auditable, and testable agent logic while leveraging Kotlin’s strengths.
Live Coding a Coding Agent and Practical Takeaways
The session features extensive live exploration, including attempts to generate a Snake game with requirements for Gradle, specific versions, compilation verification, and no mistakes. Successes and failures illustrate real-world agentic challenges: hallucinated tool calls, skipped verification steps, and the need for precise instructions. Anton shares that even with “make no mistakes” in the prompt, outcomes vary across models and runs.
The talk concludes with a repository of examples and reiterates Koog’s multi-platform nature, adapter support for various model providers, and the power of the strategy DSL. While 45 minutes cannot cover advanced topics, the presentation equips attendees with foundational knowledge to experiment with building JVM-native agents.
Code Sample: Basic Agent Setup in Koog (Kotlin)
val executor = OpenAI.promptExecutor { /* config */ }
val agent = Agent {
promptExecutor = executor
systemPrompt = "You are a helpful Kotlin developer..."
model = OpenAIModels.GPT_4O
tools = toolRegistry {
include(FileSystemProvider())
include(ShellExecutor())
}
}
agent.run("Write a Kotlin program to print Hello World")
Code Sample: Simple Strategy Graph
val strategy = strategy<String, Int> {
start forwardingTo parseNode forwardingTo incrementNode
}
val parseNode = node { input: String -> input.toInt() }
val incrementNode = node { input: Int -> input + 1 }
These examples capture the framework’s emphasis on readability and type-safe composition.
In summary, Anton Arhipov provides a grounded, pragmatic overview of constructing AI agents on the JVM. Koog enables developers to harness LLM capabilities within familiar Kotlin and JVM ecosystems, with the strategy DSL offering a powerful mechanism for controlling complexity. While challenges with model reliability persist—especially locally—the framework’s design promotes integration, reproducibility, and incremental improvement of agentic systems.