找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4564

积分

0

好友

594

主题
发表于 半小时前 | 查看: 7| 回复: 0

DeepSeek 开源了 DeepSeek Harness(dshhttps://github.com/deepseek-ai/deepseek-harness ),一个纯 Node.js 写的 agent harness。openminis 的底层支持 iSH-ARM64( https://github.com/OpenMinis/ish-arm64 )是 iSH 的一个 fork,加了 AArch64 guest 后端,能在 iPhone 和 iPad 上跑 Alpine 和 Node。

一个纯 Node 程序,一个能跑 Node 的模拟器,拼起来 dsh 就能在 iOS 上跑,不越狱,也不用另开一台机器。

拼起来不算难。后面时间主要花在另一件事上:跑起来之后,agent 在一个跟这台设备无关的盒子里,读不到日历、拿不到位置、看不见健康数据,只能在 Linux 里写文件。所以后半部分做的是给它开口子,以及决定每个口子凭什么开。

dsh-ios 项目宣传页:DeepSeek Harness on iPad & iPhone

代码在 dsh-ios 仓库,主页是 DSH,README 有中英文。

长什么样

iPad Air 真机。第一次启动约 30 秒,要把 Linux 根文件系统导入一遍,之后几秒起来。顶部那条是作者加的状态栏,绿点表示 dsh 服务已经在 127.0.0.1:3080 上,右边是终端和菜单。下面是 DeepSeek Harness 自己的 Web UI,没有改。

iPad Air 上 DeepSeek Harness Internal Testing Notice 弹窗

填 API key、选工作区就能聊。模型选择、权限预设、会话列表都是 dsh 自己的,权限预设里多出来的 "Guest Ask" 是作者加的。

DeepSeek Harness 工作区与会话界面

iPhone 17 Pro 也能跑。下面四张从左到右是启动页、dsh 界面、同一个 Linux 里的终端、服务日志。这台从点开到 dsh 响应 23.6 秒。

iPhone 17 Pro 上 DeepSeek Harness 启动流程截图

怎么做的

这个方案的本质,就是在 app 里装了一个 Linux。

dsh-ios 架构图:iSH-ARM64 Linux 模拟器

iSH-ARM64 是用户态模拟器,guest 里的 socket 就是宿主的 socket,所以 dsh 在 Linux 里监听的端口,app 的 WebView 直接连。根文件系统(Alpine + Node 22 + dsh)在 Mac 上用同一个模拟器提前做好,打进 app,第一次启动导入一次。app 做的事不多:把 dsh web 拉起来,等它能响应了在 WKWebView 里打开,挂了重启。右上角 >_ 打开的是同一个 Linux 的终端,可以 apk addnpm i -g

启动流程有个坑。一开始是在主线程上导入镜像加启动内核,iPhone 上被系统 watchdog 杀掉了:它给 app 的启动时间只有 20 秒左右,而首次导入要 30 秒。现在整个启动挪到后台线程,前面盖一层带进度和剩余时间预估的遮罩。

设备能力

做法是一座桥:app 里跑一个只监听 127.0.0.1 的 HTTP 服务,guest 里装一个 dsh 插件。每加一个能力,是 app 侧一个路由加插件里一个 tool。目前有这些:

工具 作用
device_infodevice_power 型号、系统版本、电量、温度
calendar_queryreminders_query 读日历事件、提醒事项
health_query 步数/距离/能量、心率、睡眠、运动记录
location_query 单次定位,带精度
contacts_search 按姓名查联系人
notify 发通知
file_importfile_export 经系统文件选择器进出文件
calendar_create_eventreminders_create 建日历事件、建提醒
shortcut_run 运行你自己的快捷指令

有两个决定是关于不做什么的。

联系人只能搜、不能列。没有接口会返回整本通讯录,agent 必须说出要找谁。

剪贴板整个没做。读取先砍掉的:iOS 对每次跨来源的剪贴板读取都要用户确认,没有 API 绕得开,实际效果就是不停打断使用者。写入不触发系统弹窗,本来留着,后来也去掉了,因为"agent 可以换掉你正要粘贴的内容"这个代价比这点便利大。

权限

DSH Capabilities 设备能力权限设置页

除设备信息外默认全部关闭,在 ⋯ ▸ Capabilities 里打开。页面分成"能读什么"和"能改什么"两栏,因为十几个开关平铺在一起时这两件事看起来一样。

读操作两道门:用户的开关,加 iOS 自己的授权。

写操作三道门,多的一道是每次调用都问。弹窗里写的是这次具体做什么,比如"添加这条提醒?『买牛奶』,周五到期,在『家庭』列表",不是能力名称。开关表示允许这类访问,不表示允许今天往日历里放这一条;而 iOS 对 app 内部的动作没有系统弹窗可以借用,所以这道门只能自己建。

这个确认框是阻塞的:guest 里的 fetch() 挂在连接上,app 侧的处理器卡在信号量上等结果。所以有三条规则:

  • app 在后台时直接拒绝,不排队一个使用者看不见的弹窗;
  • 同一时刻只弹一个,agent 陷入循环时不会堆出一墙对话框;
  • 没人应答就超时拒绝,回合以一句解释结束,不会一直挂着。

dsh 自己也有 approval 机制,镜像里默认是 guest-ask,所以作者去确认过会不会重复问。不会:dsh 的工具执行走一条 tools/pre-execute 瀑布流,默认放行,只有沙箱执行类工具(bash、文件读写)才会返回"要问",插件工具不在其中。也就是说对这几个写操作,app 侧的确认框是唯一一道门,去掉它就完全没有确认了。

活动记录

开关要能核查才有意义,所以记录了一条时间线。

DSH 活动记录日志时间线界面

两个来源。app 侧记每次能力调用(包括被开关拒、被系统拒、超时、限流),以及每次确认框问了什么、答了什么。guest 侧记 agent 在 Linux 里跑的每条 bash、每次改文件、每次搜索,这部分 app 本来看不见,是插件挂在 dsh 的会话事件上报回来的。

截图里可以看到 health_query(agent 调的工具)和 health.read(app 侧的能力)在同一条时间线上,以及 calendar.read days=99999 limit=99999 → 200 events, truncated 1,服务端的限流在这里是可见的。

记录内容分三档:名字、时间、耗时、结果总是记;参数记一行摘要;读操作返回的内容不记,只记形状,比如 contacts_search → 3 contacts,不记名字。一份抄了通讯录的日志比它要审计的那个能力泄露得更多。

日志还撑起三处小功能:每个开关下面的"上次使用"(被拒绝的调用不算使用)、顶栏在能力刚被用过时亮一下(跟 iOS 隐私指示器一个意思)、确认框里的"这是十分钟内第 5 次"。最后这个是发现 agent 跑飞的机会,单看一个弹窗看不出来。

性能

不如电脑快,在模拟指令集,Node 又是 jitless。从点开 app 到 dsh 服务就绪,iPhone 17 Pro 23.6 秒,iPad Air (M3) 约 26 秒,跟在 Mac 上用同一个模拟器跑差不多,瓶颈在模拟本身。起来之后聊天和常规工具调用没问题,在 guest 里跑大的 npm install 或编译比较慢。

DeepSeek Harness 冷启动耗时对比图

另一个限制是 iOS 会挂起后台 app,离开 DSH 正在进行的回合就停了。shortcut_run 尤其明显,它必然把 DSH 切到后台,所以那个工具的返回值里直接写明这一回合到此为止、结果看不到,而不是报一个会被模型当成"跑完了"的成功。

其他

自动化测试:guest 侧 31 项(每个工具走一遍完整的 agent 回合)、app 侧 89 项、UI 6 项,在模拟器、iPhone 17 Pro 和 iPad Air 上都跑过。全部本地跑,没有用 CI。

dsh-ios 自动化测试结果表格

协议是 GPL-3.0,因为 iSH / iSH-ARM64 是 GPL,app 把它编译进去了。

安装要自己用 Xcode 编译:make rootfs 生成镜像,打开 DSH.xcodeproj 选 DSH scheme 跑到设备上,README 里有步骤。因为要读 Apple Health,签名需要一个带 HealthKit 的显式 App ID,通配描述文件不带这个权限;不想弄的话可以把 HealthKit 能力和 entitlements 去掉,其余照常工作。

仓库在 dsh-ios,主页是 DSH。有问题提 issue,欢迎 PR。后续更新会放在仓库和主页上。TestFlight 欢迎大家安装试用。这类设备端 agent harness 的玩法,云栈社区也会持续关注和跟进。




上一篇:11.8k Star 开源 AI 笔记 NoteGen:内置 RAG 碎片自动整理成 Markdown
下一篇:ThreadLocal 用了弱引用为啥还内存泄漏?从存储结构到线程池场景讲透
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-8-28 07:50 , Processed in 0.835303 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表