
1. Koog이란 무엇인가 ?
Koog는 JetBrains가 공개한 Kotlin 기반 AI Agent 프레임워크다. KotlinConf 2025에서 소개되었고 Python이나 JavaScript 중심으로 발전해 온 Agent 프레임워크 생태계 안에서 Kotlin/JVM 개발자도 자신이 익숙한 언어와 도구로 Agent를 만들 수 있게 하는 것이다.
공식 문서에서는 Koog를 JVM 생태계를 위해 설계된 오픈소스 AI Agent 프레임워크라고 설명한다. Kotlin 개발자에게는 타입 안정적인 Kotlin DSL을 제공하고, Java 개발자에게는 fluent builder 스타일 API를 제공한다. Kotlin Multiplatform을 활용하면 JVM뿐 아니라 JS, WasmJS, Android, iOS 타겟에서도 Agent를 배포할 수 있다.
Koog은 다음 문제를 해결하려는 프레임워크다.
- LLM 호출 코드를 단순 API 래퍼 수준에서 끝내지 않고 Agent 실행 흐름으로 구조화한다
- Agent가 사용할 도구, 프롬프트, 전략, 메모리, 추적 기능을 Kotlin 코드 안에서 관리한다
- JVM 백엔드, Android, Kotlin Multiplatform 프로젝트에서 AI Agent를 자연스럽게 통합한다
2. 왜 Kotlin에 Agent 프레임워크가 필요한가 ?
AI Agent 생태계는 LangChain, LangGraph처럼 Python 중심으로 빠르게 성장했다.
JavaScript 진영에도 LangChain.js 같은 선택지가 있다. 하지만 Kotlin 개발자 입장에서는 기존 프레임워크를 쓰려면 언어의 경계를 넘나들어야 했다.
예를 들어 Kotlin 백엔드에서 Agent 기능을 넣고 싶을 때 선택지는 대략 다음과 같았다.
- Python Agent 서버를 따로 만들고 Kotlin 서비스에서 HTTP로 호출한다
- LLM API를 직접 호출하며 Agent 루프, 도구 호출, 히스토리 관리를 직접 구현한다
- Java 생태계의 AI 라이브러리를 Kotlin에서 감싸서 사용한다
셋 다 가능하지만, Kotlin스럽지는 않다. 특히 Agent는 단순히 “LLM에게 질문하고 답 받기”가 아니라 여러 단계의 작업을 실행하고, 도구를 호출하고, 실패를 복구하고, 실행 과정을 관찰해야 한다. 이 흐름이 애플리케이션 핵심 로직 안으로 들어올수록 타입 안정성, 테스트 가능성, 관측 가능성이 중요해진다.
이러한 환경속에서 Koog은 AI Agent를 Kotlin/JVM 구성 요소로 다룰 수 있게 한다.
3. Koog의 핵심 구성 요소
3.1 Agent
Koog에서 Agent는 사용자의 입력을 받아 LLM과 상호작용하고 필요하면 도구를 호출한 뒤 최종 응답을 반환하는 실행 단위다.
가장 기본적인 Agent는 미리 정의된 전략을 사용한다. 입력 문자열을 LLM에 전달하고, LLM이 도구 호출을 요청하면 Koog가 해당 도구를 실행한다. 도구 실행 결과는 다시 LLM에 전달되고, 더 이상 도구 호출이 필요 없을 때 최종 문자열 응답을 반환한다.
fun main() = runBlocking {
val apiKey = System.getenv("OPENAI_API_KEY")
?: error("The API key is not set.")
val agent = AIAgent(
promptExecutor = simpleOpenAIExecutor(apiKey),
llmModel = OpenAIModels.Chat.GPT4o
)
val result = agent.run("Hello! How can you help me?")
println(result)
}
`promptExecutor`는 실제 LLM Provider와 통신하는 역할을 한다. Koog는 LLM providers 문서에서 OpenAI, Anthropic, Google, DeepSeek, OpenRouter, Amazon Bedrock, Mistral, Alibaba, Ollama 등을 지원한다고 설명한다.
`llmModel`은 사용할 모델을 의미한다. 예제에서는 OpenAI의 GPT-4o 모델을 사용한다.
`agent.run()`은 Agent에게 작업을 실행시키는 부분이다. 단순한 질문이라면 바로 응답을 반환하지만 도구가 연결되어 있다면 중간에 도구를 호출하고 그 결과를 바탕으로 다시 응답을 생성할 수 있다.
3.2 Tools
LLM은 파일을 읽거나, 데이터베이스를 조회하거나, 외부 API를 호출하거나, 사용자에게 질문하는 일은 직접 할 수 없다. 이러한 작업을 가능하게 만드는 것이 Tool이다. Koog에서는 Kotlin 함수에 `@Tool`과 설명을 붙여 Agent가 사용할 수 있는 도구로 등록할 수 있다.
이 내용은 Tools overview 문서와 Basic agents 문서의 Tool 예시에서 확인할 수 있다.
@Tool
@LLMDescription("Ask the user a question by sending it to stdout and return the answer from stdin")
fun askUser(
@LLMDescription("Question from the agent")
question: String
): String {
println(question)
return readln()
}
val agent = AIAgent(
promptExecutor = simpleOpenAIExecutor(System.getenv("OPENAI_API_KEY")),
llmModel = OpenAIModels.Chat.GPT4o,
toolRegistry = ToolRegistry {
tool(::askUser)
}
)
비유하자면 Tool은 Agent의 손과 발이다. 데이터베이스 조회, 외부 API 호출, 파일 처리 같은 작업을 Tool로 제공하면 LLM은 상황에 맞춰 어떤 도구를 호출할지 판단할 수 있다.
하지만 여기서 조심해야 할 점도 있다. Tool은 Agent에게 권한을 주는 행위다. 읽기만 가능한 도구와 실제로 데이터를 변경하는 도구는 위험도가 다르다. 따라서 Tool을 설계할 때는 항상 권한 범위를 고려해야 한다.
3.3 Strategy
Agent가 단순한 질문에 답하는 수준을 넘어 복잡한 작업을 수행하려면 구체적인 실행 흐름이 필요하다.
Koog에서는 이 실행 흐름을 `Strategy`로 다룬다. 공식 문서에서는 여러 형태의 Agent 전략을 제공한다.
- Basic agent: 대부분의 간단한 사용 사례에 맞는 기본 실행 흐름
- Functional agent: Kotlin/Java 코드의 함수형 흐름으로 Agent 단계를 구성
- Graph-based agent: 노드와 엣지로 Agent 워크플로우를 정의
- Planner agent: 목표 상태를 향해 계획을 세우고 실행
여기서 흥미로운 부분은 Graph-based agent다. Agent 흐름을 그래프로 표현하면 각 단계를 명확히 나누고, 조건 분기와 재시도, 검증 루프를 모델링하기 좋아진다. 또한 실행 상태를 특정 지점에 저장하고 복구하는 persistence 기능과 잘 맞는다.
3.4 Memory, Compression, Persistence
Agent가 한 번 답하고 끝나는 챗봇이라면 메모리의 중요성이 크지 않을 수 있다. 하지만 여러 단계를 거치는 작업이라면 이야기가 달라진다. 예를 들어 Agent가 PR을 분석하다가 중간에 실패했다고 생각해 보자. 처음부터 다시 모든 파일을 읽고, 다시 분석하고, 다시 판단해야 한다면 비용도 크고 사용자 경험도 좋지 않다.
Koog는 이런 문제를 해결하기 위해 다음 기능을 제공한다.
- History compression: 긴 대화나 작업 기록을 압축해 토큰 사용량을 줄이는 기능이다. Agent가 오래 실행될수록 대화 히스토리가 길어지는데, 이를 그대로 모델에 전달하면 비용이 커지고 컨텍스트 한계에 도달할 수 있다.
- Chat memory / long-term memory: 세션 간 지식 유지나 검색 기반 응답을 지원한다
- Agent persistence: 실행 상태를 저장해 장애 발생 후 특정 지점부터 복구한다
3.5 Observability
Agent 시스템은 일반 코드보다 디버깅이 어렵다. 같은 입력이어도 모델 응답이 달라질 수 있고, 도구 호출 순서도 달라질 수 있다. 그래서 실제 운영 환경에서는 “Agent가 왜 그렇게 행동했는가”를 추적하는 능력이 중요하다.
이를 위해 Koog은 `tracing`과 `OpenTelemetry` 기능을 제공한다. `OpenTelemetry`는 무슨 일이 일어났는지 추적하기 위한 관측 도구다. 하나의 사용자 요청이 시스템 안에서 지나간 전체 경로를 Trace라고 하고, 그 안에서 나뉘는 개별 실행 단계를 Span이라고 한다.
예를 들어 Agent가 사용자의 요청을 받고, LLM을 호출하고, Tool을 실행한 뒤 다시 응답을 생성했다면 이 전체 흐름은 하나의 Trace가 된다. 그리고 AIAgent 실행, LLM 호출, Tool 호출, 최종 응답 생성 같은 단계는 각각 Span으로 기록될 수 있다.
Koog는 OpenTelemetry support 문서에서 Agent 실행, 노드 실행, LLM 호출, Tool 호출을 span으로 추적할 수 있다고 설명한다. 이를 통해 Agent가 어떤 LLM 호출을 했는지, 어떤 도구를 호출했는지, 어느 단계에서 시간이 오래 걸렸는지, 토큰과 비용이 얼마나 발생했는지 확인할 수 있다.
4. MCP와 A2A 지원
Koog 문서에서 눈에 띄는 부분 중 하나는 MCP(Model Context Protocol)와 A2A(Agent2Agent) Protocol 지원이다.
MCP(Model Context Protocol) : Agent가 외부 도구와 컨텍스트에 접근하기 위한 프로토콜
MCP는 Agent가 외부 도구와 컨텍스트에 접근하는 표준화된 방식으로 자리 잡고 있다. Koog에서 MCP 도구를 직접 Agent에 연결할 수 있기 때문에 MCP 생태계의 도구들을 활용할 수 있다.
A2A(Agent2Agent) : Agent 간 통신을 위한 프로토콜
참고 자료
- PyTorchKR: Koog, JetBrains의 새로운 Kotlin 기반 AI 에이전트 프레임워크
- JetBrains Blog: Meet Koog
- JetBrains Blog: Koog Comes to Java
- Koog 공식 문서
- Koog Quickstart
- Koog GitHub Repository
'KOTLIN' 카테고리의 다른 글
| MutableSharedFlow Internals (0) | 2026.06.14 |
|---|---|
| Kotlin Generic Type System (2) | 2025.04.10 |
| Abstract class vs interface in Kotlin (2) | 2025.04.01 |
| 다시 읽는 Effective Kotlin - Item39. 태그 클래스보다는 클래스 계층을 사용하라 (2) | 2025.03.23 |
| 다시 읽는 Effective Kotlin - Item33. 생성자 대신 팩토리 함수를 사용하라 (2) | 2025.03.02 |
