Koog Android示例应用:移动端AI代理开发实战

【免费下载链接】koog Koog is a Kotlin-based framework designed to build and run AI agents entirely in idiomatic Kotlin. 【免费下载链接】koog 项目地址: https://gitcode.com/GitHub_Trending/ko/koog

痛点:移动端AI应用开发的复杂性挑战

还在为移动端AI应用开发而头疼?面对模型集成、工具调用、状态管理的多重挑战,传统开发方式往往需要大量样板代码和复杂的架构设计。Koog框架通过纯Kotlin实现的AI代理框架,为Android开发者提供了革命性的解决方案。

读完本文你将获得:

  • ✅ Koog框架核心概念与架构解析
  • ✅ Android端AI代理完整开发流程
  • ✅ 计算器与天气代理实战代码示例
  • ✅ Jetpack Compose与Koog集成最佳实践
  • ✅ 移动端AI应用性能优化技巧

Koog框架架构解析

核心组件架构

mermaid

Android端集成架构

mermaid

环境搭建与项目配置

Gradle依赖配置

// build.gradle.kts
dependencies {
    implementation("ai.koog:agents-core:1.0.0")
    implementation("ai.koog:prompt-executor-openai-client:1.0.0")
    implementation("ai.koog:agents-features-event-handler:1.0.0")
    
    // Android相关依赖
    implementation("androidx.compose.ui:ui:1.6.0")
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
}

AndroidManifest权限配置

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

计算器代理实战开发

工具类定义

object CalculatorTools {
    abstract class CalculatorTool(
        name: String,
        description: String,
    ) : Tool<CalculatorTool.Args, CalculatorTool.Result>() {
        
        @Serializable
        data class Args(val a: Float, val b: Float) : ToolArgs

        @Serializable
        @JvmInline
        value class Result(val result: Float) : ToolResult {
            override fun toStringDefault(): String = result.toString()
        }

        final override val argsSerializer = Args.serializer()
        final override val descriptor = ToolDescriptor(
            name = name, 
            description = description, 
            requiredParameters = listOf(
                ToolParameterDescriptor("a", "First number", ToolParameterType.Float),
                ToolParameterDescriptor("b", "Second number", ToolParameterType.Float)
            )
        )
    }

    // 具体工具实现
    object PlusTool : CalculatorTool("plus", "Adds a and b") {
        override suspend fun execute(args: Args): Result = Result(args.a + args.b)
    }

    object MinusTool : CalculatorTool("minus", "Subtracts b from a") {
        override suspend fun execute(args: Args): Result = Result(args.a - args.b)
    }

    object MultiplyTool : CalculatorTool("multiply", "Multiplies a and b") {
        override suspend fun execute(args: Args): Result = Result(args.a * args.b)
    }

    object DivideTool : CalculatorTool("divide", "Divides a by b") {
        override suspend fun execute(args: Args): Result = Result(args.a / args.b)
    }
}

代理提供者实现

object CalculatorAgentProvider : AgentProvider {
    override val title: String = "Calculator"
    override val description: String = "Hi, I'm a calculator agent, I can do math"

    override suspend fun provideAgent(
        appSettings: AppSettings,
        onToolCallEvent: suspend (String) -> Unit,
        onErrorEvent: suspend (String) -> Unit,
        onAssistantMessage: suspend (String) -> String,
    ): AIAgent<String, String> {
        
        val openAiToken = appSettings.getCurrentSettings().openAiToken
        require(openAiToken.isNotEmpty()) { "OpenAI token is not configured." }

        val executor = simpleOpenAIExecutor(openAiToken)
        val toolRegistry = ToolRegistry {
            tool(CalculatorTools.PlusTool)
            tool(CalculatorTools.MinusTool)
            tool(CalculatorTools.MultiplyTool)
            tool(CalculatorTools.DivideTool)
            tool(ExitTool)
        }

        val strategy = strategy(title) {
            val nodeRequestLLM by nodeLLMRequestMultiple()
            val nodeAssistantMessage by node<String, String> { message -> 
                onAssistantMessage(message) 
            }
            val nodeExecuteToolMultiple by nodeExecuteMultipleTools(parallelTools = true)

            edge(nodeStart forwardTo nodeRequestLLM)
            edge(nodeRequestLLM forwardTo nodeExecuteToolMultiple onMultipleToolCalls { true })
            edge(nodeRequestLLM forwardTo nodeAssistantMessage transformed { it.first() } onAssistantMessage { true })
            edge(nodeAssistantMessage forwardTo nodeRequestLLM)
        }

        val agentConfig = AIAgentConfig(
            prompt = prompt("calculator") {
                system("""
                    You are a calculator agent. Use tools to solve math problems.
                    Provide clear answers and ask for next problem until user stops.
                """.trimIndent())
            },
            model = OpenAIModels.Chat.GPT4o,
            maxAgentIterations = 50
        )

        return AIAgent(
            promptExecutor = executor,
            strategy = strategy,
            agentConfig = agentConfig,
            toolRegistry = toolRegistry,
        ) {
            handleEvents {
                onToolCall { ctx ->
                    onToolCallEvent("Tool ${ctx.tool.name}, args ${ctx.toolArgs}")
                }
                onAgentRunError { ctx ->
                    onErrorEvent("${ctx.throwable.message}")
                }
            }
        }
    }
}

ViewModel状态管理

class AgentDemoViewModel(
    application: Application,
    private val agentProvider: AgentProvider
) : AndroidViewModel(application) {

    private val _uiState = MutableStateFlow(AgentDemoUiState(
        title = agentProvider.title,
        messages = listOf(Message.SystemMessage(agentProvider.description))
    ))
    val uiState: StateFlow<AgentDemoUiState> = _uiState.asStateFlow()

    fun sendMessage() {
        val userInput = _uiState.value.inputText.trim()
        if (userInput.isEmpty()) return

        _uiState.update {
            it.copy(
                messages = it.messages + Message.UserMessage(userInput),
                inputText = "",
                isInputEnabled = false,
                isLoading = true
            )
        }

        viewModelScope.launch {
            runAgent(userInput)
        }
    }

    private suspend fun runAgent(userInput: String) {
        withContext(Dispatchers.IO) {
            try {
                val agent = agentProvider.provideAgent(
                    appSettings = AppSettings(application),
                    onToolCallEvent = { message ->
                        viewModelScope.launch {
                            _uiState.update {
                                it.copy(messages = it.messages + Message.ToolCallMessage(message))
                            }
                        }
                    },
                    onErrorEvent = { errorMessage ->
                        viewModelScope.launch {
                            _uiState.update {
                                it.copy(
                                    messages = it.messages + Message.ErrorMessage(errorMessage),
                                    isInputEnabled = true,
                                    isLoading = false
                                )
                            }
                        }
                    },
                    onAssistantMessage = { message ->
                        _uiState.update {
                            it.copy(
                                messages = it.messages + Message.AgentMessage(message),
                                isInputEnabled = true,
                                isLoading = false,
                                userResponseRequested = true
                            )
                        }
                        // 等待用户响应逻辑
                    }
                )

                val result = agent.run(userInput)
                _uiState.update {
                    it.copy(
                        messages = it.messages + Message.ResultMessage(result),
                        isInputEnabled = false,
                        isLoading = false,
                        isChatEnded = true
                    )
                }
            } catch (e: Exception) {
                _uiState.update {
                    it.copy(
                        messages = it.messages + Message.ErrorMessage("Error: ${e.message}"),
                        isInputEnabled = true,
                        isLoading = false
                    )
                }
            }
        }
    }
}

Jetpack Compose UI实现

消息类型定义

sealed class Message {
    data class UserMessage(val text: String) : Message()
    data class AgentMessage(val text: String) : Message()
    data class SystemMessage(val text: String) : Message()
    data class ErrorMessage(val text: String) : Message()
    data class ToolCallMessage(val text: String) : Message()
    data class ResultMessage(val text: String) : Message()
}

data class AgentDemoUiState(
    val title: String = "Agent Demo",
    val messages: List<Message> = emptyList(),
    val inputText: String = "",
    val isInputEnabled: Boolean = true,
    val isLoading: Boolean = false,
    val isChatEnded: Boolean = false,
    val userResponseRequested: Boolean = false,
    val currentUserResponse: String? = null
)

Compose界面组件

@Composable
fun AgentDemoScreen(
    viewModel: AgentDemoViewModel,
    onBack: () -> Unit
) {
    val uiState by viewModel.uiState.collectAsState()
    
    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text(uiState.title) },
                navigationIcon = {
                    IconButton(onClick = onBack) {
                        Icon(Icons.Default.ArrowBack, contentDescription = "Back")
                    }
                }
            )
        }
    ) { padding ->
        Column(
            modifier = Modifier
                .padding(padding)
                .fillMaxSize()
        ) {
            // 消息列表
            LazyColumn(
                modifier = Modifier.weight(1f),
                reverseLayout = true
            ) {
                items(uiState.messages.reversed()) { message ->
                    MessageItem(message = message)
                }
            }
            
            // 输入区域
            if (uiState.isInputEnabled) {
                InputArea(
                    text = uiState.inputText,
                    onTextChange = viewModel::updateInputText,
                    onSend = viewModel::sendMessage,
                    isLoading = uiState.isLoading
                )
            }
            
            // 重启按钮
            if (uiState.isChatEnded) {
                Button(
                    onClick = viewModel::restartChat,
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(16.dp)
                ) {
                    Text("Restart Chat")
                }
            }
        }
    }
}

@Composable
fun MessageItem(message: Message) {
    val (backgroundColor, textColor) = when (message) {
        is Message.UserMessage -> Color.Blue to Color.White
        is Message.AgentMessage -> Color.Green to Color.White
        is Message.SystemMessage -> Color.Gray to Color.White
        is Message.ErrorMessage -> Color.Red to Color.White
        is Message.ToolCallMessage -> Color.Yellow to Color.Black
        is Message.ResultMessage -> Color.Cyan to Color.Black
    }
    
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp)
    ) {
        Text(
            text = when (message) {
                is Message.UserMessage -> "You: ${message.text}"
                is Message.AgentMessage -> "Agent: ${message.text}"
                is Message.SystemMessage -> "System: ${message.text}"
                is Message.ErrorMessage -> "Error: ${message.text}"
                is Message.ToolCallMessage -> "Tool: ${message.text}"
                is Message.ResultMessage -> "Result: ${message.text}"
            },
            color = textColor,
            modifier = Modifier
                .background(backgroundColor, RoundedCornerShape(8.dp))
                .padding(16.dp)
        )
    }
}

性能优化与最佳实践

内存管理策略

策略 实现方式 效果
工具懒加载 按需初始化工具实例 减少启动内存占用
会话压缩 自动清理历史消息 控制内存增长
结果缓存 缓存常用计算结果 减少重复计算
连接池 复用网络连接 降低连接开销

网络优化技巧

// 使用OkHttp连接池优化
val okHttpClient = OkHttpClient.Builder()
    .connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES))
    .connectTimeout(30, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .build()

val executor = simpleOpenAIExecutor(
    apiKey = openAiToken,
    httpClient = okHttpClient
)

错误处理与重试机制

class RetryAwareExecutor(
    private val delegate: PromptExecutor,
    private val maxRetries: Int = 3
) : PromptExecutor by delegate {
    
    override suspend fun execute(prompt: Prompt): PromptResult {
        var lastException: Exception? = null
        repeat(maxRetries) { attempt ->
            try {
                return delegate.execute(prompt)
            } catch (e: IOException) {
                lastException = e
                delay((attempt + 1) * 1000L) // 指数退避
            } catch (e: Exception) {
                lastException = e
                break
            }
        }
        throw lastException ?: Exception("Unknown error")
    }
}

实战应用场景扩展

电商推荐代理

object RecommendationAgentProvider : AgentProvider {
    override val title: String = "Recommendation Agent"
    override val description: String = "I can recommend products based on your preferences"
    
    override suspend fun provideAgent(
        appSettings: AppSettings,
        onToolCallEvent: suspend (String) -> Unit,
        onErrorEvent: suspend (String) -> Unit,
        onAssistantMessage: suspend (String) -> String
    ): AIAgent<String, String> {
        val toolRegistry = ToolRegistry {
            tool(ProductSearchTool)
            tool(PriceComparisonTool)
            tool(UserPreferenceTool)
            tool(ExitTool)
        }
        
        // 策略配置和代理创建逻辑
    }
}

多模态代理集成

object MultiModalAgentProvider : AgentProvider {
    override suspend fun provideAgent(
        // 参数省略
    ): AIAgent<String, String> {
        val toolRegistry = ToolRegistry {
            tool(ImageAnalysisTool)
            tool(TextToSpeechTool)
            tool(VisionProcessingTool)
            tool(ExitTool)
        }
        
        // 支持图像和文本的多模态处理
    }
}

总结与展望

Koog框架为Android开发者提供了强大的AI代理开发能力,通过纯Kotlin实现确保了代码的一致性和可维护性。本文详细介绍了:

  1. 架构设计:分层清晰的组件架构,便于扩展和维护
  2. 工具开发:灵活的工具定义机制,支持各种业务场景
  3. 状态管理:完善的ViewModel状态管理,确保UI一致性
  4. 性能优化:多层次的性能优化策略,提升用户体验

未来Koog将继续在以下方向发力:

  • 🔥 更强大的多模态支持
  • 🚀 更高效的模型推理优化
  • 📱 更完善的移动端生态集成

立即开始你的移动端AI代理开发之旅,让Koog助力你的应用智能化升级!

三连支持:点赞👍 + 收藏⭐ + 关注👀 下期预告:《Koog高级特性:自定义策略图与分布式代理集群》

【免费下载链接】koog Koog is a Kotlin-based framework designed to build and run AI agents entirely in idiomatic Kotlin. 【免费下载链接】koog 项目地址: https://gitcode.com/GitHub_Trending/ko/koog

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐