我第一次把一段完整需求丢给模型、让它”写一份 PRD”的时候,得到的东西非常像样:结构齐全、术语准确、标题分级清楚。我几乎就直接发出去了。后来是研发同事问了一句”这个接口我们哪有”,我才回头去看,发现整份文档里有一半的能力是我们系统不存在的。
那次之后,我对”一键生成 PRD”这件事的态度就固定了:不是它写得不好,而是它写得太顺,顺到我会忘记检查它凭什么这么写。
我把它当实习生,不是代笔
一个刚入职的实习生,给他一份背景,他能把框架搭得很整齐,能把常见的异常状态列全,能把脑子里那些零散的想法整理成条目。但他不知道三年前那次数据库迁移留下了一批脏数据,不知道财务那边的接口一到月底就跑批,不知道哪个字段是历史包袱、谁都不能碰。
模型的能力结构大致也是这样。它擅长穷举”常规正确”:加载中、空状态、网络失败、重复提交、权限不足。这些确实是 PRD 里最容易漏、又最耗时间的一块。它不擅长的是那些只有在这个组织里才成立的约束。
所以我的分工是这样的:结构、字段、常规异常、文档排版交出去;业务规则、数据兼容、跨系统依赖、谁为资损负责,我自己写。这条线划清楚之后,效率提升是真实的,但它不是”省下 80% 的时间”,而是把最枯燥的那一段压缩掉了。剩下的部分没有变少。
还有一件小事,效果比想象中大:告诉它这份文档的读者是谁。写给研发的,要字段、要状态、要异常分支;写给业务方的,要场景、要流程、要口径。同一份需求,换一个读者,详略完全不同。不指定读者,它会写一份对谁都成立、对谁都不够用的东西。
我的四轮对话
我不再试图用一段长提示词解决所有问题。实际跑下来,有效的是一次对话只推进一件事。
第一轮只给背景:这是什么产品,服务谁,当前最痛的地方是什么。这一轮不要它输出任何东西,只要它复述一遍理解。复述错了,后面全是白费。
第二轮让它拆模块。我会给一句很粗的需求,要求它拆成有边界的块,并标出哪些是这次必须做的。这个环节它的价值不在创意,而在于提醒我漏了什么——通常是我忘了”批量操作之后的结果反馈”或者”失败条目的二次处理”。
第三轮挑一个模块写验收标准。这一步我要求它用具体的条件和结果来描述,不要形容词。写”支持批量处理”没有意义,写”勾选超过五十条时弹出二次确认,后台异步执行并展示进度”才有用。模型在这一步表现通常不错,因为它见过大量类似的结构。
第四轮是换角色。让它从测试的角度,对刚才写的东西做极限施压:并发、超时、部分成功、极端输入。这一步经常能挖出我自己没想到的分支。但它给出的处理策略我不会照抄,因为它默认系统是理想的——它会说”引入乐观锁”,却不问我们的数据库版本支不支持。
举个具体的例子。做退款链路的时候,我第二轮拆出来的模块是”批量同意”和”风控拦截”。第三轮写验收标准,我要求它把”部分成功”写清楚:一百条里三条失败,页面要怎么显示,失败的那三条还能不能重试,重试要不要重新走风控。这几个问题我自己想的时候漏了两个。第四轮它又补了”同一批单据被两个客服同时操作”的情况。这些补上的东西都不复杂,但如果没有,研发一定会在评审时问,然后我又要回去改。
提示词的长度不是关键,关键在于每一轮只让它回答一个问题。
这四轮下来,一份核心模块的初稿大概半小时。以前我从空白文档开始,光是回忆有哪些异常状态就要一个下午。
我一度还认真比较过几个模型写文档的表现,还做过对照。结论是差别主要在排版习惯和长文记忆,不在业务理解。有的模型会主动把字段整理成清单,把流程写成有序步骤,读起来省力;有的输出更平,需要我在提示词里反复强调格式。写长文档时,前面定过的约束在后面几节被忘掉,是普遍现象,不分模型。
所以我不再做”用 A 生成、用 B 校验”这种事。两次生成的差异,大部分来自上下文而不是模型本身,我为此多花的时间,不如拿去把约束写得更死。
它编造的不是逻辑,是架构
我后来发现,模型在 PRD 里最危险的输出不是逻辑错误,而是虚构。逻辑错了,评审时会被顶回来;虚构的东西往往长得很合理,混在字段表里,没人注意。
它会给一个不存在的接口起个很自然的名字,然后前端照着这个名字去对接。它会假设有一个统一的权限中心,而实际上每个系统各管各的。它会设计”实时同步”,却没意识到我们的数据链路是 T+1 的跑批。这类错误不会让文档看起来更差,只会让它看起来更完整。
我现在的做法是,在让它写任何模块之前,先把真实的约束喂进去:核心表的字段和注释、关键接口的入参出参示例、几条不能破的业务规则。不需要完整文档,只要密度够。把整个 Swagger 导进去反而更糟,模型会在一大堆字段里丢掉最重要的那几条。
给约束的时候,我会写成断言,不写成描述。”已打款的单据不可撤销,只能走退款补偿”这种句子比”请注意状态流转的合理性”有用得多。后者它会点头,前者它没法绕。
这套习惯其实是被逼出来的。以前写给人的文档,很多前提可以省——研发知道这个系统跑在哪、知道那个字段是谁加的、知道哪些东西”不用问”。模型不知道。它会把每一处省略都当成空白,然后用自己的常识填上。它的常识来自整个互联网,不是来自我们这栋楼。
所以我现在的判断标准变了一条:如果一段描述换一个人来读会理解错,那它就不是描述,是暗示。暗示在人之间可以传递,在模型那里只会变成幻觉的入口。
这件事有个副作用,我没想到。为了让模型能准确执行,我必须把每句话的指代写清楚:谁触发、在什么状态下、失败之后回到哪、哪个字段是唯一标识。整理这些的时候我才发现,我以前那些”评审一次就过”的文档,靠的是在场的人共享同一套默认理解。台上讲两句、会上补两句,文档本身是残缺的,只是没人追究。
我回头翻过一份两年前的 PRD,里面写着”用户提交后系统处理并通知”。现在看,这句话至少藏了四个没定义的东西:提交给谁、处理失败算不算提交成功、通知走站内还是短信、重复提交怎么算。当时研发没问,因为大家都清楚。换一个人来接手,这份文档等于没有。
模型没有让我的文档变得更好,它只是让我看见原来的文档有多依赖默契。这个发现比效率提升更值钱,也更让人不太舒服。
我更怕它改旧文档
从零写新模块,其实是最适合模型的场景:没有历史,没有包袱,错了重来一遍成本很低。真正难的是改一个已经跑了三年的系统。
我试过直接说”根据新需求更新这份文档”。结果是它把整份文档重写了一遍,语气更顺了,结构更整齐了,同时悄悄删掉了两段它认为冗余的内容——一段是关于旧版本数据兼容的,一段是某个字段不能为空的限制。那两段确实是全文最枯燥的部分,也是唯一不能丢的部分。
后来我换了方式:不让它改,让它问。把要变更的那一小块贴给它,要求它以最挑剔的测试或后端视角,提出具体的问题,不要给方案。它问出来的东西通常有一半是我已经想过的,剩下那一半里,偶尔有一两个是真的漏洞。这个比例不算高,但比我一个人闷头想要划算。
判断它的回答时,我用三个筛子:这个改动会不会动到历史数据;会不会依赖一个我们控制不了的第三方;出问题的时候,谁能在半小时内说清楚发生了什么。三个里有一个答不上来,这一版就不能发。
旧文档我还有一个笨办法:每次更新都留一份改前的版本,把改动范围写清楚。不是为了追溯责任,是为了在两个月后有人问”这个规则什么时候变的”时,我能答得出来。模型没有版本意识,它会很自然地把旧约束覆盖掉,而覆盖这件事在文档里是无声的。
有一点我一开始想错了。我以为写文档变快之后,会多出时间做别的。实际发生的是,写作时间被压缩之后,那些原本被写作挡住的难题全都浮上来了:这个需求到底该不该做,历史数据怎么迁,两个部门的规则冲突听谁的,上线之后指标怎么算。
这些没有一件能交给模型。它们需要的不是文字能力,是在这个组织里待够久之后形成的判断。我甚至觉得,模型把案头工作变便宜之后,产品经理这个岗位的门槛反而更高了——以前可以用”我在写文档”来解释自己为什么没想清楚,现在没有这个缓冲了。
我也不认为这套方法适用于所有人。有人喜欢一次生成、再逐段改,那样对他们更快。我只是受不了在一份看起来很完整的文档里,逐句判断哪一句是真的。从空白开始写,至少我知道每一句是我自己写的。这份差别在赶时间的时候看不出来,在半年后回来改需求的时候会很致命。
这份分工我还在调整。模型的能力每几个月就变一次,今天要手写的约束,也许明年它自己就能问出来。但它问出来的问题是不是真的关键,还是需要有人替这个系统负责。至少现在,那个负责的人还是我。
评论