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

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

NLTagger与情感分析:为什么Apple认为你的代码很消极

想象一下,你正在构建一个分析开发团队对话的应用程序。你希望检测团队的基调是否健康,或者是否存在压力的迹象。你决定使用Apple的NLTagger,因为它本来就有、免费、支持设备端运行,并且不需要服务器。三行代码搞定,开箱即用。 第一惊喜:句子“kill the process and restart the daemon”(杀掉进程并重启守护进程)的得分是**-0.6**。负面,几乎可以说是敌意满满。接着,“Fatal error in memory allocation”(内存分配出现致命错误)的得分是**-0.8**。而“crash report uploaded successfully”(崩溃报告成功上传)——这是字面上的好消息——得分却是**-0.4**。 你的团队健康状态检测工具刚刚判断出你的开发人员处于情绪崩溃的边缘。而实际上他们只是重启了一个服务而已。 问题所在:为另一个世界设计的模型 NLTagger的.sentimentScore方法会返回一个介于-1.0(非常负面)到1.0(非常正面)之间的值。Apple在iOS 13 / macOS 10.15中引入了它,它依赖于系统集成的设备端模型,无法个性化配置,也无法查看其训练数据。 简而言之:这是一个黑盒子,它给你一个数字并希望你信任它。 对于它最初设计的用途来说,它的表现是相当不错的:例如产品评论、社交媒体评论,以及消费领域的文本,在这些场景中,“horrible”意味着糟糕,“fantastic”意味着极好。这是它的领域。而当你将它应用到其他领域时,问题就出现了。 实验:技术文本 vs. 日常文本 我们来测试一下。这是纯Swift代码,可以直接运行在Playground中: import NaturalLanguage func sentiment(of text: String) -> Double { let tagger = NLTagger(tagSchemes: [.sentimentScore]) tagger.string = text let (tag, _) = tagger.tag( at: text.startIndex, unit: .paragraph, scheme: .sentimentScore ) return Double(tag?.rawValue ?? "0") ?? 0 } --- 现在我们输入一些程序员在日常会说的话: | 句子 | 得分范围 | 实际情感 | | ---------------------------------------- | ----------- | ------------------------------------- | | "Kill the background process" | -0.5 ~ -0.7 | 中性(技术指令) | | "Fatal error: index out of range" | -0.7 ~ -0.9 | 中性(编译器消息) | | "Abort the deployment" | -0.4 ~ -0.6 | 中性(操作性决策) | | "Destroy the old database" | -0.5 ~ -0.7 | 中性(维护操作) | | "The crash was caused by a null pointer" | -0.5 ~ -0.8 | 中性(问题诊断) | | "Successfully deployed to production" | +0.3 ~ +0.5 | 正面 | 注意:这里有六个看似正常的技术场景句子,其中五个都被判断为负面。唯一的正面例句是包含术语“successfully”的,模型将其识别为消费评价中的术语。 再来看看模型在它被训练的日常领域中的表现: | 句子 | 得分范围 | 实际情感 | | ------------------------------------ | ----------- | ------------------- | | "This product is terrible" | -0.7 ~ -0.9 | 负面(正确) | | "I love this app, it's amazing" | +0.7 ~ +0.9 | 正面(正确) | | "The food was okay, nothing special" | -0.1 ~ +0.1 | 中性(正确) | 这组句子全都判断得非常准确。实际上,模型本身问题不大。问题在于,它被放在了错误的上下文中。 ## 问题根源:词汇偏见 `NLTagger`的模型并不能理解语义。它并不知道“kill a process”是一个技术隐喻,而“kill a person”是暴力行为。对它来说,“kill”就是一个带负面意味的单词,仅此而已。 这种现象被称为“词汇偏见”(_lexical bias_)——模型基于单个单词(或短语)的极性打分,而没有理解上下文。这就好比一个翻译软件将 "I'm dying of laughter" 翻译成了真正的紧急医疗状况。 技术语言充满了在日常语言中很负面的词: - **kill**、**terminate**、**abort**、**destroy**——常见于进程操作 - **fatal**、**critical**、**severe**——日志级别 - **crash**、**panic**、**fault**——系统事件 - **dead**、**zombie**、**orphan**——进程状态 - **reject**、**deny**、**block**——访问控制 - **break**、**interrupt**、**suspend**——流控制 任何使用这些词的段落——比如错误日志、事后分析报告、拉取请求中的讨论——都会被预测为负面情绪,好像有人正写着遗书。 ## 增加上下文能解决问题吗? 你可能会想:“如果提供更长的段落,模型应该会更好地理解上下文。”试试这个: ```swift let technical = """ The daemon was killed after a fatal memory error. \ We restarted the service and the crash did not recur. \ Deployment completed successfully with zero downtime. """ print(sentiment(of: technical)) // 典型结果:-0.3 ~ -0.5 这是一个描述成功解决问题的段落。结尾显然是积极的。但其中的“killed”、 “fatal”、 “error” 和“crash”这些词的负面权重,远远超过了“successfully”和“completed”的正面积极权重。模型仅仅是将词汇的极性进行平均,而无法理解叙述的含义。 ...

2026年3月28日 · Fernando