我之前带过几个刚入门的同事做同一个项目。同样的 AI 编程工具,有人一天写 500 行代码、完成 3 个功能点,有人花了半天连一个接口都没调通。
区别在哪?不是谁更聪明,不是谁打字更快——差在问问题的能力。
你在网上看到的各种"AI 编程效率提升 10 倍"的案例,大部分不是因为那个工具更厉害,而是写案例的人会问问题。
反过来,那些觉得"AI 也没多好用"的人,十有八九问题出在提问方式上——不是 AI 不行,是你没让它行。
同一个需求,不同的结果
先看一个真实的例子。需求很简单:用 Python 写一个函数,从 Excel 文件里读取客户数据,发邮件通知。
常规的提问(差):
用 python 读取 excel 文件,发邮件。AI 给了你一个最基本的方案:用openpyxl读 Excel,用smtplib发邮件。代码能用,但你一眼就看出来有问题——没有错误处理、邮件格式是纯文本、附件不会加、多个收件人不会区分。你又要修修补补十分钟。
好的提问(好):
帮我写一个 Python 脚本: - 从 input.xlsx 读取客户数据(列:姓名、邮箱、购买产品、金额) - 根据金额是否大于 1000,给对应的客户发不同模板的邮件 - 大客户(金额>1000):HTML 邮件,含感谢文案+增值服务推荐 - 普通客户:纯文本邮件,含产品使用提示 - 邮件正文要动态替换客户名和产品名 - 发送后输出发送成功的邮箱列表和发送失败的邮箱列表 - 加日志,每条日志带时间戳 Excel 可能含空行,读取时跳过。邮箱格式不对的也跳过但记录到日志里。结果完全不同。AI 生成了一个接近生产级别的脚本,包含了 Excel 读取、邮件模板引擎、收件人过滤、错误处理、日志记录。
这就是好问题跟差问题的差距。不是 AI 的差距,是你把需求说清楚了的差距。
很多人觉得自己问得已经够清楚了,但放到 AI 的视角看看,全是坑。你问"写一个发邮件的函数",AI 不会自己去猜你的收件人从哪里来、邮件正文怎么写、用哪个邮箱服务器、附件要不要、出了异常怎么办。它只能选一个"最常见的做法"。而这个"最常见的做法"通常不是你想要的,因为每个项目的需求都是独特的。
好的提问者,不是问题多的人,而是能把模糊的需求翻译成 AI 能理解的精确指令的人。这个能力本身就是一个程序员的分水岭——顶级工程师能把"改个什么东西"变成一段无需追问的精确需求,普通工程师说半天对方还是不明白。AI 只是把这种差距放大了 10 倍。
为什么"差问题"最坑人
差问题更隐蔽的坑在于,它给你的答案看起来能用。你执行了那个脚本发现没有错误处理,你感觉"还行,再加几行就好了"。但等你把错误处理加完、异常逻辑补上、邮件格式改成 HTML、再加上日志——你花的时间可能比从头写还要多。
AI 给的差答案,干扰性比没有 AI 还强。ta 给了你一个立刻能用但不够好的答案,你花了更多时间在"修补这个半成品"上。
所以我的原则是:与其花两分钟给 AI 一个模糊的问题然后花二十分钟修修补补,不如花五分钟写一个精确的 prompt,让 AI 一次性输出你真正需要的东西。这点时间的投入,后面的收益是几十倍的。
万能提问公式:场景 + 目标 + 约束 + 输出
问过上百次问题之后,我总结了一个四步提问公式,适用于几乎所有 AI 编程工具——Claude Code、Codex、Cursor,都一样。
第一步:给场景
告诉 AI 你当前在做什么。让 AI 理解上下文,而不是从零猜测。
我正在做一个 Spring Boot 3 的后端项目,使用 JPA + MySQL。 当前在写订单模块的 Service 层。第二步:定目标
告诉 AI 你需要什么。需求要具体,"帮我优化一下"这种话对 AI 没有任何意义。
需要实现一个订单取消功能。用户取消订单后:更新订单状态为 CANCELLED、恢复商品库存、如果已支付需要退款。第三步:列约束
把限制条件说清楚。技术栈、性能要求、安全策略——这些不说 AI 会按"一般人"的方式去做。
- Spring Boot 3.2 + Java 17 - 使用 @Transactional 保证原子性 - 退款调用外部 PaymentService,需要 try-catch 处理失败情况 - 每个操作打日志,区分 INFO 和 WARN - 不要用 @Autowired 字段注入,用构造方法注入第四步:定输出
告诉 AI 你期望输出的形式。接口签名、文件命名、注释风格——AI 默认给的你不一定满意。
输出格式: - 三个文件:OrderCancelService.java(接口)、OrderCancelServiceImpl.java(实现)、OrderCancelServiceTest.java(测试) - 每个公开方法加 JavaDoc - 测试覆盖正常取消、已取消订单再次取消、退款失败这 3 个场景四步连起来就是完整的 prompt:
【场景】我正在做一个 Spring Boot 3 的后端项目,使用 JPA + MySQL,当前在写订单模块的 Service 层。 【目标】需要实现一个订单取消功能。用户取消后:更新订单状态为 CANCELLED、恢复商品库存、如果已支付需退款。 【约束】Spring Boot 3.2 + Java 17,用 @Transactional 保证原子性,退款调用 PaymentService 并 try-catch 处理失败。 【输出】三个文件:接口、实现、测试。每个方法加 JavaDoc。测试覆盖 3 个场景。如果你希望每次提问都不用写这么多字,把项目和工具的通用约束写到 CLAUDE.md(参考上一篇文章),然后每次都只写目标和特殊约束就够了。
不同场景的最佳提问姿势
不同的编程场景,提问的侧重点不一样。我把常见场景的提问模板列出来。
场景一:写功能
这是最常见的场景。重点是把想要的行为描述清楚,不能有歧义。
模板:
实现 [功能名称],需要做什么。 输入:xxx,输出:xxx。 边界情况:xxxx的情况应该怎么处理。例子:
实现一个用户注册接口。 前端传 username、password、email 三个字段。 注册时校验 username 不能重复,password 用 bcrypt 加密。 邮箱非必填,不填则不发送验证邮件。 注册成功返回 201 和用户信息,失败返回 400 和错误原因。场景二:修 Bug
修 Bug 的关键是复现步骤。没有复现步骤,AI 只能猜。
模板:
在 [环境/模块] 遇到了一个 Bug: 表现:xxxx 触发条件:xxxx 期望:xxxx 自己排查到的线索:xxxx例子:
在 Chrome 浏览器上,用户登录后点击"我的订单"页面白屏。 控制台报错:TypeError: Cannot read properties of undefined (reading 'length')。 查看 network 发现是 /api/orders 接口返回的数据中 orders 字段为 null。 以前 orders 字段返回的是空数组,升级后端接口后改成了 null。场景三:重构
重构的要点是守住业务不变。告诉 AI 哪些不能改比告诉它怎么改更重要。
模板:
重构 [文件名/模块名]。 目标:xxxx(提升可读性/性能/可维护性)。 限制:不能改的——xxxx(接口签名/返回格式/业务逻辑)。 额外要求:重构后跑测试 xxxx。例子:
重构 OrderService 里的 calculateTotal 方法,这个方法有 150 行。 目标:拆成不超过 20 行的小方法,把价格策略提取到单独的策略类。 限制:方法签名不能改(输入输出不能变)、金额精度不能丢、已有的测试不能挂。场景四:调试
调试就是告诉 AI 你看到了什么,让它判断原因和解决方案。关键是把完整的错误信息和上下文给到 AI。
模板:
[贴错误信息/截图描述] 出问题的代码: [贴代码] 项目配置:[技术栈版本] 出现频率:必现/偶现例子:
Caused by: org.hibernate.LazyInitializationException: could not initialize proxy [com.example.order.entity.Order#123] - no Session 代码: Order order = orderRepository.findById(123L).orElse(null); System.out.println(order.getItems().size()); // 这一行报错 项目:Spring Boot 3.2 + JPA + MySQL Controller 里直接查 Entity,没有启用 Open-in-view踩过的最深的坑——问 AI 优化
我觉得自己踩过最深的坑就是问"优化"。
帮我把这段代码优化一下。十个 AI 有九个会给你来一个"泛泛的优化建议"——用 Stream API 替换 for 循环、把 if-else 改成 switch——这些优化有时候是负优化。Stream 在简单的遍历场景下比 for 循环慢 3 倍,改 switch 只是语法层面变了,性能根本没提升。
所谓的"优化"没有具体的目标,AI 只能给你做"语法糖优化",而不是真正的性能优化。
正确的问法是:
这段代码在数据量为 10 万条时,执行时间约 2 秒。帮我优化,目标:数据量 10 万时执行时间 <500ms。给出具体的指标,AI 才知道你到底要优化什么。
两个进阶技巧
技巧一:给 AI 设角色
AI 的角色设定对输出质量影响巨大。不同角色的 AI 输出风格完全不一样。
你是一个有 10 年经验的 Spring Boot 架构师,代码要经过 code review 级别的质量考验。你是一个安全工程师,帮我审查这段代码有没有安全漏洞。你是一个刚加入团队的新手开发者,请用最简单直接的方式实现这个功能。设角色不只是一个"小技巧",它让 AI 调用不同的知识分布去完成你的任务。架构师角色关注的是可扩展性和维护性,安全角色关注的是输入校验和 SQL 注入,新手角色关注的是简单易懂。
技巧二:反向提问
有时候你应该让 AI 来问你。
我现在要在 OrderService 里加一个"批量订单导出"的功能。 但是可能有几个细节我没想到。先列出你需要的所有信息和要考虑的边界情况,我来补充。然后你再开始写代码。AI 会问你这几个问题:导出的文件格式?分页还是全量?数据量大时的处理策略?文件上传到哪?权限控制?导出失败的重试机制?时区问题?
很多你没想到的边界情况,AI 会先想到。而且这种做法的一个好处是——你在"审 AI 的问题",不是 AI 在"猜你的需求"。前者你很容易判断对错,后者你很难判断。
技巧三:用"分步确认"代替"一步到位"
写单测或者重构这种偏复杂的工作,不要指望 AI 一次搞定全部。我自己用的方法是"两步确认法":
第一步,让 AI 出计划:
我要重构 OrderService 的价格计算方法。你先不要改任何代码,只出一个重构方案,列出你要改的文件、改动的内容范围、每个改动的理由。看完方案后,我批注或修改计划,然后发给 AI:
第二步,确认计划后执行:
以上方案我同意了。请按方案执行,执行完后跑测试验证。这种"先出计划、确认后再执行"的做法,能让 AI 的错误率降低一半以上。原因很简单——在"计划阶段"发现错误比"执行阶段"发现错误容易得多。AI 出的计划你看一眼就知道合不合理,而 AI 直接改完的代码你可能要仔细 debug 才发现有问题。
技巧四:教 AI 你的"话术"
如果你经常跟同一个 AI 配合,可以试试建立一套"快捷指令"。这些快捷指令放在 CLAUDE.md 里,每次 AI 都会读到。
例如在 CLAUDE.md 里写:
当我要求"写接口"时,表示要生成完整的 RESTful API 代码,包含 Controller、Service、DTO、Validator、单元测试。 当我要求"看代码"时,表示要分析代码质量,给出可读性、性能、安全三个维度的评估。 当我要求"改 bug"时,表示要先定位问题根因、列出复现步骤、再修代码。这样你用简短的指令就能让 AI 完成复杂的任务,不用每次都把完整需求再写一遍。既省了 token 又减少了你的打字量。
说回开头那个问题。为什么同样的工具,有人效率翻倍有人半天出不来?
不是 AI 工具的区别。真正拉开差距的,是提需求的能力。
你用 AI 的终极目标不是"让工具更聪明",而是"让自己更懒"——但懒的前提是你得把需求说清楚。你说清楚了,AI 才能替你干;你说不清楚,你就得替 AI 收拾烂摊子。
一个好问题值 10 行代码。一个好架构师值 1000 个差问题。
下次用 AI 之前,花 30 秒想想这个问题:我把需求说清楚了吗?
🎁 福利时间
私信回复「666」,我送你一份《AI编程工具大礼包》:
- Cursor / Copilot / Codex 对比表(PDF)
- 10 个程序员专属 Prompt 模板
- AI Debug 万能提问公式