🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI
广告☁️ 云服务器特惠阿里云首购 8 折 · 腾讯云合作特惠
DeepSeek Harness Hub
← 返回列表

HONYUZHE/dsh-screen-reader

DeepSeek Harnessspec-screened扫描:中风险在 GitHub 查看 ↗
未验证

让大模型实时看见 Android 屏幕的 DSH 插件:读一屏 10ms 级,增量输出约 30 token

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/18 · 已提供中文文档
综合分
30.1
GitHub 分
30.1
用户评分
—
★ Stars
1
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add HONYUZHE/dsh-screen-reader
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
信任档位:已验证本站已于 1 天前真实安装成功
是什么
dsh 原生插件 · vision
装得上吗
本站已真实安装成功(非静态推断)
安全吗
本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
还在维护吗
活跃:最近一次提交在 7 天前

档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →

🟢实装验证通过· 2026/9/24
由本站实装验证器在真实 dsh 环境安装成功,非静态推断。
数据截至 2026/9/24(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-tools@deepseek-ai/schemastery
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

由 DeepSeek 最新模型翻译生成
dsh-screen-reader

CI
license
node
platform

让大模型实时看见 Android 屏幕的 DSH 插件。

读一屏 10 毫秒级;全量输出比原始无障碍树省 61% token,增量输出只要约 30 token;
「点一下再看结果」从三次工具调用压成一次。

配套插件:dsh-screen-flow —— 本插件负责看见,
它负责等到位(等某段文字出现/消失、等画面稳定)并把一串「等 → 点 → 等」合成一次调用。
两个插件各自独立,可以只装一个。

English — A DeepSeek Harness plugin that gives
vision-capable models real-time access to an Android screen. It reads the accessibility tree over the
DSHA bridge (127.0.0.1:3090) in ~10 ms, returns deltas by default (≈30 tokens instead of ≈4100),
can block until the UI changes instead of polling, and folds act-and-observe into a single tool
call. Requires the DSHA Android app (the accessibility service owns the screen) — it is a plugin for a
DSH profile, not a standalone npm package.

实测

同一台平板(Lenovo TB710FU · Android 16 · 3200×2000)上的真实数据:

读屏延迟(复用连接):最快 7.2 ms,中位 13.4 ms
── 让模型自己 bash + curl:200 ms 起

全量读屏:4108 token → 1605 token(省 61%)
$ screen_read {delta:false, max_elements:15}
com.dsh.client 3200x2000 14:51:43 读屏100ms
c 新建会话 (310,188)
c 收起侧边栏 (635,188)
c 新建会话 (350,330)
c 搜索会话 (475,448)
c 视图选项 (555,448)
cd Android屏幕实时读取插件 (973,178)
… 省略 100 条(候选共 115 条;用 find 收窄、或 detail:"full"、或调大 max_elements)

增量读屏:约 30 token
$ screen_read {find:"插件"}
com.dsh.client 3200x2000 14:59:12 读屏141ms Δ +2 -1 ↔8
+ 进行中 Android屏幕实时读取插件 9分钟 (350,633)
~ Android屏幕实时读取插件 (973,178)→(965,178)
- 进行中 Android屏幕实时读取插件 2分钟

动作 → 看到变化:一次工具调用
$ screen_act {action:"key", key:"notifications"}
key → # com.dsh.client 3200x2000 读屏10ms Δ +16 -113 ↔1

为什么快 / 为什么省

| 做法 | 单次读屏 | 一次「点按后看结果」的往返 | 一次读屏的 token |
| --- | --- | --- | --- |
| 让模型自己 bash + curl /app/ui/dump | 200 ms 起(每次新建进程 + 新建 TCP) | 3 次工具调用(点按 / sleep / 再读屏) | 4200(原始 dump) |
| 本插件 | 7~16 ms(进程内复用 loopback 连接) | 1 次工具调用(screen_act 内置回读) | 1600 全量 / 约 30 增量 |

四个关键设计:

1. 连接复用。桥在 127.0.0.1:3090,Node 内置 fetch 对同源连接默认 keep-alive。
实测第 2 次起 7 ms,而新起一个 curl 进程要 200 ms —— 差 20 倍。
2. 增量优先。每次读屏按会话留一份指纹,默认只回「相对上一帧的变化」。
界面没动时输出就是一行 Δ +0 -0 无变化。
3. 指纹先行。判断「有没有变」只算原始 dump 的 32 位 FNV 散列(15 KB
git clone https://github.com/HONYUZHE/dsh-screen-reader.git /root/dsha-screen-reader

2. 给它一层指向 DSH 运行时的 node_modules 软链(peer 依赖由此解析)
ln -sfn ../../usr/local/lib/node_modules/@deepseek-ai/dsh/node_modules \
/root/dsha-screen-reader/node_modules

3. 登记为内置插件
cd / && echo 'dsh-screen-reader' >> /root/dsha-builtin.txt
cd / && python3 /root/.dsh/register-builtin-plugins.py

4. 确认插件进了树
dsh --profile web --dump-config | grep -A2 screen-reader

然后重启 DSHA Web(DSH 的插件树只在启动时 compose)。

⚠️ 第 3 步必须在 / 下执行:注册脚本里的 dsha-builtin.txt 是相对当前目录的
root/dsha-builtin.txt,换个目录跑会静默退回兜底清单,插件根本不会被注册。

通用 DSH profile

把仓库放到任意位置,然后在 $DSH_HOME/profiles//package.json 里接上:
json
{
"dependencies": { "dsh-screen-reader": "link:/path/to/dsh-screen-reader" },
"dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-screen-reader"] } }
}

并同样给它一层指向 DSH 运行时的 node_modules 软链。

两个工具

screen_read —— 读屏

| 参数 | 说明 |
| --- | --- |
| mode | tree(默认,无障碍树)/ image(只截图)/ both |
| detail | compact(默认)/ full(补上桥的序号与 [l,t,r,b] 区域) |
| delta | 默认 true,只回相对上次的变化;false 强制全量 |
| find | 只保留文字含该子串的条目(不区分大小写)—— 在聊天/长列表界面上最省 |
| wait_ms | 先阻塞等界面变化再读(0 = 立刻读)。这是最省的实时用法 |
| settle_ms | 配合 wait_ms:要求新画面稳定这么久才返回,避免抓到动画中间帧 |
| max_elements | 返回条目上限 |

行格式:[标记 ]文字 (x,y),标记 c=可点 d=不可用 s=已选中 v=可滚动
x=桥给的坐标不可靠(面积为 0,按文字点,别按坐标)。

screen_act —— 动作后直接回读

action: tap | input | key | swipe | launch。一个来回完成「动手 + 看结果」。

- tap 优先用 text(控件坐标随滚动/动画变,文字不变),没文字才用 x/y;
- key:back / home / recents / notifications / quicksettings / lock;
- 动作后自动等画面稳定并返回增量;输出 Δ ... 无变化 就说明这一下没打中;
- screenshot: true 额外附上动作后的截图。

给模型的提示词

插件会注入一段约 150 token 的系统提示,核心就四条:优先用 screen_read(要等变化传 wait_ms,
别自己 sleep 轮询);默认就是增量;点按优先按文字;只有没文字的界面(游戏、画布)才用 mode:"image"。
不想要就设 prompt: false。

配置

在 $DSH_HOME/profiles/web/cordis.patch.yml 里按 id 覆盖,例如关掉动作工具:
yaml
- id: screen-reader
config:
allowActions: false
actionSettleMs: 250

| 键 | 默认 | 含义 |
| --- | --- | --- |
| enabled | true | 总开关 |
| allowActions | true | 是否注册 screen_act(只读审计可关) |
| cacheMs | 120 | 同一次调用内的采样缓存时长 |
| minIntervalMs / maxIntervalMs | 60 / 240 | 等待轮询的起始间隔与退避上限 |
| maxAttempts | 3 | 读屏最多尝试几次(超时 / 瞬时无窗口 / 退化帧都会重试) |
| retryDelayMs | 120 | 读屏重试前的等待 |
| maxElements | 120 | 全量输出的条目上限 |
| maxText | 96 | 单条文字截断长度 |
| actionWaitMs / actionSettleMs | 1500 / 150 | 动作后等变化的上限与要求的稳定时长 |
| maxWaitMs | 30000 | 单次调用允许的最长等待(协作式取消预算) |
| prompt | true | 是否注入那段简短的系统提示 |
| warmup | true | 加载时预热一次桥连接(只打 /app/version,不碰屏幕),消掉首次调用的 100~200 ms 建连开销 |

文件

| 文件 | 职责 |
| --- | --- |
| lib/bridge.js | 3090 桥客户端:连接复用、超时、把 [ERR]/[POLICY_BLOCKED]/DISABLED/NO_PERMISSION 分类成稳定错误码 + 给模型的下一步建议 |
| lib/tree.js | 纯函数:解析 dump、压缩渲染、增量差分、屏幕指纹 |
| lib/reader.js | 采样缓存、可取消 sleep、waitForChange 轮询、瞬时态重试、截屏读盘 |
| lib/index.js | Cordis 插件:注册两个工具、系统提示段、会话级状态 |

测试
bash
npm test                         # = test/reader-unit.mjs,纯逻辑,不需要设备

node test/reader-unit.mjs        # 注入假桥,把重试/退化帧/取消逻辑钉死
node test/plugin-load.mjs        # 最小 cordis 上下文里真加载 + 真 dispatch
node test/smoke.mjs              # 走真机:解析 / 延迟 / 压缩率 / 差分 / 缓存 / 等待 / 截图
node test/smoke.mjs --with-ui    # 额外跑「下拉通知栏 → 复原」验证真实变化检测

| 测试 | 需要 | 覆盖 |
| --- | --- | --- |
| reader-unit.mjs | 无 | 解析边界、压缩、差分、指纹、重试、退化帧、取消、截屏路径兜底 |
| plugin-load.mjs | DSH 运行时 | 真 ToolRuntime 加载、schema 投影、参数校验、输出校验、render 全链路 |
| smoke.mjs | DSH + DSHA 设备 | 真桥延迟、压缩率、增量、waitForChange、截屏可读性 |

两个测试值得单独说:

plugin-load.mjs 用真实的 ToolRuntime + SystemPrompt 起一个最小 cordis 上下文,
把插件挂上去并真的 dispatch 一次。开发期就该跑它,别靠重启 Web 来验证 —— 它当场抓出过
「输出 schema 里 image 被 required: true 传染成必填」的 bug(不截图的那次调用会直接
INVALID_TOOL_OUTPUT,而重启验证要等到真正用图才会暴露)。

reader-unit.mjs 靠注入假桥覆盖真机难复现的路径。退化帧只在界面过渡那一瞬间出现,
用真机测不稳定,但一旦回归模型就会读到「假界面」,所以必须钉死。

已知边界

- 读屏/截屏被拒([ERR] 你拒绝了这次屏幕读取):这是 App 侧的授权决定,
插件会原样转告用户去「设置 → 设备能力授权」,不重试、不绕道。
- 无障碍服务被关掉([ERR] 无障碍服务未开启…):单独归类为 A11Y_OFF,提示用户去
DSHA「配置」页点「屏幕操作权限」。不要把它当成锁屏 —— 给「先按 home」的建议会把人带偏,
而且这种情况重试也不会自己好。
- 锁屏 / 系统弹窗:桥会回 [ERR] 取不到当前窗口,插件给出「先按 home 调回界面」的建议。
- 三种瞬时态(实测都出现过,都会自愈,插件自动重试 ≤ maxAttempts 次):
1. BRIDGE_TIMEOUT —— App 的 Activity 刚切换时第一次 dump 可能几秒不返回;
2. [ERR] 取不到当前窗口 —— 界面过渡中短暂没有窗口;
3. 退化帧 —— 过渡期只读到一个全屏、无文字的节点,把它当界面报给模型是误导。

只对这三种重试。POLICY_BLOCKED / SCREEN_DENIED / DISABLED 一律立刻抛出:
那是策略和用户的决定,重试不会让开关自己变。
- 截图代价:2000×3200 的 PNG 约 0.7 MB,附件服务会按当前路由的像素预算自动降采样;
但图片 token 比文字贵得多。界面有文字时一律用 tree,只有游戏/画布/图形按钮才用 image。
- 退化帧判据刻意收得很窄(恰好一个节点且无文字),免得把真正的无字界面(游戏、画布)
也卷进重试。如果你的场景误判了,把 maxAttempts 设成 1 即可关掉这层重试。
- 依赖设备:所有读屏能力都来自 DSHA App 的无障碍服务,没有它这个插件什么都做不了。

开发笔记

几个踩过的坑,都是实测出来的,不是想出来的:

- 桥的错误文本不能全局正则匹配。屏幕正文里完全可能出现
「你拒绝了这次屏幕读取」(比如模型正在讨论这个错误),不锚定行首就会把一次成功的
dump 误判成授权被拒。
- required: true 会传染。工具输出 schema 里复用一个 {..., required: true} 的对象字面量
当可选属性,会把那个属性变成必填。read_image 里能这么写只是因为它永远返回图片。
- 不要为了省事把 profile 的 patchReload 改成 live:Android 上 HMR 会因为缺
--expose-internals 让 dsh 起不来。源码改动只能靠重启生效。
- 注册脚本的相对路径陷阱:dsha-builtin.txt 是相对 cwd 解析的,不在 / 下跑就静默失效。

License

MIT © 2026 HONYUZHE

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

同作者(HONYUZHE)的其他插件

💬 加入社群

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

DPharness QQ 群二维码,QQ 扫码进群
QQ 扫码进群
DPharness 飞书群二维码,飞书扫码进群
飞书扫码进群