Logo
Published on

第一次學 Kotlin Koog AI 就上手 Day 04:多 LLM 供應商整合

在前面的學習中,我們已經建立了基本的 Koog AI Agent 並了解了提示系統的 DSL 語法。今天我們將探索 Koog 框架的重要特色:多 LLM 供應商整合

在實際應用中,依賴單一 LLM 供應商往往會面臨成本、效能和可靠性的挑戰。Koog 的多供應商支援讓我們能夠建立更穩健和更靈活的 AI 應用

為什麼需要多 LLM 整合?

在深入技術實作之前,讓我們先了解多 LLM 整合的重要性

能力互補優勢

每個 LLM 供應商都有其擅長領域,根據實際使用經驗,不同供應商適合不同的使用場景

實際使用場景分配

  • OpenAI:日常使用、通用對話、問答互動
  • Anthropic:程式設計、技術問題解決
  • Google Gemini:大 Context 處理、處理大量資料、長文本分析
  • 本地 Ollama:隱私保護、離線運行、無 API 限制

這裡的使用場景是根據我平常的使用習慣來區分的

可靠性和風險管控

多 LLM 策略可以顯著提升應用穩定性

實際效益

  • 故障備用:當主要供應商服務中斷時,自動切換到備用供應商
  • 過載分散:在高併發時段分散請求到多個供應商
  • 限制管理:避免觸發單一供應商的 API 限制
  • 成本控制:根據預算限制智能選擇模型

支援的 LLM 供應商

Koog 目前支援以下 LLM 供應商

模型選擇說明:每個 LLM 供應商都有眾多模型可選擇,不可能在文章中一一列出和介紹。這裡我只列舉比較常用或 CP 值比較高的模型作為範例,實際使用時請根據個人需求、預算和應用場景來選擇最適合的模型

雲端服務供應商

  • OpenAI
    • GPT-5 (mini)(2025年8月發布,最新模型)
    • GPT-4.1 (mini)(2025年4月發布)
    • 日常對話、問題解決

重要說明:雖然 GPT-5 是 OpenAI 最新的模型,但因為 Koog 框架還沒有更新相關的 model 程式碼支援,所以統一使用 GPT-4.1 (mini),包含先前的文章也是一樣

  • Anthropic

    • Claude Opus 4.1(2025年8月發布,最新模型)
    • Claude 4 Sonnet(程式設計專長)
    • 優秀的程式碼設計、寫作能力
  • Google AI

    • Gemini 2.5 Flash(2025年發布,支援 thinking 能力)
    • 強大的多模態能力和大 Context 處理
  • OpenRouter

    • 統一接入多種模型
    • 自動路由和負載均衡
    • 包含開源模型支援

本地部署

  • Ollama
    • gpt-oss:20b(OpenAI 2025年開源模型,16GB RAM 即可運行)
    • Llama 3.1、Llama 3.2
    • Code Llama、Mistral
    • 完全離線運行

這裡只有列出部份支援的 LLM 供應商而已, 沒有全部

基本多供應商配置

IntelliJ IDEA 環境變數配置

注意:基於 API 測試費用考量,本教學僅使用兩個雲端 API(OpenAI、Google)和本地模型(Ollama)進行測試

在 IntelliJ IDEA 中設定環境變數(參考 Day 02 的設定方式)

  • 編輯 Run Configuration
  • Environment variables 欄位中加入
OPENAI_API_KEY=你的OpenAI API金鑰
GOOGLE_API_KEY=你的Google API金鑰
OLLAMA_BASE_URL=http://localhost:11434

管理 Api Key 類別

object ApiKeyManager {
    val openAIApiKey: String = System.getenv("OPENAI_API_KEY")
    val googleApiKey: String = System.getenv("GOOGLE_API_KEY")
    val ollamaBaseUrl: String = System.getenv("OLLAMA_BASE_URL")

    // 檢查可用的供應商
    fun getAvailableProviders(): List<String> {
        val available = mutableListOf<String>()

        if (openAIApiKey.isNotBlank()) {
            available.add("OpenAI")
        }

        if (googleApiKey.isNotBlank()) {
            available.add("Google")
        }

        if (ollamaBaseUrl.isNotBlank()) {
            available.add("Ollama")
        }

        return available
    }
}

建立多 LLM 執行器

Koog 提供了 MultiLLMPromptExecutor 來統一管理多個 LLM 客戶端

class BasicMultiLLMSetup {
    fun createBasicMultiExecutor(): MultiLLMPromptExecutor {

        val executors = mutableMapOf<LLMProvider, LLMClient>()

        ApiKeyManager.openAIApiKey?.let { apiKey ->
            executors[LLMProvider.OpenAI] = OpenAILLMClient(apiKey)
            println("✅ OpenAI GPT 執行器已加入(大 Context 處理)")
        }

        ApiKeyManager.googleApiKey?.let { apiKey ->
            executors[LLMProvider.Google] = GoogleLLMClient(apiKey)
            println("✅ Google Gemini 執行器已加入(大 Context 處理)")
        }

        ApiKeyManager.ollamaBaseUrl?.let { baseUrl ->
            executors[LLMProvider.Ollama] = OllamaClient(baseUrl)
            println("✅ Ollama 執行器已加入(本地隱私保護)")
        }

        return MultiLLMPromptExecutor(executors)
    }
}

實作基本多 LLM 應用

讓我們建立一個簡單的多 LLM 應用,展示基本的整合使用

suspend fun main() {
    println("🤖 多 LLM 助手系統啟動中...")

    // 顯示可用的供應商
    println("📋 可用的 LLM 供應商:")
    ApiKeyManager.getAvailableProviders().forEach { provider ->
        println("   ✅ $provider")
    }

    try {
        val setup = BasicMultiLLMSetup()
        val multiExecutor = setup.createBasicMultiExecutor()

        // 建立多 LLM Agent
        val agent = AIAgent(
            executor = multiExecutor,
            systemPrompt = "你是一個智能助手,使用多個 LLM 供應商為使用者提供最佳服務。請用正體中文回答問題。",
            llmModel = OpenAIModels.CostOptimized.GPT4_1Mini
        )

        println("\n✅ 多 LLM 助手系統已就緒!")

        // 測試不同類型的問題
        val testQuestions = listOf(
            "你好,你現在正在使用哪個模型回答問題? 請具體回答出那一個模型"
        )

        println("\n👤 使用者:$question")
        println("🤖 AI 回答:")
        val response = agent.run(question)
        println(response)

    } catch (e: Exception) {
        println("❌ 系統啟動失敗:${e.message}")
        e.printStackTrace()
    }
}

執行 AI 回應內容

基本上,這裡會根據你給它的 Model 來決定使用哪個 Executor (供應商) 先使用 OpenAIModels.CostOptimized.GPT4_1Mini 來執行測試

🤖 多 LLM 助手系統啟動中...
📋 可用的 LLM 供應商:
OpenAI (GPT-4.1 mini)
Google (Gemini 2.5 Flash)
Ollama (gpt-oss:20b)
OpenAI GPT 執行器已加入(大 Context 處理)
Google Gemini 執行器已加入(大 Context 處理)
Ollama 執行器已加入(本地隱私保護)

✅ 多 LLM 助手系統已就緒!

👤 使用者:你好,你現在正在使用哪個模型回答問題? 請具體回答出那一個模型
🤖 AI 回答:
你好!我目前使用的是OpenAI的GPT-4模型來回答你的問題。如果你有任何需要,隨時告訴我!

如果我們把 Model 換成 GoogleModels.Gemini2_5Flash

🤖 多 LLM 助手系統啟動中...
📋 可用的 LLM 供應商:
OpenAI
Google
Ollama
OpenAI GPT 執行器已加入(大 Context 處理)
Google Gemini 執行器已加入(大 Context 處理)
Ollama 執行器已加入(本地隱私保護)

✅ 多 LLM 助手系統已就緒!

👤 使用者:你好,你現在正在使用哪個模型回答問題? 請具體回答出那一個模型
🤖 AI 回答:
你好!

我是一個大型語言模型,由 Google 訓練。

自動依任務選擇模型

在前面的範例,雖然 AIAgent 會自動根據模型來選擇 Executor,不過還是需要寫死模型在程式碼裡面,我們是不是可以改成,自動根據任務類型來選擇合適的模型,這樣子就不用人工介入了

建立多供應商模型選擇

BasicMultiLLMSetup 裡增加一個依 task 來選擇模型的 fun

注意,這裡沒有考慮到 AI 供應商是否可用的問題,只是單純的選擇模型

// 簡單的供應商模型選擇
fun selectModelForTask(taskType: String): LLModel {
    return when (taskType.lowercase()) {
        // 日常對話的最佳選擇
        "chat", "conversation" -> OpenAIModels.CostOptimized.GPT4_1Mini
        // 大 Context 資料處理(
        "data", "analysis" -> GoogleModels.Gemini2_5Flash
        // Ollama
        "privacy", "local" -> OllamaModels.Meta.LLAMA_3_2_3B
        // 通用任務的平衡選擇
        else -> OpenAIModels.CostOptimized.GPT4_1Mini
    }
}

建立自動依 task 來產生 AI Agent

可以把相關對應 task 的 prompt 都先寫好,只要使用者輸入對應的 task,就會自動給它對應的 AI Agent

class BasicMultiLLMAssistant {

    private val multiLLMSetup = BasicMultiLLMSetup()

    fun createAgent(taskType: String): AIAgent<String, String> {
        val multiExecutor = multiLLMSetup.createBasicMultiExecutor()
        val modelSuggestion = multiLLMSetup.selectModelForTask(taskType)

        println("Task: $taskType, 🎯 模型:${model.provider} - ${model.id}")

        return AIAgent(
            executor = multiExecutor,
            systemPrompt = buildTaskPrompt(taskType),
            llmModel = modelSuggestion,
            maxIterations = 5
        )
    }

    private fun buildTaskPrompt(taskType: String): String {
        return when (taskType.lowercase()) {
            "chat", "conversation" -> """
                你是一個友善的 AI 助手,用正體中文回答問題
                - 以自然、溫暖的方式回應
                - 提供有用的資訊和建議
                - 保持禮貌和專業的態度
            """.trimIndent()

            "data", "analysis" -> """
                你是一個資料分析助手,用正體中文回答問題
                - 仔細分析提供的大量資訊
                - 提供結構化的分析結果
                - 善於處理複雜的資料和長文本
            """.trimIndent()

            "privacy", "local" -> """
                你是一個注重隱私的本地助手,用正體中文回答問題
                - 優先保護使用者隱私
                - 提供安全可靠的建議
                - 不會將資料傳送到外部服務
            """.trimIndent()

            else -> """
                你是一個通用 AI 助手,用正體中文回答問題
                - 根據使用者需求提供協助
                - 保持專業和有用的回應
                - 適時詢問更多細節以提供更好的服務
            """.trimIndent()
        }
    }
}

測試依 task 來自動選擇 AI Agent

建立一個簡單的測試程式來驗證多 LLM 設定

suspend fun main() {
    println("🤖 多 LLM 助手系統啟動中...")

    // 顯示可用的供應商
    println("📋 可用的 LLM 供應商:")
    ApiKeyManager.getAvailableProviders().forEach { provider ->
        println("   ✅ $provider")
    }

    try {
        val setup = BasicMultiLLMAssistant()

        println("\n✅ 多 LLM 助手系統已就緒!")

        // 顯示可用的任務類型
        println("\n📋 可用的任務類型:")
        println("   1. chat - 日常對話")
        println("   2. data - 資料分析")
        println("   3. privacy - 隱私保護(本地處理)")

        // 使用者輸入任務類型
        print("\n請輸入任務類型(chat/data/privacy):")
        val taskType = readlnOrNull()?.trim() ?: "chat"

        // 建立對應的 Agent
        val agent = setup.createAgent(taskType)

        // 使用者輸入問題
        print("請輸入您的問題:")
        val question = "你好,你現在正在使用哪個模型回答問題? 請具體回答出那一個模型"

        println("\n👤 使用者:$question")
        println("🤖 AI 回答:")
        val response = agent.run(question)
        println(response)

    } catch (e: Exception) {
        println("❌ 系統啟動失敗:${e.message}")
        e.printStackTrace()
    }
}

執行 AI 回應內容

🤖 多 LLM 助手系統啟動中...
📋 可用的 LLM 供應商:
OpenAI
Google
Ollama

✅ 多 LLM 助手系統已就緒!

📋 可用的任務類型:
   1. chat - 日常對話
   2. data - 資料分析
   3. privacy - 隱私保護(本地處理)

請輸入任務類型(chat/data/privacy):chat

OpenAI GPT 執行器已加入(大 Context 處理)
Google Gemini 執行器已加入(大 Context 處理)
Ollama 執行器已加入(本地隱私保護)
Task: chat, 🎯 模型:OpenAI - gpt-4.1-mini
請輸入您的問題:
👤 使用者:你好,你現在正在使用哪個模型回答問題? 請具體回答出那一個模型
🤖 AI 回答:
你好!我現在是基於 OpenAIGPT-4 模型來回答你的問題。如果你有任何疑問或需要幫助,隨時告訴我哦!很高興為你服務。

實作錯誤處理與 Fallback 機制

在實際應用中,LLM 供應商可能會遇到服務中斷、API 限制或網路問題。讓我們繼承 BasicMultiLLMSetup,實作一個簡單實用的 Fallback 機制,當主要供應商失敗時自動切換到備用供應商

這邊接續第一個範例來實作 Fallback 機制,暫不考慮 auto fallback 選擇供應商

建立簡單的 Fallback 系統

class FallbackMultiLLMSetup : BasicMultiLLMSetup() {

    // 建立主要和備用執行器
    private val primaryExecutor = simpleOpenAIExecutor(ApiKeyManager.openAIApiKey!!)
    private val fallbackExecutor = simpleGoogleAIExecutor(ApiKeyManager.googleApiKey!!)

    // 定義主要和備用模型
    private val primaryModel = OpenAIModels.CostOptimized.GPT4_1Mini
    private val fallbackModel = GoogleModels.Gemini2_5Flash

    // 簡單的備用機制 - 主要邏輯
    suspend fun executeWithFallback(prompt: Prompt): String {
        return try {
            println("🔄 嘗試使用 OpenAI 供應商...")
            val result = primaryExecutor.execute(prompt, primaryModel)
            println("✅ OpenAI 供應商回應成功")

            // 假設回應格式,實際需要根據框架調整
            result.firstOrNull()?.content ?: "無回應內容"

        } catch (e: Exception) {
            println("❌ OpenAI 供應商失敗:${e.message}")
            println("🔄 切換到 Google 備用供應商...")

            try {
                val fallbackResult = fallbackExecutor.execute(prompt, fallbackModel)
                println("✅ Google 供應商回應成功")
                fallbackResult.firstOrNull()?.content ?: "無回應內容"

            } catch (fallbackError: Exception) {
                println("❌ Google 備用供應商也失敗:${fallbackError.message}")
                throw Exception("所有 LLM 供應商都無法使用。主要錯誤:${e.message},備用錯誤:${fallbackError.message}")
            }
        }
    }

    // 建立簡化的對話介面
    fun createSimpleFallbackChat(): SimpleFallbackChat {
        return SimpleFallbackChat(this)
    }
}

// 簡單的對話包裝器
class SimpleFallbackChat(private val setup: FallbackMultiLLMSetup) {

    suspend fun chat(question: String): String {
        // 建立簡單的文字提示
        val prompt = prompt("fallback-chat") {
            system("你是一個通用 AI 助手,用正體中文回答問題")
            user(question)
        }

        return setup.executeWithFallback(prompt)
    }
}

測試 Fallback 機制

suspend fun main() {
    println("🤖 帶有 Fallback 機制的多 LLM 助手系統啟動中...")

    // 顯示可用的供應商
    println("📋 可用的 LLM 供應商:")
    ApiKeyManager.getAvailableProviders().forEach { provider ->
        println("   ✅ $provider")
    }

    try {
        val setup = FallbackMultiLLMSetup()

        println("\n✅ Fallback 多 LLM 助手系統已就緒!")
        println("🛡️  當主要供應商失敗時,系統會自動切換到備用供應商")

        // 建立簡化的 Fallback 對話
        val chat = setup.createSimpleFallbackChat()

        val question = "你好,請介紹你自己,並告訴我你是使用哪個模型回答的?"

        println("\n👤 使用者:$question")
        println("🤖 AI 回答:")

        val response = chat.chat(question)
        println(response)

    } catch (e: Exception) {
        println("❌ 系統完全失敗:${e.message}")
        e.printStackTrace()
    }
}

執行 AI 回應內容

主要供應商正常運作

🤖 帶有 Fallback 機制的多 LLM 助手系統啟動中...
📋 可用的 LLM 供應商:
OpenAI
Google
Ollama

FallbackLLM 助手系統已就緒!
🛡️  當主要供應商失敗時,系統會自動切換到備用供應商

👤 使用者:你好,你現在正在使用哪個模型回答問題? 請具體回答出那一個模型
🤖 AI 回答:
🔄 嘗試使用 OpenAI 供應商...
OpenAI 供應商回應成功
你好!我現在使用的是基於 OpenAIGPT-4 架構的語言模型來回答你的問題。

主要供應商失敗,自動 Fallback

透過一個有問題的 OpenAI API Key,來模擬切換供應商

🤖 帶有 Fallback 機制的多 LLM 助手系統啟動中...
📋 可用的 LLM 供應商:
OpenAI (模擬失敗)
Google
Ollama

FallbackLLM 助手系統已就緒!
🛡️  當主要供應商失敗時,系統會自動切換到備用供應商

👤 使用者:你好,你現在正在使用哪個模型回答問題? 請具體回答出那一個模型
🤖 AI 回答:
🔄 嘗試使用 OpenAI 供應商...
OpenAI 供應商失敗:Error from OpenAI API: 401 Unauthorized: {
    "error": {
        "message": "Incorrect API key provided: error. You can find your API key at https://platform.openai.com/account/api-keys.",
        "type": "invalid_request_error",
        "param": null,
        "code": "invalid_api_key"
    }
}

🔄 切換到 Google 備用供應商...
Google 供應商回應成功
我是一個大型語言模型,由 Google 訓練。

Fallback 機制的優勢

這個 Fallback 實作提供了以下優勢

  • 自動容錯

    • 當主要供應商失敗時,無需人工介入即可自動切換
    • 保證服務的持續性和可用性
  • 優先級管理

    • 可根據成本、效能、可靠性設定供應商優先順序
    • 靈活調整不同場景下的選擇策略
  • 透明的錯誤處理

    • 清楚記錄每次嘗試和失敗的原因
    • 方便除錯和監控系統狀態
  • 成本優化

    • 優先使用成本較低的供應商
    • 只在必要時才使用較昂貴的備用方案

總結

今天我們學習了 Koog 框架的多 LLM 供應商整合基礎,掌握了以下核心概念

  • 了解多 LLM 整合的基本概念和價值
  • 學會配置多個 LLM 供應商環境
  • 建立簡單的多 LLM 助手應用
  • 學會根據任務類型選擇適合的模型
  • 掌握錯誤處理和 Fallback 機制的基本概念

下一篇文章我們將探索 Koog 的工具系統入門,學習如何為 AI Agent 添加實際的操作能力,從純粹的對話系統進化為能夠執行具體任務的 AI 助手

參考文件


支持創作

如果這篇文章對您有幫助,歡迎透過 贊助連結 支持我持續創作優質內容。您的支持是我前進的動力!


圖片來源:AI 產生