一个 Bot 用三个多小时给我交了 676 行代码,我花二十分钟合并上线。
当晚我用手机打开自己的博客,按下搜索——白屏,等了几秒才出结果。
跟改之前一模一样。
它没写错任何一行代码。测试清单五条,条条跑通。架构选择比我自己能想出来的更干净。但我想要的那个「快」,它一点没解决——因为我从来没说清,我要的是哪个「快」。
一、我只说了一句话,它交回来一次架构选择
这个博客到今天 388 篇文章。搜索底下是个叫 Pizza 的 WASM 检索组件,两年前接的,作者早不更新了:每次有人打开搜索框,浏览器要先把整站 /index.json 拉下来(4.6 MB),再在 WASM 里从头建一遍索引。文章越多,这个「从头建一遍」越贵。
这事我拖了半年。这次我没自己动手。
协作方是 Grok Bot。我给它注册了一个 GitHub 账号,把仓库地址甩过去——public repo,内容、模板、构建脚本、CI 配置全在里面。然后我说了一句话:
我 Blog 上的搜索基于一个几乎没人维护的组件,内容越来越多之后变慢了,给我一个更优的方案。
没有技术选型,没有约束条件,没有护栏。我甚至没告诉它 Pizza 是什么。
三个多小时后,PR 出现在仓库里:15 个文件,+676 / −26。打开描述,第一段就把我的问题重新定义了一遍:
Without a backend, search feels slow mainly because the browser re-ingests a full-text
index.jsonon every visit.
它没去优化 WASM,也没换检索库。它换掉的是索引在什么时候建:
旧: 访问 → fetch index.json (4.6MB) → WASM 里现场建索引 → 查询
└───────── 每次访问都重来一遍 ─────────┘
新: CI 构建 → 倒排 postings + 精简 meta → 静态文件
访问 → fetch segment → 存 IndexedDB → Worker 里查
└ 第二次访问零网络 ┘
# generated by hugo AI
让我意外的是另外三件事:它自己写了 225 行构建期索引脚本;它自己改了 .github/workflows/hugo.yaml,在 Hugo 之后加一步重建索引——因为它知道只有这样 Permalink 才准;它自己留了一份 52 行的 SEARCH.md。
「它会写代码」2024 年就不新鲜了。新鲜的是它自己定义了问题、自己改了流水线、自己给下一个人留了文档——这三件事在传统分工里叫「技术方案」「发布流程」「交接文档」,通常需要三次会议。
二、二十分钟合并,当晚翻车
我拉下来跑一遍 hugo server -D,按 ⌘K,搜「树莓派」,出结果,关掉。点 Merge。不到二十分钟。
然后 GitHub Actions 自己跑:构建 → 重建索引 → 推 Pages → 钉钉群弹通知。我什么都没做。这条链能一路自动跑到线上,是因为 CI 本来就是这个仓库的一部分——Bot 能改 hugo.yaml,是因为 hugo.yaml 在它看得见的地方。要是我的部署得「找运维在跳板机上跑个脚本」,这个 PR 到我这儿就断了。
当晚我用手机连着家里那条不太行的 Wi-Fi,就撞上了开头那个白屏。去看 Network,数字很清楚:
| 旧:Pizza WASM | 新:静态索引 | |
|---|---|---|
| 首屏传输(gzip) | 1.7 MB | 2.3 MB |
| 下载完之后 | 现场建索引 | 直接可查 |
| 查询耗时 | 几十到几百 ms | 几 ms |
| 第二次访问 | 全部重来 | IndexedDB 命中,零网络 |
首屏 payload 反而变大了。
这不是 bug,是架构的必然代价——倒排表本来就比原文冗余,换来的是「下载完什么都不用干」和「第二次不用下载」。总账上这笔交易划算得多。但我按下 ⌘K 那一刻的等待,一秒没少。
更糟的是接着试出来的两件事:索引没加载完时输入的查询被直接丢掉,打完字回车,什么也不发生;索引请求失败时(我拔网线试的)页面上没有任何反馈,错误只往 console 扔了一行。再翻代码,还有两个作用域 bug。
这些毛病的共同点是:它们只在索引还没加载完的那几秒里才有机会执行。 在开发机上那是 0.2 秒,在我家的 Wi-Fi 上是 8 秒。
于是我补了一个 commit,+98 / −7:流式读 response body 报进度、把加载期间输入的查询存下来等就绪后重放、加一个显式失败态、修掉那两个 bug。
现在按 ⌘K,你会看到「正在加载搜索索引… 43% (1.0/2.3 MiB)」。加载时间一秒没减少,但那几秒不再是白屏了。
三、AI 优化的是你说出口的那个词
复盘一下这次唯一真正出问题的地方。
我说的是「搜索变慢了」。
Bot 听到的是 query latency。它在 PR 测试清单里写得明明白白:hits should return in a few ms。它优化了这个指标,而且优化得非常成功——从几百毫秒到几毫秒,两个数量级。
我要的是「从按下 ⌘K 到看见第一行结果」。
在旧方案里,这两个「慢」是重合的:下载和建索引都发生在你等待的那段时间里,压下一个另一个跟着下。新方案把它们拆开了——查询快了两个数量级,首屏多了 0.6 MB。它优化的指标和我的体感,在这次重构里第一次分了家。
这不是 Bot 的错。它那五条测试清单条条合理,每条都跑通了——在一台开发机上,用一条快网。 它没测的那个场景,不是它想不到,是我从来没告诉过它那个场景存在。
我之前在 评测集是一份没人签字的文件 里写过同一件事,当时讲的是企业级评测。换成一个个人博客,逻辑一模一样:
需求提得明确 ≠ 把想做的事描述清楚
需求提得明确 = 把「怎样算做完」写下来
我写的: 「搜索变慢了,给个更优方案」
我该写的:「⌘K 到第一行结果 < 1s(4G、冷缓存);
加载期间必须有进度;失败必须有可见错误态」
# generated by hugo AI
下面那三行如果我一开始就写出来,那个 +98 行的补丁根本不会存在。Bot 完全有能力自己做出来,它只是不知道我在乎。
在你没定义的维度上,AI 是自由的。 而它的自由,恰好会落在它能测量的那些指标上。
四、让它跑起来的,是四样跟模型无关的东西
这次 Bot 干掉了开发、测试、文档、CI 集成,粗算八成以上工作量。但这不是「模型变强了」四个字能解释的——同样一个 Bot,换个仓库它一步都走不动。
一、自带上下文的仓库。 内容、模板、构建脚本、CI 配置在同一棵树里,它不用问我「你的博客怎么构建」。上下文不是塞进 prompt 的,是长在仓库里的。
二、有边界的交付通道。 GitHub 账号 + PR。它有独立身份,交付物有明确边界,而我可以拒绝。PR 是目前最成熟的 Agent 验收界面,因为它天生带着 diff、评论和一票否决权——这点我在 Grok Bot 能当队友,还当不了员工 里写过。
三、能自己跑到线上的流水线。 merge → Actions → Pages。这条链决定了「验收」是一次点击还是一场协调会。
四、一个写文档的位置。 SEARCH.md 不是给我看的,是给下一个来改这块代码的 Agent 看的——就是我一直说的 把「为什么」写进版本库。这次真正沉淀下来的资产,不是 676 行代码,是那 52 行 markdown。
这四样全是工程基础设施,跟模型能力无关,而且都是 Agent 到来之前就该有的好实践——只不过人来干活时缺了可以靠口头沟通补上,换成 Agent,缺了就是硬性阻塞。
最后
我在这次协作里一共产出三样东西:一句需求、一次 merge、一个 +98 行的补丁。
前两样以后还会继续缩水。只有第三样不会——因为它不是「检查它干完没有」,它是「告诉 AI 我到底要什么」的最后一次机会。那 98 行,本质上是我把一句没说清的需求,用代码的形式补写了一遍。这个补写迟早要发生:要么发生在需求里(便宜),要么发生在验收后(贵一点),要么发生在用户的抱怨里(最贵)。
但真正让我后背发凉的不是这个。是我意识到:这句需求,我提了十几年了。
「搜索有点慢,你看下」——这话我对人说过无数次,从来没出过问题。因为人会自己去补:工程师会想到弱网,会想到加载态,会想到失败怎么办。他不是靠我的需求想到的,是靠他见过的线上事故想到的。过去二十年,所有含糊的需求都被下游的人用常识悄悄补齐了,所以我一直以为自己需求提得挺清楚。
AI 不会补。它没有那些事故记忆,也没有「我猜领导会在乎」的动机。你说什么它做什么,说漏的地方它按自己的指标自由发挥。
所以 AI 真正改变的不是开发效率——那只是表象。它是把管理里一直存在的那层默认共识给剥掉了。以前需求含糊,交回来的东西还差不多;现在需求含糊,交回来的东西就是含糊本身的样子,一分不差。
从这个角度看,AI 是一台需求质量的显影液。它照出来的不是模型的能力边界,是你把「做完了」这件事想清楚到了什么程度。而这个能力,恰恰是过去被下游的人替你兜住、因此从未被真正测量过的东西。
至于那个搜索框——现在第一次会看着进度条走完,之后每次都是零网络、几毫秒。我找那篇四年前的 Tailscale 笔记,用了不到一秒。
换成你的团队:你上一次派活,验收标准是写在需求里,还是等东西交回来才想起来的?如果是后者——过去帮你兜住的那个人,现在还在吗?