手机端侧AI Agent实战:从LFM 2.5模型到工具调用全流程 “手机本地跑 AI Agent”这几年经常能看到但真正动手之前有三个问题绕不开模型从哪里来模型跑在什么引擎上Agent 需要调用的工具如何跟手机系统打通大部分介绍只回答了第一个问题把“能聊天”当成“能当 Agent”导致很多人把模型跑起来后才发现距离真正完成一个“查询时间—调用应用—返回结果”的任务链条还有不少工程距离。这篇文章要讨论的核心是 Liquid AI 的 LFM 2.5 系列模型以及它背后更适合端侧推理的混合架构思路同时给出一条可以在手机上复现的最小 Agent 链路包括环境准备、模型量化、Agent 循环代码、性能验证方法和常见坑位。先给结论端侧 AI Agent 的真正瓶颈往往不是“每秒能生成多少个 token”而是内存占用、工具调用的格式稳定性、系统权限边界以及长时间运行的功耗控制。LFM 2.5 这类低推理内存的架构能解决一部分问题但它不是银弹工具调用设计得好不好才是体验的分水岭。1. 这篇文章真正要解决的问题如果只是想体验一下“手机上的大模型”直接打开一个聊天 App 就够了。但 AI Agent 和聊天助手有一个本质区别Agent 要在多轮对话中完成工具调用、读取结果并继续推理。也就是说它不仅要“会说话”还要“会做事”。本地 Agent 的价值在几个场景里非常明显隐私敏感场景。日历、通讯录、健康记录、银行短信这些数据不合适全部上传到云端。弱网和离线场景。地铁、飞机、偏远地区云端 API 的延迟和不可用会直接让 Agent 瘫痪。成本敏感场景。一次简单的意图识别如果也走云端大模型累积成本并不低端侧模型把高频、低复杂度的任务留在本机只把疑难任务上传。自主可控场景。模型、提示词、工具代码、日志都在本地行为链路可以被审计。云端 Agent 的架构通常是手机客户端把任务上传到服务器服务器运行大模型并调用云端工具或手机辅助工具。端侧 Agent 则把这些能力尽可能压缩到本机本地模型负责理解与规划本地工具执行器负责调用系统能力隐私数据不离开设备。因此本文不是单纯评测某个模型“跑分多高”而是想把下面这条链路讲通端侧模型选型 → 模型转换与量化 → 本地推理服务 → Agent 工具调用循环 → 性能与稳定性验证。不管你用的是 LFM 2.5还是其他开源模型这套链路的大方向都适用。2. LFM 2.5 的架构背景为什么端侧 Agent 需要新的模型范式认识 LFM 之前先理解一个趋势传统 Transformer 架构在“端侧推理”这件事上越来越不划算。2.1 传统 Transformer 在端侧的真正瓶颈Transformer的核心是自注意力机制。模型生成第 N 个 token 时需要参考前面 N-1 个 token 的信息通常还要把历史 token 的 Key 和 Value 向量缓存下来这就是常说的KV Cache。上下文越长KV Cache 越大。云端服务器可以通过更多显卡把 KV Cache 放大但在手机上不行。手机内存是固定且共享的系统、相机、后台进程都在抢内存。如果模型推理时突然申请几十 GB 的显存结果不是变慢而是直接崩溃。所以端侧模型要解决的核心矛盾是如何在上下文不断变长的情况下让内存占用尽量平稳。这正是状态空间模型、线性注意力这类“非标准注意力”架构的价值所在。2.2 LFM 不是“另一个 GPT 变体”LFM 是 Liquid Foundation Model 的缩写来自 Liquid AI。这个团队早期研究的是流体神经网络在工程上真正值得关注的是它没有完全沿用纯 Transformer而是倾向使用混合线性注意力 / 状态空间风格的结构。用通俗的方式解释Transformer 像“读全文再答题”。每题都要翻看前面所有对话记录准确但占地方。状态空间模型像“边听边记摘要”。把历史信息压缩成一个固定大小的内部状态不管对话多长状态体积不会无限膨胀省内存但可能在需要精确回忆时丢失细节。LFM 2.5 这类模型更务实的做法是混合。一部分模块仍然保留较强的注意力能力用于精确推理另一部分模块用低内存的线性机制压缩历史。这种做法与“端侧 AI Agent 需要长上下文工具历史”的需求天然匹配。需要提醒的是LFM 2.5 的官方仓库说明、模型卡、支持的推理框架都会随版本更新变化。本文不打算编造不存在的参数量表格具体尺寸和运行框架以官方发布为准。但你只需要记住一个判断LFM 2.5 真正降低的是长上下文推理时的内存压力而不是单纯把模型文件变小。2.3 端侧 Agent 需要什么样的模型能力先看 Agent 的一个典型流程用户说“帮我查一下明天下午有没有空然后创建一个会议提醒”。Agent 理解意图拆解为“先查日历再创建提醒”。Agent 输出工具调用比如check_calendar(date...)。工具执行器读取日历返回结果。Agent 把结果组织成自然语言回复。这个链路对模型有几点要求指令遵循能力强能按格式输出工具调用能容忍较长的系统提示词和工具描述多轮对话不遗忘前面的任务上下文低延迟因为本地 Agent 可能要跑多轮推理低内存因为要和系统其他应用共存。LFM 2.5 的低内存推理优势在最后一点上非常契合端侧 Agent。如果同一台设备上同时运行模型服务和应用内存抖动会直接影响系统稳定性。3. 端侧 AI Agent 的系统结构模型不是全部很多人以为“把模型跑起来”就是 Agent 完成了。实际上模型只是 Agent 的“大脑”你还需要“手”和“记忆”。3.1 Agent 循环里的模块划分一个最小可用的端侧 Agent 至少包含输入解析模块接收用户文本、语音转写结果或其他事件。模型推理模块把系统提示词和对话历史发给本地模型拿到回复。工具调用解析模块从模型输出中识别“是否要调用工具调用哪个工具参数是什么”。工具执行器真正执行动作比如写入日历、查询天气、读取剪贴板。结果回填模块把工具执行结果追加到对话上下文让模型继续判断。记忆和上下文管理模块控制哪些历史记录该保留哪些该裁剪。云端 Agent 和端侧 Agent 的模式差异如下对比维度云端 Agent端侧 Agent模型位置云端 GPU 集群手机本地推理引擎数据隐私依赖云端策略数据默认不出设备工具调用权限通常需要用户在手机端二次确认本地工具执行器可自定义权限策略上下文管理相对宽松但成本高内存有限必须主动裁剪断网可用性弱强模型更新服务端快速迭代依赖用户下载新版本需要注意的是手机端“工具调用”与服务器端完全不同。你不能让模型直接执行任意系统命令否则一条提示词就可能让 Agent 删除本地数据。工具执行器必须做白名单校验、参数类型校验和用户确认。3.2 工具调用不一定要靠“官方 Function Calling”很多开发者在端侧复刻云端 Agent 时第一反应是找模型推理框架是否支持 Function Calling。但本地小模型对复杂 JSON Schema 的遵循能力通常不稳定真正可靠的思路是把工具描述写进系统提示词让模型输出固定 JSON再用代码解析。本地模型可能无法保证每次输出都是标准 JSON但只要提示词设计合理并在解析失败时做重试这种方式在端侧完全可用。4. 环境准备与模型量化下面实操部分以 Android 平台为例思路同样适用于 Linux 主机和开发板。4.1 设备与运行环境建议准备一台内存尽量大、支持 Vulkan 或较新 GPU 驱动的 Android 设备。比较稳妥的起步配置是 8GB 内存以上。如果设备只有 4GB 内存也不是不能跑但建议只选 1B 级别的量化模型并把上下文长度控制在 2048 以下。需要安装的工具包括Termux提供 Linux 终端环境Git用于拉取推理引擎代码CMake、Python、Ninja用于编译和脚本开发llama.cpp作为本地推理引擎。版本细节建议以当前官方仓库的 README 为准。下面代码演示的是通用流程。4.2 在 Termux 中准备 llama.cpp在 Termux 里执行pkg update -y pkg install -y git cmake python ninja build-essential git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build -DCMAKE_BUILD_TYPERelease -DGGML_VULKANON cmake --build build --config Release -j4如果你在手机上编译时发现内存不足可以去掉-j4或改成-j2。如果设备不支持 Vulkan就不要加-DGGML_VULKANON直接使用 CPU 版本即可只是推理速度会慢很多。编译完成后关键产物有两个build/bin/llama-server本地 OpenAI 兼容推理服务build/bin/llama-quantize模型量化工具。4.3 模型下载与量化如果 LFM 2.5 官方仓库已经提供 GGUF 格式可以直接下载。如果只提供 HuggingFace 原始格式则需要确认 llama.cpp 是否支持对应模型架构。这里有一个容易踩的坑不是所有模型都能直接转换成 GGUF。如果当前推理引擎还没有适配该模型架构转换后会加载失败。假设模型架构已被支持原始权重在./models/lfm2.5-hf目录下转换命令如下python3 convert_hf_to_gguf.py \ ./models/lfm2.5-hf \ --outfile ./models/lfm2.5-f16.gguf \ --outtype f16 ./build/bin/llama-quantize \ ./models/lfm2.5-f16.gguf \ ./models/lfm2.5-q4_k_m.gguf \ Q4_K_M端侧首次验证不建议直接追求最高精度。优先选择 Q4_K_M 或 Q5_K_M 这类平衡量化和质量的档位。如果只在 CPU 上运行可以先从 1B 到 3B 的模型开始设备内存充足再尝试更大参数模型。不要一上来就挑战最大模型否则遇到的第一个问题大概率是“进程被系统杀死”。5. 核心流程拆解从一个最小 Agent 代码开始模型推理服务启动后我们就可以写一个最小 Agent 循环。5.1 启动本地推理服务终端里执行./build/bin/llama-server \ -m ./models/lfm2.5-q4_k_m.gguf \ -c 4096 \ --host 127.0.0.1 \ --port 8080 \ -t 4 \ -ngl 99参数解释-m指定模型权重文件-c设置上下文长度端侧建议从 2048 或 4096 开始-t设置线程数太大会引起 CPU 争抢-ngl指定 GPU 层数越接近 99 表示尽量全部放到 GPU。如果你的设备只支持 CPU改成-ngl 0。服务启动后可以先测试一次普通对话curl http://127.0.0.1:8080/v1/chat/completions \ -H Content-Type: application/json \ -d { model: lfm2.5, messages: [ {role: user, content: 用一句话介绍你自己} ], max_tokens: 64 }如果能正常返回choices说明推理服务可用。5.2 Agent 工具注册与提示词设计下面用 Python 写一个不依赖外部框架的 Agent 循环。它不是生产级代码但足够展示端侧 Agent 的完整思路模型输出 JSON代码解析 JSON执行对应函数再把结果回填给模型。文件路径agent_loop.pyimport datetime import json import re import urllib.request API_URL http://127.0.0.1:8080/v1/chat/completions MODEL lfm2.5 TOOL_LIST [ { name: get_current_time, description: 获取当前系统时间, args_schema: {} }, { name: create_todo, description: 创建一条待办事项, args_schema: { content: string } } ] SYSTEM_PROMPT f 你是运行在手机本地的 AI Agent。 当你需要工具时只输出一个 JSON不要输出多余解释。 JSON 格式如下 {{name: 工具名, arguments: {{...}}}} 当前可用工具 {json.dumps(TOOL_LIST, ensure_asciiFalse)} def call_llm(messages): payload json.dumps({ model: MODEL, messages: messages, temperature: 0.2, max_tokens: 256 }).encode(utf-8) req urllib.request.Request( API_URL, datapayload, headers{Content-Type: application/json} ) with urllib.request.urlopen(req, timeout180) as resp: data json.loads(resp.read().decode(utf-8)) return data[choices][0][message][content] def get_current_time(): return datetime.datetime.now().isoformat() def create_todo(content: str): # 这里只是演示真正落地时应写入本地数据库或系统日历 return f已创建待办{content} TOOL_MAP { get_current_time: get_current_time, create_todo: create_todo } def extract_json(text): match re.search(r\{.*\}, text, re.S) if not match: return None try: return json.loads(match.group(0)) except json.JSONDecodeError: return None def run_agent(user_message): messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_message} ] for _ in range(5): reply call_llm(messages) print([模型原始输出], reply) parsed extract_json(reply) if parsed is None or name not in parsed: print([最终回复], reply) return reply name parsed.get(name) args parsed.get(arguments, {}) if name not in TOOL_MAP: messages.append({role: assistant, content: reply}) messages.append({ role: user, content: f工具 {name} 不存在请选择以下工具之一{list(TOOL_MAP.keys())} }) continue print(f[执行工具] {name} {args}) result TOOL_MAP[name](**args) messages.append({role: assistant, content: reply}) messages.append({ role: user, content: f工具执行结果{result}\n请根据结果用自然语言回复用户。 }) final_reply call_llm(messages) print([最终回复], final_reply) return final_reply return Agent 执行步骤超过上限请稍后重试 if __name__ __main__: user_input 帮我创建一条待办下午 4 点开会 run_agent(user_input)这段代码的核心逻辑是给模型一个系统提示词让它知道只能输出 JSON模型第一次输出可能直接是{name: create_todo, arguments: {content: 下午 4 点开会}}Python 解析 JSON检查工具名是否存在执行create_todo拿到执行结果把执行结果回填给模型模型基于结果生成自然语言回复。这种实现的最大优点是不依赖模型推理服务是否内置 Function Calling 能力因此适配性更强。缺点是本地模型可能输出不合法 JSON需要在真实项目中增加更多修复策略比如让模型重新输出、只解析 JSON 字段、或者接一个约束解码器。5.3 运行 Agentpython3 agent_loop.py预期运行路径类似[模型原始输出] {name: create_todo, arguments: {content: 下午 4 点开会}} [执行工具] create_todo {content: 下午 4 点开会} [模型原始输出] 好的我已经帮你创建了一条待办下午 4 点开会。如果模型不按常规输出会看到“模型原始输出”是一段解释文字而不是 JSON。这说明提示词还需要调整或者当前量化档位对模型理解能力影响较大。可先调低 temperature再把工具说明改成更简短、更具体的格式。6. 运行效果与性能验证方法手记跑端侧 Agent关键不是看一次推理是否成功而要看连续多轮、不同请求下的稳定性。下面提供一套低成本的验证方法。6.1 测速脚本随手写一个不引入第三方库的测速脚本用来测量耗时和吞吐。文件路径perf_test.pyimport json import time import urllib.request API_URL http://127.0.0.1:8080/v1/chat/completions MODEL lfm2.5 def chat_once(prompt, max_tokens128): payload json.dumps({ model: MODEL, messages: [{role: user, content: prompt}], max_tokens: max_tokens, temperature: 0.1 }).encode(utf-8) req urllib.request.Request( API_URL, datapayload, headers{Content-Type: application/json} ) start time.time() with urllib.request.urlopen(req, timeout120) as resp: data json.loads(resp.read().decode(utf-8)) cost time.time() - start usage data.get(usage, {}) prompt_tokens usage.get(prompt_tokens, 0) completion_tokens usage.get(completion_tokens, 0) print(fprompt_tokens: {prompt_tokens}) print(fcompletion_tokens: {completion_tokens}) print(f总耗时: {cost:.3f}s) if cost 0 and completion_tokens 0: print(f生成速度: {completion_tokens / cost:.2f} tokens/s) if __name__ __main__: test_prompt 请列举手机本地 AI Agent 的五个使用场景每个场景不超过 20 字。 chat_once(test_prompt, max_tokens256)运行python3 perf_test.py建议把同一请求重复 5 次以上并记录最快生成速度最慢生成速度是否存在超时系统内存占用是否持续上涨长时间运行后模型是否胡言乱语。6.2 如何判断成功与失败判断一次端侧 Agent 验证是否成功不要只看模型是否生成了文本而要看以下几点工具调用是否准确命中。工具参数是否从用户输入中正确抽取。工具结果回填后模型是否还能保持对话逻辑。连续运行 30 分钟后系统内存是否被释放回正常水平。模型服务在手机亮屏、锁屏、来电等事件下是否仍稳定。如果失败第一步永远是看 llama-server 的控制台日志。日志里会明确显示是内存不足、上下文长度不够还是 API 请求格式错误。7. 常见问题与排查手段问题现象可能原因排查方式解决方案服务启动后进程被杀模型太大或量化太浅设备内存不足查看dmesg或 Termux 日志用dumpsys meminfo观察内存换 Q4_K_M 或更小模型降低-c上下文长度关闭后台 App生成速度很慢CPU 线程数不足模型全部跑 CPU观察top中 CPU 占用开启 Vulkan 编译增加线程数降低模型精度输出乱码或重复量化精度过低温度设置过高连续测试同一 prompt使用 Q5_K_M 或 F16把 temperature 降到 0.1~0.3工具 JSON 输出不合法提示词太长或工具描述太复杂查看模型原始输出缩短工具描述固定 JSON 示例增加解析失败后的修复反馈多轮后遗忘之前的工具结果上下文被裁剪KV Cache 管理错误检查 llama-server 的上下文使用率增大-c优化对话历史保留关键工具结果Agent 调用不存在的工具模型幻觉工具名拼写错误打印完整模型输出限定候选工具列表降低 temperature解析层做白名单校验长时间运行后电池快速下降GPU/CPU 持续高频运行观察电量曲线和温控日志限制线程数闲置时自动卸载模型增加低功耗模式这里特别提醒一个问题在手机上用-ngl 99全量 GPU 推理并不一定比 CPU 快。端侧 GPU 驱动的完整程度、内存带宽、温控策略都会影响结果。真正可靠的判断标准是在自己设备上跑同一段脚本对比。8. 最佳实践与安全建议端侧模型看起来是“本地运行、相对安全”但一旦涉及工具调用就必须把安全边界想清楚。8.1 模型与上下文管理首次验证先使用小参数量、较低精度模型不要用最大模型挑战设备极限。上下文不是越长越好。长上下文意味着更多内存和更慢的首 token 延迟。把系统提示词、工具说明和关键历史放进去把无关历史裁掉。每次发布 Agent 时记录模型文件、量化档位、llama.cpp 提交号和提示词版本方便回滚。这一条在团队协作尤其重要。如果项目代码需要共享给团队建议把测试脚本、环境说明和模型下载清单放进 Git 仓库。配合 Cloud Codes 这类云端开发环境可以让团队成员打开浏览器即可复现同一套 Agent 工程减少“在我手机上是好的”这类问题。8.2 工具执行的安全边界工具执行器必须做白名单注册不要让模型任意执行系统命令。对创建、删除、覆盖类操作最好在真正执行前让用户确认。请求读取通讯录、定位、短信等高敏感权限时应该走系统权限申请流程而不是用 adb 命令绕过权限保护。不要信任模型输出的文件路径或 URL。所有参数都要做类型和范围校验再交给工具层执行。由于端侧代码本身就是可反编译的不要把 API Key、设备密钥硬编码到客户端需要网络请求时仍应走服务端中转和最小授权。8.3 实测与评测建议只用一组“你好”类 prompt 判断模型能力很容易得到错误结论。建议构造至少 5 到 10 条任务型测试用例覆盖日历查询、待办创建、参数抽取、长文本摘要等实际场景。评测时需要把预填充阶段和生成阶段分开看。prompt_tokens / elapsed只能反映平均速度无法体现真实体验。记录测试设备型号、系统版本、推理框架版本、量化档位、上下文长度否则测试结果无法横向比较。不要直接搬运网上他人的跑分端侧硬件的差异太大同一款芯片在不同散热策略下的表现也可能明显不同。9. 总结与后续学习方向LFM 2.5 的价值在于提醒我们端侧 AI 不只是在手机上塞一个小号 Transformer而是需要从模型架构层面考虑内存与推理效率。状态空间模型、线性注意力、混合架构这些概念也会是未来端侧模型的重要方向。如果你准备开始实践建议按这样推进先用官方 GGUF 或自行转换出的量化模型跑通 llama-server写一个最小 Agent 循环只接一个本地无副作用工具比如获取当前时间在真实任务里测试工具调用格式的稳定性而不是测试闲聊能力加入“创建待办”这类有写入行为的工具并增加用户确认最后再考虑上下文管理、多工具组合、语音入口以及更复杂的系统权限接入。建议把这篇文章收藏备用然后动手跑一次。过程中如果遇到 llama.cpp 版本差异、模型转换失败或工具输出不稳定优先查看官方仓库和模型卡再根据日志缩小问题范围。端侧 AI Agent 的门槛没有想象中高但每一步工程细节都会影响最终体验。