{"repo": "binarytape/open-aidoc", "files": {"docs/ko/koog/ktor-plugin.md": {"5508b3a594cf366b2856a33998d454a290d5e964": {"t": 1785746492.037125, "n": 6691, "h": "1ca6797758fe2afe", "c": "---\nstatus: beta\n---\n\n# Ktor 통합: Koog 플러그인\n\n--8<-- \"versioning-snippets.md:beta\"\n\nKoog는 Ktor 서버에 자연스럽게 통합되어, 양측 모두에서 관용적인(idiomatic) Kotlin API를 사용하여 서버 사이드 AI 애플리케이션을 작성할 수 있게 해줍니다.\n\nKoog 플러그인을 한 번 설치하고, `application.conf`/`YAML` 또는 코드에서 LLM 제공자(provider)를 설정한 다음 라우트(route)에서 바로 에이전트를 호출하세요. 더 이상 모듈 간에 LLM 클라이언트를 복잡하게 연결할 필요가 없습니다. 라우트에서 에이전트를 요청하기만 하면 바로 사용할 준비가 됩니다.\n\n## 개요\n\n`koog-ktor` 모듈은 서버 사이드 에이전트(agentic) 개발을 위한 관용적인 Kotlin/Ktor 통합 기능을 제공합니다.\n\n- 바로 사용 가능한 Ktor 플러그인: Application에서 `install(Koog)` 호출\n- OpenAI, Anthropic, Google, OpenRouter, DeepSeek, Ollama에 대한 최고 수준의 지원\n- YAML/CONF 및 코드를 통한 중앙 집중식 설정\n- 프롬프트, 도구, 기능을 포함한 에이전트 설정 및 라우트를 위한 간단한 확장 함수\n- 직접적인 LLM 사용 (`execute`, `executeStreaming`, `moderate`)\n- JVM 전용 MCP(Model Context Protocol) 도구 통합\n\n## 의존성 추가\n\n```kotlin\ndependencies {\n implementation(\"ai.koog:koog-ktor:$koogVersion\")\n}\n```\n\n## 빠른 시작\n\n1) 제공자 설정 (`application.yaml` 또는 `application.conf`)\n\n`koog.` 아래의 중첩된 키를 사용하세요. 플러그인이 자동으로 이를 인식합니다.\n\n```yaml\n# application.yaml (Ktor 설정)\nkoog:\n openai:\n apikey: ${OPENAI_API_KEY}\n baseUrl: https://api.openai.com\n anthropic:\n apikey: ${ANTHROPIC_API_KEY}\n baseUrl: https://api.anthropic.com\n google:\n apikey: ${GOOGLE_API_KEY}\n baseUrl: https://generativelanguage.googleapis.com\n openrouter:\n apikey: ${OPENROUTER_API_KEY}\n baseUrl: https://openrouter.ai\n deepseek:\n apikey: ${DEEPSEEK_API_KEY}\n baseUrl: https://api.deepseek.com\n # koog.ollama.* 키가 존재하면 Ollama가 활성화됩니다.\n ollama:\n enable: true\n baseUrl: http://localhost:11434\n```\n\n선택 사항: 요청된 제공자가 설정되지 않았을 때 직접 LLM 호출에서 사용할 폴백(fallback)을 설정합니다.\n\n```yaml\nkoog:\n llm:\n fallback:\n provider: openai\n # 아래의 모델 식별자 섹션을 참조하세요.\n model: openai.chat.gpt4_1\n```\n\n2) 플러그인 설치 및 라우트 정의\n\n```kotlin\nfun Application.module() {\n install(Koog) {\n // 프로그래밍 방식으로 제공자를 설정할 수도 있습니다 (아래 참조)\n }\n\n routing {\n route(\"/ai\") {\n post(\"/chat\") {\n val userInput = call.receiveText()\n // 특정 모델을 사용하여 기본 단일 실행 에이전트를 생성하고 실행합니다.\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n }\n }\n }\n}\n```\n\n참고\n\n- `aiAgent`는 구체적인 모델(`LLModel`)이 필요합니다. 라우트별 또는 용도별로 선택하세요.\n- 더 낮은 수준의 LLM 액세스가 필요한 경우, `llm()`(`PromptExecutor`)을 직접 사용하세요.\n\n## 라우트에서 직접 LLM 사용\n\n```kotlin\npost(\"/llm-chat\") {\n val userInput = call.receiveText()\n\n val messages = llm().execute(\n prompt(\"chat\") {\n system(\"You are a helpful assistant that clarifies questions\")\n user(userInput)\n },\n GoogleModels.Gemini2_5Pro\n )\n\n // 모든 어시스턴트 메시지를 하나의 문자열로 결합합니다.\n val text = messages.joinToString(separator = \"\n\") { it.content }\n call.respond(HttpStatusCode.OK, text)\n}\n```\n\n스트리밍(Streaming)\n\n```kotlin\nget(\"/stream\") {\n val flow = llm().executeStreaming(\n prompt(\"streaming\") { user(\"Stream this response, please\") },\n OpenRouterModels.GPT4o\n )\n\n // 예시: 버퍼링 후 하나의 청크로 전송\n val sb = StringBuilder()\n flow.collect { chunk -> sb.append(chunk) }\n call.respondText(sb.toString())\n}\n```\n\n모데레이션(Moderation)\n\n```kotlin\npost(\"/moderated-chat\") {\n val userInput = call.receiveText()\n\n val moderation = llm().moderate(\n prompt(\"moderation\") { user(userInput) },\n OpenAIModels.Moderation.Omni\n )\n\n if (moderation.isHarmful) {\n call.respond(HttpStatusCode.BadRequest, \"Harmful content detected\")\n return@post\n }\n\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n}\n```\n\n## 프로그래밍 방식 설정 (코드 내)\n\n모든 제공자와 에이전트 동작은 `install(Koog) {}`를 통해 설정할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n llm {\n openAI(apiKey = System.getenv(\"OPENAI_API_KEY\") ?: \"\") {\n baseUrl = \"https://api.openai.com\"\n timeouts { // 아래는 기본값입니다.\n requestTimeout = 15.minutes\n connectTimeout = 60.seconds\n socketTimeout = 15.minutes\n }\n }\n anthropic(apiKey = System.getenv(\"ANTHROPIC_API_KEY\") ?: \"\")\n google(apiKey = System.getenv(\"GOOGLE_API_KEY\") ?: \"\")\n openRouter(apiKey = System.getenv(\"OPENROUTER_API_KEY\") ?: \"\")\n deepSeek(apiKey = System.getenv(\"DEEPSEEK_API_KEY\") ?: \"\")\n ollama { baseUrl = \"http://localhost:11434\" }\n\n // 제공자가 설정되지 않았을 때 PromptExecutor에서 사용할 선택적 폴백\n fallback {\n provider = LLMProvider.OpenAI\n model = OpenAIModels.Chat.GPT4_1\n }\n }\n\n agentConfig {\n // 에이전트를 위한 재사용 가능한 기본 프롬프트 제공\n prompt(name = \"agent\") {\n system(\"You are a helpful server‑side agent\")\n }\n\n // 무한 도구 호출/루프 제한\n maxAgentIterations = 10\n\n // 에이전트가 기본적으로 사용할 수 있는 도구 등록\n registerTools {\n // tool(::yourTool) // 자세한 내용은 도구 개요를 참조하세요.\n }\n\n // 에이전트 기능 설치 (트레이싱 등)\n // install(OpenTelemetry) { /* ... */ }\n }\n}\n```\n\n## 설정 내 모델 식별자 (폴백)\n\nYAML/CONF에서 `llm.fallback`을 설정할 때 다음 식별자 형식을 사용하세요.\n\n- OpenAI: `openai.chat.gpt4_1`, `openai.reasoning.o3`, `openai.costoptimized.gpt4_1mini`, `openai.audio.gpt4oaudio`, `openai.moderation.omni`\n- Anthropic: `anthropic.fable_5`, `anthropic.sonnet_4_5`, `anthropic.opus_4`, `anthropic.haiku_4_5`\n- Google: `google.gemini2_5pro`, `google.gemini2_0flash001`\n- OpenRouter: `openrouter.gpt4o`, `openrouter.gpt4`, `openrouter.claude3sonnet`\n- DeepSeek: `deepseek.deepseek-v4-flash`, `deepseek.deepseek-v4-pro`, `deepseek.deepseek-chat`, `deepseek.deepseek-reasoner`\n- Ollama: `ollama.meta.llama3.2`, `ollama.alibaba.qwq:32b`, `ollama.groq.llama3-grok-tool-use:8b`\n\n참고\n\n- OpenAI의 경우 반드시 카테고리(`chat`, `reasoning`, `costoptimized`, `audio`, `embeddings`, `moderation`)를 포함해야 합니다.\n- Ollama의 경우 `ollama.model` 및 `ollama..` 형식을 모두 지원합니다.\n\n## MCP 도구 (JVM 전용)\n\nJVM에서는 MCP 서버의 도구를 에이전트 도구 레지스트리에 추가할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n agentConfig {\n mcp {\n // SSE를 통해 등록\n sse(\"https://your-mcp-server.com/sse\")\n\n // 또는 생성된 프로세스를 통해 등록 (stdio 전송)\n // process(Runtime.getRuntime().exec(\"your-mcp-binary ...\"))\n\n // 또는 기존 MCP 클라이언트 인스턴스에서 등록\n // client(existingMcpClient)\n }\n }\n}\n```\n## 왜 Koog + Ktor인가요?\n\n- 서버에서 에이전트를 개발하기 위한 Kotlin 우선의 타입 안전한 환경\n- 깔끔하고 테스트 가능한 라우트 코드와 중앙 집중식 설정\n- 라우트별로 적합한 모델을 사용하거나, 직접 LLM 호출 시 자동으로 폴백 적용\n- 도구(tools), 모데레이션(moderation), 스트리밍(streaming), 트레이싱(tracing) 등 프로덕션 환경에 적합한 기능 제공"}, "fac66c6f7442c17423e3420a8d143c16c28f7d70": {"t": 1785764911.144884, "n": 6691, "h": "1ca6797758fe2afe", "c": "---\nstatus: beta\n---\n\n# Ktor 통합: Koog 플러그인\n\n--8<-- \"versioning-snippets.md:beta\"\n\nKoog는 Ktor 서버에 자연스럽게 통합되어, 양측 모두에서 관용적인(idiomatic) Kotlin API를 사용하여 서버 사이드 AI 애플리케이션을 작성할 수 있게 해줍니다.\n\nKoog 플러그인을 한 번 설치하고, `application.conf`/`YAML` 또는 코드에서 LLM 제공자(provider)를 설정한 다음 라우트(route)에서 바로 에이전트를 호출하세요. 더 이상 모듈 간에 LLM 클라이언트를 복잡하게 연결할 필요가 없습니다. 라우트에서 에이전트를 요청하기만 하면 바로 사용할 준비가 됩니다.\n\n## 개요\n\n`koog-ktor` 모듈은 서버 사이드 에이전트(agentic) 개발을 위한 관용적인 Kotlin/Ktor 통합 기능을 제공합니다.\n\n- 바로 사용 가능한 Ktor 플러그인: Application에서 `install(Koog)` 호출\n- OpenAI, Anthropic, Google, OpenRouter, DeepSeek, Ollama에 대한 최고 수준의 지원\n- YAML/CONF 및 코드를 통한 중앙 집중식 설정\n- 프롬프트, 도구, 기능을 포함한 에이전트 설정 및 라우트를 위한 간단한 확장 함수\n- 직접적인 LLM 사용 (`execute`, `executeStreaming`, `moderate`)\n- JVM 전용 MCP(Model Context Protocol) 도구 통합\n\n## 의존성 추가\n\n```kotlin\ndependencies {\n implementation(\"ai.koog:koog-ktor:$koogVersion\")\n}\n```\n\n## 빠른 시작\n\n1) 제공자 설정 (`application.yaml` 또는 `application.conf`)\n\n`koog.` 아래의 중첩된 키를 사용하세요. 플러그인이 자동으로 이를 인식합니다.\n\n```yaml\n# application.yaml (Ktor 설정)\nkoog:\n openai:\n apikey: ${OPENAI_API_KEY}\n baseUrl: https://api.openai.com\n anthropic:\n apikey: ${ANTHROPIC_API_KEY}\n baseUrl: https://api.anthropic.com\n google:\n apikey: ${GOOGLE_API_KEY}\n baseUrl: https://generativelanguage.googleapis.com\n openrouter:\n apikey: ${OPENROUTER_API_KEY}\n baseUrl: https://openrouter.ai\n deepseek:\n apikey: ${DEEPSEEK_API_KEY}\n baseUrl: https://api.deepseek.com\n # koog.ollama.* 키가 존재하면 Ollama가 활성화됩니다.\n ollama:\n enable: true\n baseUrl: http://localhost:11434\n```\n\n선택 사항: 요청된 제공자가 설정되지 않았을 때 직접 LLM 호출에서 사용할 폴백(fallback)을 설정합니다.\n\n```yaml\nkoog:\n llm:\n fallback:\n provider: openai\n # 아래의 모델 식별자 섹션을 참조하세요.\n model: openai.chat.gpt4_1\n```\n\n2) 플러그인 설치 및 라우트 정의\n\n```kotlin\nfun Application.module() {\n install(Koog) {\n // 프로그래밍 방식으로 제공자를 설정할 수도 있습니다 (아래 참조)\n }\n\n routing {\n route(\"/ai\") {\n post(\"/chat\") {\n val userInput = call.receiveText()\n // 특정 모델을 사용하여 기본 단일 실행 에이전트를 생성하고 실행합니다.\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n }\n }\n }\n}\n```\n\n참고\n\n- `aiAgent`는 구체적인 모델(`LLModel`)이 필요합니다. 라우트별 또는 용도별로 선택하세요.\n- 더 낮은 수준의 LLM 액세스가 필요한 경우, `llm()`(`PromptExecutor`)을 직접 사용하세요.\n\n## 라우트에서 직접 LLM 사용\n\n```kotlin\npost(\"/llm-chat\") {\n val userInput = call.receiveText()\n\n val messages = llm().execute(\n prompt(\"chat\") {\n system(\"You are a helpful assistant that clarifies questions\")\n user(userInput)\n },\n GoogleModels.Gemini2_5Pro\n )\n\n // 모든 어시스턴트 메시지를 하나의 문자열로 결합합니다.\n val text = messages.joinToString(separator = \"\n\") { it.content }\n call.respond(HttpStatusCode.OK, text)\n}\n```\n\n스트리밍(Streaming)\n\n```kotlin\nget(\"/stream\") {\n val flow = llm().executeStreaming(\n prompt(\"streaming\") { user(\"Stream this response, please\") },\n OpenRouterModels.GPT4o\n )\n\n // 예시: 버퍼링 후 하나의 청크로 전송\n val sb = StringBuilder()\n flow.collect { chunk -> sb.append(chunk) }\n call.respondText(sb.toString())\n}\n```\n\n모데레이션(Moderation)\n\n```kotlin\npost(\"/moderated-chat\") {\n val userInput = call.receiveText()\n\n val moderation = llm().moderate(\n prompt(\"moderation\") { user(userInput) },\n OpenAIModels.Moderation.Omni\n )\n\n if (moderation.isHarmful) {\n call.respond(HttpStatusCode.BadRequest, \"Harmful content detected\")\n return@post\n }\n\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n}\n```\n\n## 프로그래밍 방식 설정 (코드 내)\n\n모든 제공자와 에이전트 동작은 `install(Koog) {}`를 통해 설정할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n llm {\n openAI(apiKey = System.getenv(\"OPENAI_API_KEY\") ?: \"\") {\n baseUrl = \"https://api.openai.com\"\n timeouts { // 아래는 기본값입니다.\n requestTimeout = 15.minutes\n connectTimeout = 60.seconds\n socketTimeout = 15.minutes\n }\n }\n anthropic(apiKey = System.getenv(\"ANTHROPIC_API_KEY\") ?: \"\")\n google(apiKey = System.getenv(\"GOOGLE_API_KEY\") ?: \"\")\n openRouter(apiKey = System.getenv(\"OPENROUTER_API_KEY\") ?: \"\")\n deepSeek(apiKey = System.getenv(\"DEEPSEEK_API_KEY\") ?: \"\")\n ollama { baseUrl = \"http://localhost:11434\" }\n\n // 제공자가 설정되지 않았을 때 PromptExecutor에서 사용할 선택적 폴백\n fallback {\n provider = LLMProvider.OpenAI\n model = OpenAIModels.Chat.GPT4_1\n }\n }\n\n agentConfig {\n // 에이전트를 위한 재사용 가능한 기본 프롬프트 제공\n prompt(name = \"agent\") {\n system(\"You are a helpful server‑side agent\")\n }\n\n // 무한 도구 호출/루프 제한\n maxAgentIterations = 10\n\n // 에이전트가 기본적으로 사용할 수 있는 도구 등록\n registerTools {\n // tool(::yourTool) // 자세한 내용은 도구 개요를 참조하세요.\n }\n\n // 에이전트 기능 설치 (트레이싱 등)\n // install(OpenTelemetry) { /* ... */ }\n }\n}\n```\n\n## 설정 내 모델 식별자 (폴백)\n\nYAML/CONF에서 `llm.fallback`을 설정할 때 다음 식별자 형식을 사용하세요.\n\n- OpenAI: `openai.chat.gpt4_1`, `openai.reasoning.o3`, `openai.costoptimized.gpt4_1mini`, `openai.audio.gpt4oaudio`, `openai.moderation.omni`\n- Anthropic: `anthropic.fable_5`, `anthropic.sonnet_4_5`, `anthropic.opus_4`, `anthropic.haiku_4_5`\n- Google: `google.gemini2_5pro`, `google.gemini2_0flash001`\n- OpenRouter: `openrouter.gpt4o`, `openrouter.gpt4`, `openrouter.claude3sonnet`\n- DeepSeek: `deepseek.deepseek-v4-flash`, `deepseek.deepseek-v4-pro`, `deepseek.deepseek-chat`, `deepseek.deepseek-reasoner`\n- Ollama: `ollama.meta.llama3.2`, `ollama.alibaba.qwq:32b`, `ollama.groq.llama3-grok-tool-use:8b`\n\n참고\n\n- OpenAI의 경우 반드시 카테고리(`chat`, `reasoning`, `costoptimized`, `audio`, `embeddings`, `moderation`)를 포함해야 합니다.\n- Ollama의 경우 `ollama.model` 및 `ollama..` 형식을 모두 지원합니다.\n\n## MCP 도구 (JVM 전용)\n\nJVM에서는 MCP 서버의 도구를 에이전트 도구 레지스트리에 추가할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n agentConfig {\n mcp {\n // SSE를 통해 등록\n sse(\"https://your-mcp-server.com/sse\")\n\n // 또는 생성된 프로세스를 통해 등록 (stdio 전송)\n // process(Runtime.getRuntime().exec(\"your-mcp-binary ...\"))\n\n // 또는 기존 MCP 클라이언트 인스턴스에서 등록\n // client(existingMcpClient)\n }\n }\n}\n```\n## 왜 Koog + Ktor인가요?\n\n- 서버에서 에이전트를 개발하기 위한 Kotlin 우선의 타입 안전한 환경\n- 깔끔하고 테스트 가능한 라우트 코드와 중앙 집중식 설정\n- 라우트별로 적합한 모델을 사용하거나, 직접 LLM 호출 시 자동으로 폴백 적용\n- 도구(tools), 모데레이션(moderation), 스트리밍(streaming), 트레이싱(tracing) 등 프로덕션 환경에 적합한 기능 제공"}, "a1df25630ddaff52f6d6609cd36b0f5d164ceb13": {"t": 1785764912.9612806, "n": 6670, "h": "f46753bd3cb8dc3e", "c": "---\nstatus: beta\n---\n\n# Ktor 통합: Koog 플러그인\n\n--8<-- \"versioning-snippets.md:beta\"\n\nKoog는 Ktor 서버에 자연스럽게 통합되어, 양측 모두에서 관용적인(idiomatic) Kotlin API를 사용하여 서버 사이드 AI 애플리케이션을 작성할 수 있게 해줍니다.\n\nKoog 플러그인을 한 번 설치하고, `application.conf`/`YAML` 또는 코드에서 LLM 제공자(provider)를 설정한 다음 라우트(route)에서 바로 에이전트를 호출하세요. 더 이상 모듈 간에 LLM 클라이언트를 복잡하게 연결할 필요가 없습니다. 라우트에서 에이전트를 요청하기만 하면 바로 사용할 준비가 됩니다.\n\n## 개요\n\n`koog-ktor` 모듈은 서버 사이드 에이전트(agentic) 개발을 위한 관용적인 Kotlin/Ktor 통합 기능을 제공합니다.\n\n- 바로 사용 가능한 Ktor 플러그인: Application에서 `install(Koog)` 호출\n- OpenAI, Anthropic, Google, OpenRouter, DeepSeek, Ollama에 대한 최고 수준의 지원\n- YAML/CONF 및 코드를 통한 중앙 집중식 설정\n- 프롬프트, 도구, 기능을 포함한 에이전트 설정 및 라우트를 위한 간단한 확장 함수\n- 직접적인 LLM 사용 (`execute`, `executeStreaming`, `moderate`)\n- JVM 전용 MCP(Model Context Protocol) 도구 통합\n\n## 의존성 추가\n\n```kotlin\ndependencies {\n implementation(\"ai.koog:koog-ktor:$koogVersion\")\n}\n```\n\n## 빠른 시작\n\n1) 제공자 설정 (`application.yaml` 또는 `application.conf`)\n\n`koog.` 아래의 중첩된 키를 사용하세요. 플러그인이 자동으로 이를 인식합니다.\n\n```yaml\n# application.yaml (Ktor 설정)\nkoog:\n openai:\n apikey: ${OPENAI_API_KEY}\n baseUrl: https://api.openai.com\n anthropic:\n apikey: ${ANTHROPIC_API_KEY}\n baseUrl: https://api.anthropic.com\n google:\n apikey: ${GOOGLE_API_KEY}\n baseUrl: https://generativelanguage.googleapis.com\n openrouter:\n apikey: ${OPENROUTER_API_KEY}\n baseUrl: https://openrouter.ai\n deepseek:\n apikey: ${DEEPSEEK_API_KEY}\n baseUrl: https://api.deepseek.com\n # koog.ollama.* 키가 존재하면 Ollama가 활성화됩니다.\n ollama:\n enable: true\n baseUrl: http://localhost:11434\n```\n\n선택 사항: 요청된 제공자가 설정되지 않았을 때 직접 LLM 호출에서 사용할 폴백(fallback)을 설정합니다.\n\n```yaml\nkoog:\n llm:\n fallback:\n provider: openai\n # 아래의 모델 식별자 섹션을 참조하세요.\n model: openai.chat.gpt4_1\n```\n\n2) 플러그인 설치 및 라우트 정의\n\n```kotlin\nfun Application.module() {\n install(Koog) {\n // 프로그래밍 방식으로 제공자를 설정할 수도 있습니다 (아래 참조)\n }\n\n routing {\n route(\"/ai\") {\n post(\"/chat\") {\n val userInput = call.receiveText()\n // 특정 모델을 사용하여 기본 단일 실행 에이전트를 생성하고 실행합니다.\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n }\n }\n }\n}\n```\n\n참고\n\n- `aiAgent`는 구체적인 모델(`LLModel`)이 필요합니다. 라우트별 또는 용도별로 선택하세요.\n- 더 낮은 수준의 LLM 액세스가 필요한 경우, `llm()`(`PromptExecutor`)을 직접 사용하세요.\n\n## 라우트에서 직접 LLM 사용\n\n```kotlin\npost(\"/llm-chat\") {\n val userInput = call.receiveText()\n\n val messages = llm().execute(\n prompt(\"chat\") {\n system(\"You are a helpful assistant that clarifies questions\")\n user(userInput)\n },\n GoogleModels.Gemini2_5Pro\n )\n\n // 모든 어시스턴트 메시지를 하나의 문자열로 결합합니다.\n val text = messages.joinToString(separator = \"\n\") { it.content }\n call.respond(HttpStatusCode.OK, text)\n}\n```\n\n스트리밍(Streaming)\n\n```kotlin\nget(\"/stream\") {\n val flow = llm().executeStreaming(\n prompt(\"streaming\") { user(\"Stream this response, please\") },\n OpenRouterModels.GPT4o\n )\n\n // 예시: 버퍼링 후 하나의 청크로 전송\n val sb = StringBuilder()\n flow.collect { chunk -> sb.append(chunk) }\n call.respondText(sb.toString())\n}\n```\n\n모데레이션(Moderation)\n\n```kotlin\npost(\"/moderated-chat\") {\n val userInput = call.receiveText()\n\n val moderation = llm().moderate(\n prompt(\"moderation\") { user(userInput) },\n OpenAIModels.Moderation.Omni\n )\n\n if (moderation.isHarmful) {\n call.respond(HttpStatusCode.BadRequest, \"Harmful content detected\")\n return@post\n }\n\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n}\n```\n\n## 프로그래밍 방식 설정 (코드 내)\n\n모든 제공자와 에이전트 동작은 `install(Koog) {}`를 통해 설정할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n llm {\n openAI(apiKey = System.getenv(\"OPENAI_API_KEY\") ?: \"\") {\n baseUrl = \"https://api.openai.com\"\n timeouts { // 아래는 기본값입니다.\n requestTimeout = 15.minutes\n connectTimeout = 60.seconds\n socketTimeout = 15.minutes\n }\n }\n anthropic(apiKey = System.getenv(\"ANTHROPIC_API_KEY\") ?: \"\")\n google(apiKey = System.getenv(\"GOOGLE_API_KEY\") ?: \"\")\n openRouter(apiKey = System.getenv(\"OPENROUTER_API_KEY\") ?: \"\")\n deepSeek(apiKey = System.getenv(\"DEEPSEEK_API_KEY\") ?: \"\")\n ollama { baseUrl = \"http://localhost:11434\" }\n\n // 제공자가 설정되지 않았을 때 PromptExecutor에서 사용할 선택적 폴백\n fallback {\n provider = LLMProvider.OpenAI\n model = OpenAIModels.Chat.GPT4_1\n }\n }\n\n agentConfig {\n // 에이전트를 위한 재사용 가능한 기본 프롬프트 제공\n prompt(name = \"agent\") {\n system(\"You are a helpful server‑side agent\")\n }\n\n // 무한 도구 호출/루프 제한\n maxAgentIterations = 10\n\n // 에이전트가 기본적으로 사용할 수 있는 도구 등록\n registerTools {\n // tool(::yourTool) // 자세한 내용은 도구 개요를 참조하세요.\n }\n\n // 에이전트 기능 설치 (트레이싱 등)\n // install(OpenTelemetry) { /* ... */ }\n }\n}\n```\n\n## 설정 내 모델 식별자 (폴백)\n\nYAML/CONF에서 `llm.fallback`을 설정할 때 다음 식별자 형식을 사용하세요.\n\n- OpenAI: `openai.chat.gpt4_1`, `openai.reasoning.o3`, `openai.costoptimized.gpt4_1mini`, `openai.audio.gpt4oaudio`, `openai.moderation.omni`\n- Anthropic: `anthropic.sonnet_4_5`, `anthropic.opus_4`, `anthropic.haiku_4_5`\n- Google: `google.gemini2_5pro`, `google.gemini2_0flash001`\n- OpenRouter: `openrouter.gpt4o`, `openrouter.gpt4`, `openrouter.claude3sonnet`\n- DeepSeek: `deepseek.deepseek-v4-flash`, `deepseek.deepseek-v4-pro`, `deepseek.deepseek-chat`, `deepseek.deepseek-reasoner`\n- Ollama: `ollama.meta.llama3.2`, `ollama.alibaba.qwq:32b`, `ollama.groq.llama3-grok-tool-use:8b`\n\n참고\n\n- OpenAI의 경우 반드시 카테고리(`chat`, `reasoning`, `costoptimized`, `audio`, `embeddings`, `moderation`)를 포함해야 합니다.\n- Ollama의 경우 `ollama.model` 및 `ollama..` 형식을 모두 지원합니다.\n\n## MCP 도구 (JVM 전용)\n\nJVM에서는 MCP 서버의 도구를 에이전트 도구 레지스트리에 추가할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n agentConfig {\n mcp {\n // SSE를 통해 등록\n sse(\"https://your-mcp-server.com/sse\")\n\n // 또는 생성된 프로세스를 통해 등록 (stdio 전송)\n // process(Runtime.getRuntime().exec(\"your-mcp-binary ...\"))\n\n // 또는 기존 MCP 클라이언트 인스턴스에서 등록\n // client(existingMcpClient)\n }\n }\n}\n```\n## 왜 Koog + Ktor인가요?\n\n- 서버에서 에이전트를 개발하기 위한 Kotlin 우선의 타입 안전한 환경\n- 깔끔하고 테스트 가능한 라우트 코드와 중앙 집중식 설정\n- 라우트별로 적합한 모델을 사용하거나, 직접 LLM 호출 시 자동으로 폴백 적용\n- 도구(tools), 모데레이션(moderation), 스트리밍(streaming), 트레이싱(tracing) 등 프로덕션 환경에 적합한 기능 제공"}, "b729cbe040f2a5acdc0425c420b5abb484cf3cb3": {"t": 1785764914.3935072, "n": 6601, "h": "b026f9f3aaee9b6a", "c": "# Ktor 통합: Koog 플러그인\n\nKoog는 Ktor 서버에 자연스럽게 통합되어, 양측 모두에서 관용적인(idiomatic) Kotlin API를 사용하여 서버 사이드 AI 애플리케이션을 작성할 수 있게 해줍니다.\n\nKoog 플러그인을 한 번 설치하고, `application.conf`/`YAML` 또는 코드에서 LLM 제공자(provider)를 설정한 다음 라우트(route)에서 바로 에이전트를 호출하세요. 더 이상 모듈 간에 LLM 클라이언트를 복잡하게 연결할 필요가 없습니다. 라우트에서 에이전트를 요청하기만 하면 바로 사용할 준비가 됩니다.\n\n## 개요\n\n`koog-ktor` 모듈은 서버 사이드 에이전트 개발을 위한 관용적인 Kotlin/Ktor 통합 기능을 제공합니다.\n\n- 바로 사용 가능한 Ktor 플러그인: Application에서 `install(Koog)` 호출\n- OpenAI, Anthropic, Google, OpenRouter, DeepSeek, Ollama에 대한 최고 수준의 지원\n- YAML/CONF 및 코드를 통한 중앙 집중식 설정\n- 프롬프트, 도구, 기능을 포함한 에이전트 설정 및 라우트를 위한 간단한 확장 함수\n- 직접적인 LLM 사용 (`execute`, `executeStreaming`, `moderate`)\n- JVM 전용 MCP(Model Context Protocol) 도구 통합\n\n## 의존성 추가\n\n```kotlin\ndependencies {\n implementation(\"ai.koog:koog-ktor:$koogVersion\")\n}\n```\n\n## 빠른 시작\n\n1) 제공자 설정 (`application.yaml` 또는 `application.conf`)\n\n`koog.` 아래의 중첩된 키를 사용하세요. 플러그인이 자동으로 이를 인식합니다.\n\n```yaml\n# application.yaml (Ktor 설정)\nkoog:\n openai:\n apikey: ${OPENAI_API_KEY}\n baseUrl: https://api.openai.com\n anthropic:\n apikey: ${ANTHROPIC_API_KEY}\n baseUrl: https://api.anthropic.com\n google:\n apikey: ${GOOGLE_API_KEY}\n baseUrl: https://generativelanguage.googleapis.com\n openrouter:\n apikey: ${OPENROUTER_API_KEY}\n baseUrl: https://openrouter.ai\n deepseek:\n apikey: ${DEEPSEEK_API_KEY}\n baseUrl: https://api.deepseek.com\n # koog.ollama.* 키가 존재하면 Ollama가 활성화됩니다.\n ollama:\n enable: true\n baseUrl: http://localhost:11434\n```\n\n선택 사항: 요청된 제공자가 설정되지 않았을 때 직접 LLM 호출에서 사용할 폴백(fallback)을 설정합니다.\n\n```yaml\nkoog:\n llm:\n fallback:\n provider: openai\n # 아래의 모델 식별자 섹션을 참조하세요.\n model: openai.chat.gpt4_1\n```\n\n2) 플러그인 설치 및 라우트 정의\n\n```kotlin\nfun Application.module() {\n install(Koog) {\n // 프로그래밍 방식으로 제공자를 설정할 수도 있습니다 (아래 참조)\n }\n\n routing {\n route(\"/ai\") {\n post(\"/chat\") {\n val userInput = call.receiveText()\n // 특정 모델을 사용하여 기본 단일 실행 에이전트를 생성하고 실행합니다.\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n }\n }\n }\n}\n```\n\n참고\n\n- `aiAgent`는 구체적인 모델(`LLModel`)이 필요합니다. 라우트별 또는 용도별로 선택하세요.\n- 더 낮은 수준의 LLM 액세스가 필요한 경우, `llm()`(`PromptExecutor`)을 직접 사용하세요.\n\n## 라우트에서 직접 LLM 사용\n\n```kotlin\npost(\"/llm-chat\") {\n val userInput = call.receiveText()\n\n val messages = llm().execute(\n prompt(\"chat\") {\n system(\"You are a helpful assistant that clarifies questions\")\n user(userInput)\n },\n GoogleModels.Gemini2_5Pro\n )\n\n // 모든 어시스턴트 메시지를 하나의 문자열로 결합합니다.\n val text = messages.joinToString(separator = \"\n\") { it.content }\n call.respond(HttpStatusCode.OK, text)\n}\n```\n\n스트리밍(Streaming)\n\n```kotlin\nget(\"/stream\") {\n val flow = llm().executeStreaming(\n prompt(\"streaming\") { user(\"Stream this response, please\") },\n OpenRouterModels.GPT4o\n )\n\n // 예시: 버퍼링 후 하나의 청크로 전송\n val sb = StringBuilder()\n flow.collect { chunk -> sb.append(chunk) }\n call.respondText(sb.toString())\n}\n```\n\n모데레이션(Moderation)\n\n```kotlin\npost(\"/moderated-chat\") {\n val userInput = call.receiveText()\n\n val moderation = llm().moderate(\n prompt(\"moderation\") { user(userInput) },\n OpenAIModels.Moderation.Omni\n )\n\n if (moderation.isHarmful) {\n call.respond(HttpStatusCode.BadRequest, \"Harmful content detected\")\n return@post\n }\n\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n}\n```\n\n## 프로그래밍 방식 설정 (코드 내)\n\n모든 제공자와 에이전트 동작은 `install(Koog) {}`를 통해 설정할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n llm {\n openAI(apiKey = System.getenv(\"OPENAI_API_KEY\") ?: \"\") {\n baseUrl = \"https://api.openai.com\"\n timeouts { // 아래는 기본값입니다.\n requestTimeout = 15.minutes\n connectTimeout = 60.seconds\n socketTimeout = 15.minutes\n }\n }\n anthropic(apiKey = System.getenv(\"ANTHROPIC_API_KEY\") ?: \"\")\n google(apiKey = System.getenv(\"GOOGLE_API_KEY\") ?: \"\")\n openRouter(apiKey = System.getenv(\"OPENROUTER_API_KEY\") ?: \"\")\n deepSeek(apiKey = System.getenv(\"DEEPSEEK_API_KEY\") ?: \"\")\n ollama { baseUrl = \"http://localhost:11434\" }\n\n // 제공자가 설정되지 않았을 때 PromptExecutor에서 사용할 선택적 폴백\n fallback {\n provider = LLMProvider.OpenAI\n model = OpenAIModels.Chat.GPT4_1\n }\n }\n\n agentConfig {\n // 에이전트를 위한 재사용 가능한 기본 프롬프트 제공\n prompt(name = \"agent\") {\n system(\"You are a helpful server‑side agent\")\n }\n\n // 무한 도구 호출/루프 제한\n maxAgentIterations = 10\n\n // 에이전트가 기본적으로 사용할 수 있는 도구 등록\n registerTools {\n // tool(::yourTool) // 자세한 내용은 도구 개요를 참조하세요.\n }\n\n // 에이전트 기능 설치 (트레이싱 등)\n // install(OpenTelemetry) { /* ... */ }\n }\n}\n```\n\n## 설정 내 모델 식별자 (폴백)\n\nYAML/CONF에서 `llm.fallback`을 설정할 때 다음 식별자 형식을 사용하세요.\n\n- OpenAI: `openai.chat.gpt4_1`, `openai.reasoning.o3`, `openai.costoptimized.gpt4_1mini`, `openai.audio.gpt4oaudio`, `openai.moderation.omni`\n- Anthropic: `anthropic.sonnet_4_5`, `anthropic.opus_4`, `anthropic.haiku_4_5`\n- Google: `google.gemini2_5pro`, `google.gemini2_0flash001`\n- OpenRouter: `openrouter.gpt4o`, `openrouter.gpt4`, `openrouter.claude3sonnet`\n- DeepSeek: `deepseek.deepseek-v4-flash`, `deepseek.deepseek-v4-pro`, `deepseek.deepseek-chat`, `deepseek.deepseek-reasoner`\n- Ollama: `ollama.meta.llama3.2`, `ollama.alibaba.qwq:32b`, `ollama.groq.llama3-grok-tool-use:8b`\n\n참고\n\n- OpenAI의 경우 반드시 카테고리(`chat`, `reasoning`, `costoptimized`, `audio`, `embeddings`, `moderation`)를 포함해야 합니다.\n- Ollama의 경우 `ollama.model` 및 `ollama..` 형식을 모두 지원합니다.\n\n## MCP 도구 (JVM 전용)\n\nJVM에서는 MCP 서버의 도구를 에이전트 도구 레지스트리에 추가할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n agentConfig {\n mcp {\n // SSE를 통해 등록\n sse(\"https://your-mcp-server.com/sse\")\n\n // 또는 생성된 프로세스를 통해 등록 (stdio 전송)\n // process(Runtime.getRuntime().exec(\"your-mcp-binary ...\"))\n\n // 또는 기존 MCP 클라이언트 인스턴스에서 등록\n // client(existingMcpClient)\n }\n }\n}\n```\n## 왜 Koog + Ktor인가요?\n\n- 서버에서 에이전트를 개발하기 위한 Kotlin 우선의 타입 안전한 환경\n- 깔끔하고 테스트 가능한 라우트 코드와 중앙 집중식 설정\n- 라우트별로 적합한 모델을 사용하거나, 직접 LLM 호출 시 자동으로 폴백 적용\n- 도구(tools), 모데레이션(moderation), 스트리밍(streaming), 트레이싱(tracing) 등 프로덕션 환경에 적합한 기능 제공"}, "fc1ef79e9ff7f07c56ff7e768b27b70ad4ca9311": {"t": 1785764916.0163865, "n": 6601, "h": "9e7fca7f99407e59", "c": "# Ktor 통합: Koog 플러그인\n\nKoog는 Ktor 서버에 자연스럽게 통합되어, 양측 모두에서 관용적인(idiomatic) Kotlin API를 사용하여 서버 사이드 AI 애플리케이션을 작성할 수 있게 해줍니다.\n\nKoog 플러그인을 한 번 설치하고, `application.conf`/`YAML` 또는 코드에서 LLM 제공자(provider)를 설정한 다음 라우트(route)에서 바로 에이전트를 호출하세요. 더 이상 모듈 간에 LLM 클라이언트를 복잡하게 연결할 필요가 없습니다. 라우트에서 에이전트를 요청하기만 하면 바로 사용할 준비가 됩니다.\n\n## 개요\n\n`koog-ktor` 모듈은 서버 사이드 에이전트 개발을 위한 관용적인 Kotlin/Ktor 통합 기능을 제공합니다.\n\n- 바로 사용 가능한 Ktor 플러그인: Application에서 `install(Koog)` 호출\n- OpenAI, Anthropic, Google, OpenRouter, DeepSeek, Ollama에 대한 최고 수준의 지원\n- YAML/CONF 및 코드를 통한 중앙 집중식 설정\n- 프롬프트, 도구, 기능을 포함한 에이전트 설정 및 라우트를 위한 간단한 확장 함수\n- 직접적인 LLM 사용 (`execute`, `executeStreaming`, `moderate`)\n- JVM 전용 MCP(Model Context Protocol) 도구 통합\n\n## 의존성 추가\n\n```kotlin\ndependencies {\n implementation(\"ai.koog:koog-ktor:$koogVersion\")\n}\n```\n\n## 빠른 시작\n\n1) 제공자 설정 (`application.yaml` 또는 `application.conf`)\n\n`koog.` 아래의 중첩된 키를 사용하세요. 플러그인이 자동으로 이를 인식합니다.\n\n```yaml\n# application.yaml (Ktor 설정)\nkoog:\n openai:\n apikey: ${OPENAI_API_KEY}\n baseUrl: https://api.openai.com\n anthropic:\n apikey: ${ANTHROPIC_API_KEY}\n baseUrl: https://api.anthropic.com\n google:\n apikey: ${GOOGLE_API_KEY}\n baseUrl: https://generativelanguage.googleapis.com\n openrouter:\n apikey: ${OPENROUTER_API_KEY}\n baseUrl: https://openrouter.ai\n deepseek:\n apikey: ${DEEPSEEK_API_KEY}\n baseUrl: https://api.deepseek.com\n # koog.ollama.* 키가 존재하면 Ollama가 활성화됩니다.\n ollama:\n enable: true\n baseUrl: http://localhost:11434\n```\n\n선택 사항: 요청된 제공자가 설정되지 않았을 때 직접 LLM 호출에서 사용할 폴백(fallback)을 설정합니다.\n\n```yaml\nkoog:\n llm:\n fallback:\n provider: openai\n # 아래의 모델 식별자 섹션을 참조하세요.\n model: openai.chat.gpt4_1\n```\n\n2) 플러그인 설치 및 라우트 정의\n\n```kotlin\nfun Application.module() {\n install(Koog) {\n // 프로그래밍 방식으로 제공자를 설정할 수도 있습니다 (아래 참조)\n }\n\n routing {\n route(\"/ai\") {\n post(\"/chat\") {\n val userInput = call.receiveText()\n // 특정 모델을 사용하여 기본 단일 실행 에이전트를 생성하고 실행합니다.\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n }\n }\n }\n}\n```\n\n참고\n\n- `aiAgent`는 구체적인 모델(`LLModel`)이 필요합니다. 라우트별 또는 용도별로 선택하세요.\n- 더 낮은 수준의 LLM 액세스가 필요한 경우, `llm()`(`PromptExecutor`)을 직접 사용하세요.\n\n## 라우트에서 직접 LLM 사용\n\n```kotlin\npost(\"/llm-chat\") {\n val userInput = call.receiveText()\n\n val messages = llm().execute(\n prompt(\"chat\") {\n system(\"You are a helpful assistant that clarifies questions\")\n user(userInput)\n },\n GoogleModels.Gemini2_5Pro\n )\n\n // 모든 어시스턴트 메시지를 하나의 문자열로 결합합니다.\n val text = messages.joinToString(separator = \"\") { it.content }\n call.respond(HttpStatusCode.OK, text)\n}\n```\n\n스트리밍(Streaming)\n\n```kotlin\nget(\"/stream\") {\n val flow = llm().executeStreaming(\n prompt(\"streaming\") { user(\"Stream this response, please\") },\n OpenRouterModels.GPT4o\n )\n\n // 예시: 버퍼링 후 하나의 청크로 전송\n val sb = StringBuilder()\n flow.collect { chunk -> sb.append(chunk) }\n call.respondText(sb.toString())\n}\n```\n\n모데레이션(Moderation)\n\n```kotlin\npost(\"/moderated-chat\") {\n val userInput = call.receiveText()\n\n val moderation = llm().moderate(\n prompt(\"moderation\") { user(userInput) },\n OpenAIModels.Moderation.Omni\n )\n\n if (moderation.isHarmful) {\n call.respond(HttpStatusCode.BadRequest, \"Harmful content detected\")\n return@post\n }\n\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n}\n```\n\n## 프로그래밍 방식 설정 (코드 내)\n\n모든 제공자와 에이전트 동작은 `install(Koog) {}`를 통해 설정할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n llm {\n openAI(apiKey = System.getenv(\"OPENAI_API_KEY\") ?: \"\") {\n baseUrl = \"https://api.openai.com\"\n timeouts { // 아래는 기본값입니다.\n requestTimeout = 15.minutes\n connectTimeout = 60.seconds\n socketTimeout = 15.minutes\n }\n }\n anthropic(apiKey = System.getenv(\"ANTHROPIC_API_KEY\") ?: \"\")\n google(apiKey = System.getenv(\"GOOGLE_API_KEY\") ?: \"\")\n openRouter(apiKey = System.getenv(\"OPENROUTER_API_KEY\") ?: \"\")\n deepSeek(apiKey = System.getenv(\"DEEPSEEK_API_KEY\") ?: \"\")\n ollama { baseUrl = \"http://localhost:11434\" }\n\n // 제공자가 설정되지 않았을 때 PromptExecutor에서 사용할 선택적 폴백\n fallback {\n provider = LLMProvider.OpenAI\n model = OpenAIModels.Chat.GPT4_1\n }\n }\n\n agentConfig {\n // 에이전트를 위한 재사용 가능한 기본 프롬프트 제공\n prompt(name = \"agent\") {\n system(\"You are a helpful server‑side agent\")\n }\n\n // 무한 도구 호출/루프 제한\n maxAgentIterations = 10\n\n // 에이전트가 기본적으로 사용할 수 있는 도구 등록\n registerTools {\n // tool(::yourTool) // 자세한 내용은 도구 개요를 참조하세요.\n }\n\n // 에이전트 기능 설치 (트레이싱 등)\n // install(OpenTelemetry) { /* ... */ }\n }\n}\n```\n\n## 설정 내 모델 식별자 (폴백)\n\nYAML/CONF에서 `llm.fallback`을 설정할 때 다음 식별자 형식을 사용하세요.\n\n- OpenAI: `openai.chat.gpt4_1`, `openai.reasoning.o3`, `openai.costoptimized.gpt4_1mini`, `openai.audio.gpt4oaudio`, `openai.moderation.omni`\n- Anthropic: `anthropic.sonnet_4_5`, `anthropic.opus_4`, `anthropic.haiku_4_5`\n- Google: `google.gemini2_5pro`, `google.gemini2_0flash001`\n- OpenRouter: `openrouter.gpt4o`, `openrouter.gpt4`, `openrouter.claude3sonnet`\n- DeepSeek: `deepseek.deepseek-v4-flash`, `deepseek.deepseek-v4-pro`, `deepseek.deepseek-chat`, `deepseek.deepseek-reasoner`\n- Ollama: `ollama.meta.llama3.2`, `ollama.alibaba.qwq:32b`, `ollama.groq.llama3-grok-tool-use:8b`\n\n참고\n\n- OpenAI의 경우 반드시 카테고리(`chat`, `reasoning`, `costoptimized`, `audio`, `embeddings`, `moderation`)를 포함해야 합니다.\n- Ollama의 경우 `ollama.model` 및 `ollama..` 형식을 모두 지원합니다.\n\n## MCP 도구 (JVM 전용)\n\nJVM에서는 MCP 서버의 도구를 에이전트 도구 레지스트리에 추가할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n agentConfig {\n mcp {\n // SSE를 통해 등록\n sse(\"https://your-mcp-server.com/sse\")\n\n // 또는 생성된 프로세스를 통해 등록 (stdio 전송)\n // process(Runtime.getRuntime().exec(\"your-mcp-binary ...\"))\n\n // 또는 기존 MCP 클라이언트 인스턴스에서 등록\n // client(existingMcpClient)\n }\n }\n}\n```\n\n## 왜 Koog + Ktor인가요?\n\n- 서버에서 에이전트를 개발하기 위한 Kotlin 우선의 타입 안전한 환경\n- 깔끔하고 테스트 가능한 라우트 코드와 중앙 집중식 설정\n- 라우트별로 적합한 모델을 사용하거나, 직접 LLM 호출 시 자동으로 폴백 적용\n- 도구(tools), 모데레이션(moderation), 스트리밍(streaming), 트레이싱(tracing) 등 프로덕션 환경에 적합한 기능 제공"}, "629390827d1bd1be42720a368a357bd13df4fe1f": {"t": 1785764917.4756668, "n": 6543, "h": "48ed4c0fa322e5d4", "c": "# Ktor 통합: Koog 플러그인\n\nKoog는 Ktor 서버에 자연스럽게 통합되어, 양측 모두에서 관용적인(idiomatic) Kotlin API를 사용하여 서버 사이드 AI 애플리케이션을 작성할 수 있게 해줍니다.\n\nKoog 플러그인을 한 번 설치하고, `application.conf`/`YAML` 또는 코드에서 LLM 제공자(provider)를 설정한 다음 라우트(route)에서 바로 에이전트를 호출하세요. 더 이상 모듈 간에 LLM 클라이언트를 복잡하게 연결할 필요가 없습니다. 라우트에서 에이전트를 요청하기만 하면 바로 사용할 준비가 됩니다.\n\n## 개요\n\n`koog-ktor` 모듈은 서버 사이드 에이전트 개발을 위한 관용적인 Kotlin/Ktor 통합 기능을 제공합니다.\n\n- 바로 사용 가능한 Ktor 플러그인: Application에서 `install(Koog)` 호출\n- OpenAI, Anthropic, Google, OpenRouter, DeepSeek, Ollama에 대한 최고 수준의 지원\n- YAML/CONF 및 코드를 통한 중앙 집중식 설정\n- 프롬프트, 도구, 기능을 포함한 에이전트 설정 및 라우트를 위한 간단한 확장 함수\n- 직접적인 LLM 사용 (`execute`, `executeStreaming`, `moderate`)\n- JVM 전용 MCP(Model Context Protocol) 도구 통합\n\n## 의존성 추가\n\n```kotlin\ndependencies {\n implementation(\"ai.koog:koog-ktor:$koogVersion\")\n}\n```\n\n## 빠른 시작\n\n1) 제공자 설정 (`application.yaml` 또는 `application.conf`)\n\n`koog.` 아래의 중첩된 키를 사용하세요. 플러그인이 자동으로 이를 인식합니다.\n\n```yaml\n# application.yaml (Ktor 설정)\nkoog:\n openai:\n apikey: ${OPENAI_API_KEY}\n baseUrl: https://api.openai.com\n anthropic:\n apikey: ${ANTHROPIC_API_KEY}\n baseUrl: https://api.anthropic.com\n google:\n apikey: ${GOOGLE_API_KEY}\n baseUrl: https://generativelanguage.googleapis.com\n openrouter:\n apikey: ${OPENROUTER_API_KEY}\n baseUrl: https://openrouter.ai\n deepseek:\n apikey: ${DEEPSEEK_API_KEY}\n baseUrl: https://api.deepseek.com\n # koog.ollama.* 키가 존재하면 Ollama가 활성화됩니다.\n ollama:\n enable: true\n baseUrl: http://localhost:11434\n```\n\n선택 사항: 요청된 제공자가 설정되지 않았을 때 직접 LLM 호출에서 사용할 폴백(fallback)을 설정합니다.\n\n```yaml\nkoog:\n llm:\n fallback:\n provider: openai\n # 아래의 모델 식별자 섹션을 참조하세요.\n model: openai.chat.gpt4_1\n```\n\n2) 플러그인 설치 및 라우트 정의\n\n```kotlin\nfun Application.module() {\n install(Koog) {\n // 프로그래밍 방식으로 제공자를 설정할 수도 있습니다 (아래 참조)\n }\n\n routing {\n route(\"/ai\") {\n post(\"/chat\") {\n val userInput = call.receiveText()\n // 특정 모델을 사용하여 기본 단일 실행 에이전트를 생성하고 실행합니다.\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n }\n }\n }\n}\n```\n\n참고\n\n- `aiAgent`는 구체적인 모델(`LLModel`)이 필요합니다. 라우트별 또는 용도별로 선택하세요.\n- 더 낮은 수준의 LLM 액세스가 필요한 경우, `llm()`(`PromptExecutor`)을 직접 사용하세요.\n\n## 라우트에서 직접 LLM 사용\n\n```kotlin\npost(\"/llm-chat\") {\n val userInput = call.receiveText()\n\n val messages = llm().execute(\n prompt(\"chat\") {\n system(\"You are a helpful assistant that clarifies questions\")\n user(userInput)\n },\n GoogleModels.Gemini2_5Pro\n )\n\n // 모든 어시스턴트 메시지를 하나의 문자열로 결합합니다.\n val text = messages.joinToString(separator = \"\") { it.content }\n call.respond(HttpStatusCode.OK, text)\n}\n```\n\n스트리밍(Streaming)\n\n```kotlin\nget(\"/stream\") {\n val flow = llm().executeStreaming(\n prompt(\"streaming\") { user(\"Stream this response, please\") },\n OpenRouterModels.GPT4o\n )\n\n // 예시: 버퍼링 후 하나의 청크로 전송\n val sb = StringBuilder()\n flow.collect { chunk -> sb.append(chunk) }\n call.respondText(sb.toString())\n}\n```\n\n모데레이션(Moderation)\n\n```kotlin\npost(\"/moderated-chat\") {\n val userInput = call.receiveText()\n\n val moderation = llm().moderate(\n prompt(\"moderation\") { user(userInput) },\n OpenAIModels.Moderation.Omni\n )\n\n if (moderation.isHarmful) {\n call.respond(HttpStatusCode.BadRequest, \"Harmful content detected\")\n return@post\n }\n\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n}\n```\n\n## 프로그래밍 방식 설정 (코드 내)\n\n모든 제공자와 에이전트 동작은 `install(Koog) {}`를 통해 설정할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n llm {\n openAI(apiKey = System.getenv(\"OPENAI_API_KEY\") ?: \"\") {\n baseUrl = \"https://api.openai.com\"\n timeouts { // 아래는 기본값입니다.\n requestTimeout = 15.minutes\n connectTimeout = 60.seconds\n socketTimeout = 15.minutes\n }\n }\n anthropic(apiKey = System.getenv(\"ANTHROPIC_API_KEY\") ?: \"\")\n google(apiKey = System.getenv(\"GOOGLE_API_KEY\") ?: \"\")\n openRouter(apiKey = System.getenv(\"OPENROUTER_API_KEY\") ?: \"\")\n deepSeek(apiKey = System.getenv(\"DEEPSEEK_API_KEY\") ?: \"\")\n ollama { baseUrl = \"http://localhost:11434\" }\n\n // 제공자가 설정되지 않았을 때 PromptExecutor에서 사용할 선택적 폴백\n fallback {\n provider = LLMProvider.OpenAI\n model = OpenAIModels.Chat.GPT4_1\n }\n }\n\n agentConfig {\n // 에이전트를 위한 재사용 가능한 기본 프롬프트 제공\n prompt(name = \"agent\") {\n system(\"You are a helpful server‑side agent\")\n }\n\n // 무한 도구 호출/루프 제한\n maxAgentIterations = 10\n\n // 에이전트가 기본적으로 사용할 수 있는 도구 등록\n registerTools {\n // tool(::yourTool) // 자세한 내용은 도구 개요를 참조하세요.\n }\n\n // 에이전트 기능 설치 (트레이싱 등)\n // install(OpenTelemetry) { /* ... */ }\n }\n}\n```\n\n## 설정 내 모델 식별자 (폴백)\n\nYAML/CONF에서 `llm.fallback`을 설정할 때 다음 식별자 형식을 사용하세요.\n\n- OpenAI: `openai.chat.gpt4_1`, `openai.reasoning.o3`, `openai.costoptimized.gpt4_1mini`, `openai.audio.gpt4oaudio`, `openai.moderation.omni`\n- Anthropic: `anthropic.sonnet_4_5`, `anthropic.opus_4`, `anthropic.haiku_4_5`\n- Google: `google.gemini2_5pro`, `google.gemini2_0flash001`\n- OpenRouter: `openrouter.gpt4o`, `openrouter.gpt4`, `openrouter.claude3sonnet`\n- DeepSeek: `deepseek.deepseek-chat`, `deepseek.deepseek-reasoner`\n- Ollama: `ollama.meta.llama3.2`, `ollama.alibaba.qwq:32b`, `ollama.groq.llama3-grok-tool-use:8b`\n\n참고\n\n- OpenAI의 경우 반드시 카테고리(`chat`, `reasoning`, `costoptimized`, `audio`, `embeddings`, `moderation`)를 포함해야 합니다.\n- Ollama의 경우 `ollama.model` 및 `ollama..` 형식을 모두 지원합니다.\n\n## MCP 도구 (JVM 전용)\n\nJVM에서는 MCP 서버의 도구를 에이전트 도구 레지스트리에 추가할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n agentConfig {\n mcp {\n // SSE를 통해 등록\n sse(\"https://your-mcp-server.com/sse\")\n\n // 또는 생성된 프로세스를 통해 등록 (stdio 전송)\n // process(Runtime.getRuntime().exec(\"your-mcp-binary ...\"))\n\n // 또는 기존 MCP 클라이언트 인스턴스에서 등록\n // client(existingMcpClient)\n }\n }\n}\n```\n\n## 왜 Koog + Ktor인가요?\n\n- 서버에서 에이전트를 개발하기 위한 Kotlin 우선의 타입 안전한 환경\n- 깔끔하고 테스트 가능한 라우트 코드와 중앙 집중식 설정\n- 라우트별로 적합한 모델을 사용하거나, 직접 LLM 호출 시 자동으로 폴백 적용\n- 도구(tools), 모데레이션(moderation), 스트리밍(streaming), 트레이싱(tracing) 등 프로덕션 환경에 적합한 기능 제공"}, "93d8eaa8d1c65ff83767f812ce3d318862abb0d2": {"t": 1785764920.956403, "n": 6748, "h": "8d555d75907a305b", "c": "# Ktor 통합: Koog 플러그인\n\nKoog는 Ktor 서버에 자연스럽게 통합되어 양쪽에서 관용적인 Kotlin API를 사용하여 서버 측 AI 애플리케이션을 작성할 수 있게 합니다.\n\nKoog 플러그인을 한 번 설치하고, `application.conf` 또는 `application.yaml` 파일이나 코드에서 LLM 공급자를 구성한 다음, 라우트에서 직접 에이전트를 호출할 수 있습니다. 더 이상 모듈 간에 LLM 클라이언트를 연결할 필요 없이, 라우트에서 에이전트를 요청하기만 하면 준비 완료입니다.\n\n## 개요\n\n`koog-ktor` 모듈은 서버 측 에이전트 개발을 위한 관용적인 Kotlin/Ktor 통합 기능을 제공합니다:\n\n- 드롭인 Ktor 플러그인: `Application`에서 `install(Koog)`\n- OpenAI, Anthropic, Google, OpenRouter, DeepSeek 및 Ollama에 대한 일급 지원\n- YAML/CONF 및/또는 코드를 통한 중앙 집중식 구성\n- 프롬프트, 도구, 기능으로 에이전트 설정; 라우트를 위한 간단한 확장 함수\n- 직접 LLM 사용 (`execute`, `executeStreaming`, `moderate`)\n- JVM 전용 Model Context Protocol (MCP) 도구 통합\n\n## 의존성 추가\n\n```kotlin\ndependencies {\n implementation(\"ai.koog:koog-ktor:$koogVersion\")\n}\n```\n\n## 빠른 시작\n\n1) 공급자 구성 (`application.yaml` 또는 `application.conf` 파일에서)\n\n`koog.` 아래에 중첩된 키를 사용하세요. 플러그인이 자동으로 이를 감지합니다.\n\n```yaml\n# application.yaml (Ktor config)\nkoog:\n openai:\n apikey: ${OPENAI_API_KEY}\n baseUrl: https://api.openai.com\n anthropic:\n apikey: ${ANTHROPIC_API_KEY}\n baseUrl: https://api.anthropic.com\n google:\n apikey: ${GOOGLE_API_KEY}\n baseUrl: https://generativelanguage.googleapis.com\n openrouter:\n apikey: ${OPENROUTER_API_KEY}\n baseUrl: https://openrouter.ai\n deepseek:\n apikey: ${DEEPSEEK_API_KEY}\n baseUrl: https://api.deepseek.com\n # Ollama is enabled when any koog.ollama.* key exists\n ollama:\n enable: true\n baseUrl: http://localhost:11434\n```\n\n선택 사항: 요청된 공급자가 구성되지 않았을 때 직접 LLM 호출에서 사용되는 폴백(fallback)을 구성합니다.\n\n```yaml\nkoog:\n llm:\n fallback:\n provider: openai\n # see Model identifiers section below\n model: openai.chat.gpt4_1\n```\n\n2) 플러그인 설치 및 라우트 정의\n\n```kotlin\nfun Application.module() {\n install(Koog) {\n // You can also configure providers programmatically (see below)\n }\n\n routing {\n route(\"/ai\") {\n post(\"/chat\") {\n val userInput = call.receiveText()\n // Create and run a default single‑run agent using a specific model\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n }\n }\n }\n}\n```\n\n참고\n\n- `aiAgent`는 구체적인 모델(`LLModel`)을 필요로 합니다. 라우트별, 사용별로 선택하세요.\n- 하위 레벨 LLM 접근을 위해서는 `llm() (PromptExecutor)`를 직접 사용하세요.\n\n## 라우트에서 직접 LLM 사용\n\n```kotlin\npost(\"/llm-chat\") {\n val userInput = call.receiveText()\n\n val messages = llm().execute(\n prompt(\"chat\") {\n system(\"You are a helpful assistant that clarifies questions\")\n user(userInput)\n },\n GoogleModels.Gemini2_5Pro\n )\n\n // Join all assistant messages into a single string\n val text = messages.joinToString(separator = \"\") { it.content }\n call.respond(HttpStatusCode.OK, text)\n}\n```\n\n스트리밍\n\n```kotlin\nget(\"/stream\") {\n val flow = llm().executeStreaming(\n prompt(\"streaming\") { user(\"Stream this response, please\") },\n OpenRouterModels.GPT4o\n )\n\n // Example: buffer and send as one chunk\n val sb = StringBuilder()\n flow.collect { chunk -> sb.append(chunk) }\n call.respondText(sb.toString())\n}\n```\n\n중재 (Moderation)\n\n```kotlin\npost(\"/moderated-chat\") {\n val userInput = call.receiveText()\n\n val moderation = llm().moderate(\n prompt(\"moderation\") { user(userInput) },\n OpenAIModels.Moderation.Omni\n )\n\n if (moderation.isHarmful) {\n call.respond(HttpStatusCode.BadRequest, \"Harmful content detected\")\n return@post\n }\n\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n}\n```\n\n## 프로그래밍 방식 구성 (코드 내)\n\n모든 공급자 및 에이전트 동작은 `install(Koog) {}`를 통해 구성할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n llm {\n openAI(apiKey = System.getenv(\"OPENAI_API_KEY\") ?: \"\") {\n baseUrl = \"https://api.openai.com\"\n timeouts { // Default values shown below\n requestTimeout = 15.minutes\n connectTimeout = 60.seconds\n socketTimeout = 15.minutes\n }\n }\n anthropic(apiKey = System.getenv(\"ANTHROPIC_API_KEY\") ?: \"\")\n google(apiKey = System.getenv(\"GOOGLE_API_KEY\") ?: \"\")\n openRouter(apiKey = System.getenv(\"OPENROUTER_API_KEY\") ?: \"\")\n deepSeek(apiKey = System.getenv(\"DEEPSEEK_API_KEY\") ?: \"\")\n ollama { baseUrl = \"http://localhost:11434\" }\n\n // Optional fallback used by PromptExecutor when a provider isn’t configured\n fallback {\n provider = LLMProvider.OpenAI\n model = OpenAIModels.Chat.GPT4_1\n }\n }\n\n agentConfig {\n // Provide a reusable base prompt for your agents\n prompt(name = \"agent\") {\n system(\"You are a helpful server‑side agent\")\n }\n\n // Limit runaway tools/loops\n maxAgentIterations = 10\n\n // Register tools available to agents by default\n registerTools {\n // tool(::yourTool) // see Tools Overview for details\n }\n\n // Install agent features (tracing, etc.)\n // install(OpenTelemetry) { /* ... */ }\n }\n}\n```\n\n## 구성 (폴백) 내 모델 식별자\n\nYAML/CONF에서 `llm.fallback`을 구성할 때는 다음 식별자 형식을 사용하세요.\n\n- OpenAI: `openai.chat.gpt4_1`, `openai.reasoning.o3`, `openai.costoptimized.gpt4_1mini`, `openai.audio.gpt4oaudio`, `openai.moderation.omni`\n- Anthropic: `anthropic.sonnet_3_7`, `anthropic.opus_4`, `anthropic.haiku_3_5`\n- Google: `google.gemini2_5pro`, `google.gemini2_0flash001`\n- OpenRouter: `openrouter.gpt4o`, `openrouter.gpt4`, `openrouter.claude3sonnet`\n- DeepSeek: `deepseek.deepseek-chat`, `deepseek.deepseek-reasoner`\n- Ollama: `ollama.meta.llama3.2`, `ollama.alibaba.qwq:32b`, `ollama.groq.llama3-grok-tool-use:8b`\n\n참고\n\n- OpenAI의 경우 카테고리(`chat`, `reasoning`, `costoptimized`, `audio`, `embeddings`, `moderation`)를 반드시 포함해야 합니다.\n- Ollama의 경우, `ollama.model` 및 `ollama..` 모두 지원됩니다.\n\n## MCP 도구 (JVM 전용)\n\nJVM에서는 MCP 서버의 도구를 에이전트 도구 레지스트리에 추가할 수 있습니다:\n\n```kotlin\ninstall(Koog) {\n agentConfig {\n mcp {\n // Register via SSE\n sse(\"https://your-mcp-server.com/sse\")\n\n // Or register via spawned process (stdio transport)\n // process(Runtime.getRuntime().exec(\"your-mcp-binary ...\"))\n\n // Or from an existing MCP client instance\n // client(existingMcpClient)\n }\n }\n}\n```\n## Koog + Ktor를 사용하는 이유?\n\n- Kotlin 우선의, 타입 세이프(type-safe)한 서버 내 에이전트 개발\n- 깔끔하고 테스트 가능한 라우트 코드와 중앙 집중식 구성\n- 라우트별로 적절한 모델을 사용하거나, 직접 LLM 호출 시 자동으로 폴백 사용\n- 프로덕션 준비 완료 기능: 도구, 중재(moderation), 스트리밍 및 추적(tracing)"}, "acc53f4a0a97c09d2eae93ab29cefc590d6b6ea3": {"t": 1785764922.6345131, "n": 6745, "h": "8bcaad5458d35085", "c": "# Ktor 통합: Koog 플러그인\n\nKoog는 Ktor 서버에 자연스럽게 통합되어 양쪽에서 관용적인 Kotlin API를 사용하여 서버 측 AI 애플리케이션을 작성할 수 있게 합니다.\n\nKoog 플러그인을 한 번 설치하고, `application.conf` 또는 `application.yaml` 파일이나 코드에서 LLM 공급자를 구성한 다음, 라우트에서 직접 에이전트를 호출할 수 있습니다. 더 이상 모듈 간에 LLM 클라이언트를 연결할 필요 없이, 라우트에서 에이전트를 요청하기만 하면 준비 완료입니다.\n\n## 개요\n\n`koog-ktor` 모듈은 서버 측 에이전트 개발을 위한 관용적인 Kotlin/Ktor 통합 기능을 제공합니다:\n\n- 드롭인 Ktor 플러그인: `Application`에서 `install(Koog)`\n- OpenAI, Anthropic, Google, OpenRouter, DeepSeek 및 Ollama에 대한 일급 지원\n- YAML/CONF 및/또는 코드를 통한 중앙 집중식 구성\n- 프롬프트, 도구, 기능으로 에이전트 설정; 라우트를 위한 간단한 확장 함수\n- 직접 LLM 사용 (`execute`, `executeStreaming`, `moderate`)\n- JVM 전용 Model Context Protocol (MCP) 도구 통합\n\n## 의존성 추가\n\n```kotlin\ndependencies {\n implementation(\"ai.koog:koog-ktor:$koogVersion\")\n}\n```\n\n## 빠른 시작\n\n1) 공급자 구성 (`application.yaml` 또는 `application.conf` 파일에서)\n\n`koog.` 아래에 중첩된 키를 사용하세요. 플러그인이 자동으로 이를 감지합니다.\n\n```yaml\n# application.yaml (Ktor config)\nkoog:\n openai:\n apikey: ${OPENAI_API_KEY}\n baseUrl: https://api.openai.com\n anthropic:\n apikey: ${ANTHROPIC_API_KEY}\n baseUrl: https://api.anthropic.com\n google:\n apikey: ${GOOGLE_API_KEY}\n baseUrl: https://generativelanguage.googleapis.com\n openrouter:\n apikey: ${OPENROUTER_API_KEY}\n baseUrl: https://openrouter.ai\n deepseek:\n apikey: ${DEEPSEEK_API_KEY}\n baseUrl: https://api.deepseek.com\n # Ollama is enabled when any koog.ollama.* key exists\n ollama:\n enable: true\n baseUrl: http://localhost:11434\n```\n\n선택 사항: 요청된 공급자가 구성되지 않았을 때 직접 LLM 호출에서 사용되는 폴백(fallback)을 구성합니다.\n\n```yaml\nkoog:\n llm:\n fallback:\n provider: openai\n # see Model identifiers section below\n model: openai.chat.gpt4_1\n```\n\n2) 플러그인 설치 및 라우트 정의\n\n```kotlin\nfun Application.module() {\n install(Koog) {\n // You can also configure providers programmatically (see below)\n }\n\n routing {\n route(\"/ai\") {\n post(\"/chat\") {\n val userInput = call.receiveText()\n // Create and run a default single‑run agent using a specific model\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n }\n }\n }\n}\n```\n\n참고\n- `aiAgent`는 구체적인 모델(`LLModel`)을 필요로 합니다. 라우트별, 사용별로 선택하세요.\n- 하위 레벨 LLM 접근을 위해서는 `llm() (PromptExecutor)`를 직접 사용하세요.\n\n## 라우트에서 직접 LLM 사용\n\n```kotlin\npost(\"/llm-chat\") {\n val userInput = call.receiveText()\n\n val messages = llm().execute(\n prompt(\"chat\") {\n system(\"You are a helpful assistant that clarifies questions\")\n user(userInput)\n },\n GoogleModels.Gemini2_5Pro\n )\n\n // Join all assistant messages into a single string\n val text = messages.joinToString(separator = \"\") { it.content }\n call.respond(HttpStatusCode.OK, text)\n}\n```\n\n스트리밍\n\n```kotlin\nget(\"/stream\") {\n val flow = llm().executeStreaming(\n prompt(\"streaming\") { user(\"Stream this response, please\") },\n OpenRouterModels.GPT4o\n )\n\n // Example: buffer and send as one chunk\n val sb = StringBuilder()\n flow.collect { chunk -> sb.append(chunk) }\n call.respondText(sb.toString())\n}\n```\n\n중재 (Moderation)\n\n```kotlin\npost(\"/moderated-chat\") {\n val userInput = call.receiveText()\n\n val moderation = llm().moderate(\n prompt(\"moderation\") { user(userInput) },\n OpenAIModels.Moderation.Omni\n )\n\n if (moderation.isHarmful) {\n call.respond(HttpStatusCode.BadRequest, \"Harmful content detected\")\n return@post\n }\n\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n}\n```\n\n## 프로그래밍 방식 구성 (코드 내)\n\n모든 공급자 및 에이전트 동작은 `install(Koog) {}`를 통해 구성할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n llm {\n openAI(apiKey = System.getenv(\"OPENAI_API_KEY\") ?: \"\") {\n baseUrl = \"https://api.openai.com\"\n timeouts { // Default values shown below\n requestTimeout = 15.minutes\n connectTimeout = 60.seconds\n socketTimeout = 15.minutes\n }\n }\n anthropic(apiKey = System.getenv(\"ANTHROPIC_API_KEY\") ?: \"\")\n google(apiKey = System.getenv(\"GOOGLE_API_KEY\") ?: \"\")\n openRouter(apiKey = System.getenv(\"OPENROUTER_API_KEY\") ?: \"\")\n deepSeek(apiKey = System.getenv(\"DEEPSEEK_API_KEY\") ?: \"\")\n ollama { baseUrl = \"http://localhost:11434\" }\n\n // Optional fallback used by PromptExecutor when a provider isn’t configured\n fallback {\n provider = LLMProvider.OpenAI\n model = OpenAIModels.Chat.GPT4_1\n }\n }\n\n agentConfig {\n // Provide a reusable base prompt for your agents\n prompt(name = \"agent\") {\n system(\"You are a helpful server‑side agent\")\n }\n\n // Limit runaway tools/loops\n maxAgentIterations = 10\n\n // Register tools available to agents by default\n registerTools {\n // tool(::yourTool) // see Tools Overview for details\n }\n\n // Install agent features (tracing, etc.)\n // install(OpenTelemetry) { /* ... */ }\n }\n}\n```\n\n## 구성 (폴백) 내 모델 식별자\n\nYAML/CONF에서 `llm.fallback`을 구성할 때는 다음 식별자 형식을 사용하세요.\n- OpenAI: `openai.chat.gpt4_1`, `openai.reasoning.o3`, `openai.costoptimized.gpt4_1mini`, `openai.audio.gpt4oaudio`, `openai.moderation.omni`\n- Anthropic: `anthropic.sonnet_3_7`, `anthropic.opus_4`, `anthropic.haiku_3_5`\n- Google: `google.gemini2_5pro`, `google.gemini2_0flash001`\n- OpenRouter: `openrouter.gpt4o`, `openrouter.gpt4`, `openrouter.claude3sonnet`\n- DeepSeek: `deepseek.deepseek-chat`, `deepseek.deepseek-reasoner`\n- Ollama: `ollama.meta.llama3.2`, `ollama.alibaba.qwq:32b`, `ollama.groq.llama3-grok-tool-use:8b`\n\n참고\n- OpenAI의 경우 카테고리(`chat`, `reasoning`, `costoptimized`, `audio`, `embeddings`, `moderation`)를 반드시 포함해야 합니다.\n- Ollama의 경우, `ollama.model` 및 `ollama..` 모두 지원됩니다.\n\n## MCP 도구 (JVM 전용)\n\nJVM에서는 MCP 서버의 도구를 에이전트 도구 레지스트리에 추가할 수 있습니다:\n\n```kotlin\ninstall(Koog) {\n agentConfig {\n mcp {\n // Register via SSE\n sse(\"https://your-mcp-server.com/sse\")\n\n // Or register via spawned process (stdio transport)\n // process(Runtime.getRuntime().exec(\"your-mcp-binary ...\"))\n\n // Or from an existing MCP client instance\n // client(existingMcpClient)\n }\n }\n}\n```\n## Koog + Ktor를 사용하는 이유?\n\n- Kotlin 우선의, 타입 세이프(type-safe)한 서버 내 에이전트 개발\n- 깔끔하고 테스트 가능한 라우트 코드와 중앙 집중식 구성\n- 라우트별로 적절한 모델을 사용하거나, 직접 LLM 호출 시 자동으로 폴백 사용\n- 프로덕션 준비 완료 기능: 도구, 중재(moderation), 스트리밍 및 추적(tracing)"}, "3a1f4caaf01fdf5089e5c769be4f71af1e5a8967": {"t": 1785764924.6220272, "n": 6770, "h": "5ef7b2b9a7d3bbb7", "c": "# Ktor 통합: Koog 플러그인\n\nKoog는 Ktor 서버에 자연스럽게 통합되어 양쪽에서 관용적인 Kotlin API를 사용하여 서버 측 AI 애플리케이션을 작성할 수 있게 합니다.\n\nKoog 플러그인을 한 번 설치하고, `application.conf` 또는 `application.yaml` 파일이나 코드에서 LLM (Large Language Model) 공급자를 구성한 다음, 라우트에서 직접 에이전트를 호출할 수 있습니다. 더 이상 모듈 간에 LLM 클라이언트를 연결할 필요 없이, 라우트에서 에이전트를 요청하기만 하면 준비 완료입니다.\n\n## 개요\n\n`koog-ktor` 모듈은 서버 측 에이전트 개발을 위한 관용적인 Kotlin/Ktor 통합 기능을 제공합니다:\n\n- 드롭인 Ktor 플러그인: `Application`에서 `install(Koog)`\n- OpenAI, Anthropic, Google, OpenRouter, DeepSeek 및 Ollama에 대한 일급 지원\n- YAML/CONF 및/또는 코드를 통한 중앙 집중식 구성\n- 프롬프트, 도구, 기능으로 에이전트 설정; 라우트를 위한 간단한 확장 함수\n- 직접 LLM 사용 (`execute`, `executeStreaming`, `moderate`)\n- JVM 전용 Model Context Protocol (MCP) 도구 통합\n\n## 의존성 추가\n\n```kotlin\ndependencies {\n implementation(\"ai.koog:koog-ktor:$koogVersion\")\n}\n```\n\n## 빠른 시작\n\n1) 공급자 구성 (`application.yaml` 또는 `application.conf` 파일에서)\n\n`koog.` 아래에 중첩된 키를 사용하세요. 플러그인이 자동으로 이를 감지합니다.\n\n```yaml\n# application.yaml (Ktor config)\nkoog:\n openai:\n apikey: ${OPENAI_API_KEY}\n baseUrl: https://api.openai.com\n anthropic:\n apikey: ${ANTHROPIC_API_KEY}\n baseUrl: https://api.anthropic.com\n google:\n apikey: ${GOOGLE_API_KEY}\n baseUrl: https://generativelanguage.googleapis.com\n openrouter:\n apikey: ${OPENROUTER_API_KEY}\n baseUrl: https://openrouter.ai\n deepseek:\n apikey: ${DEEPSEEK_API_KEY}\n baseUrl: https://api.deepseek.com\n # Ollama is enabled when any koog.ollama.* key exists\n ollama:\n enable: true\n baseUrl: http://localhost:11434\n```\n\n선택 사항: 요청된 공급자가 구성되지 않았을 때 직접 LLM 호출에서 사용되는 폴백(fallback)을 구성합니다.\n\n```yaml\nkoog:\n llm:\n fallback:\n provider: openai\n # see Model identifiers section below\n model: openai.chat.gpt4_1\n```\n\n2) 플러그인 설치 및 라우트 정의\n\n```kotlin\nfun Application.module() {\n install(Koog) {\n // You can also configure providers programmatically (see below)\n }\n\n routing {\n route(\"/ai\") {\n post(\"/chat\") {\n val userInput = call.receiveText()\n // Create and run a default single‑run agent using a specific model\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n }\n }\n }\n}\n```\n\n참고:\n- `aiAgent`는 구체적인 모델(`LLModel`)을 필요로 합니다. 라우트별, 사용별로 선택하세요.\n- 하위 레벨 LLM 접근을 위해서는 `llm() (PromptExecutor)`를 직접 사용하세요.\n\n## 라우트에서 직접 LLM 사용\n\n```kotlin\npost(\"/llm-chat\") {\n val userInput = call.receiveText()\n\n val messages = llm().execute(\n prompt(\"chat\") {\n system(\"You are a helpful assistant that clarifies questions\")\n user(userInput)\n },\n GoogleModels.Gemini2_5Pro\n )\n\n // Join all assistant messages into a single string\n val text = messages.joinToString(separator = \"\") { it.content }\n call.respond(HttpStatusCode.OK, text)\n}\n```\n\n스트리밍\n\n```kotlin\nget(\"/stream\") {\n val flow = llm().executeStreaming(\n prompt(\"streaming\") { user(\"Stream this response, please\") },\n OpenRouterModels.GPT4o\n )\n\n // Example: buffer and send as one chunk\n val sb = StringBuilder()\n flow.collect { chunk -> sb.append(chunk) }\n call.respondText(sb.toString())\n}\n```\n\n중재 (Moderation)\n\n```kotlin\npost(\"/moderated-chat\") {\n val userInput = call.receiveText()\n\n val moderation = llm().moderate(\n prompt(\"moderation\") { user(userInput) },\n OpenAIModels.Moderation.Omni\n )\n\n if (moderation.isHarmful) {\n call.respond(HttpStatusCode.BadRequest, \"Harmful content detected\")\n return@post\n }\n\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n}\n```\n\n## 프로그래밍 방식 구성 (코드 내)\n\n모든 공급자 및 에이전트 동작은 `install(Koog) {}`를 통해 구성할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n llm {\n openAI(apiKey = System.getenv(\"OPENAI_API_KEY\") ?: \"\") {\n baseUrl = \"https://api.openai.com\"\n timeouts { // Default values shown below\n requestTimeout = 15.minutes\n connectTimeout = 60.seconds\n socketTimeout = 15.minutes\n }\n }\n anthropic(apiKey = System.getenv(\"ANTHROPIC_API_KEY\") ?: \"\")\n google(apiKey = System.getenv(\"GOOGLE_API_KEY\") ?: \"\")\n openRouter(apiKey = System.getenv(\"OPENROUTER_API_KEY\") ?: \"\")\n deepSeek(apiKey = System.getenv(\"DEEPSEEK_API_KEY\") ?: \"\")\n ollama { baseUrl = \"http://localhost:11434\" }\n\n // Optional fallback used by PromptExecutor when a provider isn’t configured\n fallback {\n provider = LLMProvider.OpenAI\n model = OpenAIModels.Chat.GPT4_1\n }\n }\n\n agentConfig {\n // Provide a reusable base prompt for your agents\n prompt(name = \"agent\") {\n system(\"You are a helpful server‑side agent\")\n }\n\n // Limit runaway tools/loops\n maxAgentIterations = 10\n\n // Register tools available to agents by default\n registerTools {\n // tool(::yourTool) // see Tools Overview for details\n }\n\n // Install agent features (tracing, etc.)\n // install(OpenTelemetry) { /* ... */ }\n }\n}\n```\n\n## 구성 (폴백) 내 모델 식별자\n\nYAML/CONF에서 `llm.fallback`을 구성할 때는 다음 식별자 형식을 사용하세요.\n- OpenAI: `openai.chat.gpt4_1`, `openai.reasoning.o3`, `openai.costoptimized.gpt4_1mini`, `openai.audio.gpt4oaudio`, `openai.moderation.omni`\n- Anthropic: `anthropic.sonnet_3_7`, `anthropic.opus_4`, `anthropic.haiku_3_5`\n- Google: `google.gemini2_5pro`, `google.gemini2_0flash001`\n- OpenRouter: `openrouter.gpt4o`, `openrouter.gpt4`, `openrouter.claude3sonnet`\n- DeepSeek: `deepseek.deepseek-chat`, `deepseek.deepseek-reasoner`\n- Ollama: `ollama.meta.llama3.2`, `ollama.alibaba.qwq:32b`, `ollama.groq.llama3-grok-tool-use:8b`\n\n참고:\n- OpenAI의 경우 카테고리(`chat`, `reasoning`, `costoptimized`, `audio`, `embeddings`, `moderation`)를 반드시 포함해야 합니다.\n- Ollama의 경우 `ollama.model` 및 `ollama..` 모두 지원됩니다.\n\n## MCP 도구 (JVM 전용)\n\nJVM에서는 MCP 서버에서 도구를 에이전트 도구 레지스트리에 추가할 수 있습니다:\n\n```kotlin\ninstall(Koog) {\n agentConfig {\n mcp {\n // Register via SSE\n sse(\"https://your-mcp-server.com/sse\")\n\n // Or register via spawned process (stdio transport)\n // process(Runtime.getRuntime().exec(\"your-mcp-binary ...\"))\n\n // Or from an existing MCP client instance\n // client(existingMcpClient)\n }\n }\n}\n```\n## Koog + Ktor를 사용하는 이유?\n\n- Kotlin 우선의, 타입 세이프(type-safe)한 서버 내 에이전트 개발\n- 깔끔하고 테스트 가능한 라우트 코드와 중앙 집중식 구성\n- 라우트별로 적절한 모델을 사용하거나, 직접 LLM 호출 시 자동으로 폴백 사용\n- 프로덕션 준비 완료 기능: 도구, 중재(moderation), 스트리밍 및 추적(tracing)"}, "e1d711bc2020b356cd17bac6bbd4e23dc8e60599": {"t": 1786067793.1569705, "n": 6691, "h": "1ca6797758fe2afe", "c": "---\nstatus: beta\n---\n\n# Ktor 통합: Koog 플러그인\n\n--8<-- \"versioning-snippets.md:beta\"\n\nKoog는 Ktor 서버에 자연스럽게 통합되어, 양측 모두에서 관용적인(idiomatic) Kotlin API를 사용하여 서버 사이드 AI 애플리케이션을 작성할 수 있게 해줍니다.\n\nKoog 플러그인을 한 번 설치하고, `application.conf`/`YAML` 또는 코드에서 LLM 제공자(provider)를 설정한 다음 라우트(route)에서 바로 에이전트를 호출하세요. 더 이상 모듈 간에 LLM 클라이언트를 복잡하게 연결할 필요가 없습니다. 라우트에서 에이전트를 요청하기만 하면 바로 사용할 준비가 됩니다.\n\n## 개요\n\n`koog-ktor` 모듈은 서버 사이드 에이전트(agentic) 개발을 위한 관용적인 Kotlin/Ktor 통합 기능을 제공합니다.\n\n- 바로 사용 가능한 Ktor 플러그인: Application에서 `install(Koog)` 호출\n- OpenAI, Anthropic, Google, OpenRouter, DeepSeek, Ollama에 대한 최고 수준의 지원\n- YAML/CONF 및 코드를 통한 중앙 집중식 설정\n- 프롬프트, 도구, 기능을 포함한 에이전트 설정 및 라우트를 위한 간단한 확장 함수\n- 직접적인 LLM 사용 (`execute`, `executeStreaming`, `moderate`)\n- JVM 전용 MCP(Model Context Protocol) 도구 통합\n\n## 의존성 추가\n\n```kotlin\ndependencies {\n implementation(\"ai.koog:koog-ktor:$koogVersion\")\n}\n```\n\n## 빠른 시작\n\n1) 제공자 설정 (`application.yaml` 또는 `application.conf`)\n\n`koog.` 아래의 중첩된 키를 사용하세요. 플러그인이 자동으로 이를 인식합니다.\n\n```yaml\n# application.yaml (Ktor 설정)\nkoog:\n openai:\n apikey: ${OPENAI_API_KEY}\n baseUrl: https://api.openai.com\n anthropic:\n apikey: ${ANTHROPIC_API_KEY}\n baseUrl: https://api.anthropic.com\n google:\n apikey: ${GOOGLE_API_KEY}\n baseUrl: https://generativelanguage.googleapis.com\n openrouter:\n apikey: ${OPENROUTER_API_KEY}\n baseUrl: https://openrouter.ai\n deepseek:\n apikey: ${DEEPSEEK_API_KEY}\n baseUrl: https://api.deepseek.com\n # koog.ollama.* 키가 존재하면 Ollama가 활성화됩니다.\n ollama:\n enable: true\n baseUrl: http://localhost:11434\n```\n\n선택 사항: 요청된 제공자가 설정되지 않았을 때 직접 LLM 호출에서 사용할 폴백(fallback)을 설정합니다.\n\n```yaml\nkoog:\n llm:\n fallback:\n provider: openai\n # 아래의 모델 식별자 섹션을 참조하세요.\n model: openai.chat.gpt4_1\n```\n\n2) 플러그인 설치 및 라우트 정의\n\n```kotlin\nfun Application.module() {\n install(Koog) {\n // 프로그래밍 방식으로 제공자를 설정할 수도 있습니다 (아래 참조)\n }\n\n routing {\n route(\"/ai\") {\n post(\"/chat\") {\n val userInput = call.receiveText()\n // 특정 모델을 사용하여 기본 단일 실행 에이전트를 생성하고 실행합니다.\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n }\n }\n }\n}\n```\n\n참고\n\n- `aiAgent`는 구체적인 모델(`LLModel`)이 필요합니다. 라우트별 또는 용도별로 선택하세요.\n- 더 낮은 수준의 LLM 액세스가 필요한 경우, `llm()`(`PromptExecutor`)을 직접 사용하세요.\n\n## 라우트에서 직접 LLM 사용\n\n```kotlin\npost(\"/llm-chat\") {\n val userInput = call.receiveText()\n\n val messages = llm().execute(\n prompt(\"chat\") {\n system(\"You are a helpful assistant that clarifies questions\")\n user(userInput)\n },\n GoogleModels.Gemini2_5Pro\n )\n\n // 모든 어시스턴트 메시지를 하나의 문자열로 결합합니다.\n val text = messages.joinToString(separator = \"\n\") { it.content }\n call.respond(HttpStatusCode.OK, text)\n}\n```\n\n스트리밍(Streaming)\n\n```kotlin\nget(\"/stream\") {\n val flow = llm().executeStreaming(\n prompt(\"streaming\") { user(\"Stream this response, please\") },\n OpenRouterModels.GPT4o\n )\n\n // 예시: 버퍼링 후 하나의 청크로 전송\n val sb = StringBuilder()\n flow.collect { chunk -> sb.append(chunk) }\n call.respondText(sb.toString())\n}\n```\n\n모데레이션(Moderation)\n\n```kotlin\npost(\"/moderated-chat\") {\n val userInput = call.receiveText()\n\n val moderation = llm().moderate(\n prompt(\"moderation\") { user(userInput) },\n OpenAIModels.Moderation.Omni\n )\n\n if (moderation.isHarmful) {\n call.respond(HttpStatusCode.BadRequest, \"Harmful content detected\")\n return@post\n }\n\n val output = aiAgent(\n strategy = reActStrategy(),\n model = OpenAIModels.Chat.GPT4_1,\n input = userInput\n )\n call.respond(HttpStatusCode.OK, output)\n}\n```\n\n## 프로그래밍 방식 설정 (코드 내)\n\n모든 제공자와 에이전트 동작은 `install(Koog) {}`를 통해 설정할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n llm {\n openAI(apiKey = System.getenv(\"OPENAI_API_KEY\") ?: \"\") {\n baseUrl = \"https://api.openai.com\"\n timeouts { // 아래는 기본값입니다.\n requestTimeout = 15.minutes\n connectTimeout = 60.seconds\n socketTimeout = 15.minutes\n }\n }\n anthropic(apiKey = System.getenv(\"ANTHROPIC_API_KEY\") ?: \"\")\n google(apiKey = System.getenv(\"GOOGLE_API_KEY\") ?: \"\")\n openRouter(apiKey = System.getenv(\"OPENROUTER_API_KEY\") ?: \"\")\n deepSeek(apiKey = System.getenv(\"DEEPSEEK_API_KEY\") ?: \"\")\n ollama { baseUrl = \"http://localhost:11434\" }\n\n // 제공자가 설정되지 않았을 때 PromptExecutor에서 사용할 선택적 폴백\n fallback {\n provider = LLMProvider.OpenAI\n model = OpenAIModels.Chat.GPT4_1\n }\n }\n\n agentConfig {\n // 에이전트를 위한 재사용 가능한 기본 프롬프트 제공\n prompt(name = \"agent\") {\n system(\"You are a helpful server‑side agent\")\n }\n\n // 무한 도구 호출/루프 제한\n maxAgentIterations = 10\n\n // 에이전트가 기본적으로 사용할 수 있는 도구 등록\n registerTools {\n // tool(::yourTool) // 자세한 내용은 도구 개요를 참조하세요.\n }\n\n // 에이전트 기능 설치 (트레이싱 등)\n // install(OpenTelemetry) { /* ... */ }\n }\n}\n```\n\n## 설정 내 모델 식별자 (폴백)\n\nYAML/CONF에서 `llm.fallback`을 설정할 때 다음 식별자 형식을 사용하세요.\n\n- OpenAI: `openai.chat.gpt4_1`, `openai.reasoning.o3`, `openai.costoptimized.gpt4_1mini`, `openai.audio.gpt4oaudio`, `openai.moderation.omni`\n- Anthropic: `anthropic.fable_5`, `anthropic.sonnet_4_5`, `anthropic.opus_4`, `anthropic.haiku_4_5`\n- Google: `google.gemini2_5pro`, `google.gemini2_0flash001`\n- OpenRouter: `openrouter.gpt4o`, `openrouter.gpt4`, `openrouter.claude3sonnet`\n- DeepSeek: `deepseek.deepseek-v4-flash`, `deepseek.deepseek-v4-pro`, `deepseek.deepseek-chat`, `deepseek.deepseek-reasoner`\n- Ollama: `ollama.meta.llama3.2`, `ollama.alibaba.qwq:32b`, `ollama.groq.llama3-grok-tool-use:8b`\n\n참고\n\n- OpenAI의 경우 반드시 카테고리(`chat`, `reasoning`, `costoptimized`, `audio`, `embeddings`, `moderation`)를 포함해야 합니다.\n- Ollama의 경우 `ollama.model` 및 `ollama..` 형식을 모두 지원합니다.\n\n## MCP 도구 (JVM 전용)\n\nJVM에서는 MCP 서버의 도구를 에이전트 도구 레지스트리에 추가할 수 있습니다.\n\n```kotlin\ninstall(Koog) {\n agentConfig {\n mcp {\n // SSE를 통해 등록\n sse(\"https://your-mcp-server.com/sse\")\n\n // 또는 생성된 프로세스를 통해 등록 (stdio 전송)\n // process(Runtime.getRuntime().exec(\"your-mcp-binary ...\"))\n\n // 또는 기존 MCP 클라이언트 인스턴스에서 등록\n // client(existingMcpClient)\n }\n }\n}\n```\n## 왜 Koog + Ktor인가요?\n\n- 서버에서 에이전트를 개발하기 위한 Kotlin 우선의 타입 안전한 환경\n- 깔끔하고 테스트 가능한 라우트 코드와 중앙 집중식 설정\n- 라우트별로 적합한 모델을 사용하거나, 직접 LLM 호출 시 자동으로 폴백 적용\n- 도구(tools), 모데레이션(moderation), 스트리밍(streaming), 트레이싱(tracing) 등 프로덕션 환경에 적합한 기능 제공"}}}}