Ktor 통합: Koog 플러그인

·3분 읽기

원문: Koog Documentation — ktor-plugin 이 글은 Koog 공식 문서의 ktor-plugin 페이지를 한국어로 옮긴 번역본입니다. 문서 구조와 링크 의미를 유지하되, MkDocs 전용 UI 문법은 블로그에서 읽기 좋도록 정리했습니다.

Ktor 통합: Koog 플러그인

Koog는 Ktor 서버에 자연스럽게 적응하므로 양쪽에서 이념적 Kotlin API를 사용하여 서버 측 AI 애플리케이션을 작성할 수 있습니다.

Koog 플러그인을 한 번 설치하고 application.conf/YAML 또는 코드에서 LLM 공급자를 구성한 다음 경로에서 바로 에이전트를 호출하세요. 더 이상 모듈 간에 LLM 클라이언트를 연결할 필요가 없습니다. 경로가 에이전트를 요청하면 바로 사용할 수 있습니다.

개요

koog-ktor 모듈은 서버측 에이전트 개발을 위한 관용적인 Kotlin/Ktor 통합을 제공합니다.

  • 드롭인 Ktor 플러그인: 애플리케이션의 install(Koog)
  • OpenAI, Anthropic, Google, OpenRouter, DeepSeek 및 Ollama에 대한 최고 수준의 지원
  • YAML/CONF 및/또는 코드를 통한 중앙 집중식 구성
  • 프롬프트, 도구, 기능을 갖춘 에이전트 설정 경로에 대한 간단한 확장 기능
  • 직접 LLM 사용(실행, ExecuteStreaming, 보통)
  • JVM 전용 MCP(Model Context Protocol) 도구 통합

종속성 추가

1dependencies {2    implementation("ai.koog:koog-ktor:$koogVersion")3}

빠른 시작

  1. 공급자 구성(application.yaml 또는 application.conf)

koog.<provider> 아래에 중첩된 키를 사용합니다. 플러그인이 자동으로 이를 선택합니다.

1## application.yaml (Ktor config)2koog:3  openai:4    apikey: ${OPENAI_API_KEY}5    baseUrl: https://api.openai.com6  anthropic:7    apikey: ${ANTHROPIC_API_KEY}8    baseUrl: https://api.anthropic.com9  google:10    apikey: ${GOOGLE_API_KEY}11    baseUrl: https://generativelanguage.googleapis.com12  openrouter:13    apikey: ${OPENROUTER_API_KEY}14    baseUrl: https://openrouter.ai15  deepseek:16    apikey: ${DEEPSEEK_API_KEY}17    baseUrl: https://api.deepseek.com18  # Ollama is enabled when any koog.ollama.* key exists19  ollama:20    enable: true21    baseUrl: http://localhost:11434

선택 사항: 요청된 공급자가 구성되지 않은 경우 직접 LLM 호출에 사용되는 대체를 구성합니다.

1koog:2  llm:3    fallback:4      provider: openai5      # see Model identifiers section below6      model: openai.chat.gpt4_1
  1. 플러그인 설치 및 경로 정의
1fun Application.module() {2    install(Koog) {3        // You can also configure providers programmatically (see below)4    }56    routing {7        route("/ai") {8            post("/chat") {9                val userInput = call.receiveText()10                // Create and run a default single‑run agent using a specific model11                val output = aiAgent(12                    strategy = reActStrategy(),13                    model = OpenAIModels.Chat.GPT4_1,14                    input = userInput15                )16                call.respond(HttpStatusCode.OK, output)17            }18        }19    }20}

메모

  • aiAgent에는 구체적인 모델(LLModel)이 필요합니다. 경로별, 사용별로 선택하세요.
  • 하위 수준 LLM 액세스의 경우 llm()(PromptExecutor)을 직접 사용하세요.

경로에서 직접 LLM 사용

1post("/llm-chat") {2    val userInput = call.receiveText()34    val messages = llm().execute(5        prompt("chat") {6            system("You are a helpful assistant that clarifies questions")7            user(userInput)8        },9        GoogleModels.Gemini2_5Pro10    )1112    // Join all assistant messages into a single string13    val text = messages.joinToString(separator = "") { it.content }14    call.respond(HttpStatusCode.OK, text)15}

스트리밍

1get("/stream") {2    val flow = llm().executeStreaming(3        prompt("streaming") { user("Stream this response, please") },4        OpenRouterModels.GPT4o5    )67    // Example: buffer and send as one chunk8    val sb = StringBuilder()9    flow.collect { chunk -> sb.append(chunk) }10    call.respondText(sb.toString())11}

절도

1post("/moderated-chat") {2    val userInput = call.receiveText()34    val moderation = llm().moderate(5        prompt("moderation") { user(userInput) },6        OpenAIModels.Moderation.Omni7    )89    if (moderation.isHarmful) {10        call.respond(HttpStatusCode.BadRequest, "Harmful content detected")11        return@post12    }1314    val output = aiAgent(15        strategy = reActStrategy(),16        model = OpenAIModels.Chat.GPT4_1,17        input = userInput18    )19    call.respond(HttpStatusCode.OK, output)20}

프로그래밍 방식 구성(코드 내)

모든 공급자와 에이전트 동작은 install(Koog) {}를 통해 구성할 수 있습니다.

1install(Koog) {2    llm {3        openAI(apiKey = System.getenv("OPENAI_API_KEY") ?: "") {4            baseUrl = "https://api.openai.com"5            timeouts { // Default values shown below6                requestTimeout = 15.minutes7                connectTimeout = 60.seconds8                socketTimeout = 15.minutes9            }10        }11        anthropic(apiKey = System.getenv("ANTHROPIC_API_KEY") ?: "")12        google(apiKey = System.getenv("GOOGLE_API_KEY") ?: "")13        openRouter(apiKey = System.getenv("OPENROUTER_API_KEY") ?: "")14        deepSeek(apiKey = System.getenv("DEEPSEEK_API_KEY") ?: "")15        ollama { baseUrl = "http://localhost:11434" }1617        // Optional fallback used by PromptExecutor when a provider isn’t configured18        fallback {19            provider = LLMProvider.OpenAI20            model = OpenAIModels.Chat.GPT4_121        }22    }2324    agentConfig {25        // Provide a reusable base prompt for your agents26        prompt(name = "agent") {27            system("You are a helpful server‑side agent")28        }2930        // Limit runaway tools/loops31        maxAgentIterations = 103233        // Register tools available to agents by default34        registerTools {35            // tool(::yourTool) // see Tools Overview for details36        }3738        // Install agent features (tracing, etc.)39        // install(OpenTelemetry) { /* ... */ }40    }41}

구성의 모델 식별자(대체)

YAML/CONF에서 llm.fallback을 구성할 때 다음 식별자 형식을 사용하십시오.

  • OpenAI: openai.chat.gpt4_1, openai.reasoning.o3, openai.costoptimized.gpt4_1mini, openai.audio.gpt4oaudio, openai.moderation.omni
  • 인류학: anthropic.sonnet_4_5, anthropic.opus_4, anthropic.haiku_4_5
  • 구글: google.gemini2_5pro, google.gemini2_0flash001
  • 오픈라우터: openrouter.gpt4o, openrouter.gpt4, openrouter.claude3sonnet
  • DeepSeek: deepseek.deepseek-chat, deepseek.deepseek-reasoner
  • Ollama: ollama.meta.llama3.2, ollama.alibaba.qwq:32b, ollama.groq.llama3-grok-tool-use:8b

메모

  • OpenAI의 경우 카테고리(채팅, 추론, 비용 최적화, 오디오, 임베딩, 중재)를 포함해야 합니다.
  • Ollama의 경우 ollama.model과 ollama..이 모두 지원됩니다.

MCP 도구(JVM 전용)

JVM에서는 MCP 서버의 도구를 에이전트 도구 레지스트리에 추가할 수 있습니다.

1install(Koog) {2    agentConfig {3        mcp {4            // Register via SSE5            sse("https://your-mcp-server.com/sse")67            // Or register via spawned process (stdio transport)8            // process(Runtime.getRuntime().exec("your-mcp-binary ..."))910            // Or from an existing MCP client instance11            // client(existingMcpClient)12        }13    }14}

왜 Koog + Ktor인가?

  • 서버에서 Kotlin 최초의 유형 안전 에이전트 개발
  • 깔끔하고 테스트 가능한 경로 코드를 갖춘 중앙 집중식 구성
  • 경로별로 올바른 모델을 사용하거나 직접 LLM 호출을 위해 자동으로 대체
  • 프로덕션에 즉시 사용 가능한 기능: 도구, 조정, 스트리밍 및 추적