A sample e-commerce customer-support agent built with Koog and
Spring AI, demonstrating how to run a Koog AIAgent on top of a Spring AI ChatModel
(here backed by a local Ollama instance).
Koog is a Dutch word for a polder — a tract of low-lying land reclaimed from the sea. Kwel is the Dutch word for the groundwater that seeps up and springs through reclaimed polder land.
- Docker — required to run the example. The supporting services (PostgreSQL with pgvector and Ollama)
are started automatically via Spring Boot Docker Compose (see
compose.yml). - A JDK matching the Gradle toolchain configured in
build.gradle.kts.
Two Ollama models must be available before running the application:
nomic-embed-text— used for embeddings (vector store / long-term memory).qwen2.5:7b-instruct-q4_K_M— used for chat.
Pull them into your Ollama instance, for example:
ollama pull nomic-embed-text
ollama pull qwen2.5:7b-instruct-q4_K_M./gradlew bootRunThen send a chat request to the running application (see ChatController).
Send a POST request to the /customerSupport endpoint with a JSON body containing a prompt:
curl -X POST http://localhost:8080/customerSupport \
-H "Content-Type: application/json" \
-d '{
"prompt": "My order 84721 hasn'\''t arrived yet. Where is it?"
}'The application responds with a JSON body containing the agent's reply:
{
"response": "..."
}SpringAiChatOptionsConfigworkaround. Spring AI providerChatModelimplementations (e.g.OllamaChatModel) hard-cast the prompt's runtimeChatOptionsto their own provider-specific type (OllamaChatOptions), while Koog'sSpringAiLLMClientbuilds provider-agnostic options (DefaultChatOptions/ToolCallingChatOptions). This causes aClassCastExceptionat request time. TheChatOptionsCustomizerbean registered inSpringAiChatOptionsConfigconverts the generic options intoOllamaChatOptionsas a workaround. This is a known issue and the bean can be removed once it is addressed upstream.