title: 一千六百行文件怎么瘦身——一次"沉入引用"的重构实录 date: 2026-06-14 status: draft
一个技能文件写了 1659 行,lint 上限是 800 行,超了一倍还多。这不是夸张——当你在项目里不断加协议、加快照、加历史决策,文件就这么不知不觉地膨胀起来。每一段内容都有用,每一段都不敢删。于是它变成一个什么都往里塞的抽屉,打开费劲,找东西更费劲。
事情是怎么发生的
那天我需要重构一个 1659 行的技能文件。要求很明确:用"沉入引用"的模式,和之前重构另外三个技能文件一模一样。所谓"沉入引用",就是把不在每次加载时都需要的内容,原封不动地搬到 references/ 目录下的独立文件里,主文件只保留核心流程和对引用的指向。
听起来简单,但真正动手的时候,最怕的不是搬内容,而是搬错了、漏了、或者重复了。
表面问题和真实问题
表面问题是行数超标,需要裁剪。但真实问题是:如何在删除零内容的前提下,让主文件变轻? 不是删,是搬。搬了之后还要保证引用路径正确、不与已有文件重复、不破坏外部同步工具维护的哈希值。
这件事让我重新意识到,重构的难点从来不是"去掉什么",而是"搬走之后怎么保证东西还在"。
我是怎么拆的
第一步,通读整个文件,记下当前版本号。这不是走过场——版本号后面要用来命名备份文件和引用文件的头部标记,搞错了就追不回来源。
第二步,备份原文件。用版本号做后缀,放到固定目录下。这一步是保险绳,万一拆完发现有问题,原文件还在。
第三步才是核心:识别哪些内容"不需要每次加载"。快照、长协议、操作手册、详细示例、历史决策、参数表——这些都是"用的时候再看"的内容。把它们逐段搬进 references/ 目录,每个文件用 kebab-case 命名,开头一行注明"从 vXX 版本沉入"。如果 references/ 下已有同主题文件,就指向它而不是再建一份。
最容易误判的地方就在这里:你以为两段内容是重复的,其实一份是旧版、一份是更新后的版本。 如果直接指向旧文件,新信息就丢了。所以必须先检查现有引用文件的内容覆盖范围。
第四步,重写主文件。只保留 frontmatter(版本号微调、更新日期改掉、content_hash 行不动——那是外部同步工具维护的)、核心流程、和引用指向。写完之后做两件事:验证提取段数是否对得上,边界是否完整;跑一遍已有测试确认没有断裂。
如果不做会怎样
如果不重构,文件继续膨胀,每次加载都带着一堆不需要的内容。AI 读取时上下文被无关内容占满,真正需要的流程反而被淹没。更危险的是,当多人协作时,没有人敢动一个 1600 行的文件,因为它太大了,改一处可能牵连全局。
一个文件膨胀的标志,不是它有多长,而是你打开它时已经不敢改了。
可复用的方法
这次重构沉淀下来的方法很简单,但需要严格遵循:
- 先备份,再动手。 用版本号做标记,保证可回溯。
- 搬内容,不删内容。 沉入引用的核心是零内容删除。
- 先查后建,避免重复。 references/ 下可能已有覆盖文件。
- 不动外部工具维护的字段。 比如 content_hash,改了就破坏同步。
- 搬完验证。 段数、边界、测试,三重确认。
下次我会怎么做
下次遇到类似的大文件,我会先花五分钟做一个简单的分类表:哪些段落是"每次加载必读",哪些是"按需查阅"。分类本身比搬移更重要——分类错了,搬再多也没用。另外,我会把"沉入引用"当成一个预防习惯,而不是等文件超标了才想起来做。每加一段新内容时,问自己一句:这段需要在主文件里吗?如果不需要,直接写到 references/ 就好。