
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 存在三大痛点:
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 与同类框架对比
| 定位 | 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:
⚠️ 常见陷阱:下载的项目可能使用旧版目录结构。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
)
}
}
运行验证步骤:
五、定义自定义工具函数并实现本地业务逻辑调用
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 |
十二、总结与展望
核心要点回顾
通过本教程,我们完成了以下完整链路:
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 版本兼容矩阵
| 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 可能随版本更新而变化,请以官方文档为准。
作者注:如果本文对你有帮助,欢迎点赞收藏。遇到问题可在评论区交流。
网硕互联帮助中心




评论前必须登录!
注册