
1. 端侧 Agent 工程化的核心命题1.1 为什么端侧 Agent 的工程化比云端更棘手把 Agent 从云端搬到端侧很多人第一反应是模型压缩一下、量化一下不就行了。真做过端侧落地的人都知道模型压缩只是入场券真正让人掉头发的是工程化这一层。端侧 Agent 和云端 Agent 最大的区别在于云端你可以假设网络永远在线、算力可以弹性扩容、内存不够就加机器端侧这些假设全部不成立。设备可能是四年前的中端安卓机内存 6GB 还要被系统和其他 App 抢NPU 的算子支持残缺不全用户随时可能把 App 切到后台。我在实际项目里踩过最典型的一个坑在开发机上跑得好好的一个多步推理 Agent到了真机上第二步工具调用就崩了排查半天发现是系统在内存压力下把模型权重的一部分换出去了重新加载时 mmap 的地址变了而我们的推理引擎缓存了旧指针。这种问题在云端永远不会遇到但在端侧是家常便饭。所以端侧 Agent 工程化的核心命题不是如何让模型跑起来而是如何在资源受限、环境不可控、生命周期不确定的前提下让一个多步骤、有状态、会调用外部能力的智能体稳定地完成用户任务。这一篇是深入理解端侧 Agent系列的第四篇下半部分上一篇我们聊了模型侧的准备量化、算子适配、内存布局这一篇聚焦工程化落地编排框架怎么选、状态怎么管、容错怎么做、并发怎么扛、安全边界怎么划。适合已经能把一个 LLM 跑在端侧、但还没把它做成一个可靠产品的开发者。如果你还在纠结端侧到底能不能跑 LLM建议先看前三篇。1.2 端侧 Agent 工程化的四个核心矛盾在展开具体方案之前我先把端侧 Agent 工程化要面对的矛盾摆清楚后面所有的技术选型其实都是在这些矛盾之间做权衡。第一个矛盾是能力与预算的矛盾。Agent 要能规划、要能调用工具、要能记住上下文这些都需要 token而端侧的 token 生成速度可能只有云端的十分之一。一个在云端跑 3 秒的任务端侧可能要 30 秒用户早就把 App 关了。第二个矛盾是状态与生命周期的矛盾。Agent 是有状态的多轮对话、工具调用中间结果、任务进度都需要保存。但端侧 App 的生命周期完全由系统掌控随时可能被杀死状态必须能持久化、能恢复。第三个矛盾是自主性与安全性的矛盾。Agent 越自主能做的事情越多但端侧 Agent 直接操作用户设备上的数据、文件、甚至其他 App一旦被恶意输入诱导比如 agentpoison 这类通过污染记忆或知识库来攻击 Agent 的手法后果比云端严重得多。第四个矛盾是通用性与端侧特化的矛盾。现在主流的 Agent 编排框架大多是为云端设计的假设你有无限的 token 预算和稳定的网络。直接搬到端侧会水土不服但完全自己造轮子又成本太高。怎么在现有框架上做端侧特化是这一篇要重点讲的。2. 编排框架选型端侧到底该用什么2.1 云端主流框架为什么不能直接搬先说说大家最熟悉的几个LangChain、LlamaIndex、AutoGen、CrewAI。这些框架在云端很好用但搬到端侧会遇到几个硬伤。LangChain 的抽象层次太多一个简单的工具调用要经过 Chain、Agent、Executor、Tool 好几层封装每层都有 Python 对象的创建和销毁开销。在云端这不算什么但在端侧尤其是用 Rust 或 C 写的推理引擎旁边挂一个 Python 运行时光是解释器启动就要几百毫秒内存占用动辄上百 MB。我实测过一个基于 LangChain 的端侧 demo空载内存 280MB其中 LangChain 及其依赖占了将近 200MB模型本身才 80MB本末倒置。LlamaIndex 相对轻一些但它的核心优势在 RAG 索引端侧场景下索引构建和查询的开销也不小。AutoGen 和 CrewAI 是多 Agent 协作框架端侧根本跑不起多个 Agent 实例直接排除。那端侧到底该用什么我的经验是分两种情况如果你的端侧运行时是 Python比如某些安卓上的 Termux 环境或者桌面端可以用轻量化的编排库比如LangGraph的极简用法或者干脆自己写一个状态机如果端侧运行时是原生代码Kotlin/Swift/Rust/C那编排逻辑最好也用原生代码实现只把 LLM 推理和必要的 NLP 处理交给模型运行时。2.2 端侧编排的三种可行架构我把实际项目中验证过的端侧 Agent 编排架构归纳为三种各有适用场景。第一种状态机驱动架构。这是最轻量、最可控的方案。把 Agent 的行为定义成一个有限状态机每个状态对应一个动作生成、工具调用、等待用户输入、结束状态转移由模型输出或规则决定。这种架构的好处是状态完全可控每一步都能持久化崩溃后能从任意状态恢复。缺点是灵活性差复杂的规划能力实现起来比较别扭。适合任务边界清晰、步骤相对固定的场景比如帮我整理今天的日程这种。第二种ReAct 循环的端侧精简版。ReActReasoning Acting是 Agent 的经典范式端侧实现时要砍掉所有不必要的部分。核心就是一个循环把当前上下文喂给模型模型输出要么是最终答案要么是一个工具调用请求执行工具后把结果追加到上下文继续循环。关键优化点在于上下文要严格裁剪工具描述要极简循环要有硬性步数上限。我一般把端侧的 ReAct 循环上限设在 5 到 8 步超过就强制收敛给用户一个中间结果。第三种混合架构。简单任务走状态机复杂任务走 ReAct用一个轻量的路由器可以是一个小分类模型也可以是规则来决定走哪条路。这是我在生产环境里用得最多的方案因为端侧用户的任务分布是长尾的80% 的请求其实很简单没必要动用完整的 ReAct 循环。下面这张表是我对三种架构的对比参数是我在几个真实项目里测出来的经验值仅供参考架构类型空载内存单步延迟实现复杂度适用场景状态机驱动低20MB低仅模型推理低任务固定、步骤明确ReAct 精简版中30-50MB中多轮推理叠加中需要动态规划的任务混合架构中40-60MB视任务而定高任务分布长尾的生产环境2.3 编排框架的端侧特化要点不管你选哪种架构端侧编排都有几个必须做的特化。第一工具描述要压缩到极致。云端 Agent 的工具描述可以写得很详细因为 token 便宜。端侧不行每个工具的 schema 都要精简。我的做法是工具名用最短的英文单词参数描述只保留类型和一句话说明能省的字段全砍掉。一个云端要 200 token 的工具描述端侧压到 50 token 以内是完全可以做到的。第二上下文窗口要动态管理。端侧模型的上下文窗口通常比云端小常见 2K 到 8K而且每多一个 token 就多一份推理开销。我的策略是分层管理系统提示词固定且极简对话历史只保留最近 N 轮工具调用结果只保留关键字段超出预算的部分做摘要压缩。摘要压缩本身也要用模型所以要在压缩省下的 token和压缩消耗的 token之间算账一般历史超过 4 轮才值得压缩。第三所有阻塞操作都要有超时和取消。端侧环境不可控工具调用可能卡住比如读一个被其他 App 占用的文件模型推理可能因为系统调度变慢。每个步骤都要设超时超时后要么降级要么给用户明确反馈绝不能无限等待。提示端侧编排的一个反直觉经验是不要追求把云端框架的所有功能都搬过来。端侧 Agent 的价值在于离线可用、隐私安全、响应即时而不是功能对齐云端。砍功能比加功能更重要。3. 状态管理与持久化让 Agent 扛住进程被杀3.1 端侧 Agent 的状态到底有哪些很多人以为 Agent 的状态就是对话历史其实远不止。一个端侧 Agent 的完整状态至少包括这几类对话状态用户和 Agent 的交互历史包括用户输入、模型回复、工具调用记录。任务状态当前任务的进度比如已完成步骤 2/5正在执行步骤 3。工具状态工具调用的中间结果比如一个正在下载的文件、一个已经打开的数据库连接。记忆状态长期记忆比如用户偏好、历史任务摘要这部分通常存在向量库或 KV 库里。运行时状态模型加载状态、推理引擎的上下文、缓存等。这五类状态的生命周期和持久化需求完全不同。对话状态和任务状态必须持久化因为进程随时可能被杀工具状态大部分是临时的但关键结果要落盘记忆状态是长期资产要单独管理运行时状态通常不持久化重启后重建。3.2 状态持久化的分层设计我在项目里用的是一套分层持久化方案从快到慢分三层。第一层内存状态。当前活跃的对话上下文、正在执行的工具调用参数放在内存里读写最快。这一层不持久化进程死了就没了但因为它只保存当前这一步需要的数据丢失的代价可控。第二层轻量持久化。对话历史、任务进度这类需要跨进程存活的状态写到本地数据库。端侧我推荐用SQLite或者平台原生的 KV 存储安卓的 DataStore、iOS 的 UserDefaults 配合文件。SQLite 的好处是事务支持好、查询灵活适合结构化的对话记录KV 存储更轻适合简单的键值状态。写入频率要控制不能每生成一个 token 就写一次我的做法是每个步骤结束时写一次也就是一次模型推理加工具调用算一个步骤。第三层长期记忆。用户偏好、历史任务摘要这类数据用向量库存储。端侧的向量库选择不多常见的是sqlite-vec、ObjectBox的向量支持或者自己用 FAISS 的轻量版。这一层的写入频率最低通常一个任务结束后才更新一次。这里有个关键的设计决策状态写入必须是幂等的。因为端侧进程可能在任何时刻被杀恢复时可能重复执行某个步骤。如果状态写入不是幂等的就会出现重复记录、重复扣费之类的问题。我的做法是给每个步骤分配一个唯一 ID写入前先检查这个 ID 是否已经存在。3.3 崩溃恢复的实操流程崩溃恢复是端侧 Agent 工程化里最容易被忽视、但用户感知最强的一环。用户正在和 Agent 对话切出去接了个电话回来 App 被系统杀了重新打开如果对话没了体验直接崩盘。我的恢复流程是这样的启动时检查未完成任务。App 启动后先查本地数据库里有没有状态为进行中的任务。重建运行时状态。如果有未完成任务重新加载模型这一步最慢要提前做从数据库读取对话历史和任务进度。判断恢复点。根据最后写入的步骤 ID判断任务执行到哪一步。如果最后一步是模型已生成工具调用请求但未执行就重新执行工具如果最后一步是工具已执行但模型未生成回复就重新调用模型。给用户明确反馈。恢复后不要假装什么都没发生要给用户一个提示比如刚才的任务已恢复继续为你处理。这既是体验也是让用户知道状态是可靠的。注意恢复流程里最容易出问题的是工具调用的副作用。如果工具是发送消息这种有副作用的操作重复执行会造成困扰。所以有副作用的工具必须做幂等设计或者记录已执行标记恢复时跳过。3.4 状态压缩与清理策略端侧存储空间有限状态不能无限增长。我一般设几个阈值对话历史超过 50 轮就归档旧记录只保留摘要任务记录超过 30 天就清理长期记忆超过一定条数就做合并或淘汰。清理策略要谨慎因为用户可能突然想翻旧账。我的做法是清理前先做摘要把旧对话压缩成几句话存进长期记忆原始记录可以删但摘要保留。这样既省空间又不丢信息。4. 容错与可靠性Agent 出错了怎么办4.1 端侧 Agent 的故障分类端侧 Agent 的故障比云端复杂因为故障来源更多。我把它们分成四类模型故障推理超时、输出格式错误、输出内容不合规、模型加载失败。工具故障工具调用超时、工具返回错误、工具依赖的资源不可用。环境故障内存不足、存储空间不足、权限被拒绝、系统杀进程。逻辑故障Agent 陷入循环、规划错误、上下文溢出。这四类故障的处理策略完全不同。模型故障要靠重试和降级工具故障要靠超时和备选方案环境故障要靠资源监控和优雅退出逻辑故障要靠步数限制和循环检测。4.2 模型输出的容错处理端侧小模型的输出稳定性远不如云端大模型格式错误是家常便饭。你让它输出 JSON它可能给你输出一段带解释的文字你让它调用工具它可能把工具名拼错。所以端侧 Agent 必须有强大的输出解析容错。我的做法是三层解析第一层用严格的 JSON 解析能过就过第二层用正则提取关键字段容忍格式瑕疵第三层用规则兜底比如从文本里找工具名和参数。三层都失败就把模型的原始输出当作最终回复给用户同时记录一条日志用于后续优化。这里有个经验端侧模型的输出格式约束靠提示词不如靠约束解码。现在很多端侧推理引擎支持 GBNF 语法或者 JSON schema 约束能在解码阶段就限制输出格式比事后解析可靠得多。如果你的推理引擎支持强烈建议用上。4.3 工具调用的超时与降级工具调用是端侧 Agent 最容易卡住的地方。我的原则是每个工具调用都必须有超时超时后必须有降级方案。超时时间怎么定我的经验值是本地文件操作 500ms本地数据库查询 1s网络请求 5s如果端侧 Agent 允许联网模型推理按 token 数算每个 token 给 100ms 到 500ms 的预算。这些值要根据实际设备调整低端机要放宽。降级方案分几种如果工具是查询天气超时后可以返回缓存数据如果工具是读取文件超时后可以告诉用户文件读取失败请重试如果工具是调用另一个模型超时后可以降级到更小的模型或者直接返回中间结果。4.4 循环检测与强制收敛Agent 陷入循环是端侧特别常见的问题因为小模型的规划能力弱容易在几个状态之间来回跳。我见过最夸张的一次Agent 在调用工具 A和调用工具 B之间来回跳了 20 多次把电量耗了一大截。防循环的手段有几个步数硬上限是最基本的超过就强制结束状态指纹是更精细的做法记录每一步的状态哈希如果发现重复状态就中断工具调用频率限制同一个工具在短时间内调用超过 N 次就拒绝。强制收敛时给用户的反馈很重要。不要只说任务失败要说这个任务比较复杂我先给你一个初步结果然后把当前已有的信息整理给用户。这样用户至少拿到了部分价值而不是一无所获。4.5 常见故障速查表下面这张表是我从实际项目里总结的故障速查表遇到问题可以先对照排查故障现象可能原因排查方向处理方案模型推理卡住不动内存不足触发换页查系统内存日志降低模型精度或上下文长度输出 JSON 解析失败模型格式约束不足检查提示词和约束解码加 GBNF 约束或增强解析容错工具调用超时资源被占用或权限问题查工具依赖的资源状态加超时和降级方案Agent 反复循环规划能力不足或状态丢失查状态指纹和步数记录加步数上限和循环检测恢复后状态错乱状态写入非幂等查步骤 ID 和写入日志改为幂等写入进程被系统杀死内存占用过高查内存峰值优化内存布局及时释放5. 并发与性能端侧 Agent 怎么扛住压力5.1 端侧并发的特殊性云端 Agent 扛并发靠的是水平扩容端侧没有这个选项。端侧 Agent 的并发压力主要来自两个场景一是用户快速连续输入二是后台任务和前台任务同时跑。端侧并发的核心约束是模型推理是串行的。一个模型实例同一时刻只能处理一个请求多个请求要么排队要么用多个模型实例内存吃不消。所以端侧 Agent 的并发设计本质上是请求调度和优先级管理。5.2 请求队列与优先级设计我的做法是给所有请求建一个优先级队列分三档用户交互请求最高优先级必须立即响应后台任务中等优先级可以在用户不操作时跑预加载和预热最低优先级随时可以中断。队列的实现要轻量端侧不适合用复杂的调度器。一个简单的优先队列加一个工作线程就够了。关键是抢占机制当高优先级请求到来时低优先级的推理要能中断。这要求推理引擎支持取消操作现在主流的端侧推理引擎基本都支持。5.3 流式输出与首 token 延迟优化端侧 Agent 的用户体验很大程度上取决于首 token 延迟。用户输入后如果 3 秒内没看到任何反馈就会觉得卡。所以流式输出是必须的而且要想办法把首 token 延迟压到最低。压首 token 延迟的手段有几个提示词前置把系统提示词和工具描述放在最前面让模型尽快进入生成状态KV 缓存复用多轮对话时复用上一轮的 KV 缓存避免重复计算预填充优化如果推理引擎支持把固定的提示词部分预先填充好。我实测过同样的模型和硬件做好 KV 缓存复用后多轮对话的首 token 延迟能从 800ms 降到 200ms 左右体验提升非常明显。5.4 内存与电量的平衡端侧 Agent 还有一个云端没有的约束电量。模型推理是耗电大户长时间跑会让设备发烫、掉电快。所以端侧 Agent 必须做功耗管理。我的策略是按需加载及时释放。模型不是常驻内存的用户不活跃一段时间后就卸载下次用再加载。加载虽然慢但省电。同时推理时的线程数要控制不要把所有核心都占满留一些给系统和其他 App。提示端侧 Agent 的性能优化不要只看单次推理速度要看整体任务完成时间和功耗。一个单次推理快但需要多轮循环的方案可能比一个单次推理慢但一步到位的方案更耗电。6. 安全边界端侧 Agent 的自主性该划在哪6.1 端侧 Agent 的安全风险面端侧 Agent 直接操作用户设备安全风险比云端大得多。主要风险面包括数据泄露Agent 读取了不该读的文件、越权操作Agent 调用了不该调的工具、提示注入恶意输入诱导 Agent 执行危险操作、记忆污染agentpoison 这类攻击通过污染 Agent 的记忆或知识库来改变其行为。这些风险在云端也存在但云端有完善的隔离和审计端侧往往没有。所以端侧 Agent 的安全设计必须更保守。6.2 权限分级与工具白名单我的做法是给工具做权限分级分三档只读工具查询类风险低、受限写工具写入用户明确指定的位置风险中、敏感工具涉及隐私数据或系统操作风险高。只读工具可以直接调用受限写工具需要用户确认敏感工具必须每次显式授权。工具白名单是硬性的不在白名单里的工具一律拒绝即使模型请求了也不行。6.3 提示注入的防御提示注入是端侧 Agent 最难防的攻击因为攻击面包括用户输入、工具返回结果、甚至读取的文件内容。防御手段有几个层次输入净化是最基本的过滤明显的注入模式比如忽略之前的指令这类。但这种方法容易被绕过只能挡低级攻击。指令与数据分离是更可靠的做法在提示词里明确区分系统指令和用户数据让模型知道哪些是可信的、哪些是不可信的。这需要模型有一定的指令遵循能力端侧小模型可能做不好。输出审查是最后一道防线Agent 执行敏感操作前用一个独立的检查逻辑可以是规则也可以是一个小分类模型判断这个操作是否合理。比如 Agent 突然要删除大量文件就应该拦截并询问用户。6.4 记忆污染的防护记忆污染是最近比较受关注的攻击方式攻击者通过向 Agent 的记忆库注入恶意内容改变 Agent 的长期行为。端侧 Agent 的记忆库通常是本地的攻击者可能通过工具返回结果或者用户输入来注入。防护的核心是记忆写入的审查。不是所有内容都能进长期记忆只有经过验证的信息才能写入。我的做法是记忆写入前先做一次分类判断这条信息是事实还是指令只有事实类信息才允许写入长期记忆指令类信息只在当前会话有效。7. 端侧 Agent 工程化的实操心得7.1 从最小可用版本开始我见过太多团队一上来就想做一个功能完整的端侧 Agent结果卡在工程化细节里出不来。我的建议是从最小可用版本开始一个状态机、两个工具、一个模型先把用户输入到 Agent 回复这条链路跑通再逐步加功能。最小版本的关键是端到端跑通哪怕功能很弱。跑通之后你才知道真正的瓶颈在哪是模型太慢、还是状态管理太复杂、还是工具调用不稳定。这些信息比任何架构设计都值钱。7.2 日志与可观测性端侧 Agent 的调试比云端难因为设备在你手里用户的问题你复现不了。所以日志和可观测性必须从第一天就做好。我的做法是每个步骤都打日志包括输入、输出、耗时、内存占用日志分级关键路径用 INFO调试细节用 DEBUG日志本地存储用户反馈问题时可以导出。同时关键指标首 token 延迟、任务完成率、故障率要做本地统计方便优化时对比。7.3 灰度与回滚端侧 Agent 的更新不像云端那么灵活用户不更新 App 你就没法改。所以灰度发布很重要。我的做法是新版本先在小比例用户上跑观察故障率和性能指标没问题再全量。同时保留回滚能力一旦发现严重问题能快速切回旧版本。7.4 用户反馈的收集与利用端侧 Agent 的优化用户反馈是最宝贵的输入。但端侧收集反馈有隐私顾虑不能什么都往上传。我的做法是本地收集用户授权后上传。收集的内容包括任务类型、完成情况、用户是否满意不包含具体的对话内容。这样既能优化又不侵犯隐私。最后分享一个我在实际项目里体会最深的一点端侧 Agent 的工程化80% 的功夫在模型之外。模型选型、量化、算子适配这些固然重要但真正决定产品成败的是状态管理、容错、并发、安全这些脏活累活。把这些做好了一个中等能力的模型也能做出可靠的 Agent做不好再强的模型也是空中楼阁。这个系列写到这里端侧 Agent 从模型到工程化的主干就基本覆盖了后续如果大家感兴趣可以再聊聊具体的工具生态和端侧 RAG 的实现细节。