Cloudflare "Ask AI" 创建了一个拥有我整个账户访问权限的 API 令牌

上周,在审计我 Cloudflare 账户的 API 令牌时,我发现了一个令牌,而我从未创建过它:“Cloudflare Agent Token - 2026-04-28”,这是由 Cloudflare 控制台的 AI 助理(“Ask AI”)创建的。\n\nCloudflare 自己的提示框表明该令牌存在是为了让 AI 能够_“理解你的环境并代表你行动”_。\n\n根据令牌摘要页面,它实际授予的权限是读取所有账户、所有区域和所有用户的权限——超过 160 个权限。所有权限的操作都以:Read结尾:它无法_修改_任何内容。但“只读”这个词显得过于简单化。权限列表包括 Secrets Store:Read、Access: Keys:Read、Access: Service Tokens:Read、Zero Trust: PII:Read、Logs:Read、Account Audit Logs:Read、Billing:Read、API Tokens:Read,以及你拥有的所有 DNS、Access 和身份供应商配置。\n\n此外,这些权限永不过期。\n\n如果这样的令牌泄露,这不只是意味着“攻击者可能重新配置你的基础设施”,它还代表了全面的数据识别和泄露:你的安全态势、日志、个人身份信息(PII)、你的组织和用户的结构——所有数据都可以一次性轻松读取。对于大多数团队来说,这本身就构成了需要报告的安全漏洞。\n\n我使用了“Ask AI”功能。这创建了一个具有全面账户权限并且永久有效的凭据,它在我的账户里存在了三周,直到我偶然发现它——由于没设有效期,它将永远保持有效。没有人以显著的方式通知我“向 AI 提问”会导致这种情况发生,而“Ask AI”也并没有建议“创建一个永久的代理,可以读取你所有的数据”。\n\n一个回答问题的 AI 助理只需要在对话期间针对问题的局部读取权限。而一个永久的凭据能够读取你整个数字资产,这是完全不同的概念,且必须是一个知情的、可见的、经过慎重考虑的决定。\n\n检查你的账户:dash.cloudflare.com/profile/api-tokens。如果你看到 “Cloudflare Agent Token” 而且你不使用该代理,请立即撤销它。\n\n是的,它是只读的、第一方的和可撤销的。但它永不过期,且从未明示给我——因此“可撤销”毫无意义,因为你根本不知道它甚至存在。没有任何理由证明,赋予一个永久读取你所有秘密、日志和个人身份信息权限的令牌能符合“向聊天机器人询问问题的需求”。 本文原文为西班牙语,借助AI翻译。

2026年5月21日 · Fernando

Sentry 前端被 Brave 浏览器屏蔽:如何通过隧道解决问题

一位学生从 Brave 浏览器中进行 KeepCoding 的心理测试时报告了一个问题,但该问题从未成功上传到 Sentry。团队技术支持人员查看了控制面板,却没有发现任何内容,便让他再次测试。同时,针对生产环境的 Playwright 烟雾测试显示所有情况正常:SDK加载,事件被处理,Sentry.flush()返回了true。一切看起来都没有问题。 依据不完整数据做出的产品决策比凭直觉合理性决策更糟,因为它们是基于虚假的数据安全感做出的。 背景:为什么 Brave 的情况特别重要 Brave 是一款内置广告屏蔽功能的浏览器,称为 Shields(保护盾)。它可以在默认情况下过滤广告和追踪器,而无需安装额外的插件。根据 Brave Software 2024年公布的公开数据,该浏览器的月活跃用户已经超过8000万。这一数字之所以重要,是因为用户分布并不均匀:Brave 的用户基础更倾向于技术人员、开发者和新潮用户。 对于面向普通大众的应用,这种偏向可以忽略不计;但对于以开发者为目标群体,例如针对开发者训练营申请者的技术评估应用来说,首批报告错误的用户极有可能来自使用 Brave 的人。 类似的情况也发生在使用 uBlock Origin 的 Chrome 或 Firefox 用户,以及启用了 **严格追踪保护(Strict Tracking Protection)**的 Firefox 配置用户,或通过企业网络使用 Pi-hole DNS阻止机制的用户。这些类别的交集——即启用了某种制止追踪器的积极拦截机制的用户——据相关阻止名单的覆盖研究显示(如 EasyPrivacy 用户超过400万订阅者),很容易占据技术流量的15-20%。 问题:保护盾会屏蔽两项内容,而不仅仅是一项 Sentry 的浏览器 SDK 以两个阶段工作。在第一阶段,浏览器从 Sentry 的 CDN 下载软件开发包的 JavaScript 包,通常位于 js-de.sentry-cdn.com 或 browser.sentry-cdn.com 下。在第二阶段,SDK 初始化后,将捕获到的事件发送到以 *.ingest.sentry.io 为主机的摄取端口(endpoint)。 Brave 的保护盾(Shields)会检查两个列表:一个是浏览器的全局列表,一个是针对具体网站启用的列表。关闭保护盾仅适用于网站域名,不影响全局列表。而全局列表中包括以下一些域名: *.sentry-cdn.com *.ingest.sentry.io *.ingest.de.sentry.io 此问题已在 Brave 社区的公共讨论线程中 “Brave blocks sentry endpoint even with shield down for website” 提及,但在 Sentry 官方文档中并未做出明确警告。实际后果是,使用 Brave 的用户会在控制台看到两个错误: ...

2026年5月18日 · Fernando

导致苹果CSAM系统崩溃的对抗性碰撞(及其对苹果以外的广泛影响)

这篇文章是“64比特决定你能上传什么到互联网”的技术后续。如果你还没读过它,请先阅读。这里我们假定你已经理解了什么是感知哈希以及为什么PhotoDNA、PDQ和NeuralHash是密切关联的。 2021年8月5日,苹果宣布推出NeuralHash。仅仅13天后——8月18日——匿名研究员Asuhariet Ygvar在GitHub上发布了从iOS二进制文件中提取的完整模型的逆向工程。数日后,两个独立的研究人员——Brad Dwyer及其合作者——公布了碰撞实例:两张视觉上完全不同的图像却生成了相同的哈希值。苹果承诺其系统的一年每账户误报率为“万亿分之一”,然而事实证明,这个系统可以用普通消费级硬件成功攻击。 公众舆论将焦点放在“苹果出了错”。但后续技术分析却表明事实相反:苹果并未犯错。对抗性脆弱性是感知哈希家族的一种结构性特性。如果有问题,NeuralHash可能是市场上最复杂的设计之一。 五年后,欧盟正在制定法律,强制在WhatsApp、Signal和Telegram中部署同样的技术。这项法规假定该算法是一种不变的基础技术,如同SHA-256一样。然而事实并非如此。 偶然碰撞与对抗性碰撞 熟悉密码学哈希的读者可能会有一个直觉模型:碰撞是一个罕见的、偶然的事件,其概率可以通过2^(-n)来计算,其中n为比特数。对于SHA-256来说,需要2^128次操作来找到一个碰撞——这在已知的计算基础设施下难以实现。 感知哈希属于另一类对象。这一区别非常重要。 **偶然碰撞。**两张合法图像因偶然因素生成了相同的哈希值。对于64比特的感知哈希,概率并非2^(-64),而远大于这个值,因为“合理”图像(人类生成的图像,而非随机噪声)具有统计规律性。实际概率取决于数据集分布,远高于理论上限。 对抗性碰撞。有意生成两张图像刻意使其产生相同的哈希值。这里的区别是质的。在感知哈希中: 哈希空间很小(64-96比特)。 哈希函数“平滑”——像素的小扰动会导致哈希值的小变化。这一特性是需要的(对重新编码的容忍度),但也带来了攻击性(容易被攻击)。 基于CNN的哈希(如NeuralHash)是可微的。攻击者可以使用梯度下降直接找到碰撞。 传统哈希(例如pHash、PDQ)在同样意义上并非可微,但可以通过局部搜索和标准机器学习启发式方法进行攻击。 实际而言:在消费级GPU和PyTorch工具支持下,一个研究生可以在一个下午解决感知哈希的对抗性碰撞问题。 三种攻击类型及其不同后果 2021-2023年的学术文献区分出三种攻击方式,每种都具有不同的操作影响。 任意碰撞 给定哈希算法H,找到两张图像x₁和x₂,它们视觉上完全不同,但满足H(x₁) = H(x₂)。这是最简单的攻击:如果哈希空间很小,它就会自然发生。Ygvar在2021年8月发布的碰撞就是这种类型:一只狗和一片灰色的风景,它们视觉上毫无关系,但生成了相同的NeuralHash。 **操作用途:**降低系统的可信度。如果能够公开展示碰撞,前提“哈希是可靠的标识符”便会瓦解。 定向预影 给定目标哈希值h₀(比如从NCMEC数据库提取或估计的值),生成一个视觉上无害的图像x,使得H(x) = h₀。这种攻击才是实际操作中最令人担忧的。 **操作用途:**发送图片给受害者。攻击者生成一张猫的照片,它具有与已知CSAM材料相同的哈希值,然后通过WhatsApp发送。在系统扫描触发警报后,即使人工审查确认图片为无害,过程依然耗费了时间、法律资源(在某些情况下)以及对受害者的污名化。如果规模化——同时针对数千名受害者——系统将变得不可操作。 苹果在2021年表示该攻击不太可能发生,因为NCMEC数据库是封闭的,攻击者无法知道目标哈希值。然而Prokos等人(USENIX Security 2023)证明该论点站不住脚:攻击者不需要每个具体哈希,只需要对目标集的参考图像拥有访问权限,而在现实世界中,拥有这种访问权限对高级黑客来说并不困难。 规避 已知一张图像x(例如NCMEC数据库中的CSAM材料),生成一个修改后的图像x’,视觉上与x几乎一致但生成不同的哈希值。这种攻击破坏了系统实现其声明用途的能力。 **操作用途:**真正的CSAM分发者对其材料应用该攻击。即使对人类来说修改后的图像几乎像素级相同,系统扫描无法检测到修改后的副本。新的材料加入NCMEC数据库的速度比对抗性变体的增长速度慢,覆盖率随着时间的推移而恶化。 NeuralHash案例详细分析 NeuralHash崩溃的时间线具有教育意义。 **2021年8月5日。**苹果宣布推出CSAM检测套件。发布的技术文档声明每年每账户误报率为1万亿分之一,基于对参考数据集的内部测试。 **2021年8月18日。**Asuhariet Ygvar在GitHub上发布了AppleNeuralHash2ONNX。该项目从iOS 14.7的二进制文件中提取了NeuralHash模型,并将其转换为ONNX格式,可在任何设备上运行。代码无需特权访问:任何拥有越狱过的iPhone或静态内核分析能力的用户都能提取CoreML模型。 **2021年8月19日。**该项目的用户首次公开碰撞示例:两张视觉上截然不同的图像(collision1.png和collision2.png)在NeuralHash下生成了相同的96比特哈希。该技术基于提取的模型进行梯度搜索,大约需要50行PyTorch代码。 **2021年8月20日至27日。**苹果确认示例碰撞风险确实存在,但坚称从操作角度看,这些问题并无问题,理由如下:(a)NCMEC数据库是机密的,(b)需达到30次匹配才能触发警报。批评者回应称:(a)数据库详细内容无需全部公开,只需要渠道获取目标集中的参考图像,(b)当攻击者可以随意创建N次碰撞时,30次门槛变得微不足道。 **2021年9月。**苹果宣布延期。幕后决策是由于无法在不公开承认架构设计缺陷的情况下技术性捍卫系统。 **2023年。**Prokos、Fendley、Green、Jois和Cao发表了论文《Squint Hard Enough: Attacking Perceptual Hashing with Adversarial Machine Learning》(USENIX Security)。这篇论文对NeuralHash、PhotoDNA(黑盒)和PDQ的三种攻击类型进行了形式化研究。实验结果表明使用标准的对抗性机器学习工具,攻击成功率超过80%。该研究结束了学术争论:脆弱性并非NeuralHash的漏洞,而是哈希家族的结构特性。 那么PhotoDNA和PDQ呢? 有人偶尔会提出这样一个论点:“NeuralHash基于CNN,因此是可微的;而PhotoDNA是传统方法,因此是安全的”。这是错误的。 PhotoDNA是微软的专有技术。我们无法审核其确切实现。然而,Prokos等人展示了黑盒攻击:攻击者无需访问算法,只需通过使用该算法的服务的输入/输出行为。在实验条件下,对PhotoDNA进行黑盒攻击的碰撞生成率为75-80%。 Meta的PDQ是开源的。任何人都可以研究代码并使用梯度进行攻击。Prokos等人用与NeuralHash相同的技术成功攻破了它,虽然成功率略有差异但大致相当。 其根本原因是:所有感知哈希必须是“平滑”的才能实用。如果不“平滑”,哈希无法容忍重新编码或小的改变,也就失去了目的。如果“平滑”,则可以被攻击。平滑性和对抗性防御之间在结构上不可兼得。 PhotoDNA、PDQ、pHash、dHash、aHash、NeuralHash:这些感知哈希都存在可被攻击的风险。过程中有难易程度与成功率的差异,但它们无一能够幸免。在学术文献中,没有一种感知哈希可以同时实现操作容忍度与对抗性鲁棒性。这个问题至今仍未解决,理论上可能在不放弃其中一种特性时无法解决。 对法规的影响 这应该是Chat Control辩论中最重要的问题。 欧洲委员会提出的CSA Regulation要求通信服务提供商通过客户端扫描检测加密消息中的CSAM。这项技术中立的提案提到了“感知哈希匹配”作为可接受的方法之一。关键问题在于:该法规将这一算法视为不变的技术基础,仿佛它是密码学上稳定的。 事实并非如此。由此产生的操作后果是可以预测的。 **复杂攻击者可规避。**具有一定技术知识的实际CSAM分发者利用学术文献中已发表的规避技术修改其材料。这些材料通过系统扫描时不会触发警报。法规所承诺的检测无法实现真正的目标。 **普通用户容易受到攻击。**攻击者生成带有已知CSAM哈希值的图像,并将这些图片大规模发送给受害者(政治对手、前伴侣、记者、持不同政见者)。警报触发后启动法律流程,证明无辜的责任落在受害者身上。该系统为法律骚扰打开了新的途径,难以被轻易排除。 **系统针对普通用户而非真正犯罪分子。**那些通过非常基础手段传播材料的用户——在很多情况下并没有明确的恶意——最终成为被捕的对象。而法规实际要追查的犯罪分子并没有受到真正影响。 这三种效应的结合导致了一个关键问题:系统在检测到真实犯罪情况所需的代价/实际案例随着部署规模增加而升高,同时系统的真实阳性与虚假阳性比率不断恶化。在某些规模上下,系统产生的噪音超过了信号。NCMEC关于PhotoDNA在异构场景中的实际效率研究表明我们可能已经接近这个极限,但公开证据由于供应商的利益而存在偏差。 ...

2026年4月18日 · Fernando

64位决定你能上传什么到互联网:Chat Control背后的算法

2021年8月,苹果宣布将在每张照片上传到iCloud之前扫描你的iPhone照片。同年9月,在两周的争议后撤回了提案。2022年12月,官方宣告计划终止。与此同时,2022年,欧盟委员会提出了一项规定,要求WhatsApp、Signal和Telegram执行与苹果撤销的提案完全相同的操作。这项法规,即Chat Control,目前仍在欧洲理事会中推进讨论。 这两项尝试都依赖同一个算法:一个实现于40行Python代码的64位感知哈希算法。这不是夸张,甚至不是比喻。确实只有40行,在阅读完这篇文章后,您可以在自己的机器上运行它的实现版本。 大量的公众讨论——无论是在西班牙还是其他地方——都发生在参与者对该机制的工作原理不了解的情况下。法规的讨论充满了政治色彩(“隐私与儿童安全”对立),而技术核心却如同黑箱。本篇文章将扮演该黑箱的解药。如果读完后您想要发表观点,您可以基于技术事实。如果不想,那至少您已经了解他们让您接受的是什么。 问题:SHA-256无法识别两张图片是同一张 任何开发者第一个冲动的解决方案可能是用SHA-256。如果两张图片生成了相同的哈希值,那么它们就是同一张图片。简单、快速、加密安全。 但这不起作用。 import hashlib def sha256(path): with open(path, "rb") as f: return hashlib.sha256(f.read()).hexdigest() # 同一张图片,不同压缩 sha256("foto.jpg") # "a7f3..." sha256("foto_reencoded.jpg") # "9c2e..." (完全不同) 只改变一个比特——例如JPEG压缩质量从95降低到90,或者从WebP格式转换为JPEG,甚至亮度的微小调整——SHA-256生成的哈希值都会完全不同。数据清晰地证明:加密相似性设计为完全不容忍差异,这是一种特性,而非漏洞。 为了检测“相同的图片即使压缩不同”,需要一个容忍度更高的算法。这意味着需要一个感知哈希:一个能在图片内容不变而细微改变的情况下仍然保持一致的64位签名。 aHash:亮度平均值 最早有用的方案被称为平均哈希(Average Hash)或aHash。其理念非常简单: import numpy as np from PIL import Image def average_hash(path, size=8): img = Image.open(path).convert("L").resize((size, size)) arr = np.asarray(img, dtype=np.float32) mean = arr.mean() bits = (arr.flatten() > mean).astype(int) return "".join(str(b) for b in bits) def hamming(a, b): return sum(x != y for x, y in zip(a, b)) 图像被缩小为8×8像素的灰度图,计算亮度平均值,每个像素亮度大于平均值时为1,否则为0。结果是64位,代表全局亮度分布。 两张“相同”的图片会生成汉明距离很小的哈希值(≤ 5 位不同)。两张不同的图片则会有大的汉明距离(40+ 位)。这种方法能在图片被缩放、稍微裁剪或者重新编码时起作用。但如果有人调整了对比度或全局亮度,aHash就会失效。这是第一步。 dHash:相对梯度 下一步是2011年由Neal Krawetz提出的差异哈希(Difference Hash),简称dHash: ...

2026年4月18日 · Fernando

你的CLI有了新用户,它不是人类

你向你的AI副驾驶要求捕获一个窗口。副驾驶写下peek app "Xcode"。工具尝试寻找一个精确名称为Xcode的窗口,但没有找到,因为实际的进程名是Xcode-16.3。工具打印出Error: application not found。这位情感记忆如金鱼般的副驾驶尝试peek app "Xcode-16.3",成功了。但浪费了一次对话轮次、输入和输出的令牌,还有支付账单的用户的耐心。 现在想象另一种场景:副驾驶写下peek app xcode。工具会自动标准化名称,进行模糊匹配,找到Xcode-16.3,捕获窗口,并返回/tmp/peek/Xcode-16.3-1712524800.png。一个输出令牌。零次无效尝试。 这两种情况的差别不是一个bug,而是一个设计决策。 那些不会看你--help的用户 2025年初,Netlify的CEO Mathias Biilmann创造了术语“智能代理体验”(Agent Experience,即AX),用来描述AI代理在与一款产品互动时所拥有的体验。正如用户体验(UX)关注的是人类用户,开发者体验(DX)面向的是开发者,智能代理体验(AX)则专注于LLM。 这个概念听起来很抽象,直到你把它应用到某些具体的东西上。例如,命令行工具(CLI)。CLI已有40年的历史,其设计一直是为了与人类用户交互:描述性的信息、颜色、高度可视化的进度条以及--help页面。这些对于LLM来说全是“噪音”。一个LLM不会查看帮助信息——它会根据命令名称推断出标志。它不会欣赏绿色的“成功”提示——它只处理纯文本。它也不会观察进度条——它只等待过程完成。 传统CLI的设计旨在让人类用户理解发生了什么,而AX则优化CLI工具,以便智能代理能用最少的令牌和轮次来完成操作。 五项原则,三款工具 在过去的几个月里,我创建了三款秉持同一理念的CLI工具:peek(用于macOS窗口捕获)、lql(用于Linear问题管理)和driftkit(用于智能代理的行为审核工具)。它们都设计成即使没有说明文档,LLM也可以使用。从这些经验中总结出了五项原则。 1. 输出是契约,不是对话 传统的CLI用于窗口捕获时可能会输出类似以下的信息: ✅ Screenshot saved successfully! File: /tmp/peek/Xcode-1712524800.png Size: 1920x1080 Format: PNG 这看起来很漂亮,也很有信息量。但对于需要将路径传递到另一工具的LLM来说完全没用。它不得不解析这个输出,忽略掉表情符号,找到以File:开头的那行,并提取路径。浪费了令牌。 peek只输出一个内容: /tmp/peek/Xcode-1712524800.png 一个路径,没有其他多余信息。LLM直接读取、使用并继续。stdout的输出是一种契约:始终是一个容易解析的路径,始终保持稳定。如果更改格式,就破坏了契约,也会让所有依赖该工具的代理出错。 也就是说:你的stdout是API,而不是用来“装饰”的。 2. 容忍幻觉——不要惩罚它们 LLM会产生幻觉命名。这是一种自然现象,就像地心引力或wifi总是在你赶时间时信号变差。如果你的工具需要准确名称,那就是在向一种基于概率的机器要求精确。这是行不通的。 peek有三种搜索模式以找到应用程序: 精确匹配(不区分大小写):xcode → Xcode 标准化匹配(去除空格和短横线):thinklocal → ThinkLocal 部分匹配:xcode → Xcode-16.3 LLM并不需要知道进程的确切名称。它只需给出一个大致的名字,工具会处理剩下的事情。lql也采取类似的方法来匹配项目和团队的名字——它会根据部分内容将tokamak解析为Tokamak,而无需使用UUID。 原则很简单:如果监督代理的那个人类能够推测出它的意思,那么工具也应该能够做到。 3. 错误信息应该告诉用户怎么做,而不是发生了什么 对比一下以下两个错误消息: Error: application not found in window list Error: "Xcode" is not running. Start it with: open -a "Xcode" 第一个描述了问题所在。第二个则提供了解决问题的方法。人类读了第一个会想“哦,没打开啊。”LLM读到第一个后会……用其他名字试试,或者去Google搜索,又或者发明一个--force标志。而对于第二个,LLM会直接执行open -a "Xcode",等待,然后再试一次。问题在一个轮次内得以解决。 ...

2026年4月7日 · Fernando

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

将 Async Swift 桥接到 Sync C:使用四个函数从任何语言调用 Apple 的 LLM

Apple 的 Foundation Models 框架(macOS 26)提供了一个约 30 亿参数的 LLM,可以在设备端运行,免费,无需 API key。但有个问题:它只能使用 Swift。而且不是普通的 Swift——是 Swift 的 async 版本。 你的工具链是 Python 吗?没有绑定。用 Rust?也没支持。脚本语言 Shell?完全没法用。这个世界上最便宜的 LLM(确实免费)被困在两堵墙后:语言和并发模型。 显而易见的解决方案是搭建一个本地 HTTP 服务器,将模型暴露为 REST API,像 Ollama 那样。但这就像是用大炮打蚊子:一个进程在后台运行,占用一个端口,JSON 来回传递,每次问一个简单的问题都要用到 curl。如果只是给一个 commit 分类为 fix 或 feat,你不需要 HTTP,你需要的只是一个简单的 C 函数。 仅有 4 个函数的 dylib 所以我做了 libfoundationmodels:一个动态库,把 Apple 的框架编译为 .dylib,它仅导出 4 个 C 函数: int32_t fm_init(void); int32_t fm_is_available(void); int32_t fm_generate(system, prompt, output, output_len); int32_t fm_classify(system, prompt, choices, output, output_len); --- 嗯,算上 `fm_generate_json` 是 5 个函数,但核心思想未变:四个概念——初始化、检查可用性、生成自由文本,以及在选项中强制分类。全部同步。全部阻塞。输入缓冲区、输出缓冲区、返回代码。经典的 C 风格。 从 Python 调用它是这样的: ```python import ctypes fm = ctypes.CDLL("libfoundationmodels.dylib") fm.fm_init() buf = ctypes.create_string_buffer(256) fm.fm_classify( None, # 没有系统提示 b"fix: handle nil response in OAuth", # 要分类的文本 b"fix\nfeat\nrefactor\ntest\ndocs", # 选项 buf, 256 ) print(buf.value.decode()) # "fix" 就是这样。没有 requests。没有 urllib。没有 JSON。没有运行的服务器。调用一个 C 函数,它会内部唤醒你 Mac 的 Neural Engine,传入文本,并将结果写回缓冲区。典型延迟:200-800ms。 ...

2026年4月5日 · Fernando

苹果的情感分析认为'删除临时文件'是死亡威胁

NLTagger是苹果的情感分析API。它集成在iOS和macOS中,在设备本地运行,不需要服务器,只需三行代码即可使用。当你搜索"Swift情感分析"时,它是第一个出现的结果。 对于任何开发者在日常工作中会写的文本,它返回以下结果: 消息 NLTagger 实际情况 “delete the temp file” -0.8 中性指令 “ok” -0.8 中性确认 “run make test” -0.6 中性指令 “commit and push” -0.4 中性指令 “great job, thanks!” +1.0 正面(正确) “this is fucking broken” -1.0 负面(正确) 评分范围从-1.0(极其负面)到+1.0(极其正面)。根据苹果的评判,“delete the temp file"与"this is fucking broken"具有几乎相同的情感强度。而"ok”——英语中最中性的回应——得分是**-0.8**。 这些不是编造的数字。这些是在任何运行macOS 14+的Mac上都能重现的结果。 如何重现 import NaturalLanguage let tagger = NLTagger(tagSchemes: [.sentimentScore]) tagger.string = "delete the temp file" let (tag, _) = tagger.tag( at: tagger.string!.startIndex, unit: .paragraph, scheme: .sentimentScore ) print(tag?.rawValue ?? "nil") // "-0.8" 八行Swift代码。结果是确定性的:相同的文本在每次执行、每个设备上都产生相同的分数。这不是随机错误,而是系统性偏见。 ...

2026年4月5日 · 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