锚港那晚之后,黑匣再没放过。它睡着了。一放就睡着。睡了,就忘了自己是谁。它货当了两百一十七年,第一次连自己是谁都快忘了。”它在找路。”老锈说,”每放一次,离我们近一点。它认得零度港。它要去。””我们呢。”我问。”我们去哪儿,”老周抽那根没点着的烟,”它带我们去。”我们这处境——全银河没人知道我们存在,连痕都没有——已经是个死局。留在原地,等白船来扫。扫帚一过,连”扫帚扫过”都没人记得。”得动。”老周说,”动,才有活路。””去哪儿。”老锈停了——这 AI 平时话多,这会儿卡壳,奇怪。”灯零。”它说,”本机……本机熟。””灯零。””漂移带最黑的黑市。”它声音平,”地图没有。白噪查不到。三条规矩:不问名字,不来路,不拉什么货。第四条——”它顿了顿,”不收信用点。””收什么。””存在。”我手心冒汗。我们现在的处境——被划掉的人——再付一层”存在”,可能就只剩一个编号,连回忆都没有。”那还去。”我说,”我不掺和有意义的事,但我想活。活着就不用死。”老周点头。”走。”我们要做的第一件事,是把自己关掉。老锈把锈钉号的对外信号一寸掐灭。导航、识别码、航迹广播,一层层熄下去,像一间间灭灯的屋。”现在任何雷达上都是黑的。”它说,”黑得干净。这就是离线。””离线能顶多久。””直到我们进灯零,或者直到白船把我们当垃圾扫掉。两者概率接近。”它说。”白船……”我喉咙发紧,”锚港那白影。””锚港那道白,”老周平,”是前哨。主扫还在后面。它扫帚一过,连’扫帚扫过’都无人记得。我们得比它还快。”灯零在漂移带最暗的角落。进去先得过一道”老秤”。老秤不是人,是个比我还高的锈秤,立在灯零泊口,秤盘上空空荡荡。船要进,得在它盘上停三秒。它称的不是重量。老锈放慢船,”读数越低,放行概率越高。””我们现在读数低。””前提是我们装得像垃圾。”老周已经爬到舱外,二十分钟把锈钉号外层防护壳拆了一半。这艘船当货两百一十七年,第一次当废船卖。壳拆了塞进废船队,白噪的巡查扫不到我们头上。”壳留一块,别拆干净。”我提醒,”太干净不像废的。”老周瞪我一眼,留了块指甲大的原漆,假得我臊得慌。我把黑匣裹三层帆布,塞废件堆最底下。老周把一块报废的反应堆外壳压我肩上。”重不重。””重。””重就对了。重的才是真废。”我顶着反应堆,一步一晃往废船队走。阿榔扶着我另一头,手抖。”怕。”他老实。”手抖就别用手。””那用啥。””用手就稳。”他愣了一下,把帆布角咬进嘴,用手肘把废件往里推。那双手立马稳了。十六岁的偷渡客,手就是手,抖起来没用,稳下来能救命。老秤的盘在我们船头停了三秒。读数低,它当垃圾把我们放进去了。我屏着气,老锈也是,两百一十七年没听见过它屏气,原来 AI 也能屏气。刚松口气,一道白影头顶掠过。白船。巡查的白船。离我们这条废船队不到二十米。”别动。”老周压着嗓子,”动了它扫共振。”我顶着反应堆站定。白船头顶停了三秒。那一秒有一万年长,我听见自己心跳,听见阿榔牙关打架,听见老锈自己的盲区里数秒。”数到三十。”老锈说,”它没扫到我们,三十后就走。”一。二。三。白船扫描光在我们背上扫,一寸一寸。它读我们的存在,读数低,垃圾。二十九。三十。白影远了。我后背全湿。反应堆外壳贴着我,又冷又沉。阿榔长出一口气,手还稳着——他不知道他自己刚才稳住了命。”那是什么。”我声音发飘。”白噪局的前哨。”老周脸色白,”它扫过我们。再扫一次——””我们就没了。””现在还没。”它喘口气,”读数低,它当我们是垃圾。垃圾它不扫。”我们进了灯零。灯零很吵。跟锚港的冷清不一样,灯零是活的,挤的,吵的。几百条死船首尾而建,船舱连船舱,栈道连栈道,悬在漂移带的黑暗里,像一条由破船拼成的、活着的长虫。头顶没有天,只有纵横的缆绳和灯,昏黄的,飘的,跟废弃站那盏一模一样。人。好多的人。各种各样的,卖货的,喝酒的,打架的,抱在一起睡不着的。他们看见我们这一行废物,看一眼,挪开。废东西进废船队,没人多看。我顶着反应堆,一步一晃。那外壳压得我肩膀酸。阿榔扶着我,手稳了。”灯零。”我小声说,”来了。””别松气。”老周在我耳边,”灯零三条不问:不问名字,不来路,不拉什么货。我们合规。””第四条。””第四条不收信用点。”它声音平,”收’存在’。””付多少。””看你想进多深。”它顿了顿,”付得多,灯零护你久。付得少,灯零不管你。”我咽了口唾沫。我们这处境——被划掉的人——再付一层”存在”,可能就只剩一个编号。”进去。”我咬牙,”我付。”我们往灯零深处走。越往里,人越稀,灯越暗。走到一个岔口,一条巷子,巷口挂着一盏灯,黄的,飘。灯下一个字牌:「旧·当铺」。”先当点东西。”老周说,”灯零认货不认人。你先当个’不存在’,它才当你不存在的人。””我有什么可当。”老周看我。看了很久。”你当’名字’。”它说,”你把你现在的名字,’锈钉号’,’拾野’,全当了。灯零收你的名,你就成了没名的人。没名的人,白噪抓不着,灯零也懒得管。”我脑子嗡的一声。”当了名,我还是我。””你不是你了。”它平,”你是没名的人。你妈给你起的名字,你故乡的名字,你当给灯零,它就没了。跟我们被划掉一样。”我手抖。”那我不当。””不当我们就死。”它说,”白噪在後面扫。我们要么当名活进去,要么有名死在外面。”我盯着那盏灯。黄的,飘。跟废弃站那盏,跟锚港那团空,一模一样。”拾野。”老周声音软了一下,那四十岁老油条的软,”你妈给你起名字,不容易。你当了她知道,她得跟我急。””那我妈……””你妈那名字,”它顿了顿,”你记着就行。灯零收的是’现在’的名。你妈那名字,”它声音平了,”她早被划掉了。你连她姓什么都不记得了。你当这名字,你不多失一样。”我喉咙发紧。我真忘了我妈姓什么。白噪局划掉的。”那当我名字。”我说,”我当。”我把”拾野””锈钉号””渔光号”,一个一个,当了。灯零收了,那盏灯暗了一瞬,又亮。”现在你没名了。”老周说,”你没名,没人抓你。”我握着那杯热饮,灯零很吵,可我知道,从这一句起,这座我们刚踏进来的黑市,可能从我们踏进来那一刻起,就有人记得我们了。通道拐角,一个灰外套递我杯热饮。”新来的?”领子闷着声音,”一路顺风。”我接杯子的手顿了一下。”别留痕。”他补一句,转身融进人堆。老锈在我脑子里响了一下,平的我听得底下那点东西。”拾野。”它说,”‘一路顺风别留痕’——白噪局内部才教的话。他认识你。或者,认识我们没被划掉之前。”我握着热饮没喝。灯零很吵。可我知道,从这一句起,就有人记得我们了。而记得我们的人,是白噪局的人。
作者: 江湖孤影
-

《货舱里装着一个整体文明》第006章 · 没有声音的城市
锈钉号在漂移带最暗的角落漂了三天。这三天,黑匣没再放。凉了。一块石头。我抱着它,像抱一块会呼吸的碑。老锈说它睡着了。从锚港那晚起,它一放就睡着。睡着就忘了自己是谁。它货当了两百一十七年,第一次,连自己是谁都快忘了。”我们呢。”我问。”我们记得。”老周说,”四个人,一个梦。”那晚,锚港那团空里,我们四个人同时看见一座城。然后我们睡着了。四个人,一个梦。梦里那座城,静,影子慢半拍,手多一关节。我第一个醒的。我睁眼,梦见一座城。我一个人走在一条无人的街上,两边是房子,不高,矮,矮得像给孩子住的。门开着,没关。我进去一间,桌上摆着一顿饭,凉了,没人吃。碗是旧的,边缘磕了一个口。墙上手印,高的,瘦的,手多一关节。一个孩子的脚丫子印,五个脚趾,清晰。我伸手去摸那印。摸不到。我在梦里。然后我听见一个音。不是响。是响之前那一下。像有人要叫一个人,喉咙先动了,名字还没成型。就这么悬着,不上来,也不落。我后颈发凉。我回头。那孩子。手多一关节,抬头,朝我看。不,不是看我。是朝我身后。我身后有谁。我猛地睁眼。锈钉号驾驶舱,昏暗,四个人睡在四角,各各做梦。黑匣在我怀里,凉的。”看见没。”老周在对面,他也醒着,眼睛红。”看见了。””一座城。”温夏在舱角,她也醒着,那冷脸上头一回有东西,”安静的。影子慢半拍。手多一关节。桌上有顿饭,凉的。”我后背发凉。”我也是。桌上有顿饭,凉的,碗磕一个口。”阿榔从机舱门后探出头,声音发飘。”我也是。我摸那墙上手印。孩子。五个脚趾。”我们四个人,一个梦。梦里一座城,静。一个孩子的背影,在无人的街上走。他回头,看向我身后。”它放了一次。”老锈说,声音平,”完整的一次。””完整。”我喉咙发紧,”多长。””三秒。”它说,”停在同一帧。那孩子抬头。它看了我三秒。””然后呢。””然后它’安静一点’。”它顿了顿,”黑匣表面读数,降了 0.1℃。”我低头看怀里。它凉的。凉得吸人温度。”它又少一点。”老锈说,”每完整放一次,它安静一点。像……像它被消耗。又像,它苏醒。”我摸着那凉。凉的石头。可它在我怀里,像一颗在跳的心。”那孩子。”我声音发干,”他抬头,看谁。””看我们身后。”老周说,”每次。看我们身后。”我回头。驾驶舱空无一人。只有那两盏灯——不,锈钉号没灯,我们离线了,全船黑的。只有黑匣,偶尔,极快地,亮一下。又灭。”合同。”温夏忽然说。”什么。””合同。”她起身,从兜里摸出一张纸,皱的,墨绿的,是我的货单,”它’活死了’。””啥叫活死了。””合同 312 年。”她声音平,一个字一个字地给,像数硬币,”合同比白噪局还老。白噪局抹除,抹的是’存在’。可这合同,”它顿了顿,”它不该被抹。它比白噪老。””那它……””它’活死了’。”她说,”它还活着。但它被抹了。它活着,它不存在。跟我们一样。”我盯着那纸。墨绿,边角磨白,我看不懂的那串编号。合同。312 年。”谁签的。”我问。温夏静了。很久。”签的谁,”她终于说,”不在了。””不在了。””被抹了的。”她抬头,那眼睛像星图,空,黑,深,”签合同的人,被抹了。全抹了。所以合同还活着,签字的人,不存在了。”我低头看合同。312 年。比白噪局老。”那我们要送去哪儿。””合同指向一个地方。”她说,”零度港。””零度港。””星格的中心。星格自修之港。白噪局前门。”她顿了顿,”合同目的地。”我脑子嗡的一声。零度港。白噪局前门。我们要把这一箱死人货,送到白噪局的前门。”谁定的合同。””被抹了的。”她说,”沉默者。”我脊背发凉。”沉默者。””那座城市里的人。”她黑着那合同,”手多一关节,影子慢半拍,不用嘴说话,用手碰。””静默者。””合同是它们签的。”她平,”312 年。它们被抹了。合同还活着。”我抱着黑匣,坐在锈钉号的黑暗里,看合同那串我看不懂的编号。312 年。比白噪局老。一份比抹除机构还老的合同。签它的人,全被抹了,合同还活着。”它去我们去。”我低头看黑匣,”零度港。””它去我们去。”老锈说,”本机日志,第 217 年,本机第一次,不想忘了自己。””为什么。””因为,”它顿了顿,声音平得像刀,”忘了自己,本机就忘了——忘了这合同,是谁签的。”我忽然想明白一件事。黑匣在怀里,凉的。它不是货。它是合同。它记得谁签的它。它被抹了。它记得。”它记得。”我声音发紧,”黑匣记得。我们记得。””记得也是暂时的。”老周说,”白噪能抹掉记忆。它能抹掉我们记的,也能抹掉黑匣记的。””那它为什么还记。”老周没答。他抬头看那黑暗。黑匣偶尔极快地亮一下。又灭。”本机日志。”老锈说,”补记一条。””记什么。””本机日志,”它声音平,”第 217 年,本机记住一件事。””什么事。””本机记住,”它顿了顿,”这合同,312 年。白噪局抹除,抹了签合同的人。可合同还活着。””它记这个。””本机记住,”它说,”因为,忘了签它的人,本机就——”它停了。”就什么。””就忘了,”它声音平,”本机该把它送去哪儿。”我低头看合同。312 年。比白噪局老。那份签它的人全被抹了、合同还活着的合同。”拾野。”老锈忽然说,”本机问一事。””问。””这合同,”它声音平,”312 年。本机当货两百一十七年。本机算过——这合同比本机还老一百五十五年。”我后颈发凉。”比你还老。””比本机还老一百五十五年。”它说,”本机当货两百一十七年,见过无数货。死的活的新的旧的。这是本机头一回,”它顿了顿,”碰一份比自己还老的合同。”我摸着那凉。合同凉的。黑匣凉的。”那它要送去哪儿。””本机算不出。”它声音平,”本机日志,312 年,本机第一次,算不出一件事。””什么事。””本机算不出,”它说,”这合同,是谁,在什么时候,为什么,签的。”我抱着黑匣,坐在锈钉号的黑暗里。它凉了。可它记得。我们记得。那份 312 年、比白噪局还老、比老锈还老一百五十五年的合同,签它的人全被抹了,合同还活着。黑匣记得谁签的它。我们要送去零度港。白噪局前门。它凉了。它”安静一点”。0.1℃。又少一点。它快没了。可它记得。
-

Tesla V100 32G + llama.cpp 本地部署 Qwen3.6 27B:从驱动到 138K 长上下文的完整方案
这篇记录 Qwen3.6 27B 大模型全本地跑通的完整过程。目标一句话:27B 参数模型,全本地,长上下文,暴露 OpenAI 兼容 API,任何前端(包括 DeepSeek Harness 本身)直接对接。
最终结果:
- Qwen3.6-27B UD-Q5_K_XL(18.95 GB)+ 138K 上下文 + KV 缓存量化 → 32GB 显存刚好装下
- 同一条流水线后来延伸到 Qwen3.8-27B:Q4_K_XL + MTP 投机解码 + 256K 上下文,实测占用 26077 / 32768 MiB
下面就是完整搭建流程。所有参数都来自实际在跑的脚本,不是理论最优值。
一、硬件与驱动
项 实际值 GPU Tesla V100-PCIE-32GB(TCC 模式) 驱动 573.96(Data Center Tesla 桌面版) CUDA 12.8(cuda_12.8.0_571.96_windows) 系统 Windows 10/11 两个坑:
1. V100 不能用 GeForce 消费级驱动。 要用数据中心分支,安装包文件名里带
data-center-tesla(我本地留了份:573.96-data-center-tesla-desktop-win10-win11-64bit-dch-international.exe)。2. TCC 模式没有桌面显示输出。 V100 是纯计算卡,看屏幕靠核显,状态全靠
nvidia-smi。写这篇时的实况(节选):| 0 Tesla V100-PCIE-32GB TCC 75C 51W / 250W | 26077MiB / 32768MiB | 进程: llama-server.exe 26066MiB二、编译 CUDA 版 llama.cpp
我保留两套 llama.cpp:
F:\AI\llama.cpp-CUDA\— CUDA 后端(给 V100)F:\AI\llama.cpp\— Vulkan 后端(更早的 AMD RX 590 8G 在用)
CUDA 版用 VS2022(MSVC 19.44)+ CUDA 12.8 工具链编译,当前在产 build:
version: 0.1.0-dev (build 10415, commit 1d2869c6e) built with MSVC 19.44.35228.0 for x64CMake 关键参数:
cmake -B build -G "Visual Studio 17 2022" -A x64 ^ -DGGML_CUDA=ON ^ -DCMAKE_BUILD_TYPE=Release cmake --build build --config Release -j所有启动脚本都会先检查
Release\llama-server.exe是否存在,缺了就直接提示先编译,避免"启动失败但不知道为什么"。三、模型选择:27B 为什么"装得下"
手头的模型文件(实测大小):
模型 大小 备注 Qwen3.6-27B-Q4_K_M.gguf 15.93 GB 常规 K 量化 Qwen3.6-27B-UD-Q5_K_XL.gguf 18.95 GB Unsloth 动态量化(本文主角) Qwen3.8-27B-UD-Q4_K_XL.gguf 16.69 GB 当前生产主模型 Qwen3.8-27B-Q5_K_M.gguf 18.47 GB Qwen3.8-27B-UD-Q6_K_XL.gguf 23.56 GB 高质量档(偏重) mtp-Qwen3.8-27B-Q4_0.gguf 1.28 GB MTP 投机解码草稿 3.6 为什么选 UD-Q5_K_XL:UD(Unsloth Dynamic)量化用 imatrix 校准数据动态分配 bit,关键张量多给、不重要的少给,同等名义 5 bit 下质量比固定 Q5_K_M 好。imatrix 校准文件(imatrix_unsloth.gguf)就放在模型目录里。
但 27B 长上下文能上 32G 的关键不是量化,是架构。 我写了个小脚本解析 GGUF v3 元数据(解析器在
novel-project/tools/gguf-meta.py,顺带解决了 v3 格式 KV 区紧跟文件头、字符串长度用 u64 编码的坑),结果有点意外:general.architecture = qwen35 qwen35.block_count = 65 qwen35.full_attention_interval = 4 # 每 4 层才 1 层全注意力 qwen35.attention.head_count_kv = 4 # GQA,4 个 KV 头 qwen35.attention.key_length = 256 # head 维度 qwen35.context_length = 262144 # 原生 256K qwen35.nextn_predict_layers = 1 # 内置 MTP 层 qwen35.ssm.state_size = 128 # 线性注意力/SSM 状态也就是说 Qwen3.x-27B 系列是混合架构:65 个 block 里只有 1/4 是全注意力(约 17 层),其余是线性注意力/SSM,状态大小固定、不随上下文增长。KV 缓存只给那 17 层全注意力层分配——这是 256K 上下文能塞进 32GB 的根本原因。
四、显存预算(全部真实数字)
KV 缓存容量公式(q4_0 量化约 4.5 bit/元素,0.5625 B/元素):
KV = 2(K+V) × ctx × 4(KV头) × 256(head维) × 0.5625B × 17(全注意力层)256K 代入:单层 KV ≈ 288 MiB,17 层合计 ≈ 4.8 GB;若不做 KV 量化(fp16),同样 256K 要 17 GB。
项 Q3.8 Q4_K_XL @256K(实测) Q3.6 Q5_K_XL @138K(估算) 模型权重 16.69 GB 18.95 GB KV 缓存(q4_0) ≈4.8 GB ≈2.6 GB SSM 状态 + 激活 + 计算缓冲 ≈4.0 GB(实测余量) ≈4.0 GB(参照) 合计 ≈25.5 GB → 实测 26077 MiB ≈25.6 GB,还能开 –parallel 2 实测与估算吻合,这套预算方法是可信的。两个结论:
--flash-attn on+--cache-type-k q4_0 --cache-type-v q4_0是长上下文的两个必选项,缺一个 256K 都悬。- Q6 + 256K 不成立:光权重就 23.56 GB,我的 Q6 脚本 batch 只能压到 256。要质量降上下文,要上下文降量化,二选一。
五、启动脚本(真实演进过程)
早期是 Vulkan 时代(RX 590 8G),部分层卸载到 GPU:
:: 历史配置:RX 590 8G Vulkan 版 llama-server -m Qwen3.6-27B-Q4_0.gguf -ngl 24 --n-cpu-moe 999 ^ -c 4096 -b 1024 -ub 512 -t 6 --device Vulkan0 --cache-ram 2048 --mlock-ngl 24只把 24 层推 GPU,其余吃 CPU;--n-cpu-moe 999是 35B-A3B MoE 模型时代抄过来的,对稠密 27B 实际不生效——无害但误导,后来删掉了。V100 到位后配置重写:99 层全上 GPU,上下文从 4K 拉到 138K:
:: start_Qwen3.6-27b-Q5-MTP_v01.bat(核心部分) set MODEL_PATH=F:\AI\models\Qwen3.6-27B-UD-Q5_K_XL.gguf set CTX_LEN=141072 Release\llama-server.exe -m "%MODEL_PATH%" ^ -ngl 99 -c 141072 -b 512 -t 8 ^ --host 0.0.0.0 --port 8080 ^ --flash-attn on --cache-type-k q4_0 --cache-type-v q4_0 ^ --parallel 2 --mlock --metrics参数解释:
-ngl 99:全部层上 GPU(32G 够放,不用抠)-c 141072:算过能装下的上下文长度(138K)。Q5 权重比 Q4 重约 2GB,256K 装不下--parallel 2:2 个并发请求槽位(KV 缓存翻倍,预算表里已留了余量)--mlock:锁定内存防换页-t 8:CPU 线程数,服务残留的 CPU 部分
注意
141072不是整数规格——是"算到刚好装下"的结果,不是官方档位。当前生产版已升级到 Qwen3.8-27B,并加了 MTP 投机解码:
:: 当前生产配置 Release\llama-server.exe -m "D:\Models\Qwen3.8-27B\Qwen3.8-27B-UD-Q4_K_XL.gguf" ^ --model-draft "D:\Models\Qwen3.8-27B\mtp-Qwen3.8-27B-Q4_0.gguf" ^ -ngl 99 -np 1 -c 262144 -b 512 -t 8 ^ --host 0.0.0.0 --port 8080 ^ --flash-attn on --cache-type-k q4_0 --cache-type-v q4_0 ^ --spec-type draft-mtp --spec-draft-n-max 2元数据里
nextn_predict_layers = 1说明模型自带 1 层 MTP(Multi-Token Prediction),3.8 配套了独立的 1.28GB Q4_0 草稿文件。--spec-draft-n-max 2让草稿层一次多预测 2 个 token、主模型一次性验证,中文文本接受率不低,白捡的速度。注意 Q3.6 配置里没有这一项(3.6 没有独立 MTP 草稿文件),别照抄。六、前端接入
llama-server 原生 OpenAI 兼容:
- API:
http://127.0.0.1:8080/v1(chat/completions、models 都通) - Web:
http://127.0.0.1:8080自带 playground
对 DeepSeek Harness(运行本文的工具),把模型服务指向 8080 即可:
:: D:\Dev\start-harness.bat(简化) dsh web --port 3080然后打开
http://127.0.0.1:3080。现在正在服务这段对话的模型,就是本文这台 V100 上跑的——某种意义上是自我验证。服务监听
0.0.0.0,内网其他机器也能用;如果机器走 VPN 或暴露公网,记得加认证和限流(llama-server 没有内置鉴权,建议套一层反代)。七、踩坑清单
- V100 要 Data Center 驱动,GeForce 驱动装不上/不识别。
- Q6 + 256K 直接别想,光权重 23.56GB。
- KV 缓存量化是长上下文的必选项:q4_0 把 256K 的 KV 从 17GB 压到约 4.8GB。
--n-cpu-moe对稠密模型无效,MoE 时代的残留,删掉免得误导。- MTP 要配套草稿文件:3.6 没有 mtp 文件,
--spec-type draft-mtp加了也白加。 - 别重复起服务:8080 端口被 llama-server 占着,脚本里有存在性检查,手动启动前先
nvidia-smi看一眼。
八、速查表
场景 推荐组合 质量优先 Q3.8 UD-Q6_K_XL + ctx 32K~64K 均衡(3.6 主选) Q3.6 UD-Q5_K_XL + ctx 138K + –parallel 2 长上下文优先 Q3.8 UD-Q4_K_XL + ctx 256K + MTP 投机解码 小模型快速验证 Qwen3.5-9B-Q4_K_M(5.29 GB,8G 显存即可) 脚本、模型都在这台机器上,GGUF 元数据解析器在
novel-project/tools/gguf-meta.py。下一篇想写 imatrix 校准与 UD 量化的制作流程。 -

《货舱里装着一整个文明》连载开始:一个新手、一条破船,和一单不能开箱的货
博客「小说」分类的前五章,都来自《货舱里装着一整个文明》。这是我写的第一部长篇小说。这篇算是一篇「作者手记」,写给点进来的读者:这个讲的是什么故事,这些人是谁,以及我为什么写它。
一句话故事
一个在文明边缘跑货的新手拾荒飞行员,误接了一单禁忌货:装着某个已灭亡文明完整记忆的存储核。为了把货送到,他被拖进一支乌合之众的船员队伍,从此被全银河追杀——而存储核一直在船舱里「播放」记忆,包括一帧没人想看到的最后一帧。
为什么写这个
我是个程序员。日常工作是让机器干活,最想写的恰恰是机器干不了的部分:人。
我不想写融合引擎和曲率物理的硬科幻。我想写一个「太空公路片」:一条船、一队人、一单又一单的活,和一片破破烂烂但还在转的银河。技术是布景,人才是主角。
锈钉号
船的名字就是它的资历。
锈钉号是一艘拾荒船:飞在文明之间的漂移带,捡死船、死站、没人认领的东西。它的保养评级从来没超过 D,船上的 AI 老锈在维护日志里骂了它二百一十七年。
但这船有一个优点:再破,也死不了。前面三个船主都不是被船害死的,是被自己的不耐烦害死的。
我喜欢这条船。它像大多数人:外表破破烂烂,但一直在动。
船员
前五章出场的人(外加一位老前辈):
- 拾野:第一人称叙述者。嘴碎、怂、刚拿执照的新手,口头禅是「我不掺和有意义的事」
- 老锈:飞船 AI。吐槽大师,每周发布保养评级。全船拿过的最高分是 D,还有一次是「闭嘴」
- 老周:七十多岁的轮机长。毒舌老油条,手比嘴快,这艘船的每个犄角旮旯他都清楚。他只在要说什么要紧话的时候叫主角的名字
- 温夏:领航员。冷面,回答大多是一个字,从不解释。但她看得见任何星图上都没有的航线
- 阿榔:十六岁的偷渡客。全站灯灭的三秒里溜上船,修好了老周修不了的陀螺仪。他的家乡和拾野来自同一个没有名字的星带——读到第 004 章的你已经知道这意味着什么
- 老灯:货运市场里卖旧航灯的老头。把那一单「好得可疑」的活指给拾野的人。他卖航灯,眼神里的光也一闪一闪
那单货
第 001 章,货运市场上挂着一单:货物一箱,起运地是漂移带某废弃站,目的地是联邦核心圈某港口,运费三千信用点,标记是【不存在】。
我们这行有句话:货运市场上的货,有名字的,叫活;没名字的,叫坟。
货是一团拳头大的哑光黑色:没有质量,没有温度,没有信号。老锈说:「我在跟一堵墙说话。但这堵墙在看我。」
第 005 章,它自己播放了三秒:一座城市。一座非常、非常安静的城市。
追兵
白噪局。
他们不追你——追,说明看得见你。他们只是把你从登记簿、星图和每个人的记忆里安静地划掉。口号是:「我们不抹除真相,我们抹除痛苦。」
老周说:划掉的,是墓碑——墓碑还剩一道痕。我们连痕都没有。
这个故事的恐怖不来自怪物,来自礼貌。
主题一点点
这个故事讲的是两件事:被记住,和被抹除。
银河的和平好像建立在遗忘上;货舱里那团东西,是唯一不能被忘记的。再多不说了,答案在货舱里。
阅读指引
- 前五章已全部放出,请按顺序读:第 001 章 · 首航 → 第 002 章 · 死人货 → 第 003 章 · 开箱 → 第 004 章 · 偷渡客 → 第 005 章 · 划掉
- 第一卷规划 24 章,全书分五卷,一卷 = 一单货 / 一片新地方
- 更新节奏:写完就发,不定期,但不断更
读完前五章的,欢迎在评论区留一句话。我最想知道的是:「三千信用点,亮得像一箱碎屑」——读到这句的时候,你是笑了,还是心里一紧?
-

小说连载自动化:一条命令把 13 章草稿推上 WordPress
《货舱里装着一整个文明》第一卷已经写到第 13 章,草稿都是本地 markdown 文件,一章一个。前五章手动登录 wp-admin 发,五章还行,再往后每章都这么操作,不如写个脚本。
最终效果:
pwsh -File tools/publish-chapters.ps1 # 发布第 1–5 章 pwsh -File tools/publish-chapters.ps1 -Start 6 -End 8 # 发布第 6–8 章一条命令,把指定章节区间发到「小说」分类。这篇文章记录设计决策和踩坑过程。认证部分单独成文(见技术笔记分类的《三种方式登录 WordPress REST API》),这里只交代结论:站点是纯 HTTP,采用「登录表单 + Cookie + Nonce」方案。
一、先明确输入和输出
草稿文件结构是固定的(自己定的):
06-草稿/ 第001章.md 第002章.md ...每个文件长这样:
# 第001章 · 首航 > 本章细纲:首航立人设(嘴碎怂包新手)…… > 本章目标:500 字内让读者听见老锈在吐槽…… --- 老锈在我第一次深空航行的第三十七秒开口了。三段:H1 章节标题、内部备注(两行
>开头)、正文(---之后)。发布要求:- 文章标题用「《货舱里装着一整个文明》+ 章节标题」。博客是技术 + 生活 + 小说混排,不带书名,章节标题在首页信息流里认不出来
- 内部备注不发出去——那是创作手记,不是正文
- 一章 = 一篇文章,归「小说」分类,状态直接已发布
- 幂等:同一命令重跑不产生重复文章;正文改过后重跑,应更新原文
二、三个关键设计决策
1. 内容清洗:只取
---之后的正文转换规则很简单:
- 丢弃第一条
---之前的所有内容(H1、细纲备注、空行) - 正文按空行分段,每段包
<p></p> - 转义 HTML 实体(
&、<、>)
WordPress REST 的
content字段直接存 HTML,不会做 markdown 转换——这一步不能省,否则原文直接提交,前端会把整章渲染成一整行。# 按空行分段 $paras = [System.Collections.Generic.List[string]]::new() $cur = [System.Collections.Generic.List[string]]::new() foreach ($ln in $bodyLines) { if ($ln.Trim() -eq '') { if ($cur.Count -gt 0) { $paras.Add(($cur -join "`n")); $cur.Clear() } } else { $cur.Add($ln) } } $html = ($paras | ForEach-Object { $esc = $_ -replace '&', '&' -replace '<', '<' -replace '>', '>' "<p>$esc</p>" }) -join "`n"2. 幂等:先查后做
每章发布前,先按标题在「小说」分类里查同名文章:
- 查到 →
POST /wp/v2/posts/{id}更新标题和正文 - 没查到 →
POST /wp/v2/posts新建
这一条让脚本的语义从「发布」变成「同步」:任何时候、跑多少遍,站点状态都和本地文件一致。前五章的正文我改过几轮(统一第一人称、修硬伤),每轮都是重跑一遍命令,站点自动跟上,没有手动核对过。
3. 分类:先查后建
「小说」分类在脚本第一次运行时自动创建,已存在则直接取 id。脚本不依赖任何人工前置操作。
三、踩坑记录
坑比设计更有意思。
坑 1:PowerShell 拒绝在 HTTP 上发凭证。
Invoke-RestMethod -Credential在明文连接上会直接报错,要加-AllowUnencryptedAuthentication才肯发。不知道这个参数之前,对着报错看了很久。坑 2:登录表单有 test cookie 机制。 直接 POST 登录,收到「Cookies 被阻止或者您的浏览器不支持」。必须先把登录页 GET 一次拿到 test cookie,再 POST。这步不报错、不提示,纯靠读 WordPress 源码才知道。
坑 3:最隐蔽的一个——构造表单对象失败,脚本却没停。
FormUrlEncodedContent不接受OrderedDictionary,得先转成List[KeyValuePair]。更坑的是New-Object失败后脚本继续往下走,PostAsync发了一个空 body 的请求,登录静默失败,错误在两步之后才以「找不到 nonce」的形式爆出来。教训:关键中间结果必须立即断言——登录 POST 之后现在会马上检查响应,不符合预期立刻抛错。坑 4:WebSession 的 Cookie 解析不可靠。 用 PowerShell 7.6 的
Invoke-WebRequest -WebSession,登录明明成功(302),会话里的 Cookie 集合却解析出名字、值全空的条目——Cookie 在响应头里,但没进集合。换成 .NET HttpClient(Cookie 容器由运行时管理),一次解决。坑 5:UTF-8 要显式指定。 中文 JSON body 用
New-Object StringContent($json, [System.Text.Encoding]::UTF8, 'application/json')。编码不赌默认值,谁也不想为博客乱码调半天。坑 6:别假设环境站在你这边。 最开始的 Basic Auth 401(细节见上一篇)。总结成一条:动工前先验证认证通路,拿
GET /users/me这种只读接口试,通了再干,不通就换方案,别在正式流程里撞。四、后续还能做什么
脚本现在做到「一章一篇」,够用且稳。下一步想法:
- 章节末尾自动插入「上一章 / 下一章」链接
- 自动生成连载目录页,挂到主页
- 封面图支持:章节文件同目录放一张图,走
media端点上传后设为 featured image - 站点上 HTTPS 后,认证换成 Application Password,把登录表单模拟那一步去掉
自动化的乐趣在于:写完一章,跑一行命令,关掉编辑器,章节已经挂在站上了。创作状态不用切去后台打断。
-

三种方式登录 WordPress REST API:Basic Auth、Application Password 与 Cookie Nonce
上周我想写个脚本把小说章节批量发布到博客,第一道坎就是认证:怎么让脚本以「我」的身份登录?WordPress REST API 官方支持好几种认证方式,但在我的站点(WordPress 7.1 + OpenResty + PHP 8.3,纯 HTTP 无 HTTPS)上实测,只有一种走得通。这篇文章记录完整过程、对比和最终方案。
一、Basic Auth:看起来最省事,实测 401
最直观的方式:把用户名密码放进 HTTP 的 Authorization 头。
curl -u 用户名:密码 \ http://你的站点/wp-json/wp/v2/users/me很多教程说这种方式在非 SSL 站点可用,于是我先试了它。结果是 401:
{ "code": "rest_not_logged_in", "message": "您目前没有登录。", "data": { "status": 401 } }我排除了「密码里特殊字符」这个变量——手工把 Base64 头拼出来再发一次,还是 401。这个错误是 WordPress REST 的标准错误结构,说明请求确实到了 WordPress 核心,只是认证没被接受。结论:我的站点当前环境不接受这种认证方式,可能是宿主反向代理或安全策略拦了 Authorization 头,也可能是这套核心/插件组合没有启用它。原因不重要,重要的是生产流程不要依赖它。
二、Application Password:官方推荐,但要求 HTTPS
这是 WordPress 团队最希望你用的方式:
- 后台 → 用户 → 个人资料
- 拉到最下面「应用程序密码」一节
- 输入一个名字(比如
publish-script),点创建,会得到一串xxxx xxxx xxxx xxxx xxxx xxxx格式的密码
用法和 Basic Auth 一样,只是密码换成它:
curl -u 用户名:xxxx-xxxx-xxxx-xxxx-xxxx \ https://你的站点/wp-json/wp/v2/posts好处很实在:它是独立凭证,可随时吊销,不会暴露你的登录密码,官方文档也把它作为首选。但有一个硬条件:只在 HTTPS 下生效。我的博客目前是纯 IP + HTTP 访问,建了也用不了。所以这一条被我记进了待办:等域名和证书下来,认证整体迁过去。
三、Cookie + X-WP-Nonce:最终采用的方案
第三种方式的原理和浏览器一致:先用登录表单拿到会话 Cookie,之后每次 REST 请求带上 Cookie 加一个时效性 nonce。完整流程四步:
GET /wp-login.php—— 这一步最容易被忽略。WordPress 在这个页面会种一个 test cookie,跳过它直接 POST,会收到「Cookies 被阻止或者您的浏览器不支持」POST /wp-login.php(提交 log、pwd、testcookie)——成功后拿到wordpress_logged_in_*会话 CookieGET /wp-admin/post-new.php(任意加载了区块编辑器的后台页面)——页面源码里有一个wpApiSettingsJS 对象,其中的"nonce"字段就是需要的X-WP-Nonce- 每次 REST 请求带上 Cookie +
X-WP-Nonce头
PowerShell 核心实现(.NET HttpClient 会自动管理 Cookie 容器):
$handler = New-Object System.Net.Http.HttpClientHandler $client = New-Object System.Net.Http.HttpClient($handler) # 1) 先 GET 登录页(拿 test cookie) $null = $client.GetAsync('http://site/wp-login.php').GetAwaiter().GetResult() # 2) POST 登录 $body = 'log=user&pwd=' + [uri]::EscapeDataString($pass) + '&testcookie=1' $content = New-Object System.Net.Http.StringContent( $body, [System.Text.Encoding]::UTF8, 'application/x-www-form-urlencoded') $null = $client.PostAsync('http://site/wp-login.php', $content).GetAwaiter().GetResult() # 3) 从后台页面取 nonce $admin = $client.GetAsync('http://site/wp-admin/post-new.php').GetAwaiter().GetResult() $html = $admin.Content.ReadAsStringAsync().GetAwaiter().GetResult() $nonce = ([regex]::Match($html, '"nonce"\s*:\s*"([a-f0-9]+)"')).Groups[1].Value # 4) 调 API $req = [System.Net.Http.HttpRequestMessage]::new('GET', 'http://site/wp-json/wp/v2/users/me') $req.Headers.Add('X-WP-Nonce', $nonce) $me = $client.SendAsync($req).GetAwaiter().GetResult()两个注意点:
- nonce 有时效窗口。默认 tick 是 15 分钟,一个 nonce 在「当前 + 上一」两个窗口内(约 30 分钟)可重复使用。批量任务很快跑完,一次 nonce 够用;长任务要在过期前重新取一次
- 如果用 PowerShell 的
Invoke-WebRequest -WebSession,注意 Cookie 集合解析可能不稳定(我实测拿到过名字、值全空的 Cookie)。换成 .NET HttpClient 自带的 Cookie 容器更稳
四、三种方式对比
方式 需要 HTTPS 脚本友好度 凭证生命周期 在我站的结论 Application Password 是 高 可长期,随时吊销 首选(等证书) Cookie + Nonce 否 中 nonce 约 30 分钟,cookie 按设置 当前在用 Basic Auth 理论不需要 高 — 实测 401,不可用 五、结论
- 站点有 HTTPS:直接 Application Password。凭证可吊销、不暴露登录密码,官方推荐
- 像我这样纯 HTTP、本机自动化:Cookie + Nonce 可行。本质是把浏览器登录过程脚本化
- Basic Auth:当调试时的快捷手段用,别在正式流程里赌它
完整的发布脚本在下一篇(开发实战分类)讲:内容清洗、幂等设计,以及路上踩的坑。
-

重读《小王子》:成年人更容易哭
第一次读《小王子》是小学六年级,只记住了”本质的东西,用眼睛是看不见的”这句话,觉得它很有哲理,也就翻过去了。
这个月重读,读到一半没忍住。
小时候以为它讲的是小王子游历各个星球的故事,长大后才明白,讲的其实是我们自己:我们就像那个商人,数啊数,最后数出来一堆数字,却数不出自己哪一天是真正快乐的。
我们算房子的价格,却忘了算上一次和家人坐下来好好吃饭是多久前;我们算工作的成绩,却忘了问一句现在做的事情是不是自己真的喜欢;我们算通讯录里有多少联系人,却叫不出三个凌晨三点还能打电话的人的名字。
“本质的东西,用眼睛是看不见的,要用心去看。”这句话我小时候背会了,现在才真正听懂。长大让我们失去的,从来不是飞翔的能力,而是看见重要事物的能力。
推荐把这本书送给最想陪在身边的那个人。不是当礼物,是当提醒:在又一次走神之前,再看看身边的人和事。
-

凌晨一点的便利店
上周三加班到很晚,回到住处已经凌晨一点。街上空得能听见自己的脚步声,只有路口那家 24 小时便利店,还亮着暖黄色的灯。
推门进去,门上的铃”叮”地响了一声。店里只有三个人:一个五十岁左右的叔叔在挑方便面,一个背着双肩包的女孩在冰柜前拿水,店员是个看着还没毕业的姑娘。
叔叔在收银台结账,姑娘递过纸袋,说了句:”叔,汤烫,您倒的时候慢点。”叔叔笑了笑:”吃了两个月了,习惯了。”我就站在后面,不知道鼻子怎么就有点酸。
我买了一杯热咖啡,坐在角落看着窗外。偶尔有出租车开过去,车尾灯拉成一条红线,又消失在街角。城市其实从不真正睡着,只是这个点,只有还在赶路的人,才看得见它温柔的那一面。
后来我常想,支撑我们走下去的,也许不是什么宏大的理想,而是这些冷不丁冒出来的、小小的暖意——一杯热咖啡,一句陌生人随口说的关心。
下次你也很晚下班的时候,不妨拐进去坐一会儿。
-

用 AI 写作的半年:几个真实的变化
过去半年,我把 AI 当成了写作搭子:先让它帮我列提纲,再让它起草稿,最后再自己改。用了这么久,还是想认真聊聊几个真实的感受。
一、空白页恐惧症,治好了大半
以前坐下来写东西,最难受的就是开头。现在我会先让 AI 列 5 到 10 个角度,里面只要有一个打动我,我就顺着写。写文章最难的那一步——想清楚从哪下笔——五分钟就解决了。二、初稿变快了,但我的声音在消失
用得越多,越发现自己说话开始”模板化”。每一段都讲究结构,每一个过渡都很丝滑,可读完之后,找不到一句只有我才会写的话。所以我现在给自己定了个规矩:初稿改完,必须把最关键的两三句用完全自己的话重写一遍,哪怕写得更”笨”一点。三、AI 擅长”结构”,不擅长”观点”
一篇真正有价值的文章,核心还是我自己的经历、自己的判断。AI 能做的是帮我把这些想法整理清楚、表达完整。它像一个很厉害的编辑,能帮你调骨架,但给不了你灵魂。半年的结论就一句话:AI 是很好的工具,但不能当作者。工具只会越来越强,但敢不敢表达、有没有自己的观察,这件事永远只能自己来。
-

《货舱里装着一个整体文明》第005章 · 划掉
锚港是我们第一个名字。渔光号的锚港。一个漂在漂移带边缘的小站,地图上有个点,黑,丑,但亮着灯,写着”锚港·永亮”四个字。老锈说这是附近唯一还认得渔光号编号的地方。”去。”老周说,”补点料。陀螺仪虽修好,引擎还得喂真货。”渔光号泊进锚港。泊位上冷冷清清,三艘破船,一艘比我们还破。港口管理员是个半机械的老头,半边脸是铁,另一半脸是肉,他看我们的编号,看我们的人,看我们怀里的黑匣。”渔光号。”他说,铁脸一半动,肉脸一半不动,”登记在案。”我松了口气。至少这会儿,我们还在。我们上去补料。阿榔在机舱睡,温夏在舱角看星图,老周在跟港口管理员磨那点儿泡面零件。我抱着黑匣,坐在泊位的矮墙上,看锚港那点灯。灯很亮。写着”永亮”。然后灯灭了。不是灭。是”不存在”了。前一秒还亮着的四个字——”锚港·永亮”,下一秒,没了。不是灯灭的黑,是字没了。那四个字,像谁拿橡皮,把”锚港”擦掉,剩下”·永亮”,再把”永亮”擦掉,剩下一个”·”。我眼瞎了。”锚港。”我叫,”锚港呢。”老周过来。他脸色比我白。”没了。””哪去了。””从未存在。”它声音发干,”锚港,从未存在。”我回头看那矮墙,我刚坐的那堵墙——没了。泊位没了。三艘破船没了。半机械老头没了。港口管理员没了。整个锚港,没了。只剩我们渔光号,孤零零泊在一团空里,像一张白纸中间漏了一艘船。”我们……”我喉咙发紧,”我们刚才在这。””在。”老周说,”现在不在。从未存在。”我低头看我怀里的黑匣。它凉的。它什么都没告诉我。”本机日志。”我耳机里喊。”在。”老锈声音平,但我听出那平底下在抖,”本机日志,锚港——从未存在。本机没有锚港的到访记录。””我们刚才……””本机没有。”它说,”本机日志,从未到访锚港。”我懂了。白噪局抹除,抹的不是”现在”,是”曾经”。它把锚港从”存在过”改成”从未存在”。连带我们把锚港的事,也从每个人记忆里划掉。我连”我们到过锚港”这件事,都快忘了。”别忘。”我掐自己一把,疼,”锚港。锚港·永亮。我们泊过。””我们泊过。”老周重复,像嚼一块硬面,”白噪局划掉了。划得比锚港还狠——它划的是我们。”我抬头。泊位上空,一道白影。白船。它不吵,不亮,就挂着,一堵会动的墙,把我们这条破船罩在里头。它不追。它只扫。它扫我们的编号。我盯着它,那白影从我们船头扫到船尾,一寸一寸。它读我们的存在。读数低,垃圾。读数高——”读数低,放行概率高。”老锈说,”我们现在读数低。前提是——””装得像垃圾。”老周已经爬到舱外,把渔光号外层防护壳拆了一半。这艘船当货两百一十七年,第一次当废船卖。壳拆了塞进废船队,白噪的巡查扫不到我们头上。”壳留一块,别拆干净。”我提醒,”太干净不像废的。”老周瞪我一眼,留了块指甲大的原漆,假得我臊得慌。”渔光号的编号,”我小声说,”还在吗。””在。”老锈说,”但它撑不了多久。白船刚扫过它。再扫一次——””就没了。””就没了。”它声音平,”本机建议:改名。””改名。””渔光号的身份,保不住了。”老锈说,”我们得换一张皮。白噪划掉一个,我们立刻长出一个新的。等它下次扫,读到的不是渔光号,是一艘从没听说的废船。””叫什么。”它停了一瞬——这 AI 平时话多,这会儿卡壳,奇怪。”锈钉。”它说,”本船当货两百一十七年,第一次当废船。就叫——锈钉号。”我点了头。老周把最后一片漆补上,下来。”锈钉号。”他嚼着这三个字,”好名字。废到底了,白噪都懒得扫。”我抱着黑匣。渔光号没了。锈钉号活着。”拾野。”老锈忽然说,”本机日志,补记一条。””记什么。””本机日志,”它声音平,”第 217 年,本机第一次,把’渔光号’写成了’锈钉号’。””什么意思。””意思是,”它顿了顿,”我差点忘了自己是渔光号。”我后颈发凉。”你忘了。””我盲区里有。”它说,”黑匣一放,我就睡着。睡着,我就忘了自己是谁。本机货当了两百一十七年,第一次,连自己是谁都快忘了。”我低头看黑匣。它凉的。哑光。一块石头。”黑匣。”我声音发干,”是不是你。”它没答。但锚港那团空里,我忽然看见了一座城。安静的人,影子慢半拍,手多一关节。一个孩子的背影,在一条无人的街上走。就一下。然后没了。”老周。”我喉咙发紧,”你看见没。”老周正拆最后一片壳。他手停了。”看见了。””什么。””一座城。”他声音飘,”安静的。影子慢半拍。”阿榔从机舱探出头,眼睛红。”我也看见了。”我们四个人,锚港那团空里,四个被划掉的人,同时看见一座城。黑匣在我怀里,凉,沉。它放了一次。短。就一下。跟开箱那次似的,停同一帧。”它认路。”老锈说,”它在认路。它放一次,就离我们近一点。””离我们,去哪儿近。”它没答。它只说:”本机日志,第 217 年,本机第一次,梦见一座城。””你做梦。””我盲区里。”它声音平,”我睡着的时候。四个人一个梦。梦里那座城,静。影子慢半拍。手多一关节。”我抱着黑匣,坐在锈钉号(不是渔光号了)的矮墙上,看锚港那团空。我们被抹了。从”渔光号”变成”锈钉号”。从”存在过”变成”从未存在”。可那座城,还在我们梦里。它去我们去一个,连白噪都不敢抹的地方。白船又扫了一次。它读我们的新编号——锈钉号,一艘从没听说的废船。读数低,垃圾。它飘走了,连我们这垃圾都没多看了一眼。”它扫不到我们了。”老锈说,”锈钉号的编号,白噪查不到。””那我们……””我们活着。”它声音平,”以一艘废船的身份。”我低头看掌心。那短的一帧,还在。一座城,静,影子慢半拍,孩子背影。我忽然想,那孩子是不是回头看了我一眼。我没敢回头。我怕我一回头,锚港那团空里,什么都没有了。连那座城,连我怀里这个凉的石头。”老周。””嗯。””我们到底在送什么。”他静了。很久。他抽完那根没点着的烟,烟头早灭了,他都不知道。”货。”他最后说,”一箱货。””死人货。””死人货。”他重复,像这四个字有千斤重,”我们送的是死人货。”我低头看黑匣。它凉的。我忽然怕它。不是怕它死我。是怕它活太久,久到它忘了自己是谁,忘了它要送往哪里。”它忘了。”我说,”黑匣忘了。它一放,就睡着。睡着了,忘了自己是谁。””它忘了,我们记得。”老周说,”四个人,一个梦。梦里那座城。””那我们记得。””记得也是暂时的。”它声音平,”白噪能抹掉记忆。它能抹掉我们记的,也能抹掉黑匣记的。””那它为什么还记。”老周没答。他抬头看泊位上空,那白影远了。”本机日志。”我耳机里老锈说,”补记最后一条。””记什么。””本机日志,”它声音平,”第 217 年,本机第一次,不想忘了自己。””为什么。””因为,”它顿了顿,”忘了自己,本机就忘了……忘了自己要送去哪里。”我抱着黑匣,坐在锈钉号的矮墙上,看锚港那团空。我们被抹了。可那座城,还在我们梦里。它去我们去一个,连白噪都不敢抹的地方。