🤖

Koog入門 - AIエージェントフレームワークで単一実行エージェントを実装してみた

に公開

はじめに

最近、JetBrainsから発表されたKoogというAIエージェントフレームワークが気になったので、実際に触ってみました。本記事は連載形式でKoogの基本から応用まで段階的に解説していく予定で、今回はその第1回として「単一実行エージェント(Single-run Agents)」の実装にフォーカスします。

今回は無料で利用できるGoogle AI(Gemini)のAPIを使用して実装していきます。

Koogとは

KoogはJetBrainsが開発したAIエージェントフレームワークです。Kotlinで書かれており、AIエージェントを簡単に構築・実行できます。

対応しているLLMプロバイダー

  • OpenAI
  • Anthropic
  • Google AI (Gemini) ← 今回使用
  • OpenRouter
  • Ollama

2つの開発アプローチ

Koogでエージェントを作る方法は大きく2つあります。

  1. Simple API(シンプルAPI): 数行のコードで動く簡単なエージェントを作るための方法
  2. AI Agent(高機能版): 複数の処理を同時に実行したり、複雑な条件分岐を持つエージェントを作るための方法

今回の記事では、入門として Simple API を使って実装していきます。

今回作るもの(単一実行エージェント)

単一実行エージェント(Single-run Agent)は、以下のような特徴を持つシンプルなエージェントです。

  • 1つの入力に対して1つの応答を返す
  • 状態を持たない(ステートレス)
  • REST APIやチャットボットに最適

今回は、Spring BootアプリケーションにKoogを組み込んで、Google AI(Gemini)を使ったREST APIを実装します。

環境構築

プロジェクトにはKoog公式ドキュメントを参考に必要な依存関係を追加します。主に以下のライブラリが必要です。

  • Spring Boot Starter Web
  • Koog Agents(エージェントのコア機能)
  • Koog Prompt Executors(LLMプロバイダー連携)

詳細な設定はサンプルリポジトリを参照してください。

プロジェクト構成

koog-examples/
├── app/src/main/kotlin/com/koog/examples/
│   ├── Application.kt
│   └── phase1/
│       ├── config/AgentConfig.kt         # エージェント設定
│       ├── agent/
│       │   ├── HelloWorldAgent.kt        # 基本エージェント
│       │   └── ChatAgent.kt              # チャットエージェント
│       ├── controller/AgentController.kt # REST API
│       └── dto/                          # リクエスト/レスポンス
└── compose.yaml                          # Docker設定

エージェント設定

Spring Bootの設定プロパティとKoogのモデル設定を統合します。

@ConfigurationProperties(prefix = "agent")
data class AgentConfig(
    val apiKey: String = "",         // Google AI APIキー
    val model: String = "gemini-2.0-flash-001",  // 使用するGeminiモデル名
    val systemPrompt: String = "You are a helpful assistant. Please respond in Japanese."
) {
    // Spring設定から読み込んだ文字列をKoogのLLModelに変換
    val llmModel: LLModel
        get() = when (model) {
            "gemini-2.0-flash-001" -> GoogleModels.Gemini2_0Flash001
            "gemini-2.0-flash" -> GoogleModels.Gemini2_0Flash
            else -> GoogleModels.Gemini2_0Flash001  // デフォルト
        }
}

application.yamlでの設定例

agent:
  apiKey: ${GOOGLE_API_KEY}  # 環境変数から取得
  model: gemini-2.0-flash-001
  systemPrompt: "You are a helpful assistant. Please respond in Japanese."

HelloWorldAgent

最もシンプルな単一実行エージェントの実装です。

@Component
class HelloWorldAgent(
    private val config: AgentConfig  // Springの設定クラスをDI
) {
    private val logger = KotlinLogging.logger {}

    suspend fun runExample(): String {
        logger.info { "Starting Hello World Agent example..." }
        logger.info { "Using model: ${config.model}" }

        // AIエージェントの作成
        // simpleGoogleAIExecutor: Google AI (Gemini)用の簡易的なExecutorファクトリー
        val agent = AIAgent(
            executor = simpleGoogleAIExecutor(config.apiKey),  // Google APIキーを使用
            systemPrompt = config.systemPrompt,  // エージェントの振る舞いを定義
            llmModel = config.llmModel          // 使用するLLMモデル(Gemini)
        )

        // 基本的な対話の実行
        val userMessage = "Hello! How can you help me?"
        logger.info { "Sending message: $userMessage" }

        // runAndGetResult: 単一のメッセージを送信して結果を取得
        val result = agent.runAndGetResult(userMessage)
        logger.info { "Agent response: $result" }
        
        return result.orEmpty()  // nullの場合は空文字を返す
    }
}

ChatAgent

任意のメッセージを処理できる汎用的なエージェントです。

@Component
class ChatAgent(
    private val config: AgentConfig
) {
    private val logger = KotlinLogging.logger {}

    suspend fun processMessage(message: String): String {
        logger.info { "Processing message: $message" }
        logger.info { "Using model: ${config.model}" }

        // エージェントの作成(リクエストごとに新規作成)
        val agent = AIAgent(
            executor = simpleGoogleAIExecutor(config.apiKey),  // Google AI (Gemini)を使用
            systemPrompt = config.systemPrompt,
            llmModel = config.llmModel,
            temperature = 0.7,  // 0.0-1.0: 値が高いほど創造的な応答
            // maxIterations = 1,  // デフォルトは1(単一実行)
            // toolRegistry = ToolRegistry { ... }  // ツールを追加する場合
        )

        // ユーザーメッセージを処理
        val result = agent.runAndGetResult(message)
        logger.info { "Agent response: $result" }

        return result.orEmpty()
    }
}

ポイント

  • エージェントはステートレスなので、リクエストごとに新規作成
  • temperatureパラメータで応答の創造性を調整可能
  • 必要に応じてツールやイベントハンドラーを追加可能

REST APIコントローラー

Spring BootのコントローラーでAPIエンドポイントを定義します。

@RestController
@RequestMapping("/api/agents")
class AgentController(
    private val helloWorldAgent: HelloWorldAgent,  // SpringのDIで注入
    private val chatAgent: ChatAgent
) {
    @GetMapping("/hello")
    fun runHelloWorldAgent(): Map<String, Any> {
        return try {
            // runBlocking: suspend関数を同期的に実行
            // Spring WebMVCは現時点でコルーチンをネイティブサポートしていないため
            val result = runBlocking { helloWorldAgent.runExample() }
            mapOf(
                "status" to "success",
                "response" to result
            )
        } catch (e: Exception) {
            mapOf(
                "status" to "error",
                "message" to "Error: ${e.message}"
            )
        }
    }

    @PostMapping("/chat")
    fun chat(@RequestBody request: ChatRequest): ChatResponse {
        return try {
            val response = runBlocking { 
                chatAgent.processMessage(request.message) 
            }
            ChatResponse(
                status = "success",
                message = request.message,    // 元のメッセージも返す
                response = response           // AIの応答
            )
        } catch (e: Exception) {
            // エラー時も同じ形式でレスポンス
            ChatResponse(
                status = "error",
                message = request.message,
                response = "Error: ${e.message}"
            )
        }
    }
}

// DTOクラス
data class ChatRequest(val message: String)
data class ChatResponse(
    val status: String,
    val message: String,
    val response: String
)

動作確認

Docker Composeで環境を構築し、実際に動かしてみます。

1. 事前準備

Google AI StudioでAPIキーを取得(無料)
https://aistudio.google.com/apikey

2. 環境変数設定

.envファイルを作成

GOOGLE_API_KEY=your_google_api_key_here  # Google AI Studioで取得したキー
AGENT_MODEL=gemini-2.0-flash-001
AGENT_SYSTEM_PROMPT="You are a helpful assistant. Please respond in Japanese."

3. アプリケーション起動

docker-compose up -d

4. APIの動作確認

HelloWorldAgent(GETリクエスト)

curl http://localhost:8080/api/agents/hello

レスポンス例

{
  "status": "success",
  "response": "こんにちは!どのようなご用件でしょうか?\n\n*   質問に答えたり、\n*   情報を提供したり、\n*   文章を作成したり、\n*   翻訳したり、\n*   アイデア出しのお手伝いをしたり、\n*   その他、できることがたくさんあります。\n\n何か具体的なご希望があれば、お気軽にお申し付けください。\n"
}

ChatAgent(POSTリクエスト)

curl -X POST http://localhost:8080/api/agents/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Kotlinについて教えて"}'

レスポンス例

{
  "status": "success",
  "message": "Kotlinについて教えて",
  "response": "Kotlinは、JetBrainsが開発したプログラミング言語です。2011年に発表され、2017年にGoogleがAndroidの公式開発言語として採用したことで広く知られるようになりました。\n\n**Kotlinの主な特徴:**\n\n1. **簡潔性**: Javaよりも少ないコードで同じことができます\n2. **安全性**: Null安全性が言語レベルで組み込まれています\n3. **相互運用性**: Javaと100%互換性があります\n4. **マルチプラットフォーム**: JVM、Android、JavaScript、Nativeで動作します\n\n何か具体的にKotlinについて知りたいことはありますか?"
}

まとめ

Koogの単一実行エージェントは、AIエージェントの入門として最適な機能です。Google AI(Gemini)の無料APIを使えば費用をかけずに試すことができ、Spring Bootとの統合も簡単なので、既存のWebアプリケーションにAI機能を追加したい場合に有効でしょう。

ただし、Koogはまだ新しいフレームワークのため、サンプルコードやコミュニティ情報が限られています。特に日本語の情報はまだほとんどない状況です。しかし、JetBrains製ということもあり、今後の発展が期待できるフレームワークです。

Koog 0.3.0のリリースについて

本記事ではKoog 0.2.1を使用していますが、2025年7月にKoog 0.3.0がリリースされました。このバージョンでは、エージェントをより堅牢で実用的にする多くの新機能が追加されています。

主な新機能

  • エージェントの永続化: エージェントの状態をローカルディスク、S3、データベースに保存・復元可能に
  • チェックポイント機能: 以前の状態にロールバック可能で、障害に強いエージェントの構築が可能
  • ベクトルストレージの改善: RAG(Retrieval-Augmented Generation)パイプライン構築のための永続的なベクトルストレージサポート
  • 観測性とモデレーション: OpenTelemetryネイティブサポートによるトレーシング・ロギング、コンテンツモデレーション機能
  • 並列実行: 独立したグラフノードの並列実行、MapReduceスタイルAPIによる複数ブランチの同時処理
  • その他の機能強化: ReActスタイルの推論、画像入力サポート、WebAssemblyデプロイメント、Amazon Bedrockサポートなど

これらの新機能により、プロダクションレベルのAIエージェントアプリケーションの構築がより現実的になりました。

今後の記事予定

次回以降の記事では、ツール統合やストリーミングAPIといった基本的な機能から、Koog 0.3.0で追加されたエージェントの永続化、RAGパイプライン、並列実行などの高度な機能まで、段階的に解説していく予定です。

サンプルコード

今回の実装コードは以下のリポジトリで公開しています。

参考資料

Discussion