Agent 与自动化
3.0 · 值得看
Introducing Koog Integration for Spring AI: Smarter Orchestration for Your Agents
Introducing Koog Integration for Spring AI: Smarter Orchestration for Your Agents
Introducing Koog Integration for Spring AI: Smarter Orchestration for Your Agents
ChatModel, ChatMemoryRepository, and VectorStore. Adding Koog on top is just a three-step process. Step 1: Keep your existing Spring AI dependencies. Plain text Copy to clipboard Open code in new window EnlighterJS 3 Syntax Highlighter // LLM implementation("org.springframework.ai:spring-ai-starter-model-openai") // Chat memory implementation("org.springframework.ai:spring-ai-starter-model-chat-memory-repository-jdbc") // Vector store implementation("org.springframework.ai:spring-ai-starter-vector-store-pgvector") // LLM implementation("org.springframework.ai:spring-ai-starter-model-openai") // Chat memory implementation("org.springframework.ai:spring-ai-starter-model-chat-memory-repository-jdbc") // Vector store implementation("org.springframework.ai:spring-ai-starter-vector-store-pgvector") // LLM implementation("org.springframework.ai:spring-ai-starter-model-openai") // Chat memory implementation("org.springframework.ai:spring-ai-starter-model-chat-memory-repository-jdbc") // Vector store implementation("org.springframework.ai:spring-ai-starter-vector-store-pgvector") Step 2: Add the Koog integration dependencies. Plain text Copy to clipboard Open code in new window EnlighterJS 3 Syntax Highlighter // Koog implementation("ai.koog:koog-agents-jvm:0.8.0") // Bridges ChatModel to Koog's LLMClient / PromptExecutor implementation("ai.koog:koog-spring-ai-starter-model-chat:0.8.0") // Bridges ChatMemoryRepository to Koog's ChatHistoryProvider implementation("ai.koog:koog-spring-ai-starter-chat-memory:0.8.0") // Bridges VectorStore to Koog's KoogVectorStore implementation("ai.koog:koog-spring-ai-starter-vector-store:0.8.0") // Koog implementation("ai.koog:koog-agents-jvm:0.8.0") // Bridges ChatModel to Koog's LLMClient / PromptExecutor implementation("ai.koog:koog-spring-ai-starter-model-chat:0.8.0") // Bridges ChatMemoryRepository to Koog's ChatHistoryProvider implementation("ai.koog:koog-spring-ai-starter-chat-memory:0.8.0") // Bridges VectorStore to Koog's KoogVectorStore implementation("ai.koog:koog-spring-ai-starter-vector-store:0.8.0") // Koog implementation("ai.koog:koog-agents-jvm:0.8.0") // Bridges ChatModel to Koog's LLMClient / PromptExecutor implementation("ai.koog:koog-spring-ai-starter-model-chat:0.8.0") // Bridges ChatMemoryRepository to Koog's ChatHistoryProvider implementation("ai.koog:koog-spring-ai-starter-chat-memory:0.8.0") // Bridges VectorStore to Koog's KoogVectorStore implementation("ai.koog:koog-spring-ai-starter-vector-store:0.8.0") Step 3: Use the auto-configured Koog beans. Each Koog starter automatically exposes a Spring bean that wraps your existing Spring AI bean: Spring AI interface Koog bean(s) ChatModel PromptExecutor, LLMClient ChatMemoryRepository ChatHistoryProvider VectorStore KoogVectorStore The beans are auto-configured by default when there is a single matching Spring AI candidate, so your existing Spring AI application config stays untouched. That’s it for setup. Now let’s walk through what you can build. To make things concrete, we’ll use a customer support agent as our running example and progressively add capabilities. ## When a pure Spring AI agent reaches its limitCopy heading link One version of an agent that you could build in pure Spring AI would look like this: Plain text Copy to clipboard Open code in new window EnlighterJS 3 Syntax Highlighter @Service class CustomerSupportService( chatClientBuilder: ChatClient.Builder, vectorStore: VectorStore, chatMemory: ChatMemory, ) { // Build a fully configured ChatClient once at construction time private val chatClient: ChatClient = chatClientBuilder .defaultSystem(""" You are an e-commerce support assistant. Be concise and policy-aware. Never invent order data. If order context is missing for an order-specific request, ask for it. """.trimIndent()) .defaultAdvisors( // Vector store RAG advisor - enriches every prompt with relevant docs QuestionAnswerAdvisor( vectorStore, SearchRequest.builder() .topK(4) .similarityThreshold(0.7) .build() ), // Sliding-window chat memory advisor - keeps last N turns per session MessageChatMemoryAdvisor(chatMemory) ) .build() suspend fun createAndRunAgent(userPrompt: String, sessionId: String): String? = chatClient.prompt() .user(userPrompt) // Scope memory to session .advisorParam(ChatMemory.CONVERSATION\_ID, sessionId) .call() .tools() .content() } @Service class CustomerSupportService( chatClientBuilder: ChatClient.Builder, vectorStore: VectorStore, chatMemory: ChatMemory, ) { // Build a fully configured ChatClient once at construction time private val chatClient: ChatClient = chatClientBuilder .defaultSystem(""" You are an e-commerce support assistant. Be concise and policy-aware. Never invent order data. If order context is missing for an order-specific request, ask for it. """.trimIndent()) .defaultAdvisors( // Vector store RAG advisor - enriches every prompt with relevant docs QuestionAnswerAdvisor( vectorStore, SearchRequest.builder() .topK(4) .similarityThreshold(0.7) .build() ), // Sliding-window chat memory advisor - keeps last N turns per session MessageChatMemoryAdvisor(chatMemory) ) .build() suspend fun createAndRunAgent(userPrompt: String, sessionId: String): String? = chatClient.prompt() .user(userPrompt) // Scope memory to session .advisorParam(ChatMemory.CONVERSATION\_ID, sessionId) .call() .tools() .content() } @Service class CustomerSupportService( chatClientBuilder: ChatClient.Builder, vectorStore: VectorStore, chatMemory: ChatMemory, ) { // Build a fully configured ChatClient once at construction time private val chatClient: ChatClient = chatClientBuilder .defaultSystem(""" You are an e-commerce support assistant. Be concise and policy-aware. Never invent order data. If order context is missing for an order-specific request, ask for it. """.trimIndent()) .defaultAdvisors( // Vector store RAG advisor - enriches every prompt with relevant docs QuestionAnswerAdvisor( vectorStore, SearchRequest.builder() .topK(4) .similarityThreshold(0.7) .build() ), // Sliding-window chat memory advisor - keeps last N turns per session MessageChatMemoryAdvisor(chatMemory) ) .build() suspend fun createAndRunAgent(userPrompt: String, sessionId: String): String? = chatClient.prompt() .user(userPrompt) // Scope memory to session .advisorParam(ChatMemory.CONVERSATION\_ID, sessionId) .call() .tools() .content() } This agent implements a simple tool-calling loop that runs on top of the LLM defined in the config and inserted as a ChatClient. Besides this, the agent has two features. The first is QuestionAnswerAdvisor, which is built on top of VectorStore and behaves like RAG, enriching the conversation with relevant information from external docs. The second is ChatMemory, which keeps only a specified number of messages, helping you control the number of messages in a conversation and save tokens. But what if we don’t want a window of messages but a message history summary instead? Or, increasing complexity, what if, instead of a primitive tool-calling agentic loop, we wanted a more controllable and tailored strategy with different e-commerce support scenarios, or persistence and durable execution to make our agent fault-tolerant? This is where we reach the limits of Spring AI. But these, and many other agentic features, already exist in Koog and, thanks to the integration, they can easily be built on top of what you’ve already set up for Spring AI in your project. ## What does Koog’s Spring AI integration enable?Copy heading link First of all, this is what our e-commerce agent would look like in Koog. Plain text Copy to clipboard Open code in new window EnlighterJS 3 Syntax Highlighter @Service class CustomerSupportService( private val promptExecutor: PromptExecutor, private val chatStorage: ChatHistoryProvider, private val knowledgeBase: SearchStorage ) { suspend fun createAndRunAgent(userPrompt: String): String { val agentConfig = AIAgentConfig( prompt = prompt("ecommerce-support") { system( """ You are an e-commerce support assistant. Be concise and policy-aware. Never invent order data. If order context is missing for an order-specific request, ask for it. """.trimIndent() ) }, model = OpenAIModels.Chat.GPT5Nano, maxAgentIterations = 100 ) val toolRegistry = ToolRegistry { tools(EcommerceSupportTools()) } val agent = AIAgent( promptExecutor = promptExecutor, agentConfig = agentConfig, toolRegistry = toolRegistry, // Simple tool-calling loop strategy strategy = singeRunStrategy() ) { // Vector store RAG advisor - enriches every prompt with relevant docs install(LongTermMemory) { retrieval { storage = knowledgeBase searchStrategy = SimilaritySearchStrategy( topK = 4, similarityThreshold = 0.70 ) promptAugmenter = UserPromptAugmenter() } } // Sliding-window chat memory advisor - keeps last N turns per session install(ChatMemory) { chatHistoryProvider = chatStorage windowSize(20) } } return agent.run(userPrompt) } } @Service class CustomerSupportService( private val promptExecutor: PromptExecutor, private val chatStorage: ChatHistoryProvider, private val knowledgeBase: SearchStorage ) { suspend fun createAndRunAgent(userPrompt: String): String { val agentConfig = AIAgentConfig( prompt = prompt("ecommerce-support") { system( """ You are an e-commerce support assistant. Be concise and policy-aware. Never invent order data. If order context is missing for an order-specific request, ask for it. """.trimIndent() ) }, model = OpenAIModels.Chat.GPT5Nano, maxAgentIterations = 100 ) val toolRegistry = ToolRegistry { tools(EcommerceSupportTools()) } val agent = AIAgent( promptExecutor = promptExecutor, agentConfig = agentConfig, toolRegistry = toolRegistry, // Simple tool-calling loop strategy strategy = singeRunStrategy() ) { // Vector store RAG advisor - enriches every prompt with relevant docs install(LongTermMemory) { retrieval { storage = knowledgeBase searchStrategy = SimilaritySearchStrategy( topK = 4, similarityThreshold = 0.70 ) promptAugmenter = UserPromptAugmenter() } } // Sliding-window chat memory advisor - keeps last N turns per session install(ChatMemory) { chatHistoryProvider = chatStorage windowSize(20) } } return agent.run(userPrompt) } } @Service class CustomerSupportService( private val promptExecutor: PromptExecutor, private val chatStorage: ChatHistoryProvider, private val knowledgeBase: SearchStoraChatModel, ChatMemoryRepository, and VectorStore. Adding Koog on top is just a three-step process. Step 1: Keep your existing Spring AI dependencies. Plain text Copy to clipboard Open code in new window EnlighterJS 3 Syntax Highlighter // LLM implementation("org.springframework.ai:spring-ai-starter-model-openai") // Chat memory implementation("org.springframework.ai:spring-ai-starter-model-chat-memory-repository-jdbc") // Vector store implementation("org.springframework.ai:spring-ai-starter-vector-store-pgvector") // LLM implementation("org.springframework.ai:spring-ai-starter-model-openai") // Chat memory implementation("org.springframework.ai:spring-ai-starter-model-chat-memory-repository-jdbc") // Vector store implementation("org.springframework.ai:spring-ai-starter-vector-store-pgvector") // LLM implementation("org.springframework.ai:spring-ai-starter-model-openai") // Chat memory implementation("org.springframework.ai:spring-ai-starter-model-chat-memory-repository-jdbc") // Vector store implementation("org.springframework.ai:spring-ai-starter-vector-store-pgvector") Step 2: Add the Koog integration dependencies. Plain text Copy to clipboard Open code in new window EnlighterJS 3 Syntax Highlighter // Koog implementation("ai.koog:koog-agents-jvm:0.8.0") // Bridges ChatModel to Koog's LLMClient / PromptExecutor implementation("ai.koog:koog-spring-ai-starter-model-chat:0.8.0") // Bridges ChatMemoryRepository to Koog's ChatHistoryProvider implementation("ai.koog:koog-spring-ai-starter-chat-memory:0.8.0") // Bridges VectorStore to Koog's KoogVectorStore implementation("ai.koog:koog-spring-ai-starter-vector-store:0.8.0") // Koog implementation("ai.koog:koog-agents-jvm:0.8.0") // Bridges ChatModel to Koog's LLMClient / PromptExecutor implementation("ai.koog:koog-spring-ai-starter-model-chat:0.8.0") // Bridges ChatMemoryRepository to Koog's ChatHistoryProvider implementation("ai.koog:koog-spring-ai-starter-chat-memory:0.8.0") // Bridges VectorStore to Koog's KoogVectorStore implementation("ai.koog:koog-spring-ai-starter-vector-store:0.8.0") // Koog implementation("ai.koog:koog-agents-jvm:0.8.0") // Bridges ChatModel to Koog's LLMClient / PromptExecutor implementation("ai.koog:koog-spring-ai-starter-model-chat:0.8.0") // Bridges ChatMemoryRepository to Koog's ChatHistoryProvider implementation("ai.koog:koog-spring-ai-starter-chat-memory:0.8.0") // Bridges VectorStore to Koog's KoogVectorStore implementation("ai.koog:koog-spring-ai-starter-vector-store:0.8.0") Step 3: Use the auto-configured Koog beans. Each Koog starter automatically exposes a Spring bean that wraps your existing Spring AI bean: Spring AI interface Koog bean(s) ChatModel PromptExecutor, LLMClient ChatMemoryRepository ChatHistoryProvider VectorStore KoogVectorStore The beans are auto-configured by default when there is a single matching Spring AI candidate, so your existing Spring AI application config stays untouched. That’s it for setup. Now let’s walk through what you can build. To make things concrete, we’ll use a customer support agent as our running example and progressively add capabilities. ## When a pure Spring AI agent reaches its limitCopy heading link One version of an agent that you could build in pure Spring AI would look like this: Plain text Copy to clipboard Open code in new window EnlighterJS 3 Syntax Highlighter @Service class CustomerSupportService( chatClientBuilder: ChatClient.Builder, vectorStore: VectorStore, chatMemory: ChatMemory, ) { // Build a fully configured ChatClient once at construction time private val chatClient: ChatClient = chatClientBuilder .defaultSystem(""" You are an e-commerce support assistant. Be concise and policy-aware. Never invent order data. If order context is missing for an order-specific request, ask for it. """.trimIndent()) .defaultAdvisors( // Vector store RAG advisor - enriches every prompt with relevant docs QuestionAnswerAdvisor( vectorStore, SearchRequest.builder() .topK(4) .similarityThreshold(0.7) .build() ), // Sliding-window chat memory advisor - keeps last N turns per session MessageChatMemoryAdvisor(chatMemory) ) .build() suspend fun createAndRunAgent(userPrompt: String, sessionId: String): String? = chatClient.prompt() .user(userPrompt) // Scope memory to session .advisorParam(ChatMemory.CONVERSATION\_ID, sessionId) .call() .tools() .content() } @Service class CustomerSupportService( chatClientBuilder: ChatClient.Builder, vectorStore: VectorStore, chatMemory: ChatMemory, ) { // Build a fully configured ChatClient once at construction time private val chatClient: ChatClient = chatClientBuilder .defaultSystem(""" You are an e-commerce support assistant. Be concise and policy-aware. Never invent order data. If order context is missing for an order-specific request, ask for it. """.trimIndent()) .defaultAdvisors( // Vector store RAG advisor - enriches every prompt with relevant docs QuestionAnswerAdvisor( vectorStore, SearchRequest.builder() .topK(4) .similarityThreshold(0.7) .build() ), // Sliding-window chat memory advisor - keeps last N turns per session MessageChatMemoryAdvisor(chatMemory) ) .build() suspend fun createAndRunAgent(userPrompt: String, sessionId: String): String? = chatClient.prompt() .user(userPrompt) // Scope memory to session .advisorParam(ChatMemory.CONVERSATION\_ID, sessionId) .call() .tools() .content() } @Service class CustomerSupportService( chatClientBuilder: ChatClient.Builder, vectorStore: VectorStore, chatMemory: ChatMemory, ) { // Build a fully configured ChatClient once at construction time private val chatClient: ChatClient = chatClientBuilder .defaultSystem(""" You are an e-commerce support assistant. Be concise and policy-aware. Never invent order data. If order context is missing for an order-specific request, ask for it. """.trimIndent()) .defaultAdvisors( // Vector store RAG advisor - enriches every prompt with relevant docs QuestionAnswerAdvisor( vectorStore, SearchRequest.builder() .topK(4) .similarityThreshold(0.7) .build() ), // Sliding-window chat memory advisor - keeps last N turns per session MessageChatMemoryAdvisor(chatMemory) ) .build() suspend fun createAndRunAgent(userPrompt: String, sessionId: String): String? = chatClient.prompt() .user(userPrompt) // Scope memory to session .advisorParam(ChatMemory.CONVERSATION\_ID, sessionId) .call() .tools() .content() } This agent implements a simple tool-calling loop that runs on top of the LLM defined in the config and inserted as a ChatClient. Besides this, the agent has two features. The first is QuestionAnswerAdvisor, which is built on top of VectorStore and behaves like RAG, enriching the conversation with relevant information from external docs. The second is ChatMemory, which keeps only a specified number of messages, helping you control the number of messages in a conversation and save tokens. But what if we don’t want a window of messages but a message history summary instead? Or, increasing complexity, what if, instead of a primitive tool-calling agentic loop, we wanted a more controllable and tailored strategy with different e-commerce support scenarios, or persistence and durable execution to make our agent fault-tolerant? This is where we reach the limits of Spring AI. But these, and many other agentic features, already exist in Koog and, thanks to the integration, they can easily be built on top of what you’ve already set up for Spring AI in your project. ## What does Koog’s Spring AI integration enable?Copy heading link First of all, this is what our e-commerce agent would look like in Koog. Plain text Copy to clipboard Open code in new window EnlighterJS 3 Syntax Highlighter @Service class CustomerSupportService( private val promptExecutor: PromptExecutor, private val chatStorage: ChatHistoryProvider, private val knowledgeBase: SearchStorage ) { suspend fun createAndRunAgent(userPrompt: String): String { val agentConfig = AIAgentConfig( prompt = prompt("ecommerce-support") { system( """ You are an e-commerce support assistant. Be concise and policy-aware. Never invent order data. If order context is missing for an order-specific request, ask for it. """.trimIndent() ) }, model = OpenAIModels.Chat.GPT5Nano, maxAgentIterations = 100 ) val toolRegistry = ToolRegistry { tools(EcommerceSupportTools()) } val agent = AIAgent( promptExecutor = promptExecutor, agentConfig = agentConfig, toolRegistry = toolRegistry, // Simple tool-calling loop strategy strategy = singeRunStrategy() ) { // Vector store RAG advisor - enriches every prompt with relevant docs install(LongTermMemory) { retrieval { storage = knowledgeBase searchStrategy = SimilaritySearchStrategy( topK = 4, similarityThreshold = 0.70 ) promptAugmenter = UserPromptAugmenter() } } // Sliding-window chat memory advisor - keeps last N turns per session install(ChatMemory) { chatHistoryProvider = chatStorage windowSize(20) } } return agent.run(userPrompt) } } @Service class CustomerSupportService( private val promptExecutor: PromptExecutor, private val chatStorage: ChatHistoryProvider, private val knowledgeBase: SearchStorage ) { suspend fun createAndRunAgent(userPrompt: String): String { val agentConfig = AIAgentConfig( prompt = prompt("ecommerce-support") { system( """ You are an e-commerce support assistant. Be concise and policy-aware. Never invent order data. If order context is missing for an order-specific request, ask for it. """.trimIndent() ) }, model = OpenAIModels.Chat.GPT5Nano, maxAgentIterations = 100 ) val toolRegistry = ToolRegistry { tools(EcommerceSupportTools()) } val agent = AIAgent( promptExecutor = promptExecutor, agentConfig = agentConfig, toolRegistry = toolRegistry, // Simple tool-calling loop strategy strategy = singeRunStrategy() ) { // Vector store RAG advisor - enriches every prompt with relevant docs install(LongTermMemory) { retrieval { storage = knowledgeBase searchStrategy = SimilaritySearchStrategy( topK = 4, similarityThreshold = 0.70 ) promptAugmenter = UserPromptAugmenter() } } // Sliding-window chat memory advisor - keeps last N turns per session install(ChatMemory) { chatHistoryProvider = chatStorage windowSize(20) } } return agent.run(userPrompt) } } @Service class CustomerSupportService( private val promptExecutor: PromptExecutor, private val chatStorage: ChatHistoryProvider, private val knowledgeBase: SearchStora