凌晨一点,用户在反馈框里敲下第六轮意见:“标题挪到左边,按钮换个蓝色。”
我当时的处理逻辑:把之前所有对话历史拼进 prompt,让 LLM 从零重新生成整个页面。
结果是 20 分钟等待、20 积分蒸发。更操蛋的是——第三轮辛辛苦苦调出来的间距,这轮全没了。
这就是从头生成的三宗罪:慢、贵、不可复现。LLM 每次重掷骰子,你之前人工确认过的每个细节都可能被悄悄改掉。
为什么大家还是这么干?因为省事。生成接口是现成的,history 拼一拼就能上线——直到用户用脚投票。
想明白一件事:用户说“标题改蓝色”时,他心里的期望是其他地方一个字节都不动。
增量修改:只动该动的,其余原样保留。这才是“对话式改稿”的本体,前面几篇聊生成链路时这个雷就埋下了。
那 LLM 干嘛?它不产出 HTML,只产出“改哪、改成啥”的指令——补丁。
整页生成是让 LLM 当排版工人,补丁模式是让它当校对。后者便宜一个数量级,还快一个数量级。
协议长什么样?说人话,就是一组补丁对:
LLM 输出 JSON 数组,后端逐条应用,就这么土。
为什么不用 diff、不上 AST patch?我一开始也觉得字符串操作太 low。但 HTML 里混着模板语法、内联 style、注释,AST 解析器三天两头翻车;diff 格式 LLM 写起来错行率感人。
find/replace 的杀手锏是验证即执行:find 在基准稿里 grep 不到、或匹配到多处,这条补丁直接作废,不需要任何解析器帮你兜底。
一条补丁对不上,跳过还是中止?我选中止回退。半应用状态的页面用户看不懂,下一轮补丁又会基于这个“残血”基准稿,错误滚雪球。
所以护栏只有一条:全没对上 → 回退整页重写。慢一点,但确定。
base_html:当前被用户认可的最新 HTML 快照,所有补丁的唯一锚点。
流程三步走:
1. 用户提改稿需求。
2. LLM 基于 base_html + 指令,输出补丁对。
3. 全部应用成功 → 新 HTML 写回 base_html,进入下一轮。
类似 git:每个被接受的状态都是一次 commit,永远在最新 commit 上打 diff。
千万别把历史所有轮次的 HTML 都存着让 LLM 自己挑。它会挑错,还会把已废弃状态混进补丁里,这是纯纯的硬伤设计。
这个坑我被坑惨了,值得单独开一节。
上线三天,日志里出现灵异现象:某用户的 base_html 字段值是 0。
追代码发现:更新基准稿的后端函数里有个字段白名单 + 类型映射,我加了十几个字段,唯独漏了新上线的 base_html。没进白名单的字段走了默认逻辑——`(int)` 强转。
一段几万字符的 HTML,强转成 0。写库,落盘,安静得像什么都没发生。
下游什么惨状?下一轮补丁的 find 全部对不上(基准稿已经是 `"0"` 了),全部触发回退整页重写。用户看到的是:越改越慢、越改越丑、积分哗哗扣。
排查为什么这么难?错误现场在几十轮对话之后才爆发,第一反应全去查 LLM 的补丁质量了,没人怀疑自己的入库代码。
踩坑之后我记了两条:
补个实战细节:协议里我给每轮补丁都挂了唯一 trace_id,把“用户指令 → 补丁对 → 结果 HTML”串成一条链,排查这类链路 bug 时真能救命。本地调试要批量造这种 ID,别自己手搓,直接用 UUID 生成器一把梭。
补丁模式凭什么 14 秒?
输出 token 从几万降到几百。LLM 的大头耗时在逐 token 出结果,输出少两个数量级,速度就快两个数量级,没有魔法。
积分成本同步塌方:整页生成 20 积分,一次补丁调用近乎免费。
但真正的质变在体验:改稿从“泡杯咖啡等结果”变成“打字般的即时反馈”。反馈密度上来了,用户才敢连提十条意见——对话式改稿,改的就是这个东西。
补丁对不上,让 LLM 重试几次不就行了?
重试烧 token 且救不了命——find 对不上说明 LLM 的认知和基准稿已经脱节,重试十次还是对不上。直接回退整页重写,把两边状态拉齐。
都什么年代了还搞字符串 find/replace?
越贴近 LLM 实际擅长的输出格式越稳。结构化 patch 对格式容错为零,LLM 写错一个空格全盘崩。土方案 + 严格校验 = 高鲁棒,别拿技术审美换可用性。
base_html 一轮轮滚下去越来越大,上下文会爆吗?
会。所以要定期“压实”:历史轮次只留摘要,喂给 LLM 的永远是最新 base_html + 当前指令。基准稿是状态,不是历史,两者别混淆。
评论列表 (0条)