dsh-screen-reader
让只能处理文本的模型看见屏幕的 DeepSeek Harness 插件。 抓全屏 / 指定窗口 / 指定区域 → 交给视觉模型逐字转录 → 维护几分钟的滚动屏幕记忆 → 本地精确像素差分 → 以及对视觉链路本身的自校准。
仅支持 Windows。 依赖 PowerShell 5.1 的
System.Drawing与PrintWindow。
⚠️ 先读这一段:哪些情况下你不应该用这个插件
| 你的需求 | 更合适的选择 |
|---|---|
| 我只是想粘一张图问问题 | 用 @liustack/modlens(★3.9k、L5 跑通、Gold 信任、输出结构化 JSON)。它在这件事上比本插件成熟,本插件不打算在这一点上竞争。 |
| 我用的是支持图像输入的模型 | 直接用内置的 read_image 和图片附件——本插件的"转录"那一半本来就是给纯文本模型搭的桥 |
| 我要跨平台 | 本插件是 Windows 专属,做不到 |
| 我要精确测量像素 | 用真正的测量工具。本插件是描述器,实测尺寸误差可达 ±40% |
本插件真正不可替代的那一块是:持续读屏 / 屏幕活动记忆。 也就是"让 agent 知道你刚才在做什么",而不是"这张图里有什么"。
目录
它解决什么问题
纯文本模型看不见屏幕。于是发生这种情况:
- 用户说"我这个界面哪里不对",模型只能靠用户描述
- 模型说"你点一下那个按钮",它其实从没见过那个按钮
- 用户改完一个设置,模型不知道改成了什么
这个插件给模型三样东西:
- 看得见:把屏幕(或某个窗口、某个区域)交给一个支持图像输入的模型,拿回逐字转录
- 记得住:变化驱动地持续录制,维护一份只保留几分钟的滚动记忆
- 比得准:两张图之间"哪里变了"由本地像素差分精确算出,模型只负责解释变化
八个工具
看屏幕
| 工具 | 作用 |
|---|---|
see_screen |
立刻看一眼。支持 window(只抓某个窗口)与 region(归一化裁切放大)。输出包含从模型回答里解析出的 suggestedRegion,可直接回传做二次放大 |
screen_watch |
开关持续录制。默认关闭,必须显式 { on: true } |
screen_memory |
读最近 N 分钟的滚动视觉记忆 |
vision_routes |
探测当前有哪些模型路由声明了图像输入能力 |
看图片文件
| 工具 | 作用 |
|---|---|
see_image |
看一张图片文件(图表、设计稿、别人发来的截图) |
see_diff |
两张图的差异:本地精确像素差分定位变化区域 → 只把变化区域交给模型解释 |
vision_selftest |
自校准:程序画一张每项事实都确定的图 + 施加已知改动 → 让模型描述 → 与已知真值逐项打分 |
vision_storage |
报告(可选清理)DSH 附件库的规模 |
实测效果
以下全部是在真实运行中测出来的,不是设计目标。
视觉理解
| 项目 | 结果 |
|---|---|
| 读柱状图数值(合成图,4 根柱) | 4/4 精确命中(120 / 60 / 180 / 90),颜色、排序全对 |
| 读 Blender 大纲视图的物体清单 | 4/4(Camera / Cube / Light / 球体),与 headless Blender 取出的真值完全一致 |
| 读标题栏中文路径 | 逐字命中,含中文文件名与路径 |
| 判断哪个物体被选中 | 修复前 0/3,修复后 2/2 |
LOCATION 结构化位置输出 |
2/2 按要求吐出,能被正则解析成 region |
本地像素差分(这是插件里最可靠的一环)
| 项目 | 结果 |
|---|---|
| 真实照片(1225×1254 JPEG)程序化加 2 处已知改动 | 恰好检测到 2 个区域,零误报 |
| 位置准确性 | 边界框比真实改动大约 30–45 px(= padding 10 + 网格量化 + 膨胀 1 格) |
| 同一张图自比 | 变化像素 0,正确报"没有变化" |
| 合成校准图(4 处已知改动) | 4 个区域全部对上;其中"底部黄条消失"与"红圆移到右下"因膨胀被合并为 1 个区域(已知取舍) |
成本与失败语义
| 项目 | 结果 |
|---|---|
| 推理 token 消耗 | 简单合成图 ~790;Blender 全窗可超 6000 |
| 空正文静默失败 | 曾被复现并已修复:同一张图在预算 1200 下正文 0 字符、finish=max-tokens,而旧代码把它当成功返回 |
| 现在空正文时的行为 | 自动翻倍预算重试一次 → 仍有推理则返回推理片段并标注 → 全空才报错。绝不返回空的"成功" |
边界:它做不到什么
这一节是本文档最重要的部分。
1. 它是描述器,不是量具
实测:一条 30 px 高的色带被读成"40–45 px",误差约 40%。
- ✅ 可靠:谁比谁高、哪个被置灰、大致在左上还是右下
- ❌ 不可靠:这两个元素差 8 px 吗、这个间距是 16 还是 12
2. 低对比度差异是危险区
反向验证有效(灰色 vs 高饱和蓝的"禁用按钮"判对不难),但真正的困难——两个相近的灰色、1 px 错位、微弱色差——正是它会漏掉、或者更糟:自信地编一个的地方。而"帮我看界面哪里不对"恰恰最需要这些。
3. 形状语义是弱项
实测案例:一个被编辑成"尖顶小房子"的立方体,在 Blender 视口里。
- 模型看到了"一个非标准形状"、也说了"说明该物体已被编辑过"
- 但它始终称它为"立方体",从未把网格的编辑归因到物体上
诚实补充:该机位下尖顶本来就不明显,所以这一次漏掉部分可原谅。但"不会把网格编辑归因到物体"这个模式,不止出现在这一个案例里。
4. 分辨率不是准确度的杠杆(反直觉,但测过)
同一张 Blender 全窗图,同一提示词、同一模型,只改分辨率:
| 输入尺寸 | 选中物体 | 是否说明立方体未被选中 | 编辑痕迹 |
|---|---|---|---|
| 1942×1030(原生) | ✅ | 未明说 | 只说"黑色三角形面" |
| 1295×687(缩小 44.5% 像素) | ✅ | ✅ 明确说"未选中" | ✅ 说"非标准形状…已被编辑过" |
缩小版反而更好。 结论:模型对输入做了归一化,全窗图下源图分辨率不影响准确度。(裁切时的表现未验证。)
5. 只有一帧,没有时间与因果
- ✅ 它能答:"屏幕现在是什么"
- ❌ 它答不了:"这个弹窗是不是因为我点了 X 才出现的"
那要靠滚动记忆里的文字自己推因果——这是 screen_memory 存在的主要理由。
6. 慢且贵
每次调用都会先产出大量推理 token(实测 788 ~ 6621 字),然后才输出正文。单次调用数秒,且按 token 计费。持续录制会持续花钱,所以默认关闭,并且有 12 秒最小调用间隔。
7. 附件库会增长
每次视觉调用都会往 ${DSH_HOME}/attachments 写入一个内容寻址文件,插件无法阻止(llm.stream 的图像块需要持久化附件引用)。
实测观察:该目录会自己清零(28 个文件 / 2.1 MB → 0),但触发机制未查明。vision_storage 默认只报告,不删除——因为那些文件被历史会话引用,删了会让过去对话里的图片显示不出来。
8. 仅 Windows
scripts/capture.ps1 与 scripts/imageops.ps1 依赖 PowerShell 5.1、System.Drawing、PrintWindow、DwmGetWindowAttribute。非 Windows 上会如实报错,不会假装成功。
安装
两种方式,只有第二种被真实验证过。 详见下方验证状态表。
方式一:作为 profile bundle(推荐,但尚未实测)
dsh plugin --profile web add github:cbg33695/dsh-screen-reader
装完重启 web profile 并刷新浏览器。工具会出现在每一个会话里,不需要切换 preset。
这是 DSH 生态的标准做法,也是我把它列为推荐首选的原因:一条命令、不用切 preset、对试用者门槛最低。但我本人没有在真实实例上装过一次(见状态表)。如果你的实例不接受它,请用方式二,并把完整报错发到 issue。
方式二:作为 agent preset(已验证可用)
把 lib/ 与 scripts/ 放进 .agent-presets/<id>/plugin/,并在 agent.cordis.yml 加一行:
- id: screen-reader
name: './plugin/index.js'
disabled: false
注:方式二的相对路径解析规则与方式一不同,细节见下方设计说明。
装完先自检(10 秒)
新开一个会话,问一句:
你现在有哪些和屏幕、图片相关的工具?
应当列出八个:see_screen、screen_watch、screen_memory、vision_routes、see_image、see_diff、vision_selftest、vision_storage。
- 看得到 → 装好了。接着跑一次
vision_routes,确认这台机器上存在声明支持图像输入的模型路由(没有的话插件只能用一半功能) - 看不到 → bundle 没有被加载。改用方式二,或把 DSH 版本、profile 名、完整报错发到 issue
⚠️
vision_selftest是唯一会主动花钱的自检——它会真的调用模型。不想花钱就别跑它。
隐私
这个插件会截取你的整个桌面,默认包括你可能不希望外传的内容。
| 事实 | 说明 |
|---|---|
| 截图去哪 | 传给配置的视觉模型路由(本插件不自己发请求,走 DSH 的 llm 服务) |
| 截图存哪 | 插件自己的图在 ${DSH_HOME}/vision/,全库只保留最新 4 张(keep_ 前缀的永久保留),插件停止时删除当前那张 |
| 模型收到的附件 | 每次都往 ${DSH_HOME}/attachments 写一份(见边界 7) |
| 默认状态 | 不录屏。 必须显式调用 screen_watch({ on: true }) 才会开始持续抓屏 |
| 建议 | 在需要时开、用完关;不要在含有敏感信息的桌面上长期开着 |
持续录屏默认关闭是刻意的设计决定,不是遗漏。一个默认开着、持续把桌面传给模型 API 的插件,是错的默认。
设计说明
为什么不把整个屏幕直接丢给模型
因为它不work。实测:同一张 Blender 截图,1295×687 全窗图答错了被选中的物体;把变化区域单独裁成 675×387 后全部答对。裁切的好处不是"更清楚",而是去掉了竞争注意力的内容。
为什么差分在本地算
视觉模型做细粒度找茬很差,而且会编造"看起来合理"的差异。像素级差分是精确的、免费的、还能直接给出变化区域的边界框。所以分工是:本地算差异,模型只解释差异。
为什么提示词把"主体"放在最前
实测:要求"逐字转录全部界面文字"时,模型把被选中的球体认成了立方体;只要求"忽略文字、说明视口里的物体"时全部答对。界面文字会抢走注意力,饿死场景理解。
为什么 max-tokens 必须当成失败
这个模型会先产出大量推理 token。实测预算 1200 时,推理吃掉全部 1200,正文 0 字符,而 finish 原因是 max-tokens——不是 error。不额外判断,就会把"空的失败"当成"成功的空结果"返回。
为什么插件模块零依赖
lib/screen.js 与 lib/toolbox.js 不 import 任何 npm 包,工具定义直接构造运行期结构、schema 手写 JSON Schema。
原因:DSH 加载器对相对路径 specifier 按 composition 目录解析、对裸包名按 harness 安装位置解析。以 preset 方式安装时两者都够不到 @deepseek-ai/dsh-tools。
代价:失去 defineTool 的自动参数校验,所以每个 execute 都自己做类型兜底。以 bundle 方式安装时这个绕路其实不再必要——但保持一致让两种安装方式跑同一份代码。这是有意的取舍,见后续计划。
验证状态:哪些测过、哪些没测过
| 能力 | 状态 |
|---|---|
| 抓屏 / 窗口 / 区域裁切 / DPI 原生分辨率 | ✅ 独立验证(含失败路径与幂等性) |
| 本地像素差分 | ✅ 独立验证(合成图 + 真实照片) |
| 视觉提示词与重试链路 | ✅ 实测(多轮) |
| 附件库报告 | ✅ 实测 |
vision_selftest 的自动打分 |
❌ 从未跑过 |
| bundle 方式安装 | ❌ 从未跑过(只有 preset 方式被真实挂载验证) |
| 准确率的单一数字 | ❌ 不存在 |
没有"准确率 92%"这种数字,因为从未测过。 上面所有"实测效果"都是具体案例,不是基准。
已知问题与后续计划
v0.2 打算做:
- 跑通
vision_selftest并公布基准数字 —— 这是当前最大的空缺 - 用
@deepseek-ai/dsh-tools的defineTool重写工具定义,拿回参数校验 - 把
Configschema 接上(现在可调参数是文件头常量) - 抽掉
screen.js与toolbox.js之间重复的提示词常量 - 非 Windows 的明确降级路径
- 形状语义:尝试"先定位主体 → 再局部放大"的两段式,它已被证明对选中判断有效
已知的设计妥协:
screen.js与toolbox.js之间有约 40 行重复的提示词与错误处理(原因见上,v0.2 处理)- 全窗准确度不受分辨率影响,但裁切时是否受未验证
- 差分边界框比真实变化大 30–45 px(可调
-Padding/-Dilate/-GridW)
如何反馈
这个插件是实验性的,而且它自己承认了不少做不到的事。我最想要的反馈是"它在你这里错在哪",不是赞美。
发 issue 时请带上:
- 安装方式(bundle / preset)与
dsh --version - 你想让它看什么(哪个应用、什么画面)
- 它答错了什么,以及正确答案是什么 —— 这条最有价值。如果那个画面存在程序化真值(编辑器里的文件内容、Blender 的场景对象、某个命令的输出),请一并贴上,那样就能像我测 Blender 时一样拿到硬指标
- 识别错误请尽量附截图(自行脱敏)
- 安装失败请贴完整报错
特别欢迎这三类:
| 想知道的 | 为什么 |
|---|---|
| 它在什么画面上会"编造" | 这比"识别错"严重得多。凭空写出来的东西会让人做出错误决定,而我目前只知道它会这样做(低对比度区域),不知道边界在哪 |
| 裁切到多小才够准 | 我验证过"全屏分辨率不影响准确度",但裁切时的边界完全没验证。这直接决定用法 |
| 持续录屏的真实花费 | 我没测过连续跑一小时的 token 消耗。想长期挂机的人需要这个数字 |
如果你跑通了 vision_selftest,把分数贴上来就是最大的贡献——那是这个项目目前唯一缺的硬指标。
许可
MIT。见 LICENSE。
与其它插件的关系
本插件不打算在"图片问答"上竞争,那一块 @liustack/modlens 做得更好更成熟。本插件与它的差别在于持续性与本地计算:
- 它是"给我看这张图",本插件还有"持续看着屏幕并记住刚才发生了什么"
- 它的差异判断依赖模型,本插件的差异判断是本地精确像素计算
- 它输出结构化 JSON 证据,本插件输出带实证记录的散文
如果你的需求只是前者,请用 modlens。
No comments yet. Be the first to write one.