스프링 부트 통합
원문: Koog Documentation — spring-boot 이 글은 Koog 공식 문서의 spring-boot 페이지를 한국어로 옮긴 번역본입니다. 문서 구조와 링크 의미를 유지하되, MkDocs 전용 UI 문법은 블로그에서 읽기 좋도록 정리했습니다.
스프링 부트 통합
Koog는 자동 구성 스타터를 통해 원활한 Spring Boot 통합을 제공하므로 AI를 쉽게 통합할 수 있습니다. 최소한의 설정으로 에이전트를 Spring Boot 애플리케이션에 추가할 수 있습니다.
개요
koog-spring-boot-starter은 응용 프로그램 속성을 기반으로 LLM 클라이언트를 자동으로 구성하고 다음을 제공합니다.
종속성 주입을 위해 즉시 사용할 수 있는 Bean입니다. 다음을 포함한 모든 주요 LLM 제공업체를 지원합니다.
- 오픈AI
- 인류학
- 오픈라우터
- DeepSeek
- 미스트랄
- 올라마
시작하기
1. 의존성 추가
Gradle 빌드 구성에 Koog Spring Boot 스타터를 추가합니다.
1dependencies {2 implementation("ai.koog:koog-spring-boot-starter:$koogVersion")3}또는 메이븐의 경우
1<dependency>2 <groupId>ai.koog</groupId>3 <artifactId>koog-spring-boot-starter</artifactId>4 <version>$koogVersion</version>5</dependency>Kotlin 또는 자바 프로젝트에 다음이 있는지 확인하세요.
- Spring Boot 3(Java 17 이상이 필요함)
- 코틀린 버전 2.3.10+
- kotlinx-serialization 버전 1.10.0(즉, kotlinx-serialization-core-jvm 및 kotlinx-serialization-json-jvm)
2. 공급자 구성
application.properties에서 선호하는 LLM 제공업체를 구성하세요.
1## OpenAI Configuration2ai.koog.openai.enabled=true3ai.koog.openai.api-key=${OPENAI_API_KEY}4ai.koog.openai.base-url=https://api.openai.com5## Anthropic Configuration 6ai.koog.anthropic.enabled=true7ai.koog.anthropic.api-key=${ANTHROPIC_API_KEY}8ai.koog.anthropic.base-url=https://api.anthropic.com9## Google Configuration10ai.koog.google.enabled=true11ai.koog.google.api-key=${GOOGLE_API_KEY}12ai.koog.google.base-url=https://generativelanguage.googleapis.com13## OpenRouter Configuration14ai.koog.openrouter.enabled=true15ai.koog.openrouter.api-key=${OPENROUTER_API_KEY}16ai.koog.openrouter.base-url=https://openrouter.ai17## DeepSeek Configuration18ai.koog.deepseek.enabled=true19ai.koog.deepseek.api-key=${DEEPSEEK_API_KEY}20ai.koog.deepseek.base-url=https://api.deepseek.com21## Mistral Configuration22ai.koog.mistral.enabled=true23ai.koog.mistral.api-key=${MISTRALAI_API_KEY}24ai.koog.mistral.base-url=https://api.mistral.ai25## Ollama Configuration (local - no API key required)26ai.koog.ollama.enabled=true27ai.koog.ollama.base-url=http://127.0.0.1:11434또는 YAML 형식(application.yml) 사용:
1ai:2 koog:3 openai:4 enabled: true5 api-key: ${OPENAI_API_KEY}6 base-url: https://api.openai.com7 anthropic:8 enabled: true9 api-key: ${ANTHROPIC_API_KEY}10 base-url: https://api.anthropic.com11 google:12 enabled: true13 api-key: ${GOOGLE_API_KEY}14 base-url: https://generativelanguage.googleapis.com15 openrouter:16 enabled: true17 api-key: ${OPENROUTER_API_KEY}18 base-url: https://openrouter.ai19 deepseek:20 enabled: true21 api-key: ${DEEPSEEK_API_KEY}22 base-url: https://api.deepseek.com23 mistral:24 enabled: true25 api-key: ${MISTRALAI_API_KEY}26 base-url: https://api.mistral.ai27 ollama:28 enabled: true # Set it to `true` explicitly to activate !!!29 base-url: http://127.0.0.1:11434ai.koog.PROVIDER.api-key 및 ai.koog.PROVIDER.enabled 속성은 모두 공급자를 활성화하는 데 사용됩니다.
공급자가 API 키(예: OpenAI, Anthropic, Google)를 지원하는 경우 ai.koog.PROVIDER.enabled는 true로 설정됩니다.
기본적으로.
공급자가 Ollama와 같이 API Key를 지원하지 않는 경우 ai.koog.PROVIDER.enabled는 기본적으로 false으로 설정됩니다.
공급자는 애플리케이션 구성에서 명시적으로 활성화되어야 합니다.
공급자의 기본 URL은 Spring Boot 스타터에서 기본값으로 설정되어 있지만 신청.
참고: Environment Variables
API 키를 안전하게 유지하고 버전 제어를 방지하려면 환경 변수를 사용하는 것이 좋습니다.
Spring 구성은 LLM 공급자의 잘 알려진 환경 변수를 사용합니다.
예를 들어 OpenAI Spring 구성을 활성화하려면 환경 변수 OPENAI_API_KEY을 설정하는 것만으로도 충분합니다.
| LLM 제공업체 | 환경 변수 |
|---|---|
| 개방형 AI | OPENAI_API_KEY |
| 인류학 | ANTHROPIC_API_KEY |
GOOGLE_API_KEY |
|
| 오픈라우터 | OPENROUTER_API_KEY |
| DeepSeek | DEEPSEEK_API_KEY |
| 미스트랄 | MISTRALAI_API_KEY |
3. 프로젝트에 사용
다음은 Spring MVC RestController에서 자동으로 구성된 실행기의 사용 예입니다. 다음이 필요합니다.
- spring-boot-starter-web 의존성
- Kotlin의 경우 kotlinx-coroutines-core 및 kotlinx-coroutines-reactor 종속성을 추가해야 합니다(Java 버전 호출 차단
execute메서드). - Anthropic은 속성(ai.koog.anthropic.enabled=true)을 통해 활성화됩니다.
코틀린
1import ai.koog.prompt.dsl.prompt2import ai.koog.prompt.executor.clients.anthropic.AnthropicModels3import ai.koog.prompt.executor.model.PromptExecutor4import org.springframework.http.ResponseEntity5import org.springframework.web.bind.annotation.PostMapping6import org.springframework.web.bind.annotation.RequestBody7import org.springframework.web.bind.annotation.RequestMapping8import org.springframework.web.bind.annotation.RestController910@RestController11@RequestMapping("/api/chat")12class ChatController(private val anthropicExecutor: PromptExecutor) {1314 @PostMapping15 suspend fun chat(@RequestBody request: ChatRequest): ResponseEntity<ChatResponse> {16 return try {17 val prompt = prompt("chat") {18 system("You are a helpful assistant")19 user(request.message)20 }2122 val result = anthropicExecutor.execute(prompt, AnthropicModels.Haiku_4_5)23 ResponseEntity.ok(ChatResponse(result.first().content))24 } catch (e: Exception) {25 ResponseEntity.internalServerError()26 .body(ChatResponse("Error processing request"))27 }28 }29}3031data class ChatRequest(val message: String)32data class ChatResponse(val response: String)자바
1import ai.koog.prompt.dsl.Prompt;2import ai.koog.prompt.executor.clients.anthropic.AnthropicModels;3import ai.koog.prompt.executor.model.PromptExecutor;4import ai.koog.prompt.message.Message;5import org.springframework.http.ResponseEntity;6import org.springframework.web.bind.annotation.PostMapping;7import org.springframework.web.bind.annotation.RequestBody;8import org.springframework.web.bind.annotation.RequestMapping;9import org.springframework.web.bind.annotation.RestController;1011import java.util.List;1213@RestController14@RequestMapping("/api/chat")15public class ChatController {16 private final PromptExecutor anthropicExecutor;1718 public ChatController(PromptExecutor anthropicExecutor) {19 this.anthropicExecutor = anthropicExecutor;20 }2122 @PostMapping23 public ResponseEntity<ChatResponse> chat(@RequestBody ChatRequest request) {24 try {25 Prompt prompt = Prompt.builder("chat")26 .system("You are a helpful assistant")27 .user(request.message())28 .build();2930 List<Message.Response> result = anthropicExecutor.execute(prompt, AnthropicModels.Haiku_4_5);31 return ResponseEntity.ok(new ChatResponse(result.get(0).getContent()));32 } catch (Exception e) {33 return ResponseEntity.internalServerError()34 .body(new ChatResponse("Error processing request"));35 }36 }37}3839record ChatRequest(String message) {40}4142record ChatResponse(String response) {43}Spring Framework는 Bean 이름(anthropicExecutor)으로 Anthropic의 실행 프로그램을 주입했습니다.
그러나 @Qualifier 주석을 사용하여 여러 PromptExecutor 빈을 주입할 수도 있습니다(아래 "다중 빈 오류" 참조).
고급 사용법
LLM 공급자 대체
여러 LLM 공급자를 구성한 후 MultiLLMPromptExecutor을 통해 여러 LLM에 요청을 보낼 수 있습니다.
코틀린
1import ai.koog.prompt.dsl.prompt2import ai.koog.prompt.executor.clients.anthropic.AnthropicModels.Haiku_4_53import ai.koog.prompt.executor.clients.openai.OpenAIModels.Chat.GPT4oMini4import ai.koog.prompt.executor.clients.openrouter.OpenRouterModels.Claude3Haiku5import ai.koog.prompt.executor.llms.MultiLLMPromptExecutor6import org.slf4j.Logger7import org.slf4j.LoggerFactory8import org.springframework.stereotype.Service910@Service11class RobustAIService(private val multiLLMPromptExecutor: MultiLLMPromptExecutor) {1213 private val llms = listOf(GPT4oMini, Haiku_4_5, Claude3Haiku)1415 suspend fun generateWithFallback(input: String): String {16 val prompt = prompt("robust") {17 system("You are a helpful AI assistant")18 user(input)19 }2021 for (llm in llms) {22 try {23 val result = multiLLMPromptExecutor.execute(prompt, llm)24 return result.first().content25 } catch (e: Exception) {26 logger.warn("{} executor failed, trying next: {}", llm.id, e.message)27 }28 }2930 throw IllegalStateException("All AI providers failed")31 }3233 companion object {34 private val logger = LoggerFactory.getLogger(RobustAIService::class.java)35 }36}자바
1import ai.koog.prompt.dsl.Prompt;2import ai.koog.prompt.executor.clients.anthropic.AnthropicModels;3import ai.koog.prompt.executor.clients.openai.OpenAIModels;4import ai.koog.prompt.executor.clients.openrouter.OpenRouterModels;5import ai.koog.prompt.executor.llms.MultiLLMPromptExecutor;6import ai.koog.prompt.llm.LLModel;7import ai.koog.prompt.message.Message;8import org.slf4j.Logger;9import org.slf4j.LoggerFactory;10import org.springframework.stereotype.Service;1112import java.util.List;1314@Service15public class RobustAIService {16 private static final Logger logger = LoggerFactory.getLogger(RobustAIService.class);1718 private final List<LLModel> llms = List.of(OpenAIModels.Chat.GPT4oMini, AnthropicModels.Haiku_4_5, OpenRouterModels.Claude3Haiku);1920 private final MultiLLMPromptExecutor multiLLMPromptExecutor;2122 public RobustAIService(MultiLLMPromptExecutor multiLLMPromptExecutor) {23 this.multiLLMPromptExecutor = multiLLMPromptExecutor;24 }2526 public String generateWithFallback(String input) {27 Prompt prompt = Prompt.builder("robust")28 .system("You are a helpful AI assistant")29 .user(input)30 .build();3132 for (LLModel llm : llms) {33 try {34 List<Message.Response> result = multiLLMPromptExecutor.execute(prompt, llm);35 return result.get(0).getContent();36 } catch (Exception e) {37 logger.warn("{} executor failed, trying next: {}", llm.getId(), e.getMessage());38 }39 }4041 throw new IllegalStateException("All AI providers failed");42 }43}또한 자신의 MultiLLMPromptExecutor Bean을 등록하고 여기에 FallbackPromptExecutorSettings을 전달할 수도 있습니다.
Bean의 자동 구성을 무시하려면 @Primary 주석을 사용할 수 있습니다.
구성 참조
사용 가능한 속성
| 재산 | 설명 | 콩 상태 | 기본 |
|---|---|---|---|
ai.koog.openai.api-key |
OpenAI API 키 | openAIExecutor Bean에 필수 |
- |
ai.koog.openai.base-url |
OpenAI 기본 URL | 선택 과목 | https://api.openai.com |
ai.koog.anthropic.api-key |
인류 API 키 | anthropicExecutor Bean에 필수 |
- |
ai.koog.anthropic.base-url |
인류 기본 URL | 선택 과목 | https://api.anthropic.com |
ai.koog.google.api-key |
구글 API 키 | googleExecutor Bean에 필수 |
- |
ai.koog.google.base-url |
Google 기본 URL | 선택 과목 | https://generativelanguage.googleapis.com |
ai.koog.openrouter.api-key |
OpenRouter API 키 | openRouterExecutor Bean에 필수 |
- |
ai.koog.openrouter.base-url |
OpenRouter 기본 URL | 선택 과목 | https://openrouter.ai |
ai.koog.deepseek.api-key |
DeepSeek API 키 | deepSeekExecutor Bean에 필수 |
- |
ai.koog.deepseek.base-url |
DeepSeek 기본 URL | 선택 과목 | https://api.deepseek.com |
ai.koog.mistral.api-key |
미스트랄 API 키 | mistralAIExecutor Bean에 필수 |
- |
ai.koog.mistral.base-url |
미스트랄 기본 URL | 선택 과목 | https://api.mistral.ai |
ai.koog.ollama.base-url |
올라마 기본 URL | 선택 과목 | http://127.0.0.1:11434 |
콩 이름
자동 구성은 다음 빈을 생성합니다(구성된 경우).
openAIExecutor- OpenAI 실행기(ai.koog.openai.api-key필요)anthropicExecutor- 인류 집행자(ai.koog.anthropic.api-key필요)googleExecutor- Google 실행자(ai.koog.google.api-key필요)openRouterExecutor- OpenRouter 실행자(ai.koog.openrouter.api-key필요)deepSeekExecutor- DeepSeek 실행자(ai.koog.deepseek.api-key필요)mistralAIExecutor- 미스트랄 AI 실행자(ai.koog.mistral.api-key필요)ollamaExecutor- Ollama 집행자(ai.koog.ollama.enabled=true필요)multiLLMPromptExecutor- MultiLLMPromptExecutor
문제 해결
일반적인 문제
오류: 'PromptExecutor' 유형의 적격 Bean을 사용할 수 없습니다
해결책: 속성 파일에 공급자를 하나 이상 구성했는지 확인하세요.
오류: 'PromptExecutor' 유형의 여러 적격 Bean을 사용할 수 있음
해결책: @Qualifier을 사용하여 원하는 Bean을 지정하십시오.
코틀린
1@Service2class MyService(3 @Qualifier("openAIExecutor") private val openAIExecutor: PromptExecutor,4 @Qualifier("anthropicExecutor") private val anthropicExecutor: PromptExecutor5) {6 // ...7}자바
1@Service2public class MyService {3 private final PromptExecutor openAIExecutor;4 private final PromptExecutor anthropicExecutor;56 public MyService(@Qualifier("openAIExecutor") PromptExecutor openAIExecutor,7 @Qualifier("anthropicExecutor") PromptExecutor anthropicExecutor) {8 this.openAIExecutor = openAIExecutor;9 this.anthropicExecutor = anthropicExecutor;10 }11 // ...12}오류: API 키가 필요하지만 제공되지 않음
해결책: 환경 변수가 올바르게 설정되어 있고 Spring Boot 애플리케이션에 액세스할 수 있는지 확인하세요.
모범 사례
- 환경 변수: API 키에는 항상 환경 변수를 사용합니다.
- Nullable 주입: Nullable 유형을 사용하여 공급자가 구성되지 않은 경우를 처리합니다.
- 대체 로직: 여러 공급자를 사용할 때 대체 메커니즘 구현
- 오류 처리: 항상 프로덕션 코드의 try-catch 블록에 실행기 호출을 래핑합니다.
- 테스팅: 실제 API 호출을 피하기 위해 테스트에서 모의 객체를 사용하세요.
- 구성 유효성 검사: 실행기를 사용하기 전에 사용 가능한지 확인하세요.
다음 단계
- 최소한의 AI 워크플로를 구축하기 위한 basic agents에 대해 알아보세요.
- 고급 사용 사례에 대해 graph-based agents 살펴보기
- 에이전트의 기능을 확장하려면 tools overview을 참조하세요.
- 실제 구현을 보려면 examples을 확인하세요.
- 프레임워크를 더 잘 이해하려면 glossary을 읽어보세요.