基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
  • 知识卡片碎片时间过考点
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
    • AI 热点每日 AI 资讯与动向
AI 工作台
简历
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
开源项目2026-11-05 21:00

用 Flutter 为自托管智能体打造移动端

dev.to · AI#Flutter#智能体#开源
Editor brief · 编辑速览

开源应用 Pomelu 将多个 Hermes Agent 配置整合进手机界面,支持聊天、审批及查看智能体桌面。它通过 JSON-RPC WebSocket 和 REST 接入用户自己的网关,并介绍 Flutter 分层与 Riverpod 状态管理设计。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

把 AI Agent 接进 Telegram,能收到消息,却未必方便处理授权、补充输入和远程接管。Royan Labs 团队做的 Pomelu,是一个连接自家 Hermes Agent 网关的 Flutter 客户端:把多个机器人、聊天、审批和机器人桌面放进同一个手机应用。

它最值得读的地方,是移动端如何承接会执行操作的 Agent:断网后不能盲目重发,长回复不能越刷越卡,折叠屏切换不能丢草稿。作者给出了具体实现,也交代了没有推送服务器的代价。

Agent 聊天为什么不能直接套用消息重试

团队中有人在家用服务器上运行约十几个 Hermes Agent profile,包括研究、营销和健康机器人。Pomelu 将每个 profile 映射成侧栏里的一个机器人,各有一条聊天。

它是 Apache-2.0 开源的薄客户端,没有自己的 Agent 逻辑、账号系统、分析服务或后端。消息直接往返手机与用户的 Hermes 网关:WebSocket 入口是 /api/ws,使用 JSON-RPC;机器人、技能和定时任务走 REST。

代码按下面四层组织,目的是把协议和界面拆开:

presentation   widgets, screens, Riverpod notifiers   lib/features/*/presentation
domain         pure rules and models (no I/O)          lib/features/*/domain
data           stores, platform bridges, file work     lib/features/*/data
hermes SDK     transport, JSON-RPC, typed API, events  lib/hermes

重点看最后一行:lib/hermes 是不依赖 Flutter 的纯 Dart,协议代码可以脱离设备测试。接口只放在确实需要替换的地方,例如 WebSocket、存储和平台桥接。

认证沿用 dashboard 的密码登录,取得短期 access token 和 refresh token。每次连接前重新申请一次性 ticket,30 秒过期;凭据绑定签发它的 origin,并拒绝 user:pass@ URL。考虑到局域网和 Tailscale 使用场景,应用允许明文 HTTP,但向公网 HTTP 地址发送密码前会提示确认。

更关键的是发送语义。普通聊天重复一句话可能只是尴尬,Agent 重复执行 shell 命令,可能把任务做两遍。

Pomelu 先把消息写入本地 outbox,再显示消息行;按先后顺序逐条发送,回复流式输出期间暂停出队。附件先读取、上传,写入 prompt.submit 前先将条目标记为 submitted。

如果数据帧尚未离开手机,归为 NetworkFailure,重新入队,最多尝试五次。如果帧已经写出,随后连接断开,则归为 OutcomeUnknownFailure:服务端可能已经收到了。

连接断开,不等于操作失败。

重连后,客户端检查会话历史以及网关正在处理、排队中的用户消息。找到就确认送达;找不到也不自动重发,而是显示「delivery unconfirmed」,等待用户处理。失败轮次还会阻塞后续队列,保住对话顺序。本地队列能够跨进程退出保留,启动和重连都会唤醒仍有待发消息的聊天。

长回复和审批,为什么要用两套状态处理

Hermes 通过 message.delta 推送文本增量,同时发送工具事件和待办计划。事件经过 JSON-RPC 客户端的序列去重、重连回放,再进入纯 reducer,生成聊天状态。

性能问题出在长 Markdown:每来一点文本,就重新解析、布局整篇回复,内容越长,重复工作越多。

作者的处理是,回复超过 800 个字符后,沿 Markdown 块边界拆成多条列表行。已完成的块保持不变,只有最后一行继续重建。列表使用反向惰性列表,大 JSON 则放到另一个 isolate 解码。

流式回复中展示代码块

这条思路适用于流式界面:把已经稳定的内容从更新范围中移出去。不过,原文没有给出帧率、内存或耗时对照,800 字符应视为他们的实现阈值。

显示细节也有针对性:正文方向只判断一次,波斯语、阿拉伯语回复整体采用从右到左布局,代码块仍从左到右。执行计划则压缩成输入框上方的「Plan · 2 of 5」,点击查看所有步骤。

审批不能只当作聊天事件。clarify、approval、sudo 和 secret input 是服务端发来的 JSON-RPC 请求,需要客户端答复。独立 router 按会话保存请求,界面显示最早的一张卡片。router 才是权威状态来源,因此关闭聊天、重连后,问题仍能重新出现。

输入框上方的 Agent 授权卡片

折叠屏适配,先解决宽度和状态保留

Pomelu 没有单独设计「折叠屏模式」,而是按窗口宽度切换布局:低于 640 dp 时聊天全屏、机器人列表放抽屉;从 640 dp 起双栏显示;从 1024 dp 起加宽侧栏,聊天保持阅读宽度并居中。

Galaxy Z Fold 上并排显示机器人列表与聊天

铰链通过 MediaQuery.displayFeatures 获取,但只有真正遮挡内容的垂直铰链才会改变分栏位置。Z Fold 内屏这样的连续折痕会被忽略,否则侧栏反而容易被撑得过宽。

布局切换还必须保住输入状态。Android activity 声明折叠、尺寸和密度相关的 configChanges,避免姿态变化时重建;Flutter 为每个聊天保留一个 GlobalKey,让同一个聊天 widget 在抽屉和双栏之间移动,保留滚动位置、草稿和附件。

作者列出的测试宽度包括 360、640、840 dp,以及 iPad、Android 平板尺寸。硬件键盘支持 Return 发送、Ctrl+Tab 切换机器人、Cmd 或 Ctrl 加 1 到 9 打开机器人,右键在指针位置打开消息操作。

原文还称在「iPhone Duo」上测试了开合状态,且 iOS 的 displayFeatures 为空、安全区不对称。但它没有交代这个设备名称的具体来源,相关结论应保留疑问。

没有推送服务器,远程接管还能做到什么

Pomelu 的通知全部在本地产生。应用保持连接时,收到回复、后台任务完成或新问题信号,就弹通知;正在查看对应聊天时不打扰。

Android 可选「Stay connected」前台服务。按作者描述,Android 15 及以后版本会在应用离开屏幕几秒后切断其网络;后台连续 10 分钟不可达后,应用停止重拨,直到网络变化或用户重新打开。

另有每 15 分钟一次的后台检查:Android 用 WorkManager,iOS 用系统允许执行的 background app refresh。客户端比较各机器人的消息数量,每个机器人以最新消息通知一次。iOS 很快会挂起应用,因此作者明确把它称为尽力而为。

远程接管则依赖 Hermes 的 Bot Screen:Linux 网关上的每个机器人拥有独立 Xfce 桌面,供 computer_use 和 browser 工具操作。遇到登录、2FA 或验证码,人可以接手,再把已登录会话交还。

Pomelu 用 web view 加载网关同源页面,由 noVNC 1.7.0 携带一次性 display ticket 连接。客户端监听 display.status、display.lease,忽略旧的 lease epoch,避免过期控制权覆盖新状态。

从手机接管机器人的远程桌面

竖屏会跟随 noVNC 重绘区域,捏合暂停跟随,双击恢复;接管后单指控制鼠标、双指滚动。拖放单独设计了模式,释放前分步移动指针,满足桌面对拖动动作的判定。输入通过关闭自动纠错的隐藏字段转成按键,并补上 Esc、Tab、Ctrl、Alt 和方向键。

切到别的应用复制 2FA 码时,控制权短暂保留;稍后只有新状态仍确认自己持有控制权,才会归还,避免干扰中途接管的其他人。

运行要求是 Hermes Agent 0.21.5 或更新版本,配置 dashboard 用户名和密码,并让手机能够访问网关。原文启动命令如下:

hermes dashboard --host 0.0.0.0 --no-open

留意 --host 0.0.0.0 的监听范围。Bot Screen 另需 Linux、TigerVNC 和 Xfce,macOS、Windows 主机不提供此功能。Android 要求 10+;Google Play 与 GitHub APK 签名不同,切换须先卸载。原文称 App Store 版本尚未上线,iPhone、iPad 用户需从源码构建。

我的判断

最有价值的是对「不确定结果」的处理。它明确区分没发出去和可能已经执行,适合会产生副作用的 Agent。但这还不能证明端到端严格只执行一次:原文没交代历史匹配规则、误判边界,也没说明服务端是否支持幂等键。

如果服务端支持稳定请求 ID 和幂等提交,客户端恢复会更容易做扎实;Pomelu 的核对与人工确认,是已有协议条件下的一种取舍。

Markdown 分块、独立审批 router、按宽度布局,都有清楚的工程理由。不过作者没有提供性能对照,主要测试设备也是 Galaxy Z Fold,不能据此认定它在所有手机上同样流畅。

没有后端减少了部署环节,也失去了稳定推送的基础。对自托管用户,这可能可以接受;对依赖及时审批的团队,尤其需要评估 iOS 后台通知是否够用。

能拿来做什么

  • 做前端或 Node Agent 控制台时,把「确定未发送」和「发送后结果未知」分成两类状态,后者先核对服务端,再决定是否允许重试。
  • 优化流式 Markdown 时,先检查是否每次增量都重算全文;可以参考按块冻结已完成内容的办法,再用自己的回复长度和设备验证阈值。
  • 将审批、补充输入等请求保存在独立会话层,让页面关闭和重新挂载不影响待处理问题。
  • 评估自托管移动客户端时,把后台通知和远程桌面环境一起验证,尤其确认 iOS 通知限制,以及 Bot Screen 对 Linux、TigerVNC、Xfce 的依赖。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
AI 代码审查也要防范同源模型盲区
下一篇
用 HTML 和本地语音模型制作发布短片

资讯速览

dev.to · AI · 2026-11-05 21:00

AI 评分 8.0 / 10

相关标签

#Flutter#智能体#开源

继续阅读

  • 让编程智能体接入素材生成与创作软件
  • AI 代码审查也要防范同源模型盲区
  • 用 HTML 和本地语音模型制作发布短片
  • KV 缓存管理失误如何导致跨租户泄露
  • 假冒 Claude Code 扩展暴露供应链风险