Prompt 是一种有损压缩:AI 辅助编程的边界

views
Word count: 2.5k (~8 mins to read) Last updated:

English version: Prompts Are Lossy: The Limit of AI-Assisted Coding

引子

几年前,不少软件工程师还坚信自己无可替代:理由是,LLM 永远不可能像真正的人类那样思考。今天,他们之中相当一部分人却认为软件工程已经死了,因为 LLM 已经强大到几乎能完成所有的编码任务。

这里有一个隐藏的前提:软件工程就是编码。并非如此。代码只是工程师工作的可见产物;但真正的工作,是决定要写什么、给谁写、判断有什么外部条件限制、以及当外部条件发生变化时该如何调整。

谨记这个区别。当编程的成本变低时,开发者这个角色并不会消失;只有当决策成本也变低时,它才会消失。
而决策之所以困难,原因和模型聪不聪明没什么关系:真正的原因在于你写下的每一个 Prompt,都是对原本存在于你脑中的、信息量更大的某种认知的一次压缩。而这种压缩是有损的。模型越强,这种有损性就越是瓶颈。

No Free Lunch 定理

机器学习中的 No Free Lunch 定理指出:

在所有可能的问题上平均来看,没有任何一个算法能击败其他所有算法——性能永远是相对于某个分布而言的。

软件领域有它自己的版本:不存在“最好的”应用或网站,只有“在某个特定场景下最好的”。而场景本身往往是动态的、快速变化的、以人为中心的。对一个产品而言,唯一无损的描述就是这个产品本身;除此之外的一切,都是草图。

这就是为什么“描述清楚需求”这事,在任何稍微非平凡的场景下都不太奏效。“描述”这个动作本身,迫使你把一个高维的欲望——比如审美、边界情况、业务背景、过去尝试失败的历史——投影到一段低维的 Token 序列上。
当 LLM 把这段序列反投影回代码时,它只能用自己的先验填补丢失的维度,不是你的。

LLM 对“好代码看起来什么样”有极强的先验,但这只是问题中比较容易的那部分。更难的部分,是定义问题本身

不可避免的信息损失

如果我们能精确地描述自己想要什么,那其实就等于把这个 App 写完了——而这显然不是我们想要的。

个人认为 LLM 提供的是一份很长的“选项清单”,每个选项都附带一个推荐的“默认值”。在 LLM 时代以前,我们管这些叫“最佳实践”。这就是为什么让 AI 帮忙写一个玩具项目如此轻松:默认值恰好就是我们想要的。

但当需求是新的、模糊的,默认值就很少是正确的了。而不幸(幸运)的是,所有真实的需求都是新的——除非你在重复造轮子。
这也是为什么我们能看到那么多 vibe coder 在写日历应用、待办事项、健身追踪软件:这些本质上不是新需求,所以 LLM 对它们应该长什么样已经心中有数。
这是在微调,不是发明

模型挑不出“正确的默认值”,还有一个更根本的原因:缺乏知识。如果所有相关信息真的可以自由流动且能被即时处理,那股市应该是一条水平线——所有信息早就被定价了。但事实并非如此:不是所有信息都是公开的,而公开的信息也在不断变化。技术选型决策的知识也是完全同样的——用户这个季度真正做了什么、上一任架构师为什么选了方案 B 而不是 A、某个竞争对手刚刚调整了定价、值班工程师昨天凌晨三点踩了什么坑……这些东西从来不会出现在任何训练集里,而且它们之中的大部分下个月就不一样了。一个在“昨天的公开知识”上训练出来的 LLM,没法完全(我没说不能)替你做“今天的私域决策”。

跨越世纪的启示

关于自动生成代码机的设想早已有之。Fred Brooks 五十年前所著、软工领域经典著作《人月神话》,也早已讨论了这种机器的局限性。

本质复杂度 vs. 偶然复杂度

  • 偶然复杂度是“怎么做”的摩擦——样板代码、胶水代码、语法、重复的拼接活儿。LLM 可以几乎不费力地解决这一类问题中的大部分。
  • 本质复杂度是“做什么”的摩擦——问题本身不可化简的难度、亟待明确的模糊地带、隐式和未发现的需求……LLM 并不能让这种摩擦变小。

人月神话

这本著作表达的核心观点是:堆叠工时换不来日历上的时间。给一个已经延期的项目加人,只会让它继续延期,因为沟通成本的增长比人头数的增长更快。而一支由 Agent 组成的大军并没有什么不同。瓶颈从来不是人数或是 Agent Team 的规模——而是真正理解“在造什么、为什么造”的那一小撮人;当你往里塞更多的劳动力(无论是生物的还是其他的)时,协调他们的成本并不会变低。

没有真正的 Zero-Human-in-the-Loop:Sim2Real 问题

你可以把人类从开发流程里拿掉。但你没法把人类从需求发现这一步里拿掉,因为应用最终是给人用的。要完全自动化软件工程,就需要一个能预先知道人类会如何反应的 Agent——而且要覆盖所有重要的变体。这不是一个编码问题,而是一个仿真问题。

机器人领域有一个相近的问题,叫 sim2real:一个在仿真环境里训练好的策略,往往很难在真实世界里存活,因为没有任何仿真器能精确还原所有的摩擦、传感器噪声以及物理边界情况。软件世界也有它自己的版本——任何模型对“用户”的内部图像,与用户实际行为之间的鸿沟。区别在于,这里的“世界”不是物理,而是品味、注意力、情绪,以及一千种连用户自己都说不清的东西。在没有一个能够还原这一切的仿真器之前,我们唯一可用的传感器,就是一个真实的人,注意到“事情不对劲”这件事。

不幸(幸运)的是,自回归式的 drift 似乎不可避免:一个模仿训练分布的模型会把每一步的小误差累积成与“真实用户的行为”之间的巨大偏差;任何主要靠自身输出来自我演化的系统也会继承同样的缺陷。所以这个回路里始终需要有个人,把观察翻译成改动。语言并不重要——Rust、C++、Python,或是 Prompt——重要的是有一个人守在 loop 与现实时间接合的那座桥梁上。

重新理解软件工程

哪怕在 LLM 时代之前,一条典型的职业路径就已经是:先做几年程序员,再转到产品经理。为什么?因为代码写得越久,越会发现瓶颈从来不在你的手指上,而在“某人想要什么”、“他们最终说出了什么”、以及“最后真正被造出来的是什么”这三者之间的鸿沟里。PM 这个岗位之所以存在,正是因为这个鸿沟存在。

LLM 并没有填平这个鸿沟,它只是让鸿沟出现的位置发生了位移。把意图翻译成实现——这件最初推动资深工程师走向 PM 的事情——只会变得更加重要。头衔会变,角色不会。

为什么是信息安全?

你可能注意到,大公司在疯狂投入资源,提升模型的信息安全能力。原因是结构性的:在很多安全场景下,目标是清晰的、代码库是固定的、几乎没有人类交互、并且你能确定无疑地知道系统什么时候被攻破——没有“Agent 究竟有没有成功”这种含糊的余地。

这意味着 oracle(评判信号)很容易设计。任何在机器学习领域工作过的人都知道,一个干净的 oracle 有多重要——尤其是在用 RL 的时候。网络安全是为数不多的、反馈信号足够明确、可以真正自举出能力增长的领域。在某种意义上,它正是“为人类构建产品”的反面。

写在最后

这篇文章并不是在安慰软件工程师。很多任务确实不需要人类介入;很多用户也只想要一个“够用”的答案,而不是完美的答案——LLM 完全足以胜任这些。再说,LLM 做不到,软件工程师就一定能做到吗?软件工程师做得到的,产品经理就做不到吗?无论如何,SDE 岗位会迅速且大规模地收缩。

我想说的其实是一个更窄的论断:仍然存在一个地方,人类能够提供不可替代的价值——就在“模糊的意图”被翻译成“具体软件”的那道边界上。机器会在其他几乎所有事情上越来越强之时,你需要在这样的地方找到自己的生路。