云计算百科
云计算领域专业知识百科平台

KMP 全栈开发:用 Koog 框架构建原生 AI Agent


在这里插入图片描述


KMP 全栈开发:用 Koog 框架构建原生 AI Agent


摘要

2026 年,Kotlin Multiplatform(KMP)已从实验性技术跃迁为企业级生产方案,而 JetBrains 推出的 Koog 框架则填补了 JVM/Kotlin 生态在 AI Agent 领域的空白。本文是一篇面向新手的完整实战教程,从零开始手把手带你使用 Koog 框架在 KMP 项目中构建原生 AI Agent。内容涵盖:KMP 生态最新演进与 Koog 框架概览、多平台开发环境搭建与 Gradle 配置、Koog 核心概念(Prompt、Tool、Strategy、Graph)深度解析、Android 端首个 Agent 实例创建、自定义工具函数开发、多轮对话状态机设计、iOS 与 Desktop 端跨平台迁移验证、编译报错排查与依赖冲突解决、流式响应与线程调度性能优化,以及脱离 Python 服务实现纯 Kotlin 端侧智能体的进阶方案。全文配有完整可运行代码、详细注释、常见陷阱警示与排查方案,帮助你在最短时间内将 AI Agent 能力落地到 Android、iOS、Desktop 全平台。

适用读者:具备 Kotlin 基础语法、了解 Android 开发基本流程、对 AI/LLM 有初步认知的开发者。

技术版本基准:Kotlin 2.2+ / Koog 0.7.x / AGP 9.0 / Gradle 8.10+ / Compose Multiplatform 1.11+


目录

  • 一、KotlinConf 2026 后 KMP 生态进化与 Koog 框架概览

    • 1.1 KMP 2026 生态全景:从逻辑共享到全平台覆盖
    • 1.2 Koog 框架诞生背景与设计哲学
      • 1.2.1 为什么 JVM 生态需要原生 Agent 框架
      • 1.2.2 Koog 的五层架构设计
    • 1.3 Koog 核心能力一览
    • 1.4 Koog 与同类框架对比(Spring AI / LangChain4j)
  • 二、多平台开发环境搭建与 Gradle 依赖配置

    • 2.1 开发环境准备清单
    • 2.2 使用 KMP 向导创建项目
    • 2.3 Gradle 依赖配置详解
      • 2.3.1 根项目 settings.gradle.kts
      • 2.3.2 共享模块 build.gradle.kts
      • 2.3.3 平台特定模块配置
    • 2.4 API Key 管理与安全配置
    • 2.5 验证环境:运行第一个 Gradle Task
  • 三、Koog 核心概念解析:从 Prompt 到工具调用的映射

    • 3.1 Agent 生命周期总览
    • 3.2 Prompt 系统:结构化提示词工程
      • 3.2.1 System Prompt 与 User Prompt
      • 3.2.2 PromptTemplate 与动态变量注入
    • 3.3 LLM 抽象层:模型无关设计
    • 3.4 Tool(工具)系统:类型安全的函数调用
      • 3.4.1 工具定义与参数 Schema
      • 3.4.2 工具执行与结果回传
    • 3.5 Strategy(策略):Agent 的决策引擎
    • 3.6 Graph Workflow:图工作流引擎
  • 四、实战第一步:在 Android 端初始化首个 AI Agent 实例

    • 4.1 创建 Agent 配置类
    • 4.2 初始化 PromptExecutor
    • 4.3 构建 AIAgent 实例
    • 4.4 在 Activity/ViewModel 中集成
    • 4.5 运行与验证
  • 五、定义自定义工具函数并实现本地业务逻辑调用

    • 5.1 工具函数的设计规范
    • 5.2 实现天气查询工具
    • 5.3 实现本地数据库查询工具
    • 5.4 工具注册与 Agent 绑定
    • 5.5 工具调用链路调试
  • 六、构建多轮对话状态机与管理上下文记忆

    • 6.1 对话历史的数据模型
    • 6.2 上下文窗口管理策略
    • 6.3 持久化记忆:AIAgentStorage
    • 6.4 历史压缩:降低 Token 成本
    • 6.5 多轮对话 UI 集成
  • 七、跨平台运行验证:iOS 与 Desktop 端的无缝迁移

    • 7.1 iOS 端集成:Framework 导出与 SwiftUI 桥接
    • 7.2 Desktop 端集成:Compose Desktop 应用
    • 7.3 平台差异处理:expect/actual 模式
    • 7.4 三端统一测试验证
  • 八、常见编译报错排查与依赖冲突解决方案

    • 8.1 Kotlin/Native 编译错误
    • 8.2 依赖版本冲突
    • 8.3 Ktor 引擎冲突
    • 8.4 序列化与反射问题
    • 8.5 内存与 GC 相关问题
  • 九、性能优化技巧:流式响应处理与后台线程调度

    • 9.1 流式响应(Streaming)实现
    • 9.2 协程调度器选择
    • 9.3 并行工具调用
    • 9.4 网络层优化
    • 9.5 内存与 Token 预算控制
  • 十、进阶场景:脱离 Python 服务实现纯 Kotlin 端侧智能体

    • 10.1 端侧推理模型集成(Ollama / llama.cpp)
    • 10.2 MCP 协议对接外部系统
    • 10.3 多 Agent 协作架构
    • 10.4 生产环境部署清单
  • 十一、常见陷阱与问题排除速查表

  • 十二、总结与展望

  • 十三、详细参考资料

  • 附录

    • 附录 A:完整项目结构树
    • 附录 B:Gradle 版本兼容矩阵
    • 附录 C:Koog API 速查表
    • 附录 D:术语表

一、KotlinConf 2026 后 KMP 生态进化与 Koog 框架概览

1.1 KMP 2026 生态全景:从逻辑共享到全平台覆盖

Kotlin Multiplatform(KMP)是 JetBrains 主导研发的跨平台技术体系,其核心设计哲学是 “共享业务逻辑,保留原生 UI 体验”。与 Flutter 的"自绘 UI 跨平台"不同,KMP 聚焦于逻辑层的高度复用,让开发者在 Android、iOS、Desktop、Web 等多平台间共享网络、数据存储、业务计算等核心代码,同时保留各平台原生 UI 开发体验。

2026 年 KMP 生态的关键里程碑:

时间事件意义
2025.05 KotlinConf 2025 发布 Kotlin 2.2 + Koog 开源 AI Agent 正式进入 Kotlin 生态
2025.11 KMP 进入稳定版(GA) 生产环境可用
2026.03 Koog for Java 正式发布 企业级 JVM Agent 框架完善
2026.04 Compose Multiplatform 1.11 稳定 iOS 端 UI 共享成熟
2026.05 KotlinConf 2026:AI × Multiplatform 成为核心议题 Agent 与跨端深度融合
2026.06 KMP 新项目结构发布(配合 AGP 9.0) 工程规范统一

KMP 的代码分层架构如下:

┌─────────────────────────────────────────────────┐
│ Platform UI Layer │
│ (Android Compose / SwiftUI / Compose Desktop) │
├─────────────────────────────────────────────────┤
│ Shared Business Logic │
│ (commonMain – Kotlin 代码) │
│ ┌─────────────────────────────────────────┐ │
│ │ AI Agent Logic (Koog Framework) │ │
│ │ – Prompt Management │ │
│ │ – Tool Calling │ │
│ │ – Strategy / Workflow │ │
│ │ – Memory / Context │ │
│ └─────────────────────────────────────────┘ │
├─────────────────────────────────────────────────┤
│ Platform-specific Implementations │
│ (androidMain / iosMain / desktopMain) │
│ – Network Engine / Storage / Permissions │
└─────────────────────────────────────────────────┘

1.2 Koog 框架诞生背景与设计哲学

1.2.1 为什么 JVM 生态需要原生 Agent 框架

2026 年的 AI Agent 领域,Python 生态已相当成熟——LangChain、LlamaIndex、AutoGPT 等框架让开发者能够快速构建各种智能体应用。然而,对于 JVM 生态的开发者来说,使用 Python 框架构建 AI Agent 存在三大痛点:

  • 类型安全缺失:Python 的动态类型系统与 Kotlin/Java 的强类型体系格格不入,跨语言调用时类型错误只能在运行时暴露。
  • 协程模型不匹配:Kotlin 协程的结构化并发、取消传播、异常处理机制无法与 Python 的 asyncio 自然对接。
  • 跨语言部署复杂:引入 Python 微服务意味着额外的序列化开销、运维成本、调试难度。
  • Koog 的出现正是为了填补这个空白。JetBrains 官方定义:

    “A JVM (Java and Kotlin) framework for building predictable, fault-tolerant and enterprise-ready AI agents.”

    三个关键词:可预测、容错、企业就绪。

    1.2.2 Koog 的五层架构设计

    Koog 的架构分为五层,从上到下依次为:

    ┌──────────────────────────────────────────────────────┐
    │ Layer 5: 应用层 │
    │ Basic Agent / Functional Agent / Graph Agent / │
    │ Planner Agent │
    ├──────────────────────────────────────────────────────┤
    │ Layer 4: 核心组件 │
    │ Prompt / Strategy / Tools / Features / Storage │
    ├──────────────────────────────────────────────────────┤
    │ Layer 3: LLM 抽象层 │
    │ OpenAI / Anthropic / Ollama / MCP Protocol │
    ├──────────────────────────────────────────────────────┤
    │ Layer 2: 模型提供商 │
    │ GPT-4o / Claude / Llama / DeepSeek / 通义千问 │
    ├──────────────────────────────────────────────────────┤
    │ Layer 1: Runtime │
    │ JVM / Android / iOS (Kotlin/Native) / JS / WasmJS │
    └──────────────────────────────────────────────────────┘

    核心设计原则:

    • 纯 Kotlin 实现:完全在 Kotlin 中构建和运行 AI 智能体,无需外部服务依赖
    • 模块化功能系统:通过可组合的功能系统扩展 Agent 能力
    • 协程为核心:Agent 执行、工具调用、流式响应均为 suspend 函数或 Flow
    • 类型安全:每个操作的输入输出类型严格限定,编译期即可发现错误

    1.3 Koog 核心能力一览

    能力说明
    Kotlin DSL 构建 Agent 使用声明式 DSL 定义 Agent 行为
    自动执行规划 GOAP 规划器或 LLM 规划器,迭代式多步方案
    类型安全模型 数据驱动构建 Agent 流,类型严格限定
    MCP 集成 直接对接外部系统与工具
    嵌入与向量检索 内置 RAG 支持
    流式与并行工具调用 提升实时性
    持久化记忆与历史压缩 降低上下文成本
    可观测性与追踪 OpenTelemetry 集成,便于调试回放
    图工作流 表达复杂行为与多步任务
    多平台部署 JVM / Android / iOS / JS / WasmJS

    1.4 Koog 与同类框架对比

    维度KoogSpring AILangChain4j
    定位 Agent-first,全平台 Spring 生态集成 通用 LLM 集成
    语言 Kotlin (Java API) Java Java
    跨平台 ✅ KMP 原生 ❌ JVM only ❌ JVM only
    工具调用 类型安全 DSL 注解驱动 注解驱动
    工作流 图引擎 + GOAP 有限 Chain 模式
    可观测性 OpenTelemetry 内置 Micrometer 有限
    移动端 ✅ Android/iOS
    容错机制 Checkpoint + 恢复 有限

    二、多平台开发环境搭建与 Gradle 依赖配置

    2.1 开发环境准备清单

    在开始之前,请确保你的开发环境满足以下基本要求:

    工具最低版本推荐版本说明
    JDK 17 21 Koog 要求 Java 17+
    Kotlin 2.2.0 2.2.20 K2 编译器
    Gradle 8.8 8.10+ 构建工具
    Android Studio Ladybug+ 最新稳定版 Android 开发
    Xcode 15.4+ 16.x iOS 开发(macOS)
    IntelliJ IDEA 2025.1+ 2026.1 Desktop/JVM 开发
    KMP 插件 最新 最新 IDE 多平台支持

    安装步骤:

    # 1. 验证 JDK 版本
    java -version
    # 期望输出: openjdk version "21.x.x" 或更高

    # 2. 验证 Gradle(如使用 wrapper 则跳过)
    gradle –version

    # 3. macOS 用户验证 Xcode Command Line Tools
    xcode-select –print-path
    # 期望输出: /Applications/Xcode.app/Contents/Developer

    # 4. 验证 Kotlin 编译器(可选)
    kotlinc -version

    2.2 使用 KMP 向导创建项目

    JetBrains 提供了在线 KMP 项目向导,访问 https://kmp.jetbrains.com:

  • 选择项目名称:KoogAgentDemo
  • 选择目标平台:Android + iOS + Desktop
  • 选择 UI 框架:Compose Multiplatform(可选,本教程重点在逻辑层)
  • 点击 “Download” 下载项目压缩包
  • 解压后用 Android Studio 或 IntelliJ IDEA 打开
  • ⚠️ 常见陷阱:下载的项目可能使用旧版目录结构。2026 年 6 月后 KMP 推出了新的默认项目结构(配合 AGP 9.0),如果你使用旧版 IDE 打开新项目,可能需要手动调整。

    2.3 Gradle 依赖配置详解

    2.3.1 根项目 settings.gradle.kts

    // settings.gradle.kts
    // 项目根配置:声明插件仓库与模块结构

    pluginManagement {
    repositories {
    google() // Android Gradle Plugin
    mavenCentral() // Kotlin 插件
    gradlePluginPortal() // Gradle 插件门户
    }
    }

    dependencyResolutionManagement {
    repositories {
    google()
    mavenCentral()
    // Koog 目前发布在 Maven Central
    // 如果使用快照版本,需要添加:
    // maven("https://packages.jetbrains.team/maven/p/koog/koog")
    }
    }

    rootProject.name = "KoogAgentDemo"

    // 声明子模块
    include(":shared") // 共享业务逻辑(含 Koog Agent)
    include(":androidApp") // Android 应用壳
    include(":desktopApp") // Desktop 应用壳
    include(":iosApp") // iOS 应用壳(Xcode 项目引用)

    2.3.2 共享模块 build.gradle.kts

    // shared/build.gradle.kts
    // 核心共享模块:包含所有 Koog Agent 逻辑

    plugins {
    alias(libs.plugins.kotlinMultiplatform) // KMP 插件
    alias(libs.plugins.kotlinSerialization) // Kotlin 序列化(Koog 依赖)
    alias(libs.plugins.androidLibrary) // Android Library
    }

    kotlin {
    // ===== 目标平台声明 =====

    // Android 目标
    androidTarget {
    compilations.all {
    kotlinOptions {
    jvmTarget = "17"
    }
    }
    }

    // iOS 目标(根据 Mac 架构选择)
    iosX64()
    iosArm64()
    iosSimulatorArm64()

    // Desktop (JVM) 目标
    jvm("desktop")

    // ===== 源码集配置 =====
    sourceSets {
    // 公共源码集:所有平台共享的 Agent 逻辑
    val commonMain by getting {
    dependencies {
    // === Koog 核心依赖 ===
    implementation("ai.koog:koog-agents-core:0.7.2")
    implementation("ai.koog:koog-agents-tools:0.7.2")
    implementation("ai.koog:koog-prompt-executor:0.7.2")

    // === LLM 客户端(按需选择)===
    implementation("ai.koog:koog-llm-client-openai:0.7.2")
    // implementation("ai.koog:koog-llm-client-anthropic:0.7.2")
    // implementation("ai.koog:koog-llm-client-ollama:0.7.2")

    // === Kotlin 基础库 ===
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
    implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")

    // === 网络层(Ktor)===
    implementation("io.ktor:ktor-client-core:3.1.0")
    implementation("io.ktor:ktor-client-content-negotiation:3.1.0")
    implementation("io.ktor:ktor-serialization-kotlinx-json:3.1.0")
    }
    }

    // Android 特定实现
    val androidMain by getting {
    dependencies {
    implementation("io.ktor:ktor-client-okhttp:3.1.0")
    }
    }

    // iOS 特定实现
    val iosX64Main by getting
    val iosArm64Main by getting
    val iosSimulatorArm64Main by getting
    val iosMain by creating {
    dependsOn(commonMain)
    iosX64Main.dependsOn(this)
    iosArm64Main.dependsOn(this)
    iosSimulatorArm64Main.dependsOn(this)
    dependencies {
    implementation("io.ktor:ktor-client-darwin:3.1.0")
    }
    }

    // Desktop (JVM) 特定实现
    val desktopMain by getting {
    dependencies {
    implementation("io.ktor:ktor-client-cio:3.1.0")
    }
    }
    }
    }

    android {
    namespace = "com.example.koogagent.shared"
    compileSdk = 35
    defaultConfig {
    minSdk = 26
    }
    compileOptions {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
    }
    }

    2.3.3 平台特定模块配置

    Android 应用模块 (androidApp/build.gradle.kts):

    // androidApp/build.gradle.kts
    plugins {
    alias(libs.plugins.androidApplication)
    alias(libs.plugins.kotlinAndroid)
    alias(libs.plugins.composeCompiler)
    }

    android {
    namespace = "com.example.koogagent.android"
    compileSdk = 35

    defaultConfig {
    applicationId = "com.example.koogagent.android"
    minSdk = 26
    targetSdk = 35
    versionCode = 1
    versionName = "1.0"
    }

    buildFeatures {
    compose = true
    }

    compileOptions {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
    }

    kotlinOptions {
    jvmTarget = "17"
    }
    }

    dependencies {
    implementation(project(":shared"))

    // Compose UI
    implementation(platform("androidx.compose:compose-bom:2025.06.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.material3:material3")
    implementation("androidx.activity:activity-compose:1.9.3")
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7")

    // 协程
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
    }

    2.4 API Key 管理与安全配置

    ⚠️ 重要安全提示:永远不要将 API Key 硬编码在源代码中或提交到版本控制系统。

    方案一:local.properties(推荐开发阶段)

    # local.properties(此文件已在 .gitignore 中)
    OPENAI_API_KEY=sk-your-api-key-here
    # 如果使用国内兼容 OpenAI 协议的服务:
    # LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
    # LLM_API_KEY=sk-your-dashscope-key

    在 Gradle 中读取:

    // shared/build.gradle.kts 中添加
    android {
    defaultConfig {
    // 从 local.properties 读取 API Key
    val localProps = java.util.Properties().apply {
    load(rootProject.file("local.properties").inputStream())
    }
    buildConfigField(
    "String",
    "OPENAI_API_KEY",
    "\\"${localProps.getProperty("OPENAI_API_KEY", "")}\\""
    )
    }
    }

    方案二:环境变量(推荐 CI/CD)

    // 在 commonMain 中通过 expect/actual 获取
    // commonMain
    expect fun getApiKey(): String

    // androidMain
    actual fun getApiKey(): String = BuildConfig.OPENAI_API_KEY

    // iosMain
    actual fun getApiKey(): String {
    return NSBundle.mainBundle.infoDictionary
    ?.get("OPENAI_API_KEY") as? String ?: ""
    }

    // desktopMain
    actual fun getApiKey(): String {
    return System.getenv("OPENAI_API_KEY") ?: ""
    }

    2.5 验证环境:运行第一个 Gradle Task

    # 验证项目可以正常编译所有平台
    ./gradlew :shared:compileKotlinDesktop # Desktop/JVM
    ./gradlew :shared:compileDebugKotlinAndroid # Android
    ./gradlew :shared:compileKotlinIosArm64 # iOS(需要 macOS)

    # 如果以上命令全部成功(BUILD SUCCESSFUL),环境配置完成


    三、Koog 核心概念解析:从 Prompt 到工具调用的映射

    3.1 Agent 生命周期总览

    一个 Koog Agent 的完整生命周期如下:

    用户输入 → Prompt 组装 → LLM 请求 → 响应解析

    [是否包含 Tool Call?]
    / \\
    是 否
    ↓ ↓
    执行工具函数 返回最终回答

    工具结果回传 LLM

    [继续循环或结束]

    核心组件关系图:

    AIAgent
    ├── PromptExecutor // 负责与 LLM 通信
    │ └── LLMClient // 具体的模型客户端
    ├── Prompt // 系统提示词 + 对话历史
    ├── Tools[] // 可用工具列表
    ├── Strategy // 决策策略(单轮/多轮/图)
    └── Storage // 持久化存储

    3.2 Prompt 系统:结构化提示词工程

    3.2.1 System Prompt 与 User Prompt

    在 Koog 中,Prompt 是 Agent 与 LLM 交互的基础。它分为两部分:

    • System Prompt:定义 Agent 的角色、能力边界、行为规范
    • User Prompt:用户的实际输入

    import ai.koog.prompt.llm.LLMProvider
    import ai.koog.prompt.structural.StructuralPrompt

    // 定义系统提示词
    val systemPrompt = """
    你是一个专业的个人助理 Agent,具备以下能力:
    1. 查询天气信息
    2. 管理用户日程
    3. 搜索本地文件

    规则:
    – 回答必须简洁明了,不超过 200 字
    – 如果需要调用工具,先说明你要做什么
    – 不确定的信息不要编造,直接告知用户
    """.trimIndent()

    3.2.2 PromptTemplate 与动态变量注入

    import ai.koog.prompt.template.PromptTemplate

    // 创建带变量的提示词模板
    val assistantTemplate = PromptTemplate(
    system = """
    你是 {{role}},服务于 {{company}} 的 AI 助手。
    当前用户:{{userName}}
    当前时间:{{currentTime}}

    你可以使用以下工具来帮助用户:
    {{availableTools}}
    """.trimIndent(),
    // 运行时动态填充变量
    variables = mapOf(
    "role" to "智能客服专员",
    "company" to "示例科技有限公司",
    "userName" to "张三",
    "currentTime" to "2026-08-06 11:53",
    "availableTools" to "天气查询、日程管理、文件搜索"
    )
    )

    // 渲染最终 Prompt
    val renderedPrompt = assistantTemplate.render()
    println(renderedPrompt)

    3.3 LLM 抽象层:模型无关设计

    Koog 的 LLM 抽象层让你可以无缝切换不同的模型提供商:

    import ai.koog.prompt.llm.LLModel
    import ai.koog.prompt.llm.LLMCapability

    // 定义模型配置
    val gpt4oModel = LLModel(
    provider = LLMProvider.OpenAI,
    id = "gpt-4o",
    capabilities = setOf(
    LLMCapability.Completion, // 文本补全
    LLMCapability.Tools, // 工具调用
    LLMCapability.Streaming, // 流式输出
    ),
    contextLength = 128_000, // 上下文窗口
    maxOutputTokens = 4_096 // 最大输出 token
    )

    // 使用 Ollama 本地模型(端侧推理)
    val localModel = LLModel(
    provider = LLMProvider.Ollama,
    id = "llama3.1:8b",
    capabilities = setOf(
    LLMCapability.Completion,
    LLMCapability.Tools,
    ),
    contextLength = 8_192,
    maxOutputTokens = 2_048
    )

    3.4 Tool(工具)系统:类型安全的函数调用

    3.4.1 工具定义与参数 Schema

    Koog 的工具系统是其最核心的差异化能力之一。工具定义完全类型安全:

    import ai.koog.agents.tools.annotation.Tool
    import ai.koog.agents.tools.annotation.ToolParam
    import kotlinx.serialization.Serializable

    // 定义工具参数(必须是可序列化的数据类)
    @Serializable
    data class WeatherRequest(
    @ToolParam(description = "城市名称,如:北京、上海")
    val city: String,

    @ToolParam(description = "日期,格式 YYYY-MM-DD,默认今天")
    val date: String = ""
    )

    // 定义工具返回值
    @Serializable
    data class WeatherResponse(
    val temperature: Double,
    val condition: String,
    val humidity: Int,
    val windSpeed: Double
    )

    // 定义工具函数
    class WeatherTools {

    @Tool(
    name = "get_weather",
    description = "查询指定城市的天气信息。当用户询问天气相关问题时调用此工具。"
    )
    suspend fun getWeather(request: WeatherRequest): WeatherResponse {
    // 实际实现:调用天气 API
    val apiUrl = "https://api.weather.example.com/v1/current"
    // … 网络请求逻辑
    return WeatherResponse(
    temperature = 28.5,
    condition = "晴",
    humidity = 45,
    windSpeed = 3.2
    )
    }
    }

    3.4.2 工具执行与结果回传

    import ai.koog.agents.tools.ToolExecutor

    // 工具执行器负责:
    // 1. 接收 LLM 返回的 tool_call 指令
    // 2. 反序列化参数
    // 3. 调用对应的工具函数
    // 4. 序列化结果并回传给 LLM

    val toolExecutor = ToolExecutor(
    tools = listOf(
    WeatherTools(),
    CalendarTools(),
    FileSearchTools()
    )
    )

    // 当 LLM 返回 tool_call 时,框架自动执行:
    // LLM Response: {"tool_calls": [{"function": {"name": "get_weather", "arguments": "{\\"city\\": \\"北京\\"}"}}]}
    // → ToolExecutor 解析 → 调用 WeatherTools.getWeather(WeatherRequest(city="北京"))
    // → 序列化 WeatherResponse → 作为 tool_result 回传 LLM

    3.5 Strategy(策略):Agent 的决策引擎

    Strategy 决定了 Agent 如何处理用户请求:

    import ai.koog.agents.strategy.BasicAgentStrategy
    import ai.koog.agents.strategy.FunctionalAgentStrategy

    // 策略一:基础单轮策略(简单问答)
    val basicStrategy = BasicAgentStrategy(
    maxIterations = 5 // 最大工具调用轮次
    )

    // 策略二:函数式策略(自定义流程)
    val customStrategy = FunctionalAgentStrategy("weather-check") { ctx, input ->
    // 第一步:解析用户意图
    val intent = ctx.analyzeIntent(input)

    // 第二步:根据意图选择执行路径
    when (intent) {
    "weather_query" -> {
    val city = ctx.extractCity(input)
    val weather = ctx.callTool("get_weather", mapOf("city" to city))
    ctx.respond("今天${city}的天气是:${weather}")
    }
    "schedule_query" -> {
    val events = ctx.callTool("get_schedule", mapOf("date" to "today"))
    ctx.respond("你今天的日程:$events")
    }
    else -> {
    ctx.respond("抱歉,我暂时无法处理这个请求。")
    }
    }
    }

    3.6 Graph Workflow:图工作流引擎

    对于复杂的多步骤任务,Koog 提供了图工作流引擎:

    import ai.koog.agents.graph.GraphAgentStrategy
    import ai.koog.agents.graph.node

    val workflowStrategy = GraphAgentStrategy("order-processing") {
    // 定义节点
    val validateNode = node("validate") { ctx ->
    // 验证订单信息
    ctx.set("isValid", true)
    ctx.next("process")
    }

    val processNode = node("process") { ctx ->
    // 处理订单
    val orderId = ctx.callTool("create_order", ctx.get("orderData"))
    ctx.set("orderId", orderId)
    ctx.next("notify")
    }

    val notifyNode = node("notify") { ctx ->
    // 发送通知
    ctx.callTool("send_notification", mapOf(
    "userId" to ctx.get("userId"),
    "message" to "订单 ${ctx.get("orderId")} 已创建"
    ))
    ctx.finish("订单处理完成")
    }

    // 定义边(流转关系)
    edge(validateNode, processNode)
    edge(processNode, notifyNode)

    // 设置入口
    entry(validateNode)
    }


    四、实战第一步:在 Android 端初始化首个 AI Agent 实例

    4.1 创建 Agent 配置类

    // shared/src/commonMain/kotlin/com/example/koogagent/AgentConfig.kt
    package com.example.koogagent

    import ai.koog.prompt.llm.LLModel
    import ai.koog.prompt.llm.LLMProvider
    import ai.koog.prompt.llm.LLMCapability

    /**
    * Agent 全局配置
    * 集中管理模型选择、API 配置等
    */

    object AgentConfig {

    // 使用的 LLM 模型
    val model = LLModel(
    provider = LLMProvider.OpenAI,
    id = "gpt-4o-mini", // 开发阶段用 mini 节省成本
    capabilities = setOf(
    LLMCapability.Completion,
    LLMCapability.Tools,
    LLMCapability.Streaming
    ),
    contextLength = 128_000,
    maxOutputTokens = 4_096
    )

    // Agent 系统提示词
    val systemPrompt = """
    你是一个智能个人助手,运行在用户的移动设备上。

    你的能力:
    1. 查询实时天气
    2. 管理用户待办事项
    3. 进行简单的数学计算

    行为准则:
    – 回答简洁,不超过 150 字
    – 需要工具时主动调用
    – 遇到不确定的问题诚实告知
    – 使用中文回答
    """.trimIndent()

    // 最大工具调用迭代次数(防止无限循环)
    const val MAX_TOOL_ITERATIONS = 10

    // 请求超时时间(毫秒)
    const val REQUEST_TIMEOUT_MS = 30_000L
    }

    4.2 初始化 PromptExecutor

    // shared/src/commonMain/kotlin/com/example/koogagent/AgentFactory.kt
    package com.example.koogagent

    import ai.koog.agents.core.agent.AIAgent
    import ai.koog.prompt.executor.SingleLLMPromptExecutor
    import ai.koog.prompt.executor.clients.openai.OpenAILLMClient
    import ai.koog.prompt.executor.clients.LLMClientConfiguration

    /**
    * Agent 工厂:负责创建和配置 Agent 实例
    */

    object AgentFactory {

    /**
    * 创建基础 Agent 实例
    * @param apiKey LLM API 密钥
    * @return 配置完成的 AIAgent
    */

    fun createBasicAgent(apiKey: String): AIAgent {

    // 1. 配置 LLM 客户端
    val clientConfig = LLMClientConfiguration(
    apiKey = apiKey,
    // 如果使用国内兼容服务,设置 baseUrl:
    // baseUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1"
    )

    // 2. 创建 OpenAI 客户端
    val llmClient = OpenAILLMClient(
    configuration = clientConfig
    )

    // 3. 创建 Prompt 执行器
    val promptExecutor = SingleLLMPromptExecutor(
    llmClient = llmClient
    )

    // 4. 构建 Agent
    val agent = AIAgent(
    promptExecutor = promptExecutor,
    model = AgentConfig.model,
    systemPrompt = AgentConfig.systemPrompt,
    maxIterations = AgentConfig.MAX_TOOL_ITERATIONS
    )

    return agent
    }
    }

    4.3 构建 AIAgent 实例(带工具)

    // shared/src/commonMain/kotlin/com/example/koogagent/AgentFactory.kt(续)

    import ai.koog.agents.tools.ToolSet

    /**
    * 创建带工具的完整 Agent
    */

    fun createFullAgent(apiKey: String): AIAgent {

    val clientConfig = LLMClientConfiguration(apiKey = apiKey)
    val llmClient = OpenAILLMClient(configuration = clientConfig)
    val promptExecutor = SingleLLMPromptExecutor(llmClient = llmClient)

    // 注册工具集
    val toolSet = ToolSet(
    tools = listOf(
    WeatherTool(), // 天气查询
    TodoTool(), // 待办管理
    CalculatorTool() // 计算器
    )
    )

    val agent = AIAgent(
    promptExecutor = promptExecutor,
    model = AgentConfig.model,
    systemPrompt = AgentConfig.systemPrompt,
    tools = toolSet,
    maxIterations = AgentConfig.MAX_TOOL_ITERATIONS
    )

    return agent
    }

    4.4 在 Activity/ViewModel 中集成

    // androidApp/src/main/java/com/example/koogagent/android/ChatViewModel.kt
    package com.example.koogagent.android

    import androidx.lifecycle.ViewModel
    import androidx.lifecycle.viewModelScope
    import com.example.koogagent.AgentFactory
    import com.example.koogagent.getApiKey
    import kotlinx.coroutines.flow.MutableStateFlow
    import kotlinx.coroutines.flow.StateFlow
    import kotlinx.coroutines.flow.asStateFlow
    import kotlinx.coroutines.launch

    /**
    * 聊天界面 ViewModel
    * 管理 Agent 交互与 UI 状态
    */

    class ChatViewModel : ViewModel() {

    // UI 状态
    private val _messages = MutableStateFlow<List<ChatMessage>>(emptyList())
    val messages: StateFlow<List<ChatMessage>> = _messages.asStateFlow()

    private val _isLoading = MutableStateFlow(false)
    val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()

    private val _error = MutableStateFlow<String?>(null)
    val error: StateFlow<String?> = _error.asStateFlow()

    // Agent 实例(懒加载)
    private val agent by lazy {
    AgentFactory.createFullAgent(getApiKey())
    }

    /**
    * 发送用户消息并获取 Agent 回复
    */

    fun sendMessage(userInput: String) {
    if (userInput.isBlank()) return

    // 添加用户消息到列表
    _messages.value = _messages.value + ChatMessage(
    role = MessageRole.USER,
    content = userInput
    )

    _isLoading.value = true
    _error.value = null

    viewModelScope.launch {
    try {
    // 调用 Agent 处理用户输入
    val response = agent.execute(userInput)

    // 添加 Agent 回复
    _messages.value = _messages.value + ChatMessage(
    role = MessageRole.ASSISTANT,
    content = response.content
    )
    } catch (e: Exception) {
    _error.value = "请求失败:${e.message}"
    } finally {
    _isLoading.value = false
    }
    }
    }

    /**
    * 清空对话历史
    */

    fun clearHistory() {
    _messages.value = emptyList()
    agent.resetConversation()
    }
    }

    // 消息数据模型
    data class ChatMessage(
    val role: MessageRole,
    val content: String,
    val timestamp: Long = System.currentTimeMillis()
    )

    enum class MessageRole {
    USER, ASSISTANT, SYSTEM, TOOL
    }

    4.5 运行与验证

    // androidApp/src/main/java/com/example/koogagent/android/ChatScreen.kt
    package com.example.koogagent.android

    import androidx.compose.foundation.layout.*
    import androidx.compose.foundation.lazy.LazyColumn
    import androidx.compose.foundation.lazy.items
    import androidx.compose.material3.*
    import androidx.compose.runtime.*
    import androidx.compose.ui.Alignment
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.unit.dp
    import androidx.lifecycle.viewmodel.compose.viewModel

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    fun ChatScreen(viewModel: ChatViewModel = viewModel()) {
    val messages by viewModel.messages.collectAsState()
    val isLoading by viewModel.isLoading.collectAsState()
    var inputText by remember { mutableStateOf("") }

    Scaffold(
    topBar = {
    TopAppBar(title = { Text("Koog AI 助手") })
    }
    ) { padding ->
    Column(
    modifier = Modifier
    .fillMaxSize()
    .padding(padding)
    ) {
    // 消息列表
    LazyColumn(
    modifier = Modifier.weight(1f),
    contentPadding = PaddingValues(16.dp),
    verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
    items(messages) { message ->
    MessageBubble(message = message)
    }

    // 加载指示器
    if (isLoading) {
    item {
    Row(
    modifier = Modifier.fillMaxWidth(),
    horizontalArrangement = Arrangement.Center
    ) {
    CircularProgressIndicator(modifier = Modifier.size(24.dp))
    }
    }
    }
    }

    // 输入区域
    Row(
    modifier = Modifier
    .fillMaxWidth()
    .padding(16.dp),
    verticalAlignment = Alignment.CenterVertically
    ) {
    OutlinedTextField(
    value = inputText,
    onValueChange = { inputText = it },
    modifier = Modifier.weight(1f),
    placeholder = { Text("输入消息…") },
    maxLines = 3
    )

    Spacer(modifier = Modifier.width(8.dp))

    Button(
    onClick = {
    viewModel.sendMessage(inputText)
    inputText = ""
    },
    enabled = !isLoading && inputText.isNotBlank()
    ) {
    Text("发送")
    }
    }
    }
    }
    }

    @Composable
    fun MessageBubble(message: ChatMessage) {
    val isUser = message.role == MessageRole.USER

    Surface(
    modifier = Modifier
    .fillMaxWidth()
    .wrapContentWidth(
    if (isUser) Alignment.End else Alignment.Start
    ),
    shape = MaterialTheme.shapes.medium,
    color = if (isUser)
    MaterialTheme.colorScheme.primaryContainer
    else
    MaterialTheme.colorScheme.surfaceVariant
    ) {
    Text(
    text = message.content,
    modifier = Modifier.padding(12.dp),
    style = MaterialTheme.typography.bodyLarge
    )
    }
    }

    运行验证步骤:

  • 在 Android Studio 中选择模拟器或真机
  • 点击 Run 按钮(或 ./gradlew :androidApp:installDebug)
  • 应用启动后,在输入框输入"你好,介绍一下你自己"
  • 观察 Agent 是否正确返回基于 System Prompt 的自我介绍

  • 五、定义自定义工具函数并实现本地业务逻辑调用

    5.1 工具函数的设计规范

    在 Koog 中,一个好的工具函数应遵循以下规范:

    规范说明示例
    单一职责 每个工具只做一件事 get_weather 只查天气
    描述清晰 description 让 LLM 知道何时调用 “当用户询问天气时调用”
    参数类型安全 使用 @Serializable 数据类 WeatherRequest
    错误处理 返回有意义的错误信息 而非抛异常
    幂等性 相同输入产生相同结果 查询类工具天然幂等

    5.2 实现天气查询工具

    // shared/src/commonMain/kotlin/com/example/koogagent/tools/WeatherTool.kt
    package com.example.koogagent.tools

    import ai.koog.agents.tools.annotation.Tool
    import ai.koog.agents.tools.annotation.ToolParam
    import io.ktor.client.*
    import io.ktor.client.request.*
    import io.ktor.client.statement.*
    import kotlinx.serialization.Serializable
    import kotlinx.serialization.json.Json

    /**
    * 天气查询工具
    * 调用公开天气 API 获取实时天气数据
    */

    class WeatherTool(
    private val httpClient: HttpClient = HttpClient()
    ) {

    private val json = Json { ignoreUnknownKeys = true }

    // === 请求/响应数据模型 ===

    @Serializable
    data class WeatherQuery(
    @ToolParam(description = "要查询天气的城市名称,例如:北京、上海、广州")
    val city: String,

    @ToolParam(description = "温度单位:celsius(摄氏)或 fahrenheit(华氏),默认摄氏")
    val unit: String = "celsius"
    )

    @Serializable
    data class WeatherResult(
    val city: String,
    val temperature: Double,
    val unit: String,
    val condition: String,
    val humidity: Int,
    val windSpeed: Double,
    val forecast: String // 简短预报
    )

    @Serializable
    data class ApiWeatherResponse(
    val temp: Double,
    val condition: String,
    val humidity: Int,
    val wind_speed: Double
    )

    // === 工具函数 ===

    @Tool(
    name = "query_weather",
    description = """
    查询指定城市的当前天气信息。
    适用场景:用户询问某个城市的天气、温度、是否需要带伞等。
    返回温度、天气状况、湿度、风速等信息。
    """
    .trimIndent()
    )
    suspend fun queryWeather(query: WeatherQuery): WeatherResult {
    return try {
    // 调用天气 API(这里用模拟数据演示)
    // 实际项目中替换为真实 API 调用
    val response = httpClient.get(
    "https://api.openweathermap.org/data/2.5/weather"
    ) {
    parameter("q", query.city)
    parameter("appid", "YOUR_WEATHER_API_KEY")
    parameter("units", if (query.unit == "celsius") "metric" else "imperial")
    }

    val apiResponse = json.decodeFromString<ApiWeatherResponse>(
    response.bodyAsText()
    )

    WeatherResult(
    city = query.city,
    temperature = apiResponse.temp,
    unit = query.unit,
    condition = apiResponse.condition,
    humidity = apiResponse.humidity,
    windSpeed = apiResponse.wind_speed,
    forecast = generateForecast(apiResponse.condition)
    )
    } catch (e: Exception) {
    // 返回友好的错误信息而非抛异常
    WeatherResult(
    city = query.city,
    temperature = 999.0,
    unit = query.unit,
    condition = "查询失败",
    humidity = 0,
    windSpeed = 0.0,
    forecast = "抱歉,暂时无法获取${query.city}的天气数据:${e.message}"
    )
    }
    }

    private fun generateForecast(condition: String): String {
    return when {
    condition.contains("rain") -> "有雨,建议带伞"
    condition.contains("sun") -> "晴天,适合外出"
    condition.contains("cloud") -> "多云,气温适宜"
    condition.contains("snow") -> "有雪,注意保暖"
    else -> "天气状况一般"
    }
    }
    }

    5.3 实现本地数据库查询工具

    // shared/src/commonMain/kotlin/com/example/koogagent/tools/TodoTool.kt
    package com.example.koogagent.tools

    import ai.koog.agents.tools.annotation.Tool
    import ai.koog.agents.tools.annotation.ToolParam
    import kotlinx.serialization.Serializable
    import kotlinx.coroutines.sync.Mutex
    import kotlinx.coroutines.sync.withLock

    /**
    * 待办事项管理工具
    * 使用内存存储(实际项目可替换为 Room/SQLDelight)
    */

    class TodoTool {

    // 线程安全的待办列表
    private val todos = mutableListOf<TodoItem>()
    private val mutex = Mutex()
    private var nextId = 1

    @Serializable
    data class TodoItem(
    val id: Int,
    val title: String,
    val isCompleted: Boolean = false,
    val createdAt: Long = 0L
    )

    @Serializable
    data class AddTodoRequest(
    @ToolParam(description = "待办事项的标题/内容")
    val title: String
    )

    @Serializable
    data class ListTodoRequest(
    @ToolParam(description = "过滤条件:all(全部)、pending(未完成)、completed(已完成)")
    val filter: String = "all"
    )

    @Serializable
    data class CompleteTodoRequest(
    @ToolParam(description = "要标记完成的待办事项 ID")
    val id: Int
    )

    @Serializable
    data class TodoResponse(
    val success: Boolean,
    val message: String,
    val items: List<TodoItem> = emptyList()
    )

    @Tool(
    name = "add_todo",
    description = "添加一条新的待办事项。当用户说要记住某事、添加任务、创建提醒时使用。"
    )
    suspend fun addTodo(request: AddTodoRequest): TodoResponse {
    return mutex.withLock {
    val item = TodoItem(
    id = nextId++,
    title = request.title,
    createdAt = kotlinx.datetime.Clock.System.now()
    .toEpochMilliseconds()
    )
    todos.add(item)
    TodoResponse(
    success = true,
    message = "已添加待办:「${request.title}」(ID: ${item.id})"
    )
    }
    }

    @Tool(
    name = "list_todos",
    description = "查看待办事项列表。当用户询问待办、任务列表、还有什么没做时使用。"
    )
    suspend fun listTodos(request: ListTodoRequest): TodoResponse {
    return mutex.withLock {
    val filtered = when (request.filter) {
    "pending" -> todos.filter { !it.isCompleted }
    "completed" -> todos.filter { it.isCompleted }
    else -> todos.toList()
    }
    TodoResponse(
    success = true,
    message = "共 ${filtered.size} 条待办",
    items = filtered
    )
    }
    }

    @Tool(
    name = "complete_todo",
    description = "将指定 ID 的待办事项标记为已完成。当用户说完成了某事、做完了某任务时使用。"
    )
    suspend fun completeTodo(request: CompleteTodoRequest): TodoResponse {
    return mutex.withLock {
    val index = todos.indexOfFirst { it.id == request.id }
    if (index == 1) {
    TodoResponse(
    success = false,
    message = "未找到 ID 为 ${request.id} 的待办事项"
    )
    } else {
    todos[index] = todos[index].copy(isCompleted = true)
    TodoResponse(
    success = true,
    message = "已完成:「${todos[index].title}」"
    )
    }
    }
    }
    }

    5.4 工具注册与 Agent 绑定

    // shared/src/commonMain/kotlin/com/example/koogagent/AgentFactory.kt(完整工具注册)

    /**
    * 创建带有全部业务工具的 Agent
    */

    fun createBusinessAgent(apiKey: String): AIAgent {

    val llmClient = OpenAILLMClient(
    configuration = LLMClientConfiguration(apiKey = apiKey)
    )

    val promptExecutor = SingleLLMPromptExecutor(llmClient = llmClient)

    // 注册所有工具
    val toolSet = ToolSet(
    tools = listOf(
    WeatherTool(), // 天气查询
    TodoTool(), // 待办管理
    CalculatorTool() // 数学计算
    )
    )

    return AIAgent(
    promptExecutor = promptExecutor,
    model = AgentConfig.model,
    systemPrompt = AgentConfig.systemPrompt,
    tools = toolSet,
    maxIterations = AgentConfig.MAX_TOOL_ITERATIONS
    )
    }

    5.5 工具调用链路调试

    // 启用 Koog 内置的调试日志
    import ai.koog.agents.core.config.AgentDebugConfig

    val agent = AIAgent(
    promptExecutor = promptExecutor,
    model = AgentConfig.model,
    systemPrompt = AgentConfig.systemPrompt,
    tools = toolSet,
    debugConfig = AgentDebugConfig(
    logPromptSent = true, // 记录发送给 LLM 的完整 Prompt
    logToolCalls = true, // 记录工具调用详情
    logToolResults = true, // 记录工具返回结果
    logTokenUsage = true, // 记录 Token 消耗
    logLevel = AgentDebugConfig.LogLevel.DEBUG
    )
    )

    // 调试输出示例:
    // [Koog DEBUG] >>> Prompt sent to LLM (tokens: 342)
    // [Koog DEBUG] <<< LLM response: tool_call {name: "query_weather", args: {"city": "北京"}}
    // [Koog DEBUG] >>> Executing tool: query_weather
    // [Koog DEBUG] <<< Tool result: {"city": "北京", "temperature": 28.5, …}
    // [Koog DEBUG] >>> Sending tool result back to LLM
    // [Koog DEBUG] <<< Final response (tokens: 89)


    六、构建多轮对话状态机与管理上下文记忆

    6.1 对话历史的数据模型

    // shared/src/commonMain/kotlin/com/example/koogagent/memory/ConversationManager.kt
    package com.example.koogagent.memory

    import kotlinx.serialization.Serializable

    /**
    * 对话消息模型
    */

    @Serializable
    data class ConversationMessage(
    val role: Role,
    val content: String,
    val timestamp: Long,
    val toolCallId: String? = null, // 工具调用关联 ID
    val metadata: Map<String, String> = emptyMap()
    ) {
    enum class Role {
    SYSTEM, // 系统提示
    USER, // 用户输入
    ASSISTANT, // AI 回复
    TOOL // 工具结果
    }
    }

    /**
    * 对话会话
    */

    @Serializable
    data class ConversationSession(
    val sessionId: String,
    val messages: MutableList<ConversationMessage> = mutableListOf(),
    val createdAt: Long,
    val lastActiveAt: Long,
    val totalTokensUsed: Int = 0
    )

    6.2 上下文窗口管理策略

    /**
    * 上下文窗口管理器
    * 负责在 Token 限制内维护有效的对话历史
    */

    class ContextWindowManager(
    private val maxContextTokens: Int = 128_000,
    private val reservedForResponse: Int = 4_096
    ) {

    /**
    * 策略:滑动窗口 + 摘要压缩
    * 当历史消息超过窗口大小时:
    * 1. 保留 System Prompt(始终保留)
    * 2. 保留最近 N 轮完整对话
    * 3. 将更早的对话压缩为摘要
    */

    fun manageContext(messages: List<ConversationMessage>): List<ConversationMessage> {
    val availableTokens = maxContextTokens reservedForResponse

    // 估算当前 token 数(简化:1 中文字 ≈ 1.5 token)
    val currentTokens = messages.sumOf { estimateTokens(it.content) }

    if (currentTokens <= availableTokens) {
    return messages // 未超限,全部保留
    }

    // 超限处理:保留最近 10 轮 + 压缩早期历史
    val recentMessages = messages.takeLast(20) // 10轮 = 20条消息
    val earlyMessages = messages.dropLast(20)

    // 将早期消息压缩为摘要
    val summary = compressToSummary(earlyMessages)

    return listOf(
    ConversationMessage(
    role = ConversationMessage.Role.SYSTEM,
    content = "[历史对话摘要] $summary",
    timestamp = System.currentTimeMillis()
    )
    ) + recentMessages
    }

    private fun estimateTokens(text: String): Int {
    // 简化的 token 估算
    return (text.length * 1.5).toInt()
    }

    private fun compressToSummary(messages: List<ConversationMessage>): String {
    // 实际实现中可以调用 LLM 生成摘要
    // 这里简化为提取关键信息
    val userMessages = messages.filter {
    it.role == ConversationMessage.Role.USER
    }
    return "用户之前询问了:${userMessages.joinToString("、") {
    it.content.take(50)
    }}"
    }
    }

    6.3 持久化记忆:AIAgentStorage

    // shared/src/commonMain/kotlin/com/example/koogagent/memory/AgentStorage.kt
    package com.example.koogagent.memory

    import ai.koog.agents.storage.AIAgentStorage
    import ai.koog.agents.storage.StorageKey

    /**
    * Agent 持久化存储
    * 支持跨会话记忆保留
    */

    class PersistentAgentStorage : AIAgentStorage {

    // 实际项目中可替换为 SQLDelight / Room / DataStore
    private val storage = mutableMapOf<String, String>()

    override suspend fun save(key: StorageKey, value: String) {
    storage[key.id] = value
    // 实际实现:写入本地数据库
    // database.insertOrReplace(key.id, value, System.currentTimeMillis())
    }

    override suspend fun load(key: StorageKey): String? {
    return storage[key.id]
    // 实际实现:从数据库读取
    // return database.getById(key.id)?.value
    }

    override suspend fun delete(key: StorageKey) {
    storage.remove(key.id)
    }

    override suspend fun clear() {
    storage.clear()
    }
    }

    // 使用示例:在 Agent 中启用持久化
    val agent = AIAgent(
    promptExecutor = promptExecutor,
    model = AgentConfig.model,
    systemPrompt = AgentConfig.systemPrompt,
    tools = toolSet,
    storage = PersistentAgentStorage(), // 启用持久化
    // Agent 会自动保存/恢复对话状态
    )

    6.4 历史压缩:降低 Token 成本

    /**
    * 对话历史压缩器
    * 当对话过长时,使用 LLM 自身来压缩历史
    */

    class HistoryCompressor(
    private val agent: AIAgent
    ) {

    /**
    * 压缩对话历史为简短摘要
    * @param messages 需要压缩的历史消息
    * @param maxSummaryTokens 摘要最大 token 数
    */

    suspend fun compress(
    messages: List<ConversationMessage>,
    maxSummaryTokens: Int = 500
    ): String {
    val historyText = messages.joinToString("\\n") { msg ->
    "[${msg.role}]: ${msg.content}"
    }

    val compressionPrompt = """
    请将以下对话历史压缩为不超过
    ${maxSummaryTokens} token 的摘要。
    保留关键信息:用户意图、重要决定、待处理事项。
    去除寒暄、重复内容。

    对话历史:
    $historyText

    压缩摘要:
    """.trimIndent()

    val result = agent.execute(compressionPrompt)
    return result.content
    }
    }

    6.5 多轮对话 UI 集成

    // 在 ViewModel 中集成上下文管理
    class ChatViewModel : ViewModel() {

    private val contextManager = ContextWindowManager()
    private val conversationHistory = mutableListOf<ConversationMessage>()

    fun sendMessage(userInput: String) {
    // 1. 添加用户消息
    conversationHistory.add(
    ConversationMessage(
    role = ConversationMessage.Role.USER,
    content = userInput,
    timestamp = System.currentTimeMillis()
    )
    )

    // 2. 管理上下文窗口
    val managedContext = contextManager.manageContext(conversationHistory)

    // 3. 带上下文调用 Agent
    viewModelScope.launch {
    val response = agent.execute(
    input = userInput,
    conversationHistory = managedContext
    )

    // 4. 保存 AI 回复到历史
    conversationHistory.add(
    ConversationMessage(
    role = ConversationMessage.Role.ASSISTANT,
    content = response.content,
    timestamp = System.currentTimeMillis()
    )
    )

    // 5. 更新 UI
    _messages.value = conversationHistory.map { it.toUiMessage() }
    }
    }
    }


    七、跨平台运行验证:iOS 与 Desktop 端的无缝迁移

    7.1 iOS 端集成:Framework 导出与 SwiftUI 桥接

    步骤一:配置 Kotlin/Native Framework 导出

    // shared/build.gradle.kts 中添加 iOS framework 配置
    kotlin {
    // … 已有的 target 配置 …

    // 配置 iOS Framework 导出
    listOf(iosX64(), iosArm64(), iosSimulatorArm64()).forEach { target ->
    target.binaries.framework {
    baseName = "SharedKoogAgent"
    isStatic = true // 静态链接,简化集成

    // 导出 Koog 相关依赖
    export("ai.koog:koog-agents-core:0.7.2")
    export("ai.koog:koog-agents-tools:0.7.2")
    }
    }
    }

    步骤二:创建 iOS 桥接层

    // shared/src/iosMain/kotlin/com/example/koogagent/IOSAgentBridge.kt
    package com.example.koogagent

    import kotlinx.coroutines.*
    import platform.Foundation.NSBundle

    /**
    * iOS 平台桥接类
    * 将 Kotlin Agent 暴露为 Objective-C/Swift 友好的 API
    */

    class IOSAgentBridge {

    private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
    private var agent: AIAgent? = null

    /**
    * 初始化 Agent(从 Swift 调用)
    */

    fun initializeAgent(apiKey: String) {
    agent = AgentFactory.createFullAgent(apiKey)
    }

    /**
    * 发送消息(异步回调方式,对 Swift 友好)
    */

    fun sendMessage(
    message: String,
    onSuccess: (String) -> Unit,
    onError: (String) -> Unit
    ) {
    scope.launch {
    try {
    val response = agent?.execute(message)
    withContext(Dispatchers.Main) {
    onSuccess(response?.content ?: "无响应")
    }
    } catch (e: Exception) {
    withContext(Dispatchers.Main) {
    onError(e.message ?: "未知错误")
    }
    }
    }
    }

    /**
    * 销毁 Agent,释放资源
    */

    fun destroy() {
    scope.cancel()
    agent = null
    }
    }

    // iOS 平台获取 API Key
    actual fun getApiKey(): String {
    return NSBundle.mainBundle.infoDictionary
    ?.get("LLM_API_KEY") as? String
    ?: throw IllegalStateException("LLM_API_KEY not configured in Info.plist")
    }

    步骤三:SwiftUI 集成

    // iosApp/ContentView.swift
    import SwiftUI
    import SharedKoogAgent // 导入 Kotlin Framework

    struct ContentView: View {
    @StateObject private var chatVM = ChatViewModel()

    var body: some View {
    VStack {
    // 消息列表
    ScrollView {
    LazyVStack(alignment: .leading, spacing: 12) {
    ForEach(chatVM.messages) { msg in
    MessageBubbleView(message: msg)
    }
    }
    .padding()
    }

    // 输入栏
    HStack {
    TextField("输入消息…", text: $chatVM.inputText)
    .textFieldStyle(.roundedBorder)

    Button("发送") {
    chatVM.send()
    }
    .disabled(chatVM.isLoading)
    }
    .padding()
    }
    }
    }

    // ViewModel:桥接 Kotlin Agent
    class ChatViewModel: ObservableObject {
    @Published var messages: [ChatMessageUI] = []
    @Published var inputText = ""
    @Published var isLoading = false

    private let bridge = IOSAgentBridge()

    init() {
    // 初始化 Agent
    let apiKey = Bundle.main.infoDictionary?["LLM_API_KEY"] as? String ?? ""
    bridge.initializeAgent(apiKey: apiKey)
    }

    func send() {
    guard !inputText.isEmpty else { return }

    let userMsg = ChatMessageUI(role: .user, content: inputText)
    messages.append(userMsg)
    isLoading = true

    let text = inputText
    inputText = ""

    bridge.sendMessage(
    message: text,
    onSuccess: { [weak self] response in
    DispatchQueue.main.async {
    self?.messages.append(
    ChatMessageUI(role: .assistant, content: response)
    )
    self?.isLoading = false
    }
    },
    onError: { [weak self] error in
    DispatchQueue.main.async {
    self?.messages.append(
    ChatMessageUI(role: .assistant, content: "错误: $error)")
    )
    self?.isLoading = false
    }
    }
    )
    }
    }

    struct ChatMessageUI: Identifiable {
    let id = UUID()
    let role: Role
    let content: String

    enum Role { case user, assistant }
    }

    7.2 Desktop 端集成:Compose Desktop 应用

    // desktopApp/src/main/kotlin/Main.kt
    import androidx.compose.desktop.ui.tooling.preview.Preview
    import androidx.compose.material3.MaterialTheme
    import androidx.compose.runtime.*
    import androidx.compose.ui.window.Window
    import androidx.compose.ui.window.application
    import com.example.koogagent.AgentFactory
    import com.example.koogagent.getApiKey
    import kotlinx.coroutines.launch

    fun main() = application {
    Window(
    onCloseRequest = ::exitApplication,
    title = "Koog AI Agent – Desktop"
    ) {
    MaterialTheme {
    DesktopChatApp()
    }
    }
    }

    @Composable
    fun DesktopChatApp() {
    // Desktop 端与 Android 端共享完全相同的 Agent 逻辑
    // 只有 UI 布局可能略有不同
    SharedChatScreen() // 引用 shared 模块中的通用 UI
    }

    7.3 平台差异处理:expect/actual 模式

    // === commonMain ===
    // shared/src/commonMain/kotlin/com/example/koogagent/platform/Platform.kt

    /**
    * 平台抽象:处理各平台差异
    */

    expect object Platform {
    /** 平台名称 */
    val name: String

    /** 获取安全存储的 API Key */
    fun getSecureApiKey(): String

    /** 获取网络引擎 */
    fun createHttpClient(): HttpClient

    /** 日志输出 */
    fun log(tag: String, message: String)
    }

    // === androidMain ===
    actual object Platform {
    actual val name = "Android ${Build.VERSION.SDK_INT}"

    actual fun getSecureApiKey(): String {
    // 使用 Android Keystore 或 BuildConfig
    return BuildConfig.OPENAI_API_KEY
    }

    actual fun createHttpClient(): HttpClient {
    return HttpClient(OkHttp) {
    install(ContentNegotiation) { json() }
    }
    }

    actual fun log(tag: String, message: String) {
    android.util.Log.d(tag, message)
    }
    }

    // === iosMain ===
    actual object Platform {
    actual val name = UIDevice.currentDevice.systemName + " " +
    UIDevice.currentDevice.systemVersion

    actual fun getSecureApiKey(): String {
    return NSBundle.mainBundle.infoDictionary
    ?.get("LLM_API_KEY") as? String ?: ""
    }

    actual fun createHttpClient(): HttpClient {
    return HttpClient(Darwin) {
    install(ContentNegotiation) { json() }
    }
    }

    actual fun log(tag: String, message: String) {
    println("[$tag] $message")
    }
    }

    // === desktopMain ===
    actual object Platform {
    actual val name = "Desktop (${System.getProperty("os.name")})"

    actual fun getSecureApiKey(): String {
    return System.getenv("OPENAI_API_KEY") ?: ""
    }

    actual fun createHttpClient(): HttpClient {
    return HttpClient(CIO) {
    install(ContentNegotiation) { json() }
    }
    }

    actual fun log(tag: String, message: String) {
    println("[$tag] $message")
    }
    }

    7.4 三端统一测试验证

    // shared/src/commonTest/kotlin/com/example/koogagent/AgentIntegrationTest.kt
    package com.example.koogagent

    import kotlin.test.Test
    import kotlin.test.assertNotNull
    import kotlinx.coroutines.test.runTest

    /**
    * 跨平台集成测试
    * 此测试会在所有目标平台上运行
    */

    class AgentIntegrationTest {

    @Test
    fun testAgentCreation() = runTest {
    // 验证 Agent 可以正常创建
    val agent = AgentFactory.createBasicAgent("test-api-key")
    assertNotNull(agent)
    }

    @Test
    fun testToolRegistration() = runTest {
    // 验证工具注册正确
    val agent = AgentFactory.createFullAgent("test-api-key")
    assertNotNull(agent)
    // 验证工具数量
    // assertEquals(3, agent.tools.size)
    }

    @Test
    fun testContextManagement() = runTest {
    // 验证上下文管理器
    val manager = ContextWindowManager(maxContextTokens = 1000)
    val messages = (1..100).map { i ->
    ConversationMessage(
    role = ConversationMessage.Role.USER,
    content = "消息 $i:这是一段测试文本",
    timestamp = System.currentTimeMillis()
    )
    }

    val managed = manager.manageContext(messages)
    // 验证压缩后消息数量减少
    assert(managed.size < messages.size)
    }
    }

    运行测试:

    # 运行所有平台的测试
    ./gradlew :shared:allTests

    # 只运行 Desktop (JVM) 测试
    ./gradlew :shared:desktopTest

    # 只运行 Android 测试
    ./gradlew :shared:testDebugUnitTest

    # 运行 iOS 测试(需要 macOS + Xcode)
    ./gradlew :shared:iosSimulatorArm64Test


    八、常见编译报错排查与依赖冲突解决方案

    8.1 Kotlin/Native 编译错误

    错误 1:Unresolved reference: ai.koog

    e: file.kt: (3, 20): Unresolved reference: ai

    原因:iOS target 未正确配置 Koog 依赖。

    解决方案:

    // 确保 iosMain 的 dependencies 中包含 Koog
    val iosMain by creating {
    dependsOn(commonMain)
    dependencies {
    // Koog 依赖在 commonMain 中声明即可
    // 但需要确保 Ktor 引擎正确
    implementation("io.ktor:ktor-client-darwin:3.1.0")
    }
    }

    错误 2:Cannot find 'libkoog' in framework

    ld: library not found for -lkoog

    解决方案:清理构建缓存重新编译:

    ./gradlew clean
    ./gradlew :shared:compileKotlinIosArm64
    # 如果仍然失败,删除 .gradle 和 build 目录
    rm -rf .gradle build shared/build
    ./gradlew :shared:compileKotlinIosArm64

    8.2 依赖版本冲突

    错误 3:Conflict found for kotlinx-coroutines-core

    > Conflict found for org.jetbrains.kotlinx:kotlinx-coroutines-core:
    – version 1.8.1 required by project :shared
    – version 1.9.0 required by ai.koog:koog-agents-core:0.7.2

    解决方案:在根 build.gradle.kts 中强制统一版本:

    // build.gradle.kts (root)
    subprojects {
    configurations.all {
    resolutionStrategy {
    // 强制使用高版本
    force("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
    force("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
    force("io.ktor:ktor-client-core:3.1.0")
    }
    }
    }

    或者使用 Version Catalog(推荐):

    # gradle/libs.versions.toml
    [versions]
    kotlin = "2.2.20"
    coroutines = "1.9.0"
    serialization = "1.7.3"
    ktor = "3.1.0"
    koog = "0.7.2"

    [libraries]
    koog-core = { module = "ai.koog:koog-agents-core", version.ref = "koog" }
    koog-tools = { module = "ai.koog:koog-agents-tools", version.ref = "koog" }
    koog-executor = { module = "ai.koog:koog-prompt-executor", version.ref = "koog" }
    koog-openai = { module = "ai.koog:koog-llm-client-openai", version.ref = "koog" }
    coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
    serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" }
    ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }

    8.3 Ktor 引擎冲突

    错误 4:No Http client engine found

    io.ktor.client.engine.HttpClientEngineNotFoundException:
    No Http client engine found. Please add engine dependency.

    原因:commonMain 中使用了 HttpClient 但未在平台模块中添加引擎。

    解决方案:确保每个平台模块都有对应引擎:

    // androidMain → ktor-client-okhttp
    // iosMain → ktor-client-darwin
    // desktopMain (jvm) → ktor-client-cio 或 ktor-client-java

    8.4 序列化与反射问题

    错误 5:Serializer for class 'XXX' is not found

    kotlinx.serialization.SerializationException:
    Serializer for class 'WeatherRequest' is not found.

    原因:数据类缺少 @Serializable 注解或序列化插件未应用。

    解决方案:

    // 1. 确保 build.gradle.kts 中应用了序列化插件
    plugins {
    kotlin("plugin.serialization") version "2.2.20"
    }

    // 2. 所有需要序列化的类都加 @Serializable
    @Serializable
    data class WeatherRequest(
    val city: String,
    val date: String = ""
    )

    8.5 内存与 GC 相关问题

    错误 6:iOS 端 OutOfMemoryError

    Kotlin/Native 的内存模型与 JVM 不同,长对话可能导致内存压力。

    解决方案:

    // 限制对话历史长度
    val MAX_HISTORY_SIZE = 50 // 最多保留 50 条消息

    fun addToHistory(message: ConversationMessage) {
    history.add(message)
    if (history.size > MAX_HISTORY_SIZE) {
    // 移除最早的消息
    history.removeAt(0)
    }
    }


    九、性能优化技巧:流式响应处理与后台线程调度

    9.1 流式响应(Streaming)实现

    流式响应让用户无需等待完整生成,可以逐字看到 AI 回复:

    // shared/src/commonMain/kotlin/com/example/koogagent/streaming/StreamingAgent.kt
    package com.example.koogagent.streaming

    import ai.koog.agents.core.agent.AIAgent
    import ai.koog.prompt.executor.StreamingPromptExecutor
    import ai.koog.prompt.executor.clients.openai.OpenAILLMClient
    import kotlinx.coroutines.flow.Flow
    import kotlinx.coroutines.flow.map

    /**
    * 流式 Agent:支持逐 token 输出
    */

    class StreamingAgent(
    private val agent: AIAgent
    ) {

    /**
    * 流式执行:返回 Flow<String>,每个元素是一个 token/chunk
    */

    fun executeStreaming(input: String): Flow<String> {
    return agent.executeStreaming(input)
    .map { chunk ->
    chunk.delta?.content ?: ""
    }
    }
    }

    // 在 ViewModel 中使用
    class ChatViewModel : ViewModel() {

    fun sendStreamingMessage(userInput: String) {
    _messages.value += ChatMessage(role = USER, content = userInput)

    // 创建一个占位的 AI 消息
    val aiMessageIndex = _messages.value.size
    _messages.value += ChatMessage(role = ASSISTANT, content = "")

    viewModelScope.launch {
    try {
    streamingAgent.executeStreaming(userInput)
    .collect { token ->
    // 逐 token 更新 UI
    val current = _messages.value[aiMessageIndex]
    _messages.value = _messages.value.toMutableList().apply {
    this[aiMessageIndex] = current.copy(
    content = current.content + token
    )
    }
    }
    } catch (e: Exception) {
    _error.value = "流式请求失败:${e.message}"
    }
    }
    }
    }

    9.2 协程调度器选择

    import kotlinx.coroutines.*

    /**
    * 协程调度最佳实践
    */

    object AgentDispatcher {

    /**
    * Agent 执行:使用 IO 调度器(网络密集型)
    */

    val agentExecution = Dispatchers.IO

    /**
    * 工具执行:根据工具类型选择
    */

    val toolExecution = Dispatchers.Default // CPU 密集型工具

    /**
    * UI 更新:主线程
    */

    val uiUpdate = Dispatchers.Main

    /**
    * 示例:正确的协程使用
    */

    suspend fun executeAgentWithProperDispatch(
    agent: AIAgent,
    input: String
    ): String {
    // Agent 调用在 IO 线程
    return withContext(agentExecution) {
    val response = agent.execute(input)
    response.content
    }
    // 回到调用者的线程(通常是 Main)
    }
    }

    // 在 ViewModel 中
    viewModelScope.launch(AgentDispatcher.agentExecution) {
    val result = agent.execute(userInput)

    withContext(AgentDispatcher.uiUpdate) {
    // 更新 UI
    _messages.value += ChatMessage(ASSISTANT, result.content)
    }
    }

    9.3 并行工具调用

    当 LLM 一次返回多个 tool_call 时,可以并行执行:

    import kotlinx.coroutines.async
    import kotlinx.coroutines.awaitAll

    /**
    * 并行工具执行器
    */

    class ParallelToolExecutor(
    private val tools: Map<String, suspend (String) -> String>
    ) {

    /**
    * 并行执行多个工具调用
    */

    suspend fun executeParallel(
    toolCalls: List<ToolCall>
    ): List<ToolResult> = coroutineScope {

    // 为每个工具调用创建异步任务
    toolCalls.map { call ->
    async(Dispatchers.Default) {
    try {
    val toolFn = tools[call.functionName]
    ?: throw IllegalArgumentException("Unknown tool: ${call.functionName}")

    val result = toolFn(call.arguments)
    ToolResult(
    toolCallId = call.id,
    content = result,
    isError = false
    )
    } catch (e: Exception) {
    ToolResult(
    toolCallId = call.id,
    content = "工具执行失败:${e.message}",
    isError = true
    )
    }
    }
    }.awaitAll() // 等待所有工具完成
    }
    }

    @Serializable
    data class ToolCall(
    val id: String,
    val functionName: String,
    val arguments: String
    )

    @Serializable
    data class ToolResult(
    val toolCallId: String,
    val content: String,
    val isError: Boolean
    )

    9.4 网络层优化

    /**
    * 优化的 HttpClient 配置
    */

    fun createOptimizedHttpClient(): HttpClient {
    return HttpClient {
    // 连接超时
    install(HttpTimeout) {
    connectTimeoutMillis = 10_000 // 连接超时 10s
    requestTimeoutMillis = 60_000 // 请求超时 60s(LLM 可能较慢)
    socketTimeoutMillis = 60_000 // Socket 超时
    }

    // 自动重试
    install(HttpRetry) {
    retryOnServerErrors(maxRetries = 3)
    retryOnException(maxRetries = 2)
    delayMillis { retry ->
    1000L * retry // 递增延迟:1s, 2s, 3s
    }
    }

    // JSON 序列化
    install(ContentNegotiation) {
    json(Json {
    ignoreUnknownKeys = true
    isLenient = true
    })
    }

    // 连接池(JVM 平台)
    engine {
    maxConnectionsCount = 20
    endpoint {
    maxConnectionsPerRoute = 10
    keepAliveTime = 30_000
    }
    }
    }
    }

    9.5 内存与 Token 预算控制

    /**
    * Token 预算管理器
    * 防止单次请求消耗过多 Token
    */

    class TokenBudgetManager(
    private val maxTokensPerRequest: Int = 4_096,
    private val maxTokensPerSession: Int = 100_000
    ) {
    private var sessionTokensUsed = 0

    /**
    * 检查是否还有预算
    */

    fun canProceed(estimatedTokens: Int): Boolean {
    return (sessionTokensUsed + estimatedTokens) <= maxTokensPerSession
    }

    /**
    * 记录消耗
    */

    fun recordUsage(tokensUsed: Int) {
    sessionTokensUsed += tokensUsed
    }

    /**
    * 获取剩余预算
    */

    fun remainingBudget(): Int {
    return maxTokensPerSession sessionTokensUsed
    }

    /**
    * 重置(新会话)
    */

    fun reset() {
    sessionTokensUsed = 0
    }
    }


    十、进阶场景:脱离 Python 服务实现纯 Kotlin 端侧智能体

    10.1 端侧推理模型集成(Ollama / llama.cpp)

    // shared/src/commonMain/kotlin/com/example/koogagent/local/LocalModelAgent.kt
    package com.example.koogagent.local

    import ai.koog.prompt.llm.LLModel
    import ai.koog.prompt.llm.LLMProvider
    import ai.koog.prompt.executor.SingleLLMPromptExecutor
    import ai.koog.prompt.executor.clients.ollama.OllamaLLMClient
    import ai.koog.prompt.executor.clients.LLMClientConfiguration

    /**
    * 纯端侧 Agent:使用本地 Ollama 模型
    * 完全不需要云端 API,数据不出设备
    */

    object LocalAgentFactory {

    /**
    * 创建本地 Agent
    * 前提:设备上已运行 Ollama 服务
    * – Android:通过 Termux 或专用 App 运行 Ollama
    * – Desktop:直接安装 Ollama
    * – iOS:使用 llama.cpp 的 iOS 绑定
    */

    fun createLocalAgent(): AIAgent {

    // 配置本地 Ollama 连接
    val localConfig = LLMClientConfiguration(
    baseUrl = "http://localhost:11434", // Ollama 默认端口
    apiKey = "" // 本地模型不需要 API Key
    )

    val ollamaClient = OllamaLLMClient(
    configuration = localConfig
    )

    val promptExecutor = SingleLLMPromptExecutor(
    llmClient = ollamaClient
    )

    // 使用本地模型
    val localModel = LLModel(
    provider = LLMProvider.Ollama,
    id = "llama3.1:8b", // 8B 参数模型,适合端侧
    capabilities = setOf(
    LLMCapability.Completion,
    LLMCapability.Tools
    ),
    contextLength = 8_192,
    maxOutputTokens = 2_048
    )

    return AIAgent(
    promptExecutor = promptExecutor,
    model = localModel,
    systemPrompt = AgentConfig.systemPrompt,
    tools = ToolSet(
    tools = listOf(
    TodoTool(),
    CalculatorTool()
    // 注意:端侧模型能力有限,工具不宜过多
    )
    ),
    maxIterations = 5 // 端侧模型迭代次数要少
    )
    }
    }

    10.2 MCP 协议对接外部系统

    MCP(Model Context Protocol)是 Koog 支持的标准协议,用于连接外部工具和数据源:

    // shared/src/commonMain/kotlin/com/example/koogagent/mcp/MCPIntegration.kt
    package com.example.koogagent.mcp

    import ai.koog.agents.mcp.MCPClient
    import ai.koog.agents.mcp.MCPToolProvider

    /**
    * MCP 集成:连接外部工具服务
    * MCP 允许 Agent 动态发现和调用外部系统的能力
    */

    class MCPIntegration {

    /**
    * 连接 MCP 服务器并获取可用工具
    */

    suspend fun connectToMCPServer(
    serverUrl: String
    ): MCPToolProvider {

    val mcpClient = MCPClient(
    serverUrl = serverUrl,
    // 可选:认证信息
    headers = mapOf(
    "Authorization" to "Bearer ${getApiKey()}"
    )
    )

    // 连接并发现可用工具
    val toolProvider = MCPToolProvider(mcpClient)
    toolProvider.initialize()

    // 打印发现的工具
    toolProvider.availableTools.forEach { tool ->
    Platform.log("MCP", "发现工具: ${tool.name}${tool.description}")
    }

    return toolProvider
    }

    /**
    * 将 MCP 工具注入 Agent
    */

    suspend fun createAgentWithMCP(
    apiKey: String,
    mcpServerUrl: String
    ): AIAgent {

    val mcpTools = connectToMCPServer(mcpServerUrl)

    return AIAgent(
    promptExecutor = SingleLLMPromptExecutor(
    OpenAILLMClient(LLMClientConfiguration(apiKey = apiKey))
    ),
    model = AgentConfig.model,
    systemPrompt = AgentConfig.systemPrompt,
    tools = ToolSet(
    // 合并本地工具和 MCP 远程工具
    tools = listOf(TodoTool()),
    externalToolProviders = listOf(mcpTools)
    )
    )
    }
    }

    10.3 多 Agent 协作架构

    /**
    * 多 Agent 协作:不同 Agent 负责不同领域
    */

    class MultiAgentOrchestrator {

    private val weatherAgent: AIAgent // 天气专家
    private val scheduleAgent: AIAgent // 日程专家
    private val routerAgent: AIAgent // 路由 Agent

    /**
    * 路由 Agent 决定将请求分发给哪个专家 Agent
    */

    suspend fun handleRequest(input: String): String {
    // 第一步:路由判断
    val routingResult = routerAgent.execute(
    """
    分析以下用户请求,判断应该由哪个专家处理:
    – weather: 天气相关
    – schedule: 日程/待办相关
    – general: 通用问题

    用户请求:$input

    只回答分类结果(weather/schedule/general):
    """.trimIndent()
    )

    // 第二步:分发到对应专家
    return when {
    routingResult.content.contains("weather") ->
    weatherAgent.execute(input).content
    routingResult.content.contains("schedule") ->
    scheduleAgent.execute(input).content
    else ->
    "我是通用助手。$input 的回答是…"
    }
    }
    }

    10.4 生产环境部署清单

    检查项状态说明
    API Key 安全管理 使用加密存储,不硬编码
    网络超时配置 设置合理超时,避免 ANR
    错误重试策略 指数退避重试
    Token 预算控制 防止成本失控
    对话历史限制 避免内存溢出
    用户输入校验 防注入攻击
    日志脱敏 不记录敏感信息
    离线降级方案 网络不可用时的兜底
    版本兼容 模型 API 版本锁定
    性能监控 响应时间、成功率

    十一、常见陷阱与问题排除速查表

    #问题现象原因解决方案
    1 Unresolved reference: ai.koog 依赖未正确添加 检查 commonMain dependencies
    2 Serializer not found 缺少 @Serializable 或插件 添加注解 + 应用 serialization 插件
    3 No HttpClient engine 平台模块缺少引擎依赖 各平台添加对应 Ktor 引擎
    4 Agent 无响应/超时 API Key 无效或网络问题 验证 Key,检查网络代理设置
    5 工具不被调用 Tool description 不够清晰 优化 description,明确触发条件
    6 无限循环调用工具 maxIterations 未设置 设置合理上限(5-10)
    7 iOS 编译失败 Kotlin/Native 缓存问题 ./gradlew clean + 删除 build
    8 内存溢出(iOS) 对话历史过长 限制历史长度 + 定期压缩
    9 版本冲突 多库依赖同一库不同版本 resolutionStrategy 强制统一
    10 流式响应卡顿 UI 线程阻塞 确保 collect 在正确调度器
    11 401 Unauthorized API Key 过期或格式错误 重新生成 Key,检查前缀
    12 429 Rate Limit 请求频率超限 添加限流器,指数退避
    13 Android 崩溃 NetworkOnMainThread 主线程发起网络请求 确保在协程 IO 调度器中执行
    14 Desktop 窗口无响应 同步阻塞 UI 线程 使用 suspend + viewModelScope
    15 中文乱码 编码设置问题 确保 UTF-8,检查 Content-Type

    十二、总结与展望

    核心要点回顾

    通过本教程,我们完成了以下完整链路:

  • 环境搭建:从零配置了支持 Android/iOS/Desktop 三端的 KMP 项目
  • 框架理解:深入理解了 Koog 的五层架构、Prompt/Tool/Strategy 核心概念
  • Agent 创建:在 Android 端成功初始化并运行了第一个 AI Agent
  • 工具开发:实现了天气查询、待办管理等类型安全的自定义工具
  • 对话管理:构建了多轮对话状态机,实现了上下文窗口管理和持久化
  • 跨平台验证:将同一套 Agent 逻辑无缝迁移到 iOS 和 Desktop
  • 问题排查:掌握了常见编译错误和运行时问题的解决方法
  • 性能优化:实现了流式响应、并行工具调用、Token 预算控制
  • 进阶方案:探索了纯端侧推理、MCP 协议、多 Agent 协作
  • 2026 年后的展望

    • Koog 生态成熟:预计 2026 下半年 Koog 将达到 1.0 稳定版
    • 端侧模型进步:随着手机 NPU 性能提升,8B 甚至 13B 模型的端侧推理将成为常态
    • MCP 标准化:MCP 协议将成为 Agent 工具互操作的事实标准
    • KMP + AI 融合:KotlinConf 2026 已明确 AI × Multiplatform 是核心方向

    一句话总结:2026 年,Kotlin 开发者不再需要 Python 来构建 AI Agent。Koog + KMP 让你用熟悉的语言、熟悉的工具链,在全平台构建类型安全、可预测、企业就绪的原生智能体。


    十三、详细参考资料

    资源链接说明
    Koog 官方网站 https://www.jetbrains.com/koog/ 官方文档与下载
    Koog GitHub https://github.com/JetBrains/koog 源码与示例
    Koog 发布公告 https://blog.jetbrains.com/ai/2025/06/meet-koog/ KotlinConf 发布博客
    KMP 官方文档 https://kotlinlang.org/docs/multiplatform.html KMP 核心文档
    KMP 项目向导 https://kmp.jetbrains.com 在线创建 KMP 项目
    Compose Multiplatform https://www.jetbrains.com/compose-multiplatform/ 跨平台 UI
    Kotlin 2.2 发布说明 https://kotlinlang.org/docs/whatsnew22.html 新语言特性
    JetBrains Blog (Koog for Java) https://blog.jetbrains.com/ai/2026/03/koog-comes-to-java/ Java API 发布
    OpenAI API 文档 https://platform.openai.com/docs 模型 API 参考
    Ollama 官方 https://ollama.ai 本地模型运行
    MCP 协议规范 https://modelcontextprotocol.io Agent 工具互操作标准

    附录

    附录 A:完整项目结构树

    KoogAgentDemo/
    ├── settings.gradle.kts
    ├── build.gradle.kts
    ├── gradle/
    │ └── libs.versions.toml # 版本目录
    ├── local.properties # API Key(不提交 Git)
    ├── shared/ # 共享模块(核心)
    │ ├── build.gradle.kts
    │ └── src/
    │ ├── commonMain/kotlin/com/example/koogagent/
    │ │ ├── AgentConfig.kt # Agent 配置
    │ │ ├── AgentFactory.kt # Agent 工厂
    │ │ ├── tools/
    │ │ │ ├── WeatherTool.kt # 天气工具
    │ │ │ ├── TodoTool.kt # 待办工具
    │ │ │ └── CalculatorTool.kt
    │ │ ├── memory/
    │ │ │ ├── ConversationManager.kt
    │ │ │ ├── ContextWindowManager.kt
    │ │ │ └── AgentStorage.kt
    │ │ ├── streaming/
    │ │ │ └── StreamingAgent.kt
    │ │ ├── local/
    │ │ │ └── LocalModelAgent.kt
    │ │ └── platform/
    │ │ └── Platform.kt # expect 声明
    │ ├── commonTest/kotlin/
    │ │ └── AgentIntegrationTest.kt
    │ ├── androidMain/kotlin/
    │ │ └── platform/Platform.android.kt
    │ ├── iosMain/kotlin/
    │ │ ├── platform/Platform.ios.kt
    │ │ └── IOSAgentBridge.kt
    │ └── desktopMain/kotlin/
    │ └── platform/Platform.desktop.kt
    ├── androidApp/ # Android 壳工程
    │ ├── build.gradle.kts
    │ └── src/main/
    │ ├── java/…/
    │ │ ├── MainActivity.kt
    │ │ ├── ChatViewModel.kt
    │ │ └── ChatScreen.kt
    │ └── AndroidManifest.xml
    ├── iosApp/ # iOS 工程
    │ ├── iosApp.xcodeproj
    │ └── iosApp/
    │ ├── ContentView.swift
    │ └── Info.plist
    └── desktopApp/ # Desktop 壳工程
    ├── build.gradle.kts
    └── src/main/kotlin/Main.kt

    附录 B:Gradle 版本兼容矩阵

    KotlinAGPGradleKoogKtorCoroutines
    2.2.20 9.0.0 8.10 0.7.2 3.1.0 1.9.0
    2.2.0 8.7.0 8.9 0.7.0 3.0.3 1.9.0
    2.1.20 8.5.0 8.7 0.6.4 3.0.1 1.8.1

    ⚠️ Koog 0.7.x 要求 Kotlin ≥ 2.2.0。使用旧版 Kotlin 会导致编译错误。

    附录 C:Koog API 速查表

    类/函数包路径用途
    AIAgent ai.koog.agents.core.agent Agent 主类
    SingleLLMPromptExecutor ai.koog.prompt.executor 单模型执行器
    OpenAILLMClient ai.koog.prompt.executor.clients.openai OpenAI 客户端
    OllamaLLMClient ai.koog.prompt.executor.clients.ollama Ollama 客户端
    LLModel ai.koog.prompt.llm 模型定义
    LLMProvider ai.koog.prompt.llm 提供商枚举
    LLMCapability ai.koog.prompt.llm 模型能力
    @Tool ai.koog.agents.tools.annotation 工具注解
    @ToolParam ai.koog.agents.tools.annotation 参数注解
    ToolSet ai.koog.agents.tools 工具集合
    PromptTemplate ai.koog.prompt.template 提示词模板
    AIAgentStorage ai.koog.agents.storage 持久化接口
    MCPClient ai.koog.agents.mcp MCP 客户端
    GraphAgentStrategy ai.koog.agents.graph 图工作流策略
    FunctionalAgentStrategy ai.koog.agents.strategy 函数式策略

    附录 D:术语表

    术语英文解释
    Agent AI Agent 具备自主决策和工具调用能力的 AI 实体
    Prompt Prompt 发送给 LLM 的指令/上下文文本
    Tool Calling Function Calling LLM 调用外部函数获取信息或执行操作
    Strategy Strategy Agent 的决策逻辑/执行流程
    Graph Workflow Graph Workflow 基于有向图的复杂工作流
    GOAP Goal-Oriented Action Planning 目标导向行动规划
    MCP Model Context Protocol 模型上下文协议,Agent 工具互操作标准
    RAG Retrieval-Augmented Generation 检索增强生成
    Token Token LLM 处理文本的基本单位
    Context Window Context Window 模型一次能处理的最大 token 数
    Streaming Streaming 逐 token 流式输出响应
    KMP Kotlin Multiplatform Kotlin 跨平台技术
    expect/actual expect/actual KMP 平台差异化实现机制

    本文写于 2026 年 8 月,基于 Koog 0.7.x 与 Kotlin 2.2+。框架 API 可能随版本更新而变化,请以官方文档为准。

    作者注:如果本文对你有帮助,欢迎点赞收藏。遇到问题可在评论区交流。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » KMP 全栈开发:用 Koog 框架构建原生 AI Agent
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!