内容
# 本地视觉 (`macvis`)
[](https://github.com/junmo-kim/mac-local-vision/actions/workflows/ci.yml)
[](LICENSE)

适用于 AI 代理和端到端测试的零 token、设备端视觉 —— 作为 **100% 纯 Swift 单个二进制文件**,基于苹果原生的 `Vision` 和 `FoundationModels` 框架构建。无需 Node、无需 Python,无需运行时依赖:操作系统 *即* 是依赖。
- **零 token OCR** — 在本地提取文本/布局,永不消耗云视觉 token。
- **快速端到端定位** — `find` 返回一个单词的精确像素中心,用于点击/断言。
- **二维码/条形码扫描** — `barcode` 解码 Vision 支持的每种符号(二维码、Code128、EAN、PDF417 等),只需一次调用。
- **二维码生成** — `make-qr` 编写一个可扫描的二维码 PNG(CoreImage,无需 Vision)。
- **设备端语义 `ask`** *(测试版)* — 通过苹果基础模型(macOS 27 测试版)进行多模态推理。
- **本地人脸分类** — 在不上传任何内容的情况下,按人分类照片。
## 小巧且快速
一个 **~240 KB 精简的单个二进制文件**(框架是操作系统,没有捆绑任何内容 —— 无需 Node,无需 Python,无需 `node_modules`),每次调用都是全新的 **~0.3 秒端到端** —— 进程启动 *加上* 识别,无需守护进程保持预热:
| 命令 | 延迟 |
| --- | --- |
| `find`(定位一个单词) | **0.30 秒** |
| `ocr`(整页) | **0.29 秒** |
| `doctor` | **0.13 秒** |
<sub>在 1080×2400 截图(19 行,韩语 + 英语)上的 5 次最佳结果,Apple M4。</sub>
与将截图发送到云视觉 API 相比:无需网络往返,无需视觉 token,无需每次调用成本,且没有任何内容离开机器。
`ask`(多模态 LLM 推理,需要 macOS 27(测试版)+ Apple Intelligence)是一种不同的快速 —— 仍然无需云往返,但成本是实际生成时间,而不是进程启动:
| 提示 | 延迟 |
| --- | --- |
| 短提示,简单图像 | **0.8 秒** |
| 较长提示,简单图像 | **3.0 秒** |
| 复杂现实截图,详细提示 | **6.8 秒** |
<sub>小样本,MacMini-M4,macOS 27 测试版。</sub>
## 要求
Apple Silicon Mac,macOS 26+。无其他依赖 —— `Vision` 和 `FoundationModels` 随操作系统发布。构建 `ask`(多模态)路径还需要 macOS 27 SDK(Xcode 27);其他所有内容均可在 macOS 26 上构建和运行。
## 安装
Apple Silicon,macOS 26+。
**Homebrew**
```bash
brew install junmo-kim/tap/macvis
```
**mise**
```bash
mise use -g github:junmo-kim/mac-local-vision # 添加 @0.1.0 以固定版本
```
两者都获取相同的预构建二进制文件 —— 它是启用 `ask` 的,因此 Vision 命令在 macOS 26+ 上运行,而 `ask` 在 macOS 27 上启用。然后运行 `macvis doctor` 以查看此处可用的内容。
<details><summary><b>直接下载/从源代码构建</b></summary>
**直接下载** — 从 [Releases](https://github.com/junmo-kim/mac-local-vision/releases) 获取 `macvis-<version>-macos-arm64.tar.gz`,然后:
```bash
shasum -a 256 -c macvis-*-macos-arm64.tar.gz.sha256 # 验证下载
tar xzf macvis-*-macos-arm64.tar.gz
sudo mv macvis /usr/local/bin/ # 或 ~/.local/bin 在您的 $PATH 上
```
二进制文件是临时签名的(未进行公证),因此直接下载的副本可能会触发 Gatekeeper —— 在系统设置 → 隐私和安全下批准它。(Homebrew / mise 安装避免了这种情况。)
**从源代码**(Swift 6.2+ 工具链 / Xcode 26):
```bash
swift build -c release && cp .build/release/macvis /usr/local/bin/
```
</details>
## 状态
| 命令 | 状态 | 要求 |
| --- | --- | --- |
| `ocr` / `find` | ✅ 工作正常 | Apple Silicon · macOS 26 |
| `barcode` | ✅ 工作正常 — 二维码 + Vision 支持的每个 1D/2D 符号学在一个命令中 | Apple Silicon · macOS 26 |
| `qr` | ✅ 工作正常 — `barcode` 限制为仅二维码,服务端(无 `--symbology` 标志) | Apple Silicon · macOS 26 |
| `make-qr` | ✅ 工作正常 — CoreImage,无需 Vision;通过 `barcode`/`qr` 往返 | 任意 Mac · macOS 26 |
| `doctor` | ✅ 工作正常 | macOS 26 |
| `sort-faces` / `find-person` | ✅ 工作正常 — 同会话分组;跨时间身份近似(参见备注) | Apple Silicon · macOS 26 |
| `mcp` | ✅ 工作正常 — stdio JSON-RPC,公开 ocr/find/barcode/qr/make-qr/doctor 作为工具(+macOS 27 构建上的 ask) | macOS 26 |
| `serve` | ✅ 工作正常 — 远程/非 Mac 节点的 HTTP JSON-RPC MCP 服务器 | macOS 26 |
| `ask` | 🟢 测试版 — 针对预发布苹果堆栈;在一个 macOS 27 测试版启动时验证实时端到端推理(参见备注) | macOS 27(测试版)+ Apple Intelligence |
> **`sort-faces` 准确性**:面部通过人脸图像打印在人脸剪辑上进行分组(苹果不提供公共人脸嵌入 API)。这可靠地将近似重复/同会话面部分组,但跨大姿势/光线/年龄变化的身份信号较弱 — 调整 `--threshold`(距离在输出中)。不是人脸识别数据库。
> **`ask` 是测试版**,因为它依赖于预发布的苹果堆栈 — macOS 27(测试版)和新的 Foundation Models *多模态* API。调用 — `session.respond { prompt; Attachment(image) }` — 与苹果官方 [WWDC26 Foundation Models 会话](https://developer.apple.com/videos/play/wwdc2026/241/) 匹配,并针对 macOS 27 SDK 构建。在真正的 macOS 27 测试版启动时,错误路径(Apple Intelligence 关闭 → `apple_intelligence_not_enabled`,退出 `71`)和实时端到端推理都已验证:准确的答案,完整的 `--stream` 输出(不是增量),以及 **~1-7 秒** 的延迟,取决于图像复杂性和答案长度。Apple Intelligence 本身被限制在合格的、内部启动的安装中,因此 `ask` 跟踪平台:它随着 macOS 27 的发布而从测试版升级。macvis 的其余部分(`ocr` / `find` / `sort-faces` / `mcp`)今天在 macOS 26 上是稳定的。
## 构建和测试
```bash
swift build -c release # 二进制文件在 .build/release/macvis
swift test # 纯逻辑 + ask 管道 + Vision OCR 固定装置
```
> 使用真正的 macOS 27 API 构建 `ask` 路径需要 Xcode 27 SDK;当前目标在 macOS 26 上编译,`ask` 在 `@available(macOS 27, *)` + 运行时可用性保护后面。
## 用法
```bash
macvis ocr ./receipt.png # 提取文本
macvis find ./screen.png --target "提交" # 单词的像素中心
macvis find ./screen.png --target "결제하기" # 非拉丁语也支持(区域感知)
macvis barcode ./ticket.png # 扫描每个二维码/条形码符号
macvis qr ./ticket.png # 仅扫描二维码
macvis make-qr "https://example.com" --out ./qr.png # 编写可扫描的二维码 PNG
macvis ask ./design.png --prompt "主要主题颜色?" # 测试版 — 需要 macOS 27(测试版)
macvis doctor # 这里有哪些模式可用
```
`find` 默认过滤为 `--min-confidence 0.3`(`ocr` 保留所有内容,默认 `0.0`);降低它以适应模糊或无头渲染。
输出默认为 YAML(`--format json` 用于 `jq`)。数据输出到 stdout;日志和结构化错误输出到 stderr。退出代码区分错误参数 (`64`)、永久 `ask` 不合格 (`70`) 和可重试的失败 (`71`)。
### 示例输出
`find` 返回精确的点击点 (`x`,`y` = 中心) 加上边界框:
```yml
$ macvis find ./screen.png --target "提交"
found: true
x: 456
y: 66
left: 380
top: 48
width: 152
height: 36
confidence: 1
text_found: 提交
```
`--format json` 用于 `jq`:
```json
$ macvis find ./screen.png --target "设置" --format json
{"found":true,"x":126,"y":69,"left":38,"top":48,"width":176,"height":42,"confidence":1,"text_found":"设置"}
```
`barcode` 在一次调用中扫描每个二维码/条形码符号,并返回每个代码的负载、符号学和像素框;`code_count: 0`(不是错误,退出 `0`)当未找到任何代码时:
```yml
$ macvis barcode ./ticket.png
image_width: 1080
image_height: 2400
code_count: 1
codes:
- payload: "https://example.com/ticket/abc123"
symbology: qr
x: 512
y: 300
left: 480
top: 270
width: 64
height: 64
confidence: 1
```
使用 `--symbology qr,code128` 限制为特定的符号学(逗号分隔);未知符号学名称是结构化的 `bad_request`/`unknown_symbology` 错误,退出 `64`。
`qr` 是 `barcode` 缩小为仅二维码,服务端强制执行 — 无 `--symbology` 标志可覆盖它。输出形状与 `barcode` 相同,只是始终限于二维码:
```yml
$ macvis qr ./ticket.png
image_width: 1080
image_height: 2400
code_count: 1
codes:
- payload: "https://example.com/ticket/abc123"
symbology: qr
x: 512
y: 300
left: 480
top: 270
width: 64
height: 64
confidence: 1
```
`make-qr` 是 `barcode`/`qr` 的写入对应端 — 它通过 CoreImage(`CIQRCodeGenerator`)将文本编码为可扫描的二维码 PNG,而不是 Vision,因此它在任何 Mac 上都可用,无论 Vision/Apple Intelligence 是否可用。给出 `--out` 以写入文件并获取其路径;省略它以获取 base64 中的 PNG 作为 `image_data`(适用于没有本地文件系统访问权限的远程/MCP 调用者):
```yml
$ macvis make-qr "https://example.com" --out ./qr.png
path: ./qr.png
width: 250
height: 250
correction_level: M
```
`--correction-level L|M|Q|H` 将代码密度换成损伤容忍度(默认 `M`);`--size N` 设置每个模块的像素放大倍数(默认 `10`),而不是整体图像边长 — 报告的 `width`/`height` 是实际生成的图像,因为模块数量取决于有效载荷长度和纠正级别。未知纠正级别是 `bad_request`/`invalid_correction_level`,退出 `64`。
`doctor` 报告此处运行的内容,加上派生区域的 OCR 语言和(当 `ask` 可用时)它当前可以回答的语言:
```yml
$ macvis doctor
ocr: available
find: available
sort-faces: available
barcode: available
ask: "unavailable: needs_macos_27_sdk"
ocr_languages:
- ko-KR
- en-US
ask_languages: []
```
`ask_languages` 镜像 `ask` 的自身状态 — 当 `ask` 本身不可用时为空(包括在 macOS 26 上,此时仅限文本模型可用,而基于图像的 `ask` 不可用),并且在 `ask` 报告 `available` 时为完整的一组约 24 种支持语言。一旦就绪,`ask`不限于设备的系统语言 — 它用提示的语言流利地回答,而不是一种 `--lang` 样式的覆盖。
## 从 LLM 代理使用
两种等效的集成 — 两种都运行相同的 `VisionService` 引擎,因此输出相同。
**MCP 服务器(stdio)** — `macvis mcp` 说 stdio JSON-RPC 并公开 `ocr` / `find` / `barcode` / `qr` / `make-qr` / `doctor` 作为工具(加上 macOS 27 构建上的 ask):
```json
{ "mcpServers": { "mac-vision": { "command": "/path/to/macvis", "args": ["mcp"] } } }
```
**MCP 服务器(HTTP)** — `macvis serve` 为非 Mac 或远程节点运行 HTTP JSON-RPC 端点。默认为 `0.0.0.0:9090`;使用 `--host` / `--port` 限制:
```bash
macvis serve --host 127.0.0.1 --port 9090 # 仅限环回(最安全)
macvis serve # 所有接口 — 启动时警告;用防火墙限制
```
配置远程节点使用 `type: http` 和 Mac 的局域网地址:
```json
{ "mcpServers": { "macvis": { "type": "http", "url": "http://192.168.x.y:9090/mcp" } } }
```
远程调用者将图像作为 `data` 字段中的 base64 传递,而不是 `path`。没有内置身份验证 — 将其视为 LAN 上的文件系统读取服务,并相应地保护。
**Claude 代码技能** — 该存储库在 [`skills/macvis/`](skills/macvis/SKILL.md) 中附带了一个。将其符号链接到您的技能目录:
```bash
ln -s "$PWD/skills/macvis" ~/.claude/skills/macvis
```
代理然后在自然语言触发器上调用 `macvis`(从图像读取文本,查找 UI 元素的坐标...)。技能从您的 `PATH` 调用 `macvis`,因此请先安装它(参见 [安装](#install))。
## 架构
单个 `VisionService` 接缝执行每个请求,并由 CLI 和 MCP 服务器共享,因此两者产生相同的输出。调用在进程内运行 — Vision OCR 没有沉重的模型需要保留,而 MCP 服务器已经是长寿命的,因此没有守护进程需要管理。
## 许可证
MIT © 2026 Kim Junmo