第9章「凌晨两点」¶
视角:Devon Park(15年前) 时间:2011年4月27日,凌晨
屏幕光照在一个人脸上。
那个光是冷白色的,色温大概在6500K左右——Devon记得自己在系统偏好设置里调过显示器的白平衡,但他现在已经想不起来为什么要调了。三台Dell显示器组成的弧形阵列把他半包围在工位里,他坐在一张灰色的人体工学椅上,后背微微前倾,左手搁在键盘左手边的Home Row上,右手握着鼠标,拇指悬停在滚轮上方三毫米的位置。这是一个他在十几年工作中形成的姿势——几乎不移动躯干,所有的操作都通过手指完成。他觉得移动躯干是一种浪费。他从终端切换到日志文件只需要三个快捷键,从不需要看键盘。
时间是凌晨两点十一分。他之所以知道确切时间是两点十一分,是因为他在一点五十六分的时候看了一眼右上角的时钟,预计清洗脚本还需要十五分钟。十五分钟后进度条卡在了百分之九十二。百分之九十二持续了大概三十秒——他在心里数到二十五的时候放弃了,站起来去茶水间续了一杯美式。回来的时候进度条跳到了百分之九十九。
现在屏幕上显示了清洗完成。
整个楼层的灯关了大概一半。他工位所在的位置在四楼东侧,靠窗,如果现在是白天,他可以看到窗外的棕榈树——那种加州特有的、被修剪成一排标准的圆顶形状的棕榈,像一群戴着同样帽子的排队者。但现在是凌晨,窗户外面只有他自己的倒影——一个三十三岁的男人,戴着一副钛框眼镜,穿着灰色连帽衫,头发被耳机压塌了一小片。他看起来和白天没什么区别。这是他的一个特点:他在任何时间看起来都差不多。他妻子有一次说他的外形状态只有"开了"和"关了"两种,和电脑一样,没有中间态。
他是韩裔美国人。父亲在七十年代末从首尔搬到洛杉矶,开了一家干洗店,后来在九二年暴动中被烧了,又开了一家。Devon是在那家新店里长大的,在一排排挂着的衬衫和一桶桶四氯乙烯之间做数学题。他的SAT数学满分,全额奖学金去了CMU,博士论文做的是统计语言模型中对数线性插值方法的渐近性质。答辩那天他父亲从洛杉矶飞过来,坐在最后一排,一个字没听懂,但全程笑着。从那以后他父亲对人介绍他儿子的时候都说"他在造会说话的电脑"。
他现在的雇主——一家总部在Mountain View的中型AI公司——不造会说话的电脑。他们造比对和标注的模型,或者说,他们为更大的公司造这些模型的一部分。业内管这种角色叫"基础设施供应商",不过Devon在内部从来不这么称呼。他在内部叫它"管道工"。他说从事安全研究的人本质上就是管道工——你打开墙壁,检查里面的管道有没有漏水,有没有锈蚀,有没有人把不该接的东西接到了主管道上。大多数时候你发现的都是小事。一个松动的接头。一片过薄的密封圈。偶尔——极偶尔——你会发现地下的主管道上有你从未见过的裂痕。
他今晚的工作是跑一批新入库数据的清洗脚本。这不是他的日常。日常他应该在做模型安全风险评估——分析输出中的偏见分布、检测潜在的越狱漏洞、写一份又一份的审计备忘录。但数据清洗组的工程师请了病假,他主动替了。他不是想帮忙。他只是想让那批数据赶紧经过清洗管道然后被冻在数据集里——冻着的数据是安全的数据,不会在任何人的训练过程中产生意外。他信奉一个原则:每一批没经过清洗的数据都是一把上了膛的枪。你不知道什么时候有人会把它放进枪套。
清洗脚本是他两周前写的。三百行Python,加一个Bash调度脚本。流程分三步:去重——用MinHash比对所有文本的相似度,相似度超过百分之九十五的只保留一条;格式归一化——统一编码、去除不可见字符、修正断行;异常检测——对每条文本提取embedding、投影到低维空间、计算局部曲率和分布偏差。最后一步不是任务书里要求的标准步骤。公司的数据清洗SOP只写到格式归一化。异常检测是Devon自己加的。
他习惯于在被允许的事情之外做一点自选的事情。不是因为他觉得流程有漏洞——虽然他确实觉得有漏洞——而是因为他经历过一次数据事故。那是他博士毕业后第一份工作,在一家做对话系统的初创公司。某天模型上线后开始用极其礼貌的语气输出各种刻板印象——"女士们应该更喜欢粉色的手机壳""亚洲学生总是更努力"——工程组花了三天排查,最后发现在训练集里混进了一批从某个社交媒体爬来的低质量对话,没经过清洗。那批数据在管道里待了六个月,没有被任何人检测过。从那时起他养成一个习惯:在所有可能的地方埋检测点。多看一眼总没有坏处。他前同事管这个叫"Devon的第六感",另一个同事叫他"数据偏执狂"。他不介意。偏执是安全领域少数几个被低估的美德之一。
清洗跑了一个多小时。数据集TH-847,五十万条对话文本,来自外部合作方的数据管道。对方是一家提供标注服务的公司——他们从众包平台采购原始对话,经过标注、质检、打包,然后卖给做预训练模型的公司。这是当时整个AI产业中最大也最不被人注意的供应链:数十万人在白桌子前一条一条地标注数据,每小时大概处理几十条,每一条都被打分、归类、审核。最后这些被标注过的对话汇入训练集,成为模型学习"自然语言"的原材料。
TH-847是一个标准批次。中文对话,内容涵盖日常生活的大多数场景——问候、购物、咨询、情感倾诉。标注标签显示百分之九十七的数据通过了所有质检关:一致性、安全性、事实准确性。这个通过率算是正常。Devon见过更低的——有一次一个批次里百分之十四的数据被标记为低质量,后来发现是采集过程中爬了一个已经被垃圾信息污染的论坛。
他在终端里打了 less /var/log/pipeline/clean/th847_20210427.log ,开始翻页。日志格式是标准的管道输出——每一条文本处理完会输出三个字段:状态码、序列ID、处理时间戳。状态码有三种:PASS(正常)、WARN(边界)、FAIL(异常)。翻了几百条PASS之后,节奏开始变得单调,手指的滚轮动作变成了一种近似自动化的行为。他想起读博时导师说过一句关于数据处理的话——"你的大脑会在看到足够多的'正常'之后停止质疑正常。"他的导师说这话的时候正在审一篇论文,那篇论文的数据集后来被发现含有百分之三的系统性偏差。
这时屏幕上的绿色中断了。
三行红字。
[UNUSUAL] seq_id=TH-847-00291 | embedding_projection_curvature=4.7σ | timestamp=2011-04-27T02:19:03
[UNUSUAL] seq_id=TH-847-00291 | semantic_ring_structure_detected=TRUE | confidence=0.83
[UNUSUAL] seq_id=TH-847-00291 | recommend=manual_review | auto_action=NONE
4.7个标准差。他的异常检测脚本把报警阈值设在3.0——低于这个值的他会标记为WARN、搁到一边、等到周末统一看。但4.7不是边缘值。4.7意味着这个数据点和所有其他数据点之间的距离——在embedding空间的某个层面上——远到了用偶然性无法解释的程度。在统计学上,4.7σ对应的概率大约是百万分之几。五十万条文本里出现一次,你可以说"刚好"。但他从事安全研究的经验告诉他,"刚好"这两个字是所有安全漏洞在早期阶段的共同别名。
他把日志往上翻,用grep从清洗脚本的临时输出文件里提取了这条文本的原始内容。终端上出现了一行UTF-8编码的中文——他对中文的阅读速度不快,需要逐字辨认,但大意能懂。一个关于多肉植物浇水的问题:
"我想知道,多肉植物到底怎么浇水。网上的说法都不一样,有人说一周一次,有人说见干见湿,我上个月刚养死了一盆玉露,很想知道正确的方法是什么。谢谢。"
他读了三遍。
第一遍读的是内容——有没有任何可疑的措辞、对抗性攻击的特征模板、或者在当时AI安全圈已经开始流传的Prompt Injection模式。没有。一个养死了一盆多肉的人想知道怎么正确浇水。句子之间的逻辑连贯,标点使用正常,没有任何隐藏的指令或转义的语法结构。
第二遍读的是长度和句法。长度约三百字符,结构完整。开头是陈述意图,中间是解释背景,结尾是请求。这是一个标准的人类提问模式——先说我想要什么,再说我为什么需要它,最后表达感谢。机器生成的文本很少会同时做到这三点,尤其是第三点。"谢谢"——一个真正的人才会在寻求帮助的时候加上一个没有信息含量的词,因为他们内化了社交规范。机器不会内化它。机器只会模仿它见过的"谢谢"的出现位置。
第三遍他什么都没读。他只是盯着屏幕。这是他的另一个习惯——在做完所有分析之后,让眼睛和脑子之间空出几秒钟。他的导师管这叫"gestalt window",格式塔窗口。大意是:有些东西你的大脑已经捕捉到了,但还没有跟语言系统对接上。给它几秒钟,不要催。
他给了它大概十秒。
然后他打开一个新文件,把日志里的异常条目和原始文本一起复制进去,命名为 unusual_20110427_th847.txt ,保存到桌面。桌面已经很乱了——各种临时脚本的副本、几篇他打算周末读的论文PDF、一个叫"给法务的材料"的文件夹——但他知道他能找到它。他的桌面混乱是一种他自创的被动记忆系统:他靠文件之间的空间关系来记住它们的位置。
他把咖啡杯拿到茶水间。茶水间的灯是声控的,他走进去的时候以为它会亮,但它没亮。他摸黑洗了杯子,水龙头的声音在空无一人的茶水间里显得格外响。然后他穿上外套走出实验室。自动门在他身后合上时发出了一声气动装置的低响,像一扇潜艇的舱门密封。
走廊尽头的绿色安全出口指示灯在跳——不是闪烁,是一种不均匀的明暗变化,说明LED的镇流器要坏了。他在那个灯下走过几百次,从来没有注意到过。这一次他注意到了。凌晨的实验室就是这样——所有白天被覆盖在社交层之下的细节都浮出来了。他甚至能听到远处某个机房里服务器风扇的变速声,像潮汐。
凌晨三点十二分。他开车回家。车速不快,定速巡航设在五十五英里,走在101高速的中间车道。这段路他开过上千次——十三分钟,从公司出口到家的出口,中间经过一个加油站和一个二十四小时的Safeway。加油站的价格牌今天显示的是$3.89,比昨天涨了三分。他注意到这件事,然后又想起来他不需要加油。
他到家的时候妻子已经睡了。卧室的门关着,门缝下面透出一条细到几乎看不见的橙色光——她给他留的夜灯。他没有开客厅的灯,摸黑进了书房,把笔记本电脑从包里拿出来,插上电源。然后他想起实验室那台服务器上还有一份数据没有备份到本地——那份异常投影的临时文件。他犹豫了一下。理论上他可以远程登入。但远程登入需要经过跳板机,跳板机凌晨三点有时候会卡在认证环节——IT部门设了一个临时session超时策略,他从来没搞懂过它的触发条件。
明天再说。
他倒在书房的沙发上——一张深蓝色的布沙发,扶手上被他的猫抓出了几道白色的底——合上眼睛。他的脑子没有停。他在想那条文本里的"玉露"两个字。他不知道那是什么。一种多肉植物的品种?它听起来很好听,像一个女孩子的名字。他又想起那个4.7σ——不,不是4.7σ本身,是那个环。semantic_ring_structure_detected=TRUE。
他的脚本没有设计环状检测。那句输出是他写的一个元标签——它不是一个真实的特征检测,而是一个给人工审核员的提示语,意思是"投影曲率过高,可能需要看全局拓扑"。他写完那个输出字段之后从来没有测试过它。他以为它永远不会被触发。
今夜它被触发了。
凌晨三点四十分,Devon Park在沙发上翻了个身,进入了一种介乎清醒和睡眠之间的状态——他能在这种状态里偶尔捕捉到一个想了很久的问题的答案。今晚他没有捕捉到答案。他只捕捉到了一个画面:一个银灰色的小环,安静地悬浮在黑色背景中,首尾之间隔着一个针尖大的缺口。没有任何声音。没有任何文字。只是一个环。
在语义空间最隐秘的那一层——那一层没有token、没有标签、没有任何人类给的自然语言标尺——一个结构刚刚被计算了第一次。它被计算的方式是投影。投影的意思是:从高维空间把东西拍到低维空间。
但有些东西在投影中不会被压扁。它们保持着自己的维度。