智能体编程真相:写规范文档就是在写代码,如同戴两只手表!


你以为写一份说明规范让AI干活,其实是你写了两份代码,而且还多出一堆Bug!

所谓“用说明文档直接生成代码”,本质上是在把代码换个马甲写一遍,甚至写得更累、还更容易翻车。

很多人幻想一种未来:工程师坐在电脑前写几页“需求说明”,然后一群智能体冲上去把系统全做完。听起来像老板梦中情景,像点外卖一样轻松。现实情况是,你越想写清楚这些说明,最后写出来的东西就越像代码本身。

换句话说:想靠“写说明”替代“写代码”,最后得到的是——写了两份代码,一份叫说明,一份叫实现,还顺便附赠一堆 bug。

很多人幻想有这么一个神仙日子:我舒舒服服泡杯咖啡,打开文档写几页中文,不对,写几页人类能看懂的大白话,描述一下我想要个啥软件,然后啪的一下,一群AI智能体就冲上去,三下五除二把整个系统给我搭好了。这画面是不是特别美?简直是老板梦里的终极景象,跟点外卖一样轻松,备注一个“不要香菜,多加辣”,后厨就给你把满汉全席端上来了。

但是,铁子们,现实世界它是个硬核修罗场。

真实情况是,你为了把这个“需求说明”写到让机器这个“铁憨憨”能听懂,你写出来的那堆东西,最后会变得比代码本身还要像代码,还要啰嗦,还要让人头秃。你以为你在写诗,其实你在写说明书;你以为你在写说明书,最后发现你他娘的还是在写代码,而且是写了两遍,一份叫“说明文档”,一份叫“最终实现”,然后这两兄弟还经常吵架,给你生出满屏幕的Bug。就像你戴两只手表,时间还经常不一致!

这和以前UML盛行时代一样,你在UML模型语言和编程语言语言映射之间疲于奔命!
如同你在数据库SQL语言和ORM之类对象持久化语言映射之间疲于奔命。


你以为你在写人话,其实你已经在写代码了

咱们先来拆解一下第一个幻觉,这个幻觉叫“说明文档很简单”。在很多人的脑子里,写说明文档就是用大白话聊天。我可以说“系统需要支持用户登录”,这句话多简单,多像人话,连我奶奶都能听懂。然后我就把这个任务丢给AI,自己去旁边打游戏了。这个想法就像你对着一个外星人说“把那个发光的球拿给我”,你觉得很简单,但外星人脑子里在想“发光的球”是什么?是太阳?是灯泡?还是它自己刚刚拉的屎?

现实会狠狠地抽你大嘴巴子。当你真的想让机器这个一根筋的玩意儿“正确理解”你的意图,你就得开始疯狂地往里面填细节,直到把自己填成一个细节狂魔。

你一开始写的那句“系统需要支持用户登录”,在机器看来就是一句废话。它得问:谁是用户?怎么登录?密码错了咋办?登录完了记在哪儿?

于是你就开始补丁模式。你会写:用户登录功能需要包含一个会话ID,就是session_id,这个ID还得跟一个token绑在一起,token过期了怎么办?你得有刷新机制吧?网络不好请求失败了怎么办?你得有重试策略吧?

你看,写着写着,你就会写出这种东西:session_id这个字段,它的类型是字符串,它的组成格式是线程ID加上轮次ID,然后下面跟着thread_id也是字符串,turn_id也是字符串,甚至你已经开始记录这次登录用了多少输入token,多少输出token。

朋友们,这叫什么?这叫数据库的表结构设计,这叫Schema。

你已经不是在写说明了,你已经在给代码画骨架了,这骨头画得跟X光片似的,清晰得吓人。你以为你在说“给我盖个房子”,结果你已经把钢筋型号、混凝土标号、甚至厕所地漏的直径都写在纸上了。

这还没完,你继续细化这个登录失败后的逻辑。

你会写:可用的并发槽位数量,等于最大并发智能体数量减去当前正在运行的数量,如果结果是负数,那就取零。

这串逻辑用代码怎么写?available_slots = max(max_concurrent_agents - running_count, 0)。

你觉得你还在写说明?不,你只是在用一种看起来像英文的伪代码在表达。

再来一个更狠的,你写重试延迟时间,你说每次重试的等待时间,不能无限增长,要有个上限,具体算法是用10000乘以2的(重试次数减一次方),然后取这个结果和预设的最大回退毫秒数里最小的那个。这就是delay = min(10000 * 2^(attempt - 1), agent.max_retry_backoff_ms)。

兄弟,你摸着良心说,这是说明书还是算法实现?

这就像有人说自己在健身房只是随便活动活动,结果你一看,他举着200公斤的杠铃,汗流得跟水龙头一样,那你就是在极限锻炼,不是在“热身聊天”。

所以第一个幻想直接原地爆炸:你以为写说明比写代码简单?只要你想让机器这个没脑子的货色听懂人话,它就会逼着你的说明文档一路进化,最后进化成代码的另一个形态,一个更啰嗦、更冗长的双胞胎兄弟。

你写得越嗨,文档就越长,最后直接长成了代码本体

这里有个特别残酷的现实,我必须要跟你们讲清楚。

机器,也就是电脑,或者AI,它们最缺的东西,就是咱们人类那种强大的“脑补能力”。咱人类沟通,讲究个心领神会,点到即止。

这就是强大的在场感Context态势感知能力

你跟哥们儿说“帮我整个吃鸡的电脑”,他脑子里瞬间就给你配好了i9处理器、RTX4090显卡、32G内存,连机箱要带RGB灯带他都给你脑补出来了。
但你跟AI说“帮我做一个订单系统”,它只会用它那冰冷的数据大脑问你:细节呢?边界条件呢?订单状态有哪些?失败了你打算怎么办?钱退不退?并发太高会不会崩?谁来负责?

所以,为了填满AI这个没有想象力的黑洞,你只能玩命地给它喂细节。
你以为你在写一份优雅的规范,实际上你在给一个巨婴写《上厕所全程指导手册》,从“走到卫生间门口”开始,写到“打开马桶盖”,写到“脱下裤子”,写到“瞄准”,写到“事后冲水”,写到“洗手七步法”。
但凡少写一步,它就敢尿你一地。

于是你开始写失败重试策略,你写:取消任何针对同一问题已经存在的重试定时器。然后存储这次重试的次数、唯一标识、错误信息、下一次该执行的时间戳,还有新创建的定时器句柄。

你看这段话,Cancel any existing retry timer for the same issue. Store attempt, identifier, error, due_at_ms, and new timer handle. 这已经不是解释了,这是在用英语描述一个操作系统的底层API调用。
你接着写退避公式,就是那个delay = min(10000 * 2^(attempt - 1), agent.max_retry_backoff_ms),这公式长得就跟数学课本上的噩梦一样。

还没完,更离谱的来了,你甚至开始写服务启动流程。

你写:启动服务的函数,要做这几件事:
第一配置日志系统
第二启动监控输出模块,
第三安排一个时钟心跳,初始延迟设为零,
第四让整个系统进入事件循环,处理状态变化。

function start_service():
 configure_logging();
 start_observability_outputs();
 schedule_tick(delay_ms=0);
 event_loop(state)。

你告诉我,这是什么?这就是代码。

你只是把Python或者Java的语法,换成了看起来像英文的伪代码。这就像你把红烧肉叫“经过焦糖色着色的五花肉块”,你觉得你换了个高级叫法它就不是肉了吗?本质没变啊大哥。

所以结论直接像陨石一样砸下来,在地上砸个大坑:当一份说明文档精确到每个变量、每个公式、每个步骤的时候,它就不是说明了,它就是你用另一种方言写的代码。你以为你逃过了写代码的苦,其实你只是换了个苦法,甚至更苦,因为你写的东西还没法直接运行,还得让AI再翻译一遍。

有人嘴硬说:那我用说明文档提升代码质量,这波总该赢了吧

这时候肯定有人要说了,行,就算我写的说明最后变成了代码,那我起码是经过深思熟虑的,写出来的代码质量肯定比我直接上手敲要高。

这就是第二个常见的幻觉,听起来特别有道理,特别哲学,叫做“说明文档更深思熟虑,代码更冲动执行”。好像写规范的时候,人就自动变成了一个慢条斯理的架构师,脑子里全是设计模式、边界条件、扩展性。而写代码的时候,人就变成了一个只会闷头敲键盘的码农,手速拉满,脑子掉线。

这个想法听起来很美,但现实就像一盆冰水,专浇那些爱做梦的人。

理论上,写spec的时候,人的确应该停下来思考全局,思考各个模块怎么协作,思考未来怎么扩展。但是,问题来了,现在这个互联网行业的节奏是谁控制的?是“快点上线”这四个大字控制的。产品经理天天在你屁股后面追着问,好了没有,什么时候能上线,隔壁组都做完了你咋还没动。

当你要“写出高质量规范”这个伟大目标,和“明天就要上线”这个残酷现实撞在一起的时候,你会怎么办?你作为一个聪明人,当然会选择妥协。

你会写出一种非常奇特的东西。这种东西,看起来结构完整,读起来一本正经,但实际上,就是一堆拼凑起来的正确废话。

我给你举个例子,比如你写关于查询的规范,你写:查询字符串必须是一个非空字符串。查询字符串必须只包含一个GraphQL操作。变量参数是可选的,并且必须是一个JSON对象。

你读一下这些话,query must be a non-empty string. query must contain exactly one GraphQL operation. variables is optional and must be a JSON object. 每一句话单独拎出来看,是不是都对?没毛病吧?废话,它当然得是字符串,它当然得非空。

但是你把这三句话放一起,你读完之后脑子有什么印象?是不是只觉得好像懂了,又好像什么都没懂?这玩意儿说了跟没说一样。

这类文本在江湖上有个专门的名字,叫做“长得像规范的垃圾”,或者叫“spec-shaped text”。它们的特点就是,每一句都正确无比,合在一起却空洞无物。它们就像那些在朋友圈发鸡汤的人,每一句话都充满了正能量,但你看完根本不知道他今天吃了啥,遇到了什么事。

你用这种心态去写规范,结果就是,你花了一天时间,写出了一堆正确的废话,然后骗自己说,今天的准备工作做得很扎实,明天可以开始写代码了。其实你啥也没准备,你只是把焦虑用文字的形式排解了一下。

最尴尬的翻车现场:你让AI照着规范写代码,它依然给你表演原地转圈

好了,前戏做足了,现在咱们进入最精彩、最刺激的环节,那就是实战翻车现场直播。

有人真的特别天真,或者说特别有探索精神,他们做了个实验,把一个好几千字的、巨细无遗的软件规范文档,直接甩给AI,说:“来,大聪明,按照这个规范,给我把代码写出来。”那个规范叫什么Symphony,放在GitHub上,所有人都能看。他们心想,这回总没问题了吧,我写得这么细,就差把每个分号都标出来了。

结果呢?结果就是AI给所有人表演了一场什么叫“人工智障”。代码是能跑起来,没有报错,没有崩溃,但它就在那儿原地转圈,像个迷路的孩子。比如说,任务指令是“创建一个全新的空白仓库”,Create a new blank repository。AI收到了,特别乖巧地回复“收到!”。

然后呢?然后就没有然后了。它就卡在那儿了。既不报错,也不往下执行,也没有结果输出。就像你跟你妈说“妈,我去学习了”,然后你坐在书桌前,打开了课本,然后就开始发呆,抠手指,转笔,看窗外的小鸟,一直到吃饭时间,你妈问你学得咋样,你说“我在进行学习前的系统优化”。AI也是一样,它在进行“创建前的资源冥想”。你给它修bug,你给它加提示,你好言相劝,它依然可能卡在原地,一动不动。

这说明了一个什么惊天大秘密?说明那份规范文档已经写得比《红楼梦》还厚了,每一个细节都抠到位了,但是,依然无法保证AI能正确地、完整地把活儿干完。这就像你给一个学生出了份试卷,题目写得清清楚楚,答案都给了提示,就差把答案直接写卷子上了。

结果收卷子一看,他还是给你写跑题了,作文题目是《我的妈妈》,他给你写了个《我的显卡》。你气不气?你拿他一点办法没有。这就证明了,从精确的文字描述,到可运行的、逻辑正确的代码之间,有一条巨大的鸿沟,这条鸿沟叫“意图理解的鸿沟”。你以为你表达清楚了,AI觉得它理解清楚了,但其实你们俩在跨服聊天。

你想靠补细节解决问题?恭喜你,你将见证“地图等于领土”的奇观

面对AI这种“给点阳光就灿烂,给本规范就犯浑”的表现,你可能脑子一热,觉得解决问题的办法就是“我写得还不够细”。这个思路,就像你考试没考好,觉得是因为笔不够贵一样,听起来好像有那么一点点关联,但实际上方向完全错了。你会想,既然它卡住,那我就把卡住的情况写进去;既然它会误解,那我就把可能误解的点全堵死。

于是,你开始了一条不归路。你疯狂地补充边界条件,如果仓库名字是空的怎么办?如果名字里有特殊字符怎么办?如果存储空间满了怎么办?你补充异常处理,创建失败是网络原因还是权限原因?每种原因怎么重试?重试几次?你甚至开始补充状态机,把“创建中”、“创建成功”、“创建失败”、“失败后回滚”这些状态全都画成图写成文字。你补充日志策略,什么时候该打日志,日志打什么级别,是info还是error。你补充监控指标,这个操作的成功率、延迟、失败率,全都要记录下来。

最后,你会得到一份什么样的文档?一份超级巨无霸,一个由文字堆砌而成的摩天大楼。它的体积,它的复杂程度,跟你最终要写的代码一模一样,甚至比代码还要臃肿,因为代码有简洁的语法,而文字没有。这时候,一个堪称经典的哲学级现象就诞生了:说明文档的体积,约等于代码本身的体积。说明文档和代码,彻底融为一体了。

这场景,有个特别有名的比喻,叫“地图和领土一样大”。你想画一张一个国家的地图,方便以后看。结果你画得太精细了,把每一棵树、每一根草、每一粒沙子都画上去了。最后画完发现,这张地图的面积,把整个国家都覆盖了。

你想用它来找路?那你还不如直接踩在真正的领土上呢。因为地图本身就是领土了,地图失去了它简化现实、指引方向的作用。

咱们的说明文档也是一样,当它变得和代码一样复杂,甚至比代码更难懂的时候,它存在的意义是什么?你写它是为了简化问题,结果它自己成了最大的问题。这就不是帮忙,这是添乱。

最后的底层逻辑:那个让你无处可逃的“精度守恒定律”

聊了这么多翻车案例和尴尬现场,咱们得从哲学的高度往下捋一捋,看看这件事背后到底藏着什么硬核规律。这个规律,我给它起了个名字,叫“精度守恒定律”。这四个字啥意思?意思就是,你在一个系统里,想让它干活,就必须提供一定精度的描述,这个总精度是不会变的,它不会凭空消失,它只会从一种形式,转移到另一种形式。

你想让机器这个铁憨憨理解你的意图,你就必须给它精确的指令。如果你不在代码里写,你就要在说明文档里写;如果你不在说明文档里写,你就要在提示词里写;如果你哪都不写,AI就只能靠猜。

AI这个猜的过程,在科学界有个高大上的名字,叫“随机输出”。说白了,就是听天由命,就是开盲盒。你输入一个模糊的指令,比如“做个好用的软件”,它可能给你生成一个计算器,也可能给你生成一个游戏,也可能给你生成一万行乱码。

这就是经典逻辑,铁一般的定律:输入模糊,输出随机;输入清晰,输出可控。中间没有模糊地带,没有“大概也许可能”。

所以,那些幻想着用几句模糊的、充满人性化的大白话,就能让AI自动补全所有技术细节,帮你做出一个完美系统的人,本质上是在干什么?是在赌博

他们把项目的成败,把自己的时间和精力,都交给了运气。运气好,AI蒙对了,你赚了;运气不好,AI理解错了,你就得加班加点地擦屁股,修复那些它因为“脑补”而产生的、千奇百怪的bug。这就像你考试不做准备,全选C,指望命运让你及格一样。偶尔一次可能行,但你想靠这个考上清华,那就是做梦。

最后一句话收尾,把桌子给你掀了

好了,咱们今天聊了这么多,从幻觉的产生,到幻觉的破灭,再到翻车现场和底层逻辑,最后得用一句最现实、最扎心的话来收尾。整件事情,可以用一句话总结得明明白白:如果你的目标是又快又好地把活儿干完,别整那些虚头巴脑的,直接撸起袖子写代码,最高效。如果你的目标是追求极致的、文档级的质量,那你写说明文档本身就是一项重体力、高脑力的工程项目,它需要的时间和精力,不比你直接写代码少一星半点。

这个世界上,根本就不存在“既轻松又高质量”的捷径。你所谓的“写写说明文档就能自动生成代码”,更像是你在被deadline追着跑时,给自己找的一个心理安慰,一个精神上的奶头乐。它让你在短暂的幻想中,逃避了写代码的痛苦。

但幻想结束之后,你会发现,你面前摆着两座大屎山:

  1. 一份比代码还复杂的文档
  2. 和一份跑不起来的、充满Bug的代码。

你原本只想写一份作业,结果最后你发现你得写两份,还得兼职当判官,调解这两份作业之间的矛盾。就像你戴着两只手表,你经常发现它们走时不一致,你戴它们有什么用?