
从零实现一个 Android AI AgentReAct Function Calling 实战本文配套开源项目AI Agent DemoApache 2.0 协议技术栈Kotlin Jetpack Compose MVVM Retrofit DeepSeek API一、为什么要在手机上做 AI Agent2025 年以来“AI Agent” 是开发者圈最热的概念之一。市面上的教程大多是 Python 命令行 Demo但在真实用户场景中手机才是 Agent 最自然的载体查定位、看设备信息、打开设置、发短信——这些能力天然属于移动端。本文以一个完整的 Android 开源项目为例拆解 AI Agent 的两大核心机制ReAct 循环和Function Calling。二、整体架构项目采用标准 Android 分层架构Agent 核心逻辑放在领域层UI 层Compose MVVM │ ChatViewModel 收集 FlowAgentState ▼ 领域层AgentManager ← Agent 的大脑 │ ReAct 循环思考 → 调用工具 → 观察结果 → 再思考 ▼ 工具层ToolExecutor ← Agent 的手脚 │ 定位 / 设备信息 / 天气 / 设置 / 短信 ▼ 数据层Retrofit OkHttp ← 对话 API 各工具的数据来源三、核心一ReAct 循环ReActReasoning Acting是当前 LLM Agent 的主流范式模型不直接给出最终答案而是边推理边行动——先决定调用哪个工具拿到工具结果后再继续推理直到能给出最终回答。实现一个 ReAct 循环只需要 60 行左右的核心代码funrun(userInput:String):FlowAgentStateflow{// 初始会话系统提示词 用户输入valmessagesmutableListOfMessage(Message(rolesystem,content你是一个Android手机助手...),Message(roleuser,contentuserInput))valtoolstoolExecutor.getToolDefinitions()varmaxIterations5// 防止模型无限调用工具varfinalAnswerwhile(maxIterations--0){emit(AgentState.Thinking( 思考中...))// tool_choice auto由模型自行决定是否调用工具valrequestChatRequest(messagesmessages,toolstools,tool_choiceauto)valresponseapiService.chat(request)valassistantMsgresponse.choices.first().message// 模型未要求调用工具 → 已给出最终回答if(assistantMsg.tool_calls.isNullOrEmpty()){finalAnswerassistantMsg.content?:抱歉我没有理解你的问题break}// 记录模型的工具调用意图messages.add(Message(roleassistant,contentassistantMsg.content,tool_callsassistantMsg.tool_calls))// 执行每个工具并把结果回传for(toolCallinassistantMsg.tool_calls){emit(AgentState.ToolCalling( 调用工具:${toolCall.function.name}))valresulttoolExecutor.executeTool(toolCall.function.name,parseArguments(toolCall.function.arguments))messages.add(Message(roletool,contentresult,tool_call_idtoolCall.id))}}emit(AgentState.Completed(finalAnswer))}.flowOn(Dispatchers.IO)三个关键设计点多轮消息回填assistant工具调用意图和tool执行结果消息都要追加回messages这是 ReAct 的核心——模型看到工具结果后才会继续推理maxIterations上限防止模型陷入循环调用5 轮后强制兜底文案FlowAgentState而非回调Agent 执行是异步长任务用 Flow 天然获得结构化并发、生命周期安全和线程切换flowOn(IO)UI 层collect即可响应式更新界面。四、核心二Function Calling 工具注册工具以 JSON Schema 形式声明给模型模型据此决定调哪个工具、传什么参数fungetToolDefinitions():ListToolDefinitionlistOf(ToolDefinition(typefunction,functionToolFunction(nameget_weather,description查询指定城市的实时天气和今日预报,parametersToolParameters(propertiesmapOf(citytoToolProperty(string,城市名称例如上海)),requiredlistOf(city)))),// 定位、设备信息、设置、短信等工具同构声明...)Schema 质量决定 Agent 质量——description写清楚什么时候用如当用户询问天气时调用 get_weather模型才能正确路由。工具执行本身则用 try-catch 包裹降级单个工具失败不中断整个循环。五、核心三状态流驱动 UIAgent 运行过程的四个状态思考中 / 调用工具 / 完成 / 出错用 sealed class 建模sealedclassAgentState{dataclassThinking(valtext:String):AgentState()dataclassToolCalling(valtext:String):AgentState()dataclassCompleted(valresult:String):AgentState()dataclassError(valmessage:String):AgentState()}ViewModel 收集后更新ChatUiStateCompose 界面据此渲染 思考中…“提示、工具调用过程气泡和最终回复——用户能直观看到 Agent 的思考过程”这也是 AI 应用体验的核心差异点。六、踩坑记录真实经历没有对话历史当前实现每次请求都是全新 messages模型不记得上一轮对话。做多轮对话需持久化会话历史API Key 泄露曾在 git 历史中硬编码 Key 并推送到公开仓库最终通过重建仓库 force push 平台吊销 Key 解决。教训从第一天起就用local.properties BuildConfig 注入UI 线程阻塞工具执行涉及网络与系统调用必须整体flowOn(IO)UI 只负责 collect。七、总结AI Agent 的核心并不神秘ReAct 循环60 行 工具 Schema 注册 状态流。掌握这套模式后你可以在任何平台Android / iOS / Web / 桌面快速复制出 Agent 应用。完整代码与仿微信长按菜单、热词栏等细节见仓库AI Agent Demo欢迎 Star 与交流。关键词AI Agent、ReAct、Function Calling、DeepSeek、Android、Jetpack Compose、Kotlin