从零实现一个 Android AI Agent:ReAct + Function Calling 实战
2026/9/5 2:09:10 网站建设 项目流程

从零实现一个 Android AI Agent:ReAct + Function Calling 实战

本文配套开源项目:AI Agent Demo(Apache 2.0 协议)
技术栈:Kotlin + Jetpack Compose + MVVM + Retrofit + DeepSeek API

一、为什么要在手机上做 AI Agent

2025 年以来,“AI Agent” 是开发者圈最热的概念之一。市面上的教程大多是 Python + 命令行 Demo,但在真实用户场景中,手机才是 Agent 最自然的载体:查定位、看设备信息、打开设置、发短信——这些能力天然属于移动端。

本文以一个完整的 Android 开源项目为例,拆解 AI Agent 的两大核心机制:ReAct 循环Function Calling

二、整体架构

项目采用标准 Android 分层架构,Agent 核心逻辑放在领域层:

UI 层(Compose + MVVM) │ ChatViewModel 收集 Flow<AgentState> ▼ 领域层(AgentManager) ← Agent 的"大脑" │ ReAct 循环:思考 → 调用工具 → 观察结果 → 再思考 ▼ 工具层(ToolExecutor) ← Agent 的"手脚" │ 定位 / 设备信息 / 天气 / 设置 / 短信 ▼ 数据层(Retrofit + OkHttp) ← 对话 API + 各工具的数据来源

三、核心一:ReAct 循环

ReAct(Reasoning + Acting)是当前 LLM Agent 的主流范式:模型不直接给出最终答案,而是边推理边行动——先决定调用哪个工具,拿到工具结果后再继续推理,直到能给出最终回答。

实现一个 ReAct 循环只需要 60 行左右的核心代码:

funrun(userInput:String):Flow<AgentState>=flow{// 初始会话:系统提示词 + 用户输入valmessages=mutableListOf<Message>(Message(role="system",content="你是一个Android手机助手..."),Message(role="user",content=userInput))valtools=toolExecutor.getToolDefinitions()varmaxIterations=5// 防止模型无限调用工具varfinalAnswer=""while(maxIterations-->0){emit(AgentState.Thinking("🧠 思考中..."))// tool_choice = "auto":由模型自行决定是否调用工具valrequest=ChatRequest(messages=messages,tools=tools,tool_choice="auto")valresponse=apiService.chat(request)valassistantMsg=response.choices.first().message// 模型未要求调用工具 → 已给出最终回答if(assistantMsg.tool_calls.isNullOrEmpty()){finalAnswer=assistantMsg.content?:"抱歉,我没有理解你的问题"break}// 记录模型的工具调用意图messages.add(Message(role="assistant",content=assistantMsg.content,tool_calls=assistantMsg.tool_calls))// 执行每个工具,并把结果回传for(toolCallinassistantMsg.tool_calls){emit(AgentState.ToolCalling("🔧 调用工具:${toolCall.function.name}"))valresult=toolExecutor.executeTool(toolCall.function.name,parseArguments(toolCall.function.arguments))messages.add(Message(role="tool",content=result,tool_call_id=toolCall.id))}}emit(AgentState.Completed(finalAnswer))}.flowOn(Dispatchers.IO)

三个关键设计点:

  1. 多轮消息回填assistant(工具调用意图)和tool(执行结果)消息都要追加回messages,这是 ReAct 的核心——模型"看到"工具结果后才会继续推理;
  2. maxIterations上限:防止模型陷入循环调用,5 轮后强制兜底文案;
  3. Flow<AgentState>而非回调:Agent 执行是异步长任务,用 Flow 天然获得结构化并发、生命周期安全和线程切换(flowOn(IO)),UI 层collect即可响应式更新界面。

四、核心二:Function Calling 工具注册

工具以 JSON Schema 形式声明给模型,模型据此决定"调哪个工具、传什么参数":

fungetToolDefinitions():List<ToolDefinition>=listOf(ToolDefinition(type="function",function=ToolFunction(name="get_weather",description="查询指定城市的实时天气和今日预报",parameters=ToolParameters(properties=mapOf("city"toToolProperty("string","城市名称,例如:上海")),required=listOf("city")))),// 定位、设备信息、设置、短信等工具同构声明...)

Schema 质量决定 Agent 质量——description写清楚"什么时候用"(如"当用户询问天气时,调用 get_weather"),模型才能正确路由。工具执行本身则用 try-catch 包裹降级,单个工具失败不中断整个循环。

五、核心三:状态流驱动 UI

Agent 运行过程的四个状态(思考中 / 调用工具 / 完成 / 出错)用 sealed class 建模:

sealedclassAgentState{dataclassThinking(valtext:String):AgentState()dataclassToolCalling(valtext:String):AgentState()dataclassCompleted(valresult:String):AgentState()dataclassError(valmessage:String):AgentState()}

ViewModel 收集后更新ChatUiState,Compose 界面据此渲染"🧠 思考中…“提示、工具调用过程气泡和最终回复——用户能直观看到 Agent 的"思考过程”,这也是 AI 应用体验的核心差异点。

六、踩坑记录(真实经历)

  1. 没有对话历史:当前实现每次请求都是全新 messages,模型不记得上一轮对话。做多轮对话需持久化会话历史;
  2. API Key 泄露:曾在 git 历史中硬编码 Key 并推送到公开仓库,最终通过重建仓库 + force push + 平台吊销 Key 解决。教训:从第一天起就用local.properties+ BuildConfig 注入
  3. 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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询