两个 Prompt 套路:让 AI 代码少踩一半坑
向AI提出需求后,它生成代码并运行通过。审查时逻辑看似合理,测试也顺利过关,于是代码被部署上线。但用户反馈不久后问题频发,这背后隐藏着AI编程的常见陷阱。
两个 Prompt 套路,让 AI 代码少踩一半坑
你给AI一个需求,它写出了代码,跑通了。你看了一眼,逻辑说得过去,测试也过了,就上线了。

然后用户反馈出问题了。
它改好了一个地方,埋了三个新坑。你盯着日志与代码一脸茫然:这地方明明是它写的,我也看了,怎么上线就炸?
如果这个场景你经历过,你不是一个人。
AI写代码最大的坑,不是它写不出来,而是它写出来后你误以为正确。你能看懂每一行代码在干什么,但你看不到它跳过了什么——那些被训练数据平均化掉的边界情况,那些看起来合理但其实不该这么做设计选择,那些在训练数据里出现频率太低所以被模型忽略掉了极端场景。
下面这两个Prompt套路,一个管生成方案对不对,一个管验证代码稳不稳。加在Prompt里成本几乎为零,但省下来的半夜debug时间很实在。
套路一:在 Prompt 末尾加七个字
方法简单到让人怀疑:在你提给AI的任何需求后面,加一句——
从第一性原理出发。
就这样。七个字。
为什么这七个字有效
AI默认工作方式叫类比推理。你让它写一个数据过滤器,它在训练数据里搜到几千个数据过滤器的实现,找一个最像的改一改给你。代码能跑,逻辑也说得过去,但它跳过了最关键一步:你确定这件事应该用过滤器来解决吗?
类比推理快,但它有一个致命缺陷:如果你提的问题本身就有偏差,AI会在一个有偏差的方向上给你一个看起来没问题的答案。就像你问怎么让马车跑得更快,类比推理的AI会告诉你换更好的马、减重、改装轮子,唯独不会告诉你应该发明汽车。
第一性原理做的事刚好相反:不参考现有方案,回到最根本事实重新推演。
它不是让AI更聪明,而是让AI先停下来想清楚这个问题的本质是什么,再动手。
一个真实的例子
AIHOT是一个AI资讯聚合项目,从海外信源抓取内容。某天抓取功能挂了,开发者把报错甩给AI,AI第一反应是修那个报错的函数,哪里报错修哪里,几分钟改好。
跑了一下午,又挂了。
换了个姿势:把整个需求重新描述一遍,末尾加上从第一性原理出发。AI这次没有直接修报错,而是从更底层往回推:这个抓取功能依赖的流量路由逻辑,是四月份写的,当时的设计假设,比如信源响应格式、网络拓扑,现在已经不成立了。
于是问题从修一个报错的函数变成了重构一层路由逻辑。不是换个更大的创可贴,是把伤口清创、重新缝合。
不加 vs 加了,AI 给出的方案差多远
假设你让AI写一个消息队列的消费者。不加这七个字,它给你一个教科书式的while-true-poll循环:
while True:messages = queue.receive_messages(MaxNumberOfMessages=10)for msg in messages:process(msg)queue.delete_message(msg)
能跑。但消息量翻十倍的时候,消费者来不及处理,消息越堆越多,内存吃满,OOM。这个方案的本质是不管来多少消息,我每次只取十条,它没考虑如果消息来得比我处理得快怎么办。
加了从第一性原理出发,AI会重新推演消费消息这件事的终极目标:不是为了消费而消费,是为了在延迟可接受的前提下不丢数据、不爆内存。方案变了:
while True:queue_depth = queue.get_queue_depth()batch_size = min(max(10, queue_depth // 10), 100)messages = queue.receive_messages(MaxNumberOfMessages=batch_size)with ThreadPoolExecutor(max_workers=batch_size) as executor:futures = [executor.submit(process, msg) for msg in messages]for f in as_completed(futures, timeout=30):...
它自己加了背压感知和动态批次调整,积压越多,批次越大,处理越快,压力小了自动缩回默认值。这不是什么高深技术,但你没提,类比推理的AI不会主动加,因为它见过的几千个消息队列示例里,大部分都是固定批次的简单写法。
这七个字什么时候最管用
不是所有场景都需要第一性原理。写一个简单的CRUD接口、配一个Nginx路由,类比推理就足够了,不需要重新发明轮子。
但下面三种情况值得加:
- 你在修一个反复出现的bug。AI修了三次还出问题,说明它只在表面修修补补,没有找根因。
- 你要做一个设计决策。选数据结构、定模块边界、设计API,这些事如果方向错了,后面改的代价很大。
- 你也不确定最优方案是什么。需求模糊的时候,类比推理会给你一个别人都这么做的方案。第一性原理至少能让你看清楚这个方案的前提假设是什么。
套路二:让 AI 攻击自己的代码
功能写完了,测试跑过了,Code Review也过了。
这时候你再跟AI说一句:
开启多Agent对抗式审查这段代码。站在恶意用户和极端场景的角度,找出所有可能导致系统崩溃或数据异常的漏洞。
正常开发的时候,你的大脑处于建设模式,想着功能怎么实现、逻辑怎么走通、正常路径怎么覆盖。你不会去想如果发布时间是2038年会怎样,也不会去想如果用户上传了一个50MB的纯文本但所有内容都在一行里、HTML清洗函数要遍历多少DOM节点。
对抗式审查逼AI切到攻击模式。它不再是帮你写代码的助手,而是你的对手,它要找到你代码里所有能被搞崩的地方。
两个大概率你没想到的 bug
还是AIHOT项目的真实案例。开发者用Claude Code开启了约40个Agent做对抗式审查,跑出来的问题列表让整个团队出了一身冷汗。挑两个最典型的:
OOM死循环。从某些海外站点抓到的内容文件特别大,worker进程处理到一半被系统的OOM killer杀掉。原来的代码逻辑是A任务失败了就重试,worker被杀掉之后,调度器自动拉起一个新的worker。新worker拿到同一个A任务,读同一份超大文件,又被OOM killer杀掉,然后又被拉起,一个死循环。
正常开发的时候,你在乎的是重试逻辑对不对,你不会去想如果导致失败的原因是资源不足,重试是在帮倒忙。但对抗式审查的Agent上来就问了一句:如果单条消息的处理所需内存超过worker的内存上限,你的重试机制会发生什么?
未来时间污染。某海外信源的服务器配置错了时区,返回的文章发布时间是明天中午十二点。爬虫收到之后不做任何校验,直接按信源给的时间写入数据库。结果用户的信息流排序逻辑是按发布时间倒序,于是那几篇来自未来的文章,永远排在所有人的信息流最顶端。
对抗式审查的Agent问了开发团队自己从没想过的问题:如果外部数据源的任何字段值落在合理范围之外,你的代码会怎么样?
这些bug有一个共同特征:上线前很难被发现,但一旦触发,影响很大。而且它们不是某个人写错了代码导致的,是整个设计里根本就没有考虑过这条路径。
传统测试 vs 对抗式审查
| 测试方式 | 能发现的bug | 发现不了的bug |
|---|---|---|
| 单元测试 | 逻辑错误、边界值 | 跨模块交互问题、资源竞争 |
| 集成测试 | 接口不匹配、数据格式错误 | 极端输入、资源耗尽、时序异常 |
| 人工Code Review | 代码风格、明显逻辑漏洞 | 隐蔽的边界条件、组合爆炸 |
| 对抗式审查 | 恶意输入、资源泄漏、外部数据污染、死循环条件 | 业务逻辑本身的合理性 |
对抗式审查补的不是测试的短板,它补的是你能想到的测试用例之外的那个世界。
传统测试验证的是我想到的可能出问题的场景,对抗式审查探索的是我根本没想到的场景。这是两种完全不同的思维,所以两种都需要。
两个套路怎么搭
第一性原理管生成:AI动手写代码之前,先让它想清楚这件事的本质是什么。方向对了,方案不会差太远。
对抗式审查管验证:代码写完之后,让AI换个角色,找那些正常思维路径上根本不会去想的漏洞。逻辑对了,还要扛得住边界攻击。
一个在前,一个在后。前一个避免做错事,后一个避免做漏事。两个加起来,就是一个足够轻量但仍然有效的质量闭环。
注意一个坑
对抗式审查跑出来的结果,不能全信,也不能全改。
它有时候会为了找问题而找问题,把一个发生概率无限接近零的边界条件,描述得像是随时会炸。你需要自己做判断:这个问题发生的概率多大?发生了影响多大?修它的成本多大?
优先级排一下,先改那些高概率高影响的。剩下的记在TODO里,写明触发条件,下个迭代再看。
另外一个教训:每次改完核心功能就跑一次对抗式审查,别攒到上线前一天。那时候发现问题属于灵魂拷问,半夜改代码上线,还是带着已知的坑上线?
两个都很难受。
一个额外的应用场景
前面说的是代码。但这两个套路其实不止于写代码。
写技术方案的时候,加一句从第一性原理出发,AI会帮你追问这个方案到底要解决什么问题,而不是堆砌别人的架构。写完方案再让它做对抗式审查,如果你是评审人,你会质疑哪些点,能提前暴露很多逻辑漏洞。
做商业分析、写项目复盘、甚至做个人决策,这两个套路都能用。本质上是让AI先退一步想清楚本质,再换个角度找盲点,这套思维方式,比任何具体的Prompt模板都值钱。
总结
两个句子,记住就行:
问方案,加一句从第一性原理出发。问安全,加一句对抗式审查。
试一次,成本为零。不好用,你就当多打了几个字。