项目背景与开发目标
大家好,我是小木头。最近我们分享了不少关于 Pi Durable 的内容,那么在移动设备上是否能基于 Pi Durable 开发一个智能体呢?今天我就来聊聊最近我的试验。我用 Pi Durable 开源了一个移动应用叫 Moose。我最初想体验的就包括了对话、重复任务、检查点,通过 URL 安装 Skill,以及基本的文件读写工具。这些基本功能在移动设备上的支持情况究竟怎么样呢?也是我感兴趣的。
“Moose 我已经在 iOS 的模拟器中完成了基本的集成和任务执行的测试。”
我做这个项目主要有两个目的:一个是体验用 Pi Durable 搭建 Agent,它整个的开发过程,看看会话、任务、工具这些接口实际放进应用是怎样组合的;另一个呢,是尝试移动设备在 Agent 上的能力边界。Moose 的做法是把 Pi Durable 的核心放在移动应用里运行,对话任务的状态都通过本地数据库保存,文件工具则通过设备接口访问工作区。那接下来我就围绕这几个能力点分享框架提供了什么,以及应用还需要负责什么。
核心与平台的分工架构
先看核心与平台的分工。Moose 直接在手机上运行 Pi Durable 的核心逻辑。我为手机应用设置专门的打包入口,把数据库和文件操作接到了 Expo,并在构建时检查避免引入依赖 nodejs 的实现。这里首先解释几个名词:Hermes 是 react native 使用的 Javascript 引擎,负责在手机上执行 Javascript 代码。Pi Durable 的核心逻辑也就在这里运行。
但 Javascript 引擎并不提供 nodejs 的文件系统和子进程接口,所以这些能力需要另外接入。在 Moose 里,React Native 负责界面。Pi Durable 负责会话、模型调用,工具调用和任务的状态管理。Expo SQLite 提供了数据库。网络接口负责发送模型请求并接收流式的响应。
“手机本地运行的是 Agent,它的核心和状态的管理,模型请求仍然发给所选的服务商。”
文件系统和密钥存储呢,也分别通过对应的平台模块来接入。所以手机本地运行的是 Agent 它的核心和状态的管理,模型请求仍然发给所选的服务商。这个区别呢,也帮助我判断每一项能力应该放在哪一层。
任务管理与状态持久化机制
任务和对话是我体验 Pi Durable 开发方式的主要入口。保存一段聊天记录,主要看聊天历史能否重新打开;保存一个重复的任务,还要知道执行了几次、现在是在运行还是等待、本轮请求有没有提交。Moose 把重复任务分成了 运行和等待两个阶段,每一轮都使用一个稳定的请求 ID。如果提交需要重试,就继续使用这个 ID 避免重复入队。
“假设任务间隔1分钟,应用中断了10分钟,重新打开时当前实现只补做一次,再计算下一轮的时间。”
提交成功后保存进度,再等待下一次。假设任务间隔1分钟,应用中断了10分钟,重新打开时当前实现只补做一次,再计算下一轮的时间。它并不会一次提交所有错过的轮次。
任务的中断或停止也要区分对象。停止重复任务,是停止后续的调度。已经提交的回答需要在对话里面另外的停止。任务主要在前台执行,重开时从保存的状态继续。
“我关心的开发体验就是这些:运行状态怎样交给框架管理,又怎样通过应用的界面来表达清楚。”
Skill 指令加载与能力边界限制
Moose 目前只做了基础的 Skill 指令加载,提供一个 https 的 URL。应用下载单个的 SKILL.md 文件,保存在本地,再选择是否对当前的会话启用。但安装了指令文件,并不代表这个 Skill 的全部能力都能运行。
当前的版本中,还没有 Bash 或 Shell 的支持,也不能执行 Python、Node 等脚本,也不能安装它们需要的依赖。Skill 配套的脚本参考文档和其他资源也不会一起下载。
“所以如果关键步骤依赖这些能力呢,当前就无法完整的执行。其中独立的文字指令依然是有用的。”
所以如果关键步骤依赖这些能力呢,当前就无法完整的执行。其中独立的文字指令依然是有用的。
模型连接与密钥安全管理
连接模型也是应用负责的一部分。Moose 支持 API Key,我也探索了实验性的接入 chatgpt 的订阅。
它也支持设备码的方式。设备码方式呢,由用户在浏览器完成授权,应用轮询结果。浏览器回调方式则通过手机本机的临时监听接收回调。密钥交给 SecureStore 来完成保存。
“整体上 UI 界面保持了简洁,空间主要给消息和输入。”
检查点在菜单里重新发送呢,则是通过长按消息后的选项来实现。
文件系统接入与执行环境适配
文件读写属于我最初的需求,也是构建移动端执行环境的原因。关键的问题是 Pi 已经有了 read、write、edit 这些工具,那么,怎样让它们使用手机上的文件系统呢?
Pi 的做法是通过 ExecutionEnv(执行环境接口)来访问底层的文件。工具负责参数和结果,那么执行环境则负责实际的读取和写入。
“因此 Moose 复用了 Pi 的三个文件工具,在下面接入了 Expo FileSystem。”
模型发起工具调用,Pi 处理工具逻辑,再通过 ExecutionEnv 把文件操作交给 Expo。工具注册里面就是常规地创建 read、write 和 edit。
工作区环境由平台侧来创建,再注入运行时。这样呢工具的逻辑就可以复用。设备文件的访问有明确的接入位置,会话管理也不需要直接依赖某个原生的文件接口。
工作区隔离与数据持久化逻辑
文件操作接通以后,还要确定它属于哪个会话。Moose 为每个对话分配一个独立的工作区。
模型看到的路径统一从 /workspace 开始,比如 /workspace 下面的 notes 目录,再到 todo.md。实际目录位于应用私有存储中,通过会话 ID 来区分。
“模型不需要知道比如 ios 上的完整路径。”
不同对话呢也有各自的目录。例如,可以要求把“准备下期视频”写入 notes 下面的 todo.md,再读取内容。随后把内容改成 “完成下一期视频的选题”,就能用到写入、修改和读取三个工具。
关闭并重开原来的会话,仍然会选择同一个工作区,文件也会保留。那对于我来说呢,这也是观察设备能力的一条非常具体的路径:模型提出需求、提出要执行的任务、工具执行、结果呢回到会话中,内容保存在了设备上。
这次也想分享一个可以复用的 npm 包,叫 pi-durable-Expo-env。它就是为使用 Pi Durable 的 Expo 应用提供基于设备文件系统的执行环境。如果另一个应用也使用 Pi Durable,它同样需要把 ExecutionEnv 接到移动设备的文件接口。那这个包就负责其中的适配,包括了工作区的目录文件的读写以及对应接口的行为。
“Moose 则负责自己的产品规则,比如每个会话对应哪个目录、向模型开放哪些工具。”
包并不需要知道 Moose 的聊天布局,应用也不需要重新实现 Pi 文件工具的参数和结果逻辑。这是我希望把它单独整理出来的原因,其他的 Expo 项目可以复用设备文件访问这一层,再保留自己的应用设计。
接入这个包可以按三个职责理解:第一,包来负责创建基于 Expo FileSystem 的工作区执行环境。第二应用按会话或者项目选择工作区,把环境提供给第三工具注册决定向模型开放哪些动作或哪些功能。Moose 选择按对话来分配工作区,再来注册 read、write、edit 这些工具。
其他产品可以按照自己的会话或项目的规则来分配目录,复用相同的适配层。这个分工让我更容易判断哪些是框架已经提供的功能、哪些是移动设备的适配,哪些又是自己应用的规则。包的使用方法和接口也可以结合说明文档来看。在 Moose 中,也能找到实际接入位置,供你参考如何使用这个包。
检查点机制与状态恢复逻辑
最后来聊一个很容易混淆的问题:检查点保存了什么?Moose 的检查点保存对话历史,恢复时从那段历史创建一个新的会话。原会话保留。
因为文件目录按会话分配,新分支获得的是一个空的工作区。所以可能出现这样的情况:历史消息里面还写着“已经创建 todo.md”,但新会话的工作区里并没有这个文件。
“这是因为消息历史与磁盘内容保存的是两类状态。”
历史记录描述曾经发生了什么事情,新会话的目录则按自己的规则创建。原会话文件呢依然保留。
可以记住三种操作: 1. 重开原会话,历史和文件都存在都保留。 2. 创建新会话呢使用新的历史和空的工作区。 3. 恢复检查点则沿用检查点的历史来创建一个分支,但分支的工作区是空的。
这是目前在 Moose 中关于工作区、关于会话、关于历史的管理规则。在未来的开发中也会根据实际的使用体验和反馈呢,来做调整。
因此应用里说恢复时,要让用户知道恢复是哪种状态。消息、任务进度和工作目录需要分别决定怎样保存和恢复。这是我在体验持久化 Agent 的时候,一个很具体的设计问题。
开发流程验证与能力边界探索
如果你也想体验这套开发方式,可以从一个小流程观察:启动应用、完成一段对话、保存并且重新打开。再调用文件工具,写入、修改和读取一个文件。
重开原会话来检查其中的内容。再增加一个新会话,以及一次检查点的恢复。就能看到会话与目录的关系了。
“重复任务和 Skill 也可以分别观察哪些状态被保存,重新打开后会发生什么。”
界面怎样把规则表达给用户?这些操作就对应着核心、存储和执行环境的几个接口。对于我来说呢,开发体验就体现在它们能否组合起来,以及应用自己的规则能否放在明确的位置。
现在回到这个项目最初的目的:我想体验 Pi Durable 怎样支持 Agent 开发,也想继续尝试移动设备上的能力。文件工具是其中一个非常具体的实践。搜索当然可以连接到网络服务,语音也可以连接到对应的设备接口。需要终端的任务则可以选择合适的执行环境。
“这些呢都是接下来可以继续探索尝试的方向。”
每接入一个功能都能继续观察框架接口怎样复用,以及移动应用需要补充一些什么。
后台执行挑战与未来方案探讨
最后我想把一个自己使用中意识到的用户体验方面的问题分享给大家。提交一个长时执行的任务之后,如果需要一直留在应用里等它完成,那这样的移动 Agent 离日常使用还有多远呢?
当前 Moose 主要在前台执行。因此切换应用或锁屏后,任务可能短暂继续,但也可能因为系统挂起或回收应用而中断。
“Pi Durable 当然了,它保存了状态。这为重新打开后的恢复提供了基础。”
但恢复状态和离开界面后的持续执行需要分别解决。因此移动 Agent 除了能调用哪些工具,还要考虑执行过程由谁来承载。界面关闭后,负责推理和调度的运行时是否仍然存在?如果中断,哪些步骤能继续、哪些结果要重新核查呢?
一种选择是保留本地运行,接入系统提供的长任务能力。比如安卓有它的前台服务,iOS 有 Continued Processing 这些机制。
“它们需要和实际的运行时来连接,处理进度、取消和系统结束任务的情况。”
这些还是 Moose 有待验证的方向。Expo 的 BackgroundTask 解决的是可以延后,由系统选择时间执行的工作。它不能直接理解成给当前 Agent 循环打开一个持续运行的开关。
那么另一种选择呢,是让独立的远程 Host 来承载 Agent。它的运行时手机只负责提交任务和查看状态。
“这样又要重新考虑设备文件、密钥和同步了。”
只把工具放在远程,还要确保后续的调度和推理能够继续运行。我还并不确定这个问题上的最佳方案是什么。
“如果是你,会更希望 Agent 留在手机本地接受系统调度并加强恢复呢?还是把长任务交给独立的 Host?”
你有实践过本地的后台方案吗?欢迎分享你遇到的限制和你的解决方案。如果你在这方面已经有一些经验,欢迎在评论区来分享你的看法吧。
结论
本视频通过开源应用 Moose,详细展示了在移动设备上基于 Pi Durable 开发 Agent 的完整技术路径与架构设计。核心结论在于:移动端的 Pi Durable 实现了本地运行 Agent 逻辑与状态管理,同时通过 ExecutionEnv 接口成功复用了 Pi 的文件工具(read/write/edit),并借助 Expo FileSystem 实现了基于会话 ID 隔离的工作区持久化。开发体验的关键在于清晰划分框架提供的核心能力(如会话管理、模型调用)与移动端适配层(如数据库、文件系统、密钥存储),并通过 npm 包 pi-durable-Expo-env 实现了执行环境的模块化复用。
然而,当前方案仍面临显著的局限性:首先是 Skill 能力受限,不支持 Shell/Python 脚本执行及依赖安装;其次是检查点恢复机制中历史消息与磁盘文件状态的分离,导致新分支会话拥有空工作区;最核心的挑战在于长时任务的后台执行。由于移动系统(iOS/Android)对前台应用的限制,Moose 目前仅支持前台执行或短暂后台存活。视频指出,解决长时 Agent 运行需在“本地接入系统级后台服务(如 iOS Continued Processing)”与“远程 Host 承载运行时并同步状态/密钥”之间做出权衡,目前尚无最佳实践定论。