模型 / 数据集
Arthur-Ficial/apfel avatar
Arthur-Ficial/apfel

apfel:把 Mac 自带的 Apple FoundationModels 接成 UNIX 工具和本地 OpenAI 服务

The free AI already on your Mac. CLI tool, OpenAI-compatible server, and interactive chat — all on-device via Apple Intelligence. No API keys, no cloud, no downloads.

6,384 个 Star245 个 ForkSwiftMIT

秒懂

它是什么?
apfel 是一个 Swift 写的命令行工具,把 Apple Silicon 上内置的 FoundationModels 暴露成管道友好的 CLI 和 http://localhost:11434/v1 接口。它不下载模型、不需要 API key,代价是 macOS 26 Tahoe 起步、4096 token 上下文,以及被系统护栏和系统版本牵着走。
适合谁用?
如果你的机器是 Apple Silicon、已升级到 macOS 26 Tahoe 并开启了 Apple Intelligence,apfel 值得先跑三条命令验证:brew install apfel、apfel --count-tokens -f 你的长文档 "Summarize this"、以及 apfel -o json "Translate to German: hello" | jq .content。前者告诉你 4096 token 的窗口是否够用,后者确认结构化输出在你机器上按预期工作。
能商用吗?
可以。MIT 是宽松许可证:你可以使用、修改并销售基于它的软件,只需保留版权和许可证声明。
还在维护吗?
在维护。仓库最近一次提交在 1 天前。
用什么语言写的?
主要是 Swift(依据 GitHub 的语言统计)。

以上回答依据项目的 GitHub 数据(最近同步于 2026年9月15日)和我们的分析,不构成法律意见。

开源项目深度解析

它解决的是哪一类麻烦

大多数本地 LLM 方案的第一步是下载权重:几 GB 到几十 GB,占磁盘、要显存、还得挑量化版本。apfel 走的是另一条路,README 的第一句话就是 Apple Silicon Mac 已经内置了一个 LLM,通过 Apple FoundationModels 提供,apfel 只是把它暴露出来。所以它的用户画像很具体:手里是 M1 及以后的 Mac,系统已经升到 macOS 26 Tahoe,Apple Intelligence 已经打开,想在不引入任何外部依赖的前提下,让 shell 脚本里多一个能理解自然语言的环节。

典型场景是那些不值得调用云 API 的小任务。把 git diff 按仓库约定过一遍、从 PDF 里抽关键结论、把一段英文提示翻译成 shell 命令、给本地跑着的 OpenAI SDK 一个能直接用的 base_url。这些任务的共同点是输入输出都很短,失败也无所谓,重跑一次就行。apfel 的定位正好卡在这里:它不是要替代 Ollama 或 llama.cpp,而是让系统里已经存在的那块算力变得可编程。README 里那句 no API keys, no cloud, no downloads 不是营销话术,而是这个项目全部价值的前提。

三种入口共用一套 FoundationModels 调用

apfel 对外有三个形态:UNIX 工具、OpenAI 兼容服务、交互式 REPL,但底下是同一层。README 的表格把它们并列:apfel "prompt" 或 echo "text" | apfel 得到管道友好的答案,apfel --serve 得到一个可以塞进 OpenAI SDK 的 http://localhost:11434/v1 后端,apfel --chat 进入交互模式。

服务端的模型名固定为 apple-foundationmodel,README 给出的 curl 例子和 Python 例子都用这个名字。这意味着任何按 OpenAI 协议写的客户端,只要把 base_url 指过去、api_key 随便填,就能跑起来,代码里不需要任何 apfel 特有的分支。工具调用在三种上下文里都可用,这一点 README 明确写了。

上下文窗口是运行时读取的,不是写死的常量:macOS 26 上是 4096 token,macOS 27 上是 8192。这个设计说明 apfel 没有自己维护一份模型配置,而是直接问系统当前能给多少。好处是系统升级后不用改 apfel;坏处是同一个脚本在不同系统版本上行为不同,这一点后面单独说。

安装与第一次调用

前置条件在 README 里写得很直白:macOS 26 Tahoe 及以上、Apple Silicon M1+、Apple Intelligence 已启用。三者缺一,apfel 装上也跑不出结果。

Homebrew 是主路径:

brew install apfel

升级用 brew upgrade apfel。想从源码构建,README 说不需要 Xcode,只要装了 macOS 26.4 SDK 和 Swift 6.3 的 Command Line Tools:

git clone https://github.com/Arthur-Ficial/apfel.git && cd apfel && make install

第一次调用建议从简单的开始,确认系统这层通了:

apfel "What is the capital of Austria?"

管道用法是它作为 UNIX 工具的核心:echo "Summarize: $(cat README.md)" | apfel。附件用 -f,可以叠加,README 举的例子是对比两个 Swift 文件:apfel -f old.swift -f new.swift "What changed between these two files?"。PDF 和图片也走 -f,README 说是设备端做文本提取、OCR 和图像内容判断,不需要联网。

脚本里最实用的两个开关是 --code 和 -o json。--code 只输出代码,不带说明文字和 markdown 围栏,README 说如果结果为空会以退出码 7 结束,所以可以直接重定向进文件:apfel --code "a python function that deduplicates a list" > dedupe.py。要更严格的结构,用 --schema 指向一个 JSON Schema 文件,README 称这是 guided generation,输出保证符合 schema。

服务端后台运行走 brew services start apfel,README 把它类比成 Ollama 的用法,另外支持两个环境变量:APFEL_TOKEN 设置访问令牌,APFEL_MCP 指向工具脚本。

MCP 工具调用与退出码构成的可组合性

apfel 用 --mcp 挂载 Model Context Protocol 服务器,README 的示例是 apfel --mcp ./mcp/calculator/server.py "What is 15 times 27?"。这个例子的输出分层值得注意:工具发现和调用过程走 stderr,最终答案走 stdout。

这个分层不是随手为之。它意味着你可以把 stdout 直接喂给下一个命令,而调试信息留在终端上可见,或者被重定向丢弃。同样的思路贯穿其他设计:-q 安静模式让赋值语句干净,result=$(apfel -q "Capital of France? One word.");--code 保证管道里没有多余字符;-o json 配合 jq 取字段。这些都是把 LLM 当成一个行为可预测的命令行程序来对待,而不是当成一个需要人工阅读的对话窗口。

--count-tokens 是这个思路里最实用的一条:apfel --count-tokens -f README.md "Summarize this" 会在真正发送前算出 token 预算。在 4096 的窗口下,这不是锦上添花,而是避免静默截断的必要步骤。

4096 token 和系统护栏是两个硬约束

apfel 的能力上限不在它自己手里。README 明确写出上下文窗口在 macOS 26 上是 4096 token,macOS 27 上才是 8192,并且是运行时读取的。4096 是什么概念:一份中等长度的 README 加上一段 diff 就可能吃掉大半。README 里那些看起来很长用法的例子,比如 apfel -f README.md "Summarize this",实际能不能跑通取决于你那份 README 有多长。用 --count-tokens 先量一下,比事后猜测为什么摘要缺了一半要省事。

第二个约束是 Apple 的系统护栏。README 提供了一个 --permissive 开关,说明是 reduces guardrail false positives for creative/long prompts,示例是让它写一段惊悚小说的开头。反过来说,默认模式下的误报是真实存在的,否则不需要这个开关。而 --permissive 只是降低误报,不是关掉护栏。

第三个约束是模型本身不可控。apfel 没有权重文件,模型随 macOS 更新而变。同一个 prompt 在 26.0 和 26.4 上得到不同结果,这不是 bug,而是这个架构的必然结果。如果你的输出需要可复现,比如要写进测试用例或做回归对比,apfel 不适合承担这个角色。

和 Ollama 的差别在模型归谁管

最自然的对照是 Ollama,两者都提供本地 OpenAI 兼容接口,README 也主动把自己和 Ollama 相提并论,端口是 11434,后台服务用 brew services 管理。差别在于模型从哪来、归谁管。

Ollama 自己下载和管理权重,你可以指定具体模型和量化版本,可以固定在一个已知的 tag 上,上下文长度由模型和你的配置决定,通常远超 4096。代价是磁盘占用、首次下载时间,以及你得自己跟上模型更新。

apfel 反过来:零下载、零磁盘占用、零模型管理,但你也就失去了对模型的一切控制权。选哪个取决于你更怕什么。怕的是环境不可控、结果不可复现,选 Ollama。怕的是在每台开发机上装一堆权重、维护一套模型版本,而任务本身只是把 diff 读一遍,选 apfel。两者并不互斥,同一台机器上 apfel 占 11434,Ollama 换个端口即可共存,脚本里按任务性质分流。

维护成本与 MIT 许可下要注意的事

apfel 的版本节奏可以从发布记录看出来:v1.9.0 在 2026 年 8 月 2 日,v1.9.1 在 8 月 5 日,v1.10.0 在 9 月 7 日。一个月左右一个功能版本,中间夹着补丁版本。这个节奏说明它还在活跃开发,也说明接口在小版本之间可能调整。README 里有一句容易被忽略的提示:升级之后要重新执行 apfel demos ./apfel-demos 来刷新示例脚本。因为 demo 是编译进二进制的,brew upgrade 之后磁盘上那份旧脚本不会自动更新。这是升级流程里一个具体的、必须手动做的动作,不是可选项。

许可方面,仓库标注 MIT。这意味着你可以把它嵌进内部工具链、修改源码、随产品分发,只要保留版权声明和许可文本。但有一层 MIT 覆盖不到的东西:apfel 调用的是 Apple 的 FoundationModels 框架,你实际使用这套推理能力时,受的是 macOS 和 Apple Intelligence 的条款约束,而不是 apfel 的 MIT 许可。这两件事要分开看。以上只是对仓库标注和 README 的陈述,不构成法律意见,真要商用分发请自行核对 Apple 的相关条款。

另一个维护成本来自系统依赖:apfel 的可用性绑定在 macOS 26 Tahoe 和已启用的 Apple Intelligence 上。团队里只要有一台机器没升级或没开这个功能,脚本就会在那里失败,而且失败点不在 apfel 的代码里。

编辑结论

如果你的机器是 Apple Silicon、已升级到 macOS 26 Tahoe 并开启了 Apple Intelligence,apfel 值得先跑三条命令验证:brew install apfel、apfel --count-tokens -f 你的长文档 "Summarize this"、以及 apfel -o json "Translate to German: hello" | jq .content。前者告诉你 4096 token 的窗口是否够用,后者确认结构化输出在你机器上按预期工作。只做一次性、可重试的辅助任务,比如把 git diff 交给它按约定审查、把 PDF 摘要写进脚本、给本地 SDK 一个不花钱的 base_url,它是合适的。反过来,如果你的项目要跨平台、要长上下文、要可复现的模型版本,或者需要把推理结果作为审计证据长期留存,apfel 是错的工具:它的模型随 macOS 更新而变,上下文窗口由系统在运行时决定,输出还受 Apple 的护栏影响。真正要先验证的不是 apfel 本身,而是你的 Mac 上 Apple Intelligence 是否真的可用,因为 apfel 只是这层系统能力的转发者,不是替代品。

官方来源

  1. Arthur-Ficial/apfel on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
社区笔记

社区笔记