
这几天我干了一件挺有意思的事用 SDDSpecification-Driven Development规格驱动开发的方式跟 AI 协作开发了一个中文排版用的 npm 包并且真的发布到了 npm 上。整个过程走下来我对“AI 协作开发”这几个字的理解彻底变了。以前总觉得 AI 就是个高级代码补全器让它写段函数、改个 bug 可以正经做项目不靠谱。现在我发现只要流程设计对路AI 完全可以像一支外包团队那样拿着规格文档按契约交付而我要做的就是写好需求、拆好任务、审好代码。这篇文章会把 SDD 的核心思路、规格文档怎么写、六步实践具体怎么落地、以及发布 npm 包时踩到的各种坑全部写出来。想认真尝试 AI 协作开发、又不想停留在“帮我写段代码”聊天阶段的朋友这篇应该能给你不少能直接抄作业的参考。1. SDD 是什么为什么它跟 AI 协作是绝配1.1 从“对话式编程”到“规格驱动”中间差的是契约大多数人和 AI 协作的方式是这样的打开聊天窗口输入“帮我写一个函数实现某某功能”AI 啪一下给你一段代码你复制粘贴跑一下报错再贴回去让它改如此反复。这种“对话式编程”不是不能用但它有几个很要命的问题。第一需求是聊出来的不是写下来的聊到后面你自己都忘了最初要什么第二AI 每次生成的代码只对当前对话负责没有全局约束改着改着就面目全非第三没人验收AI 说“完成了”你就真信了功能到底对不对、边界情况处理没处理全靠运气。SDD 的思路正好相反先写规格再写代码。规格文档就是人和 AI 之间的“合同”里面写清楚输入是什么、输出是什么、有哪些功能要求、哪些边界情况必须处理。AI 的活儿不是“自由发挥写代码”而是“照着合同交货”。代码写得不对不是让 AI “修一下”而是对照规格一条条检查哪条没满足改哪条。我在做这个排版 npm 包的时候最深的一个体会就是这个把需求写成规格之后整个项目突然变得可控了。AI 不再是一个“话痨结对程序员”而是一个“按单交付的承包商”我作为项目负责人只需要管好规格和验收。1.2 三级分类框架认清 AI 协作的三种水位说到这儿就得提一下 ThoughtWorks 的 Birgitta Böckeler 提出的 AI 结对编程分类框架。这个框架把 AI 在开发中的角色分成了三级我理解下来大概是这样的。第一级是“编辑器内联补全”就是 IDE 里那种灰色提示你写个函数名它帮你补完。这个阶段 AI 是提词器它只对“当前正在敲的这行代码”负责没有能力理解整个项目。第二级是“任务级 Agent”像 Claude Code、Codex 这类工具已经能做到你给它一个任务它能自己翻代码、改文件、跑命令甚至提交 commit。这个阶段 AI 已经从“提词器”进化成了“初级程序员”但它依然缺乏对需求的完整理解你说一步它做一步。第三级才是真正的“规格驱动开发”。这个阶段人负责写规格文档、拆任务、做评审AI 负责在规格约束下批量实现代码。Birgitta 那套分类框架的核心启示就是AI 能力越强人越应该往“上游”走——把精力花在定义问题而非实现细节上。我这次做排版 npm 包就是按第三级来实践的。说实话刚上手的时候我也怀疑过就一个小工具用得着搞这么正式吗结果真的做下来才发现规格驱动带来的收益不是“写代码更快”而是“返工更少”。1.3 为什么“写规格”比“写代码”更值钱很多人一听 SDD 就觉得是“多了写文档的负担”。但我的实际体验正好相反写规格省下的时间远远大于写规格花掉的时间。原因很简单。跟人协作需求不清晰你还可以开会扯皮跟 AI 协作需求不清晰它真的会给你编。你只说“处理一下标点”它可能把英文句号全给你替换成中文句号把 URL 里的斜杠也改了甚至把小数点的含义都搞乱。AI 是语言模型不是读心术需求文档里没写的东西它只会用“最可能的理解”去实现而这个“最可能”往往跟你要的不是一回事。规格文档的意义就是把“最可能的理解”变成“唯一的约束”。我这次写的规格里连“URL 和邮箱地址不处理”“小数点和版本号里的点号不转换”这种细节都写进去了。正是因为写清楚了AI 一次实现就基本对了后面只做了很少的修正。2. 项目需求与规格设计动手之前先想明白“做什么”2.1 为什么选“排版工具”当 SDD 的练手项目先说一下我做的是什么。这是一个叫 cjk-compose 的小工具核心功能是文本级的中文排版规范化。听起来有点抽象举几个例子你就明白了。“Hello世界这是一段测试text。”——这句话里中文和英文之间缺空格逗号用的是半角的读起来很挤。经过排版工具处理之后会变成“Hello 世界这是一段测试 text。”——中英文之间自动补空格中文语境下的标点换成全角整体清爽很多。这类需求在中文内容生产场景里特别常见。公众号编辑器、文档平台、内容中台很多都在用类似的能力做文本清洗。我选择这个项目练手一是因为它的边界相对清晰适合验证 SDD 流程二是因为它规模适中可以用 AI 快速实现又不至于小到一个函数就搞定三是因为它有明确的“对错标准”好验收不像某些业务逻辑对错全凭感觉。当然最核心的原因是这个工具足够老实地覆盖“规格文档应该覆盖的那些事”。中文和英文之间怎么加空格、全角半角怎么转换、禁则处理做不做、HTML 输出怎么兼容——每个决策点都是写规格的好素材。2.2 功能清单与 API 设计写规格之前我先把功能范围圈定了。第一版只做四件事中文与英文之间自动插入半角空格中文与数字之间自动插入半角空格中文语境下错误使用的半角标点转全角连续空格压缩与基础空白整理HTML 输出和禁则处理放到第二版但规格里要把接口预留好免得以后升级 break API。API 设计我参考了 pangu 这类成熟库的用法但做了一点简化。核心就一个函数import { format } from cjk-compose; const output format(input, { spacing: true, // 中英文/数字间加空格 punctuation: true, // 标点标准化 output: text // 输出格式text | html });CLI 也配上方便在终端里直接处理文件cjk-compose -i input.txt -o output.txt --format text为什么 API 要这么设计因为一个排版工具最忌讳的就是“一把梭”式地替用户做全部决定。有的用户只想加空格不想动标点有的用户处理的是 Markdown 源码里面全是半角标点动标点反而坏事。所以每个能力都要做成独立开关默认全开但用户可以按需关闭。这个决策如果不在规格阶段定下来等 AI 帮你写完了再改改起来就是伤筋动骨。2.3 边界情况清单把蛋疼场景提前列出来这部分是我觉得 SDD 最有价值的地方。跟 AI 协作边界情况不说清楚它一定会踩雷。我在规格里直接列了一个“禁区清单”第一个坑是 URL 和邮箱。你写一段英文 URL比如https://example.com/path如果排版工具在里面乱插空格链接就废了。所以规格里明确写凡是匹配 URL 或邮箱模式的内容整体跳过不处理内部任何字符。第二个坑是小数点和版本号。3.14里面的点v2.0.1里面的点都不能转成中文句号。如果 AI 傻乎乎地把所有英文句号全替换成中文句号那这份文本基本就不能要了。第三个坑是 HTML 标签。如果用户传进来的是Its strongimportant/strong你处理的应该是文本节点而不是标签内部的内容。这个在纯文本场景下可以简化但一旦开了 HTML 输出模式就必须考虑。第四个坑是中文引号。很多人打字习惯用直引号但在中文排版规范里应该用弯引号“”。这个转换规则比标点转换复杂因为引号是成对出现的不能简单地按字符替换得做配对处理。这些边界情况如果在开发过程中才发现你只能在代码里打补丁很容易补出一个 bug 又带出另一个 bug。但写在规格里AI 在一开始实现的时候就会主动处理这就是“前置约束”和“后置补救”的区别。2.4 一份可用的规格文档长什么样我把我那份规格文档的结构简化一下放在这儿想照着做的人可以直接参考# cjk-compose 排版工具规格 v0.1.0 ## 1. 项目目标 输入任意混合中英文、数字、标点的文本输出符合中文排版规范的文本。 ## 2. 输入输出 - 输入: string - 输出: string - 异常: 非字符串输入抛出 TypeError ## 3. 功能需求 1. 中英文之间插入半角空格 2. 中文与数字之间插入半角空格 3. 中文语境下半角标点转全角逗号、句号、问号、感叹号、冒号、分号、括号 4. 连续空格压缩为单个空格 5. 直引号配对转换为弯引号 ## 4. 边界与例外 1. URL、邮箱地址整体跳过 2. 小数点3.14、版本号v2.0.1中的点号不转换 3. HTML 模式下手标签内容不处理 4. 连续 3 个及以上全角标点不追加转换 ## 5. 非目标第一版不做 - 不做分词 - 不做字体嵌入 - 不做完整的中文排版引擎 ## 6. 验收标准 对给定 fixture 文件逐条断言覆盖上述所有功能与边界。注意第 5 节“非目标”这个是很多人写规格容易漏掉的。明确“不做什么”比明确“做什么”还重要。AI 是生成模型你不限制它它就喜欢“超额完成”加一些你没要求的东西反而引入风险。3. 六步实践指南从规格到 npm 发布3.1 第一步把规格文档当作“唯一事实来源”这次项目我采用的就是社区里流传的 SDD 六步实践流程。第一步很简单把上面那份规格写完整存成SPEC.md放进项目仓库根目录。为什么强调“放进仓库”因为规格只有在版本管理里才是活的。AI 实现的每一版代码都对应某个版本的规格代码和规格要能对得上。如果规格只在聊天窗口里存在翻几条消息就没了AI 改着改着就“自由发挥”了。写规格的时候我还有个习惯同时把验收用例写好。不是严格意义上的测试代码而是“当输入是 X输出应当是 Y”这样的断言清单。这个习惯帮我省了很多事——因为后续 AI 实现完我只要拿这份断言清单去验证就行不用每次重头想“它写得对不对”。3.2 第二步把规格拆成一批可交付的小任务规格文档是给 AI 看的总纲但 AI 一次处理不了太多上下文所以我把它拆成了 5 个小任务初始化 npm 包结构package.json、目录、基础类型定义实现中英文空格插入功能实现标点标准化功能实现引号配对与边界情况过滤编写测试与 CLI 入口每个任务的描述都直接引用规格里的条款。比如任务 3 的描述是“参照 SPEC.md 第 3.3 条实现中文语境下半角标点转全角。注意第 4.2 条规定的 URL、小数点和版本号场景不得转换。”任务描述越精确AI 实现越靠谱。这一步我最大的感受是任务拆得越小AI 犯错的概率就越低。一个任务负责一个纯函数AI 的输出就可以被精准验收。反过来说如果你塞给它一个“把整个包实现出来”的大任务AI 很容易在某个角落里自作主张等你在集成测试时才发现排查成本就高了。3.3 第三步用 AI Agent 按任务逐个实现拆好任务之后就轮到 AI Agent 上场了。我用的工具是命令行的 AI 编程 Agent比如 Claude Code、Codex 这一类启动后直接把规格文档路径和当前任务描述丢给它让它自己读仓库、写代码、跑测试。这一步有个操作习惯值得分享给 Agent 的任务我会把“完成标准”写得很具体比如“实现后运行npm test确保test/space.test.js下所有用例通过”。AI Agent 是目标导向的你给它一个可验证的目标它会主动去跑测试、看报错、修代码直到达标为止。如果你只说“实现这个功能”它写完就停了代码对不对全靠你人肉检查。不过话说回来AI Agent 干活的时候人不能完全撒手。我基本上每个任务完成后都会快速瞄一眼 diff看有没有“跑偏”的迹象。整体上 5 个任务里有 3 个是一次通过的剩下的 2 个在做完评审时发现了问题具体放在第四步说。3.4 第四步人工审查别把 AI 当监工不当人AI 实现完之后审查环节是省不掉的。我这次审查发现了两个典型问题都是 AI 在边界情况下“自作聪明”导致的。第一个问题出在空格插入功能上。规格要求“中英文之间插入空格”但 AI 把3 月这种中文字和数字之间的空格也处理了。这个功能本身没问题但它把v2.0.1这种版本号里的空格也处理了——它先按 URL/版本号规则跳过了点号却忘了跳过整个版本号 token。结果v2.0.1被输出成了v 2.0.1从语义上完全错了。第二个问题比较隐蔽。AI 实现引号配对时把所有都当成中文语境下的引号处理结果把 JSON 字符串里的引号也转换成了中文引号“”。虽然我的规格里写了“中文语境”但没定义“什么是中文语境”AI 就默认了“包含中文的句子里的所有引号都处理”。这个 bug 在纯文本场景下问题不大但一旦用户传入带 JSON 的文本转换结果就是灾难性的。这两个问题的共同点是什么都出在规格没写清楚的地方。审查环节的价值就是把这些“规格空白区域”暴露出来然后你去补规格、改代码。审查一次规格完善一次AI 后续的实现就更接近“一次做对”。3.5 第五步测试验证让断言替你说“不行”SDD 的第五步是测试验证。我的做法是规格里的每一条功能需求和每一条边界情况至少对应一个测试用例。测试框架用的是 Node.js 内置的node:test这个在 Node 18 里直接可用不用额外装依赖。测试用例我举两个例子import { test } from node:test; import assert from node:assert/strict; import { format } from ../src/index.js; test(中英文之间插入半角空格, () { assert.equal(format(Hello世界), Hello 世界); }); test(版本号中的点号不转换, () { assert.equal(format(当前版本v2.0.1已发布), 当前版本 v2.0.1 已发布); });第二个用例其实就是我在审查中发现的那个 bug 的回归测试。先把 bug 修掉再把断言固化为测试用例这样以后 AI 或者任何人改了代码只要跑一遍测试问题就会立刻暴露。3.6 第六步构建、版本管理、发布测试全部通过之后最后一步是构建和发布。虽然这个包是纯 JavaScript 写的不需要编译但为了保险起见我还是加了prepublishOnly脚本让发布前自动跑一遍 lint 和 test防止“脑子一热发了个坏包”的事故。版本管理用的是 npm 自带的 semver 流程npm version patch提交一个新版本号然后再npm publish发布。这里有一个小坑后面避坑实录里会详细说——发布之前一定要确认package.json里的files字段只打包该打包的文件不然node_modules或者测试文件被一起发布到 npm 上既浪费空间又显得特别不专业。4. 核心实现细节与关键代码解析4.1 中英文之间插入空格两个正则搞定排版包的核心功能里最简单的就是中英文之间插入空格。核心实现其实就两个正则替换const CJK_RE /[\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u3040-\u30FF\uAC00-\uD7AF]/; export function insertSpacing(text) { return text .replace(new RegExp((${CJK_RE.source})([A-Za-z0-9]), g), $1 $2) .replace(new RegExp(([A-Za-z0-9])(${CJK_RE.source}), g), $1 $2); }第一行CJK_RE覆盖了 CJK 统一表意文字、扩展 A 区、兼容表意文字、日文假名和韩文音节。做中文排版的时候这个字符集合比我一开始想象的重要得多——如果不把日文假名和韩文包含进去用户处理多语言文本时就会出现“中文和英文之间有空格日文和英文之间没空格”这种不统一的情况。两个 replace 分别处理“中文在前英文在后”和“英文在前中文在后”两种方向。这里要特别注意正则里的字符组千万不能写成[A-Za-z]就把数字漏了数字和中文之间的空格也是排版规范的一部分所以字符组里要带上0-9。4.2 标点标准化转换表加上下文判断标点标准化比加空格要麻烦一点因为它不是简单的字符替换得结合上下文判断。核心逻辑分两层第一层是半角转全角的映射表const HALF_TO_FULL { ,: , .: 。, ?: , !: , :: , ;: , (: , ): , [: 【, ]: 】 };第二层是判断“当前半角符号是否处于中文语境”。我的简化策略是如果符号前面有 CJK 字符就认为是中文语境执行转换如果前面是拉丁字母或数字则不转换保持原样。这个策略看起来简单实战中效果不错但有两个例外必须在转换之前先处理。一个是小数点3.14里的.前面是数字3按规则不转换这里天然安全但3.14 版本。这种句子结尾的.前面是4也不会被转换这就不对了。所以规格里专门加了边界规则当.前面是数字、后面是空格或句子结束符时按句号处理。这个补丁逻辑看起来有点“脏”但真实世界的文本就是这样规格驱动开发的意义恰恰在于把这些脏逻辑提前想清楚。4.3 直引号配对转换为弯引号引号配对是我这个小项目里实现上最绕的一个功能。ASCII 直引号在英文文本里是中立引号但在中文排版里需要转换成成对的弯引号“和”。实现思路是状态机遍历字符串用一个布尔变量记录“当前是否在左引号状态”。遇到时如果当前是左引号状态则输出”否则输出“然后翻转状态。但这里有个现实问题用户有时候只写了一个引号比如 “他说” 后面忘了闭合引号那状态机就会“错位”后面所有引号都反了。我的处理是当文本里的引号数量为奇数时最后一个引号保持原样不做转换。这不算完美但至少避免了“越改越错”的尴尬。想深入处理的话下一步可以用 NLP 模型判断引号方向但作为排版工具的第一版这种工程折中是合理的。4.4 HTML 输出模式排版规则与标记结构的平衡第二版我加了 HTML 输出模式这里其实藏着一个排版工具最常见的设计难点处理 HTML 时你不能把标签当普通文本处理。我的方案是分两遍走第一遍先把[^]这种标签通过正则提取出来替换成占位符\x00加上序号第二遍对剩余文本执行所有的排版规则最后再把标签按序号放回去。export function formatHtml(html) { const tags []; const placeheld html.replace(/[^]/g, (tag) { tags.push(tag); return \x00${tags.length - 1}\x00; }); const formatted format(placeheld, { output: text }); return formatted.replace(/\x00(\d)\x00/g, (_, i) tags[Number(i)]); }这个占位符方案在绝大多数场景下够用但有一个已知局限如果 HTML 属性值里包含中文文本比如title你好世界属性里的内容也会被排版处理。严格来说应该用真正的 HTML 解析器按 DOM 节点处理但作为文本级排版工具用占位符方案换取轻量依赖我认为是划算的。这个取舍也在规格文档里明确写了避免以后有人拿它当完整 HTML 处理器用。5. npm 发布全程与避坑实录5.1 发布前检查清单别让细节坑了自己代码写完、测试通过之后发布 npm 包前我过了一遍检查清单每一条都是血泪教训换来的。第一确认package.json里的files字段。这个字段决定哪些文件会进入发布的包。我的配置是{ files: [dist, README.md, LICENSE] }不加这个字段npm 会把所有文件都打包进去包括测试文件、源码目录、甚至node_modules里不该出现的东西。这个不是洁癖问题是专业性问题——别人npm install你的时候下载的是你的整个项目而不是最小可用的产物。第二确认main、module、exports三个字段指向正确的入口文件。很多新手发布完包发现别人import报错基本都是这三个字段没配对。我用的是exports字段做双入口require走 CommonJSimport走 ESM。第三prepublishOnly脚本必须挂上。这个脚本会在npm publish之前自动执行我把它配成了先跑测试再跑单元测试{ scripts: { test: node --test test/, lint: eslint src/, prepublishOnly: npm run lint npm test } }这样一来就算哪天脑子一热直接npm publish也不会把没测试过的代码发出去。5.2 完整发布流程从登录到版本号发布流程本身不复杂但新手容易在“登录”这个环节卡住。npm login会让你输入用户名、密码和邮箱注意邮箱必须和 npm 账号注册时的邮箱一致否则登录会失败。登录之后先跑一遍npm publish --dry-run这个命令会模拟发布展示即将上传的文件清单。我每次发布前都会看一遍这个清单确认里面没有“不该出现的东西”。这个习惯帮我避免过至少两次“误传 node_modules”的事故。正式发布前还要确认版本号。如果是一次 bug 修复用npm version patch把版本号从0.1.0升到0.1.1如果是新功能用npm version minor升到0.2.0破坏性 API 变更才用npm version major。这个 semver 规范必须严格遵守因为 npm 生态的依赖解析就是建立在版本语义之上的乱升版本号迟早坑到别人也坑到自己。发布完成后建议立刻npm install cjk-compose装到你自己的一个测试项目里验证一下发布出去的包真的能用。这一步很多老手都跳过但新包第一次发布很容易在files配置上出问题导致包本身是空的或者入口文件缺失只有真正“从 registry 拉下来用一次”才能发现。5.3 高频报错一栏表这些坑我都替你踩过了发布和安装 npm 包的过程中有几个报错是我这次实打实遇到的也是新手群里出现频率最高的整理成一张表方便直接查报错现象原因解决办法npm : 无法加载文件 npm.ps1因为在此系统上禁止运行脚本Windows PowerShell 默认执行策略限制以管理员身份运行 PowerShell执行Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser或者改用 CMD 运行 npmnpm ERR! code CERT_HAS_EXPIRED使用了旧的镜像源证书已过期检查.npmrc里的 registry 配置换成官方源https://registry.npmjs.org/或更新到新镜像地址然后npm cache clean --forcenpm WARN deprecated node-domexception1.0.0依赖树里有老旧的间接依赖用npm ls node-domexception定位来源更新对应的顶层依赖不要慌deprecated 不等于不能用npm WARN using --force recommended protections disabled有人执行了npm install --force别用--force硬装优先解决依赖冲突。--force会绕过完整性校验指不定装进来什么无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称Node.js 没装好或 PATH 没配置重新安装 Node.js LTS 版本安装时勾选“Add to PATH”装完后重启终端再试这里面我想重点说一下最普遍的 PowerShell 那个错误。很多 Windows 用户第一次跑npm -v就碰到这个第一反应是“npm 坏了”其实不是这是 PowerShell 的执行策略拦截了.ps1脚本。解决办法有两个一是用Set-ExecutionPolicy放开当前用户的脚本执行权限这也是我推荐的方案不会降低系统安全性因为RemoteSigned只允许本机脚本和受信任发布者的签名脚本运行二是干脆不用 PowerShell用 CMD 或 Git Bash 跑 npm。我个人的习惯是Windows 开发机上直接用终端Windows Terminal PowerShell把执行策略改好一劳永逸。5.4 发布后的收尾文档、示例和持续迭代包发布上去只是第一步后面的收尾工作同样重要。第一个是 README我必须得说README 写得好的包和写得烂的包使用体验天差地别。一份合格的 README 至少要包含这个包解决什么问题、安装命令、两行代码的快速上手示例、完整的 API 说明、以及常见问题的处理。我这次还加了一个“这个包不做什么”的章节明确告诉用户禁则处理和分词的边界免得有人装完之后骂骂咧咧。第二个是示例项目。我在仓库里放了一个examples/目录里面是一个可以直接跑的 demo包含了几段典型的混合文本和对应的处理结果。别小看这个动作很多用户选包的标准就是“有没有一眼能看懂的示例”。我自己选依赖库的时候就特别反感那种 README 写得云里雾里、全靠翻源码猜用法的包。第三个是版本迭代节奏。0.1.0发出去之后我给自己定了两条规矩每次改动都先改规格文档再改代码每次新版本发布前必须跑完整测试套件。这不是流程洁癖而是 SDD 的核心理念在发布后的延续——规格驱动开发不是一次性动作它是整个项目生命周期的默认工作方式。写在最后一点真实体会这次做完 cjk-compose 这个包我最大的收获不是“会发布 npm 包”了而是彻底想通了一件事AI 协作开发的瓶颈从来不在 AI 的代码生成能力而在人能不能把需求讲清楚。以前我写代码脑子里有个大概的想法就开始敲边敲边想写出来什么样算什么样。但用 SDD 做这个包的时候我第一次在动手写代码之前把每个功能的输入、输出、边界、例外、验收标准全部过了一遍。这个过程的体验非常奇妙——当你把需求描述得足够精确的时候你会发现 AI 写代码的速度快到离谱因为剩下的真的只是“翻译”工作。当然SDD 也不是万能灵药。它更适合那些需求边界清晰、有明确验收标准的工具型项目。如果你做的是一个探索性的、需求每天都在变的项目前面先花大量时间写规格可能反而拖慢节奏。这时候我建议你用轻量规格只写核心约束和边界别的交给 AI 自由发挥边探索边补规格。最后再分享一个小技巧把规格文档的版本号写进 README。这样一来使用者看到的说明和 AI 实现所依据的规格永远能对得上。我在 cjk-compose 的 README 里加了一行“本版本实现基于 SPEC.md v0.2.0”查问题的时候特别省事——你先看版本号再看对应版本的规格最后对着代码找差异基本上一找一个准。这大概就是我对“AI 协作开发新范式”最朴素的理解AI 负责跑得快人负责看得远。规格就是那条把远和快连起来的线。