Apple的设备端模型在聊天方面表现糟糕,但在结构化输出和工具调用方面表现出色

我花了几周时间对Apple的设备端模型进行压力测试——这是一个约3B参数的模型,运行在任何Apple Silicon Mac的Neural Engine上。为了全面测试,我构建了Think Local,这是一个macOS应用,可以测试模型的每项功能:聊天、图像生成、结构化输出、工具调用和参数比较。 我的结论:作为聊天机器人,这个模型表现糟糕。但作为结构化输出和工具调用引擎,它出人意料地优秀。 这种区别很重要,因为它完全改变了你应该如何使用这个模型。 聊天表现令人失望——但这没关系 Apple的模型上下文窗口只有4,096个token。对比一下:Claude有100万个token,GPT-4o有128K。使用Apple的模型时,你放入200个token的系统提示,150个token的模式定义和三轮对话,就已经用了70%。 自由文本的质量也不令人印象深刻。回答正确但通用,长会话中重复性强,安全防护机制经常出现令人困扰的误报——问它网络安全相关问题,有时会拒绝回答,因为它对"攻击"这个词理解过于字面化。 如果你把它当聊天机器人来评估,它就是一个平庸的模型。但这样评估就像批评螺丝刀不是好锤子一样。 闪光点:约束解码 这里一切都不同了。Foundation Models支持@Generable——一个将Swift结构体转换为模式的宏,模型必须遵守这个模式。这不是"请求JSON然后祈祷"。这是约束解码:在生成过程中,模型字面上无法输出违反模式的token。 @Generable struct BugReport { @Guide(.anyOf(["bug", "feature", "task"])) var type: String @Guide(.anyOf(["low", "medium", "high", "critical"])) var priority: String var title: String var description: String } 使用这个模式,你告诉它"分类:应用在旋转设备时崩溃",它会返回: { "type": "bug", "priority": "high", "title": "Crash on device rotation", "description": "The application crashes when the user rotates..." } 受限字段(type、priority)始终有效——它不能编造列表之外的值。自由字段(title、description)连贯且简洁。我用几十种不同的输入进行了测试:在200多次执行中,模式错误为零。 在这个模型中,自由生成和约束解码之间的差异是巨大的。这就像让初级开发者随意写作与给他一个有定义字段的表单之间的区别。表单总是获胜。 工具调用:一个知道自己不知道什么的3B模型 这是最让我惊讶的。定义一个工具get_weather(city: String),问它"马德里天气如何?",它会生成一个带有正确参数的结构化调用。问它"法国的首都是什么?",它会直接回答——它知道不需要工具。 一个3B参数的模型,在你的笔记本电脑上运行,无需网络,能区分何时使用工具,何时不用。它不完美——对于模糊的提示有时会困惑——但在明确输入上的准确率很显著。 Apple的工具调用使用相同的约束解码机制:调用是一个@Generable结构体,所以参数始终有效。没有损坏的JSON解析,也没有编造的参数。 Image Playground:没人提到的另一个模型 Apple Intelligence不仅仅是文本。Image Playground是一个独立的框架,在设备上生成三种风格的图像:动画、插图和素描。它也完全在Neural Engine上运行,无需网络。 模式重复:对于它设计的用途,它工作得很好。图标、贴纸、简单构图——结果出人意料地好。图像中的文本、详细的人体解剖学、复杂构图——灾难性的。 Think Local包含一个图像工作室,你可以在其中测试提示并并排比较风格。通过十分钟的提示测试获得的直觉是任何基准测试都无法提供的。 数据 在Apple Silicon Mac上测量,使用Think Local的资源监视器: 指标 值 生成速度 ~40 tok/s 冷启动(无预热) ~800ms 冷启动(有预热) ~200ms 模型内存 ~1.2 GB 上下文窗口 4,096 tokens 参数 ~3B 电池影响 最小(Neural Engine) 电池数据很重要:Neural Engine在推理方面的消耗明显少于CPU。在生成过程中,CPU因为数据封装和UI略有上升,但繁重的工作交给Neural Engine。这使得在后台使用模型进行工具开发成为可能——git钩子、代码检查器、分类器——而不会耗尽笔记本电池。 ...

2026年4月7日 · Fernando

我花了 $15 百万 token 写了 'fix: typo'

昨天我用 Claude Code 写了一条 commit message。diff 是一行修改:一个注释里的拼写错误。Claude Opus 读取了 diff,思考了两秒钟,生成了 fix: correct typo in auth comment。为此,它用了大约 800 个输入 token 和 30 个输出 token,分别花费 $15 和 $75 每百万 token。总成本:不到一分钱。但是,把这个过程放大到一天 40 次 commits,250 个工作日,一家公司有 200 名开发者使用 coding agents,那么这些看似微不足道的花费会积累成数千美元的开销,付出的只是等同于贴创可贴的智力劳动。 问题并不是 Opus 太贵。问题在于 coding agents 不会区分 $0.001 的任务和 $0.10 的任务。一切都通过同样的大模型执行。生成 commit 信息、分类一个 issue、验证格式 —— 全部使用高成本的模型,就像雇用一位外科医生来贴创可贴。 数据与成本 我们用 Claude Opus 4(上一代,目前大部分生产环境还在用的版本)的价格来算一个账: 任务 输入 Token 数 输出 Token 数 成本 生成 commit 信息(小型 diff) ~800 ~30 $0.014 分类某个 issue ~500 ~50 $0.011 验证 commit 格式 ~300 ~20 $0.006 生成 standup 报告 ~2000 ~200 $0.045 这些任务都不需要一个拥有 2 万亿参数和多步推理能力的大模型。这些仅仅是带有强约束的分类和生成任务。本质上就像是根据颜色对卡片进行分类。 ...

2026年4月5日 · Fernando

你的 Mac 自带一款免费的 LLM,你可能还没用上

你每个月可能花费 20 到 200 美元来访问 LLM(大型语言模型)。Claude、GPT、Gemini,无论哪一个都在烧你的钱。而这些模型从你的脚本和开发工具调用的大多数场景都可归结如下几类: “把这个错误分类到这五个类别之一。” “给这个变量起个名字。” “告诉我这个 commit 是 fix、feat 还是 refactor。” “用两句话总结这段文字。” 与此同时,你的 Apple Silicon Mac 上还坐着一个拥有 30 亿参数的语言模型:全系统集成、无需支付费用、无需网络连接、无需 API 密钥、甚至不需要网络延迟。而你大概根本没用过。 基础模型框架(Foundation Models Framework) 自 macOS 26 (Tahoe) 起,Apple 推出了 Foundation Models Framework,允许访问 Apple Intelligence 支持的语言模型。这是一个原生的 Swift 框架,适用于 macOS 26、iOS 26 和 iPadOS 26,兼容所有支持 Apple Intelligence 的 Apple Silicon 设备。 值得注意的不仅仅是它免费——这的确很棒,更特别的是它生成 Swift 类型化输出。它不会返回需要你用正则表达式和上帝保佑才能解析的 String,而是直接输出一个结构体(struct)。 import FoundationModels @Generable struct CommitClassification { @Guide(description: "The type of change") @Guide(.anyOf(["fix", "feat", "refactor", "test", "docs", "chore"])) let type: String @Guide(description: "One-line summary of the change, max 72 chars") let summary: String } --- `@Generable` 宏告诉框架在编译时生成架构(schema)。语言模型利用这个架构生成结构化输出。`@Guide` 则限制了可能的值——通俗地说,你给模型铺好了轨道,它就不会出轨。 以下是用法示例: ```swift let session = LanguageModelSession(instructions: """ You are a commit message classifier. Given a git diff, classify the change and write a summary. """) let diff = "..." // 你的 git diff 数据 let result = try await session.respond( to: "Classify this diff:\n\(diff)", generating: CommitClassification.self ) print("\(result.type): \(result.summary)") // "fix: handle nil response in auth flow" 就是这样。没有 URLSession(网络请求),也没有 API 密钥,也不需要解析 JSON,不需要 try? JSONDecoder().decode(SomeType.self, from: data)。整个模型在设备内部运行,依托于你 Mac 的 Neural Engine(神经引擎),并返回 Swift 类型数据,编译器将会为它进行类型检查。 ...

2026年4月4日 · Fernando