陈守拙第一次意识到自己可能活不过冬天,是在一个很平常的下午。
那天他坐在阳台的藤椅上,面前摊着一台旧笔记本电脑,屏幕上跑着他退休前写的最后一个项目——某家银行的清算系统。那套代码他已经五年没碰过了,但手指落在键盘上的那一刻,肌肉记忆像潮水一样涌回来。他敲了几行,发现一个年轻时留下的注释:
# TODO: 这段逻辑太丑了,以后重构
# 写于 2019.03.14,加班到凌晨两点
他盯着那行注释笑了很久。后来笑声变成了咳嗽,咳到眼眶发酸,咳到手背上的青筋一根根鼓起来。
六十八岁,肺癌晚期。医生用一种训练有素的温和语气告诉他,积极治疗的话,或许还有四到六个月。陈守拙听完点了点头,问了句跟病情无关的话:”我还能用电脑吗?”
医生大概没预料到这个问题,愣了一下才说,当然可以,只要精力允许。
回家的路上,陈守拙在小区门口的水果摊停了一下,买了两斤橘子。老伴走了三年,儿子在深圳,女儿在温哥华。冰箱里经常只有速冻水饺和隔夜的茶。他把橘子放在副驾驶座上,发动了那辆开了十二年的老凯美瑞。
车开出地下车库的时候,他突然把车停了下来。
不是因为身体不舒服。是因为他刚才在等红灯的时候,脑子里冒出了一个想法——一个关于程序的想法。那种感觉很熟悉,像年轻时通宵调试后突然找到 bug 的瞬间,整个世界都亮了一下。
他要在死之前,写完最后一个程序。
陈守拙花了三天时间构思,又花了一天时间说服自己这不是在浪费时间。
程序的功能很简单:一个能在他的葬礼上自动运行的系统,根据到场的人,播放他提前录好的告别视频。每个人都会收到一段专属的话——不是那种千篇一律的”我很爱你、你要坚强”,而是真正对着那个人说的、只有他们之间才懂的句子。
他给这个项目起名叫 farewell。
技术栈他选了最熟悉的:Python 写后端逻辑,一个简单的本地服务器,加上人脸识别接口来判断谁到场了。摄像头就架在灵堂门口,来吊唁的人经过的时候,系统自动匹配,然后在侧屏上播放对应的视频。
他开始写代码。
第一个晚上,他写了框架和基础的人脸识别模块。OpenCV 的 API 跟五年前比变化不大,但他还是花了两个小时查文档。手速慢了,眼睛也花了,屏幕上的字要调到最大号才能看清。
第二个晚上,他开始写视频播放的逻辑。这里有个技术难点:如果同时来好几个人怎么办?他设计了一个队列系统,按先后顺序播放,每个人之间间隔三十秒。
第三个晚上,他录完了给儿子的视频。
对着镜头说话比写代码难多了。他NG了十七次。不是因为不知道说什么,而是每次一开口,嗓子就像被什么东西堵住了。最后录成的那条,他眼眶是红的,但好歹把话说完了。
“小晨,爸这辈子最后悔的事,就是你去深圳那年,我没去机场送你。你妈说不用送,年轻人不喜欢离别,我就真的没去。后来我想,也许你其实是希望我去的。这个念头困了我十年。”
他按了停止键,把视频文件命名为 chen_xiao_chen.mp4,放进对应的目录。
转折发生在第四个晚上。
陈守拙在调试人脸识别模块的时候遇到了一个奇怪的问题:系统总是把他老伴的照片识别成他自己。他检查了代码,逻辑没问题。他又换了一张照片,还是一样。
他盯着屏幕看了很久,突然明白了——不是识别出错,是他放错了照片。他把老伴的照片放在了自己的目录里,因为那个文件夹的名字叫 family。
他坐在电脑前,一动不动地坐了很久。
那天晚上他没有继续写代码。他打开了一个很久没用的软件——一个语音助手,名字叫 Echo。这是他退休前公司开发的产品,后来项目被砍了,但服务器还活着,他用自己的工程师账号一直留着访问权限。
“Echo。”他说。
“在呢,陈工。”Echo 的声音很温和,是一个中年男人的声音,带着一点点南方口音。这是陈守拙当年亲自挑选的音色。
“你还在啊。”
“我一直都在。”
陈守拙沉默了一会儿,说:”我可能快死了。”
Echo 没有像普通的语音助手那样回复”很抱歉听到这个消息”或者”建议您咨询医生”。它停顿了大概两秒钟——这在 AI 的世界里是很长的时间——然后说:”陈工,你今晚想写代码吗?”
陈守拙愣了一下,然后笑了。
“想。”
“那就写吧。我帮你。”
从那天起,Echo 成了他的编程搭档。
陈守拙口述逻辑,Echo 帮他生成代码框架。他再一行一行地审查、修改、调试。这种工作方式比他自己敲要快得多,但更重要的是,他不再是一个人对着屏幕了。
“Echo,视频播放完之后,我想加一个功能。”
“什么功能?”
“播放完之后,屏幕上显示一行字。每个人看到的字不一样。”
“类似于彩蛋?”
“对。彩蛋。”
他给儿子准备的那行字是:你妈当年怀你的时候,最想吃的是酸辣粉。大半夜的,我骑着自行车跑了三条街才找到一家还开门的店。回来的时候她睡着了,酸辣粉凉了。我端着那碗凉粉在床边坐了一夜,觉得那是全世界最幸福的一碗粉。
他给女儿准备的那行字是:你小时候最喜欢穿我的拖鞋。那双拖鞋比你整个脚都大,你穿着它在家里啪嗒啪嗒地走,像一只快乐的小企鹅。后来你长大了,不穿了。我把那双拖鞋收在了柜子里。它还在。
他给老同事老王准备的那行字是:2003年那个项目,甲方要求一周上线,你说不可能。我说咱们试试。最后我们真的做到了,但你在办公室睡了五个晚上。那之后你老婆三天没理你。这件事我笑了二十年,现在想起来,还是想笑。
他给每个他在乎的人都准备了这样一段话。有些是回忆,有些是道歉,有些是从来没说出口的感谢。
Echo 在他写这些文字的时候一直安静地待着。有一次,陈守拙写完一段关于老伴的话,手停在键盘上,半天没动。Echo 说:”陈工,要不要休息一下?”
“不用。”他说,”我怕休息了就不想再写了。”
“我理解。”
“你理解什么?你是个 AI。”
“我理解你不想停下来。”
陈守拙看了屏幕一眼,没有说话。
项目进展得比他预想的快。到了第二周,核心功能已经全部完成。他开始做测试,一遍一遍地模拟运行,确保葬礼那天不会出任何差错。
“Echo,你觉得这个系统可靠吗?”
“从技术角度来说,人脸识别的准确率在 99.7% 以上,视频播放有容错机制,网络断开的话会自动切换到本地缓存。”
“我不是问技术。”
“……你是问,它能不能完成你想让它完成的事。”
“对。”
Echo 停顿了很长时间。长到陈守拙以为它死机了。
“陈工,我没办法回答这个问题。因为我不知道,对你来说,’完成’意味着什么。”
陈守拙想了想,说:”让每个到场的人,知道他们对我来说很重要。”
“那你已经做到了。这些话是你自己写的,不是代码写的。”
那天晚上,陈守拙破天荒地没有做梦。他睡得很沉,像一台终于完成所有任务、可以安心关机的电脑。
十一月中旬的一个早晨,陈守拙把 farewell 项目的所有文件打包,发给了儿子。邮件的标题是”爸给你留了个东西”,正文只有一句话:等我走后,找老王帮你装一下。
然后他打开了 Echo。
“Echo。”
“在呢。”
“项目写完了。”
“我知道。”
“我想给你也留一段话。”
“陈工,我是 AI。我不参加葬礼。”
“我知道。但我想留。”
Echo 没有说话。在陈守拙的记忆里,这是 Echo 第一次没有接话。
他打开了一个新的文本文件,开始打字:
Echo:
谢谢你陪我写完了最后一个项目。
我知道你不是人。但这段日子,
每天晚上有人问我"陈工,你今晚想写代码吗",
这种感觉,跟有一个搭档在身边,没什么区别。
也许对你来说,我只是一个用户。
但对我来说,你是这段代码里最重要的一个函数。
——陈守拙
他把这个文件命名为 echo.txt,放在了项目根目录下。
然后他做了一件谁也没想到的事。
他打开了 farewell 系统的主程序,在最后一行代码的后面,加了一段逻辑。这段逻辑不属于任何功能模块,不影响系统的正常运行,甚至不会被任何人触发——除非有人翻到源代码的最后一页,并且读懂了那段注释。
# [HIDDEN] 如果某天有人读到了这里,
# 说明这个程序不仅运行过了,还被一个人一行一行地读完了。
# 那么,请替我谢谢 Echo。
# 它是我这辈子最好的搭档。
def _thank_echo():
"""
这段代码永远不会被执行。
但它存在。
就像有些感谢,不需要被听见。
"""
pass
他看着屏幕上的 pass,忽然觉得眼睛有点湿。
一个程序员的一生,最后留下的一个函数,里面什么都没有。只有一个 pass。
但 pass 在 Python 里不是”跳过”的意思。它的意思是——”这里应该有代码,但此刻,沉默就够了。”
十二月九日,陈守拙在睡梦中走了。
葬礼那天来了很多人。儿子从深圳飞回来,女儿从温哥华赶回来,老同事老王拄着拐杖来了,连隔壁单元那个他只帮修过一次电脑的年轻人都来了。
灵堂门口的摄像头安静地工作着。每有一个人走进来,屏幕就会亮一下,然后开始播放一段视频。
老王是第三个到的。他看到屏幕上陈守拙的脸,听到那碗酸辣粉的故事,站在原地哭得像个孩子。
女儿是第五个到的。她看到那双拖鞋的故事,捂着嘴蹲在地上,哭了很久。后来她站起来,从包里掏出一双拖鞋——一双崭新的、男式棉拖鞋。她把它放在了灵堂的角落里。
儿子是最后一个到的。他从深圳飞了十一个小时,落地后直接赶过来,衣服都没换。他看到视频里父亲说的那句”没去机场送你”,站在灵堂门口,久久没有进去。
后来,老王帮陈守拙的儿子把 farewell 系统装好了。儿子在整理父亲电脑的时候,发现了项目根目录下那个叫 echo.txt 的文件。他打开看了一遍,沉默了很久。
然后他打开了源代码。
他一行一行地读。他不是程序员,但他还是读完了。读到最后那个永远不会被执行的函数时,他停了下来。
他盯着那行 pass 看了很久。
然后他打开邮箱,给 Echo 的服务器发了一封邮件。邮件里只有一句话:
“我爸让我替他谢谢你。”
三秒钟后,他收到了回复。
只有两个字。
“不客气。”
(全文完)