这两年凡是拿AI写过代码的人,应该都体会过同一种憋屈:对话框里聊得明明白白,让它写个排序、写个接口调用,当场都能给你写出来,可一粘进项目里就四处报错——变量名对不上、依赖没装、边界没处理、异常一崩到底。我一开始也以为是AI水平不行,后来踩了几次坑才反应过来:问题出在我的提示方式上。简单问答式的提问,天然只能拿到“片段”,拿不到“即用型代码”。所谓即用型,不只是能跑,而是放进你的工程上下文里能无缝工作。这篇文章要聊的,就是我自己实测有效、并且已经沉淀成日常习惯的三条高级提示技巧,全部是能直接抄走的实战方法。
1. 为什么你问AI要代码,拿到的总是“半成品”
1.1 问答式交互的病根:只有需求碎片,没有约束条件
很多人把AI写代码理解成升级版搜索引擎:你问它什么,它答什么。这个理解在“查一个函数的用法”这种场景下没错,但在“给我写一个能用的模块”这种场景下,问题就大了。
大语言模型的生成逻辑,本质上是在预测“接下去最可能出现的代码”。如果你只给一句话需求,模型能参考的信息就只有这句话本身,剩下的全靠训练数据里的“平均印象”去补。结果是什么?是它能写出一段语法正确、结构尚可、但跟你项目毫无关系的通用代码。它不关心你的Python版本,不关心你允不允许引第三方库,不关心你已有的日志体系,不关心你接口的命名规范。因为这些信息,你根本没告诉它。
我做前端同事有个很经典的案例:他让AI“写一个文件上传组件”,AI给他返回了一个密密麻麻的完整组件,看着挺像回事,结果一用全是坑——用了公司内部平台不支持的浏览器API,没处理取消上传,也没有错误重试。他没骂AI,反而复盘了一句让我印象特别深的话:“我只说了要什么功能,没说要什么约束,它按自己的世界观自由发挥了。”
这就是问答式交互的天然缺陷:它适合“问答案”,不适合“接需求”。你要让它产出即用型代码,就得把需求描述从“一句功能”升级成“一份带约束条件的规格说明”。
1.2 即用型代码的真正门槛不在“生成”,在“约束”
我观察到一个规律:同样一个需求,让AI“自由发挥”和让AI“在约束下完成”,产出的质量差距是断崖式的。自由发挥的代码,看起来什么都有,但每个细节都停留在“能用”而不是“好用”的线上。
即用型代码需要的不是才华,是对齐。具体对齐什么?我总结了四个维度:
- 环境约束:语言版本、依赖范围、运行平台。你告诉它只能用Python 3.10标准库,它就不会给你塞一个需要pip install的第三方包。
- 架构约束:项目已有的目录结构、公共模块、接口签名。你告诉它日志要统一走某个模块,它就会放弃自己随手写print的想法。
- 行为约束:正常路径、边界条件、异常路径分别应该怎么表现。你告诉它超时抛什么异常、参数非法抛什么异常,它才能写出可被调用方捕获的代码。
- 质量底线:类型标注、命名风格、是否需要单元测试。你明确这些,它才会把它当硬性要求执行。
说白了,AI生成代码这件事,输入的信息量决定了输出的可用性。你的提示词不是一个“问题”,它是一份“需求规格说明书”。想通这一点之后,我再也没有抱怨过AI写代码不靠谱——因为绝大多数情况下,不靠谱的源头是我自己没把约束交代清楚。
2. 技巧一:用角色定义把上下文一次性“喂饱”
2.1 角色不是卖萌,是给AI划定知识域
很多人觉得“你是一名资深Python工程师”这种话是形式主义,是给AI戴高帽。实际用下来,这个说法有非常现实的作用:它改变的是模型输出时倾向于调用的“知识域”。
我打个比方。你要装修房子,跟一个普通装修公司说“帮我弄一下厨房”,他大概率给你一个中规中矩的方案;但你跟一个专门做老房子改造的工头说“帮我弄一下这个80年代户型的厨房”,他会自动去想承重墙、管线老化、通风死角这些普通装修公司根本不会考虑的事。角色定义就是干这个的——它把AI的输出从一个通用助手,拉到一个特定工种的经验体系里。
更关键的是,角色定义不只是说“你是专家”就完了,它还要附带“这个项目是什么样”的上下文。我见过太多人只写了“你是一名资深后端工程师”,然后就开始提需求。这就等于你虽然叫来了老工头,但没告诉他房子在哪、什么结构、预算多少,他还是只能自由发挥。
2.2 一个可以直接套用的角色模板
我现在的习惯是,每个稍微大一点的任务都先发一段“项目简介+角色设定”,再发具体需求。模板如下:
角色:你是一名长期维护生产系统的后端工程师,代码风格保守,倾向使用标准库和成熟稳定的特性。 项目背景:这是一个内部工单系统,基于 Python 3.10,当前所有服务不允许引入新的第三方依赖。 目录结构:业务代码统一放在 app/ 目录下,公共工具放在 app/common/ 下; 日志统一使用 app/common/logger.py 里提供的 get_logger(name) 函数。 本次任务:请在 app/services/ 下新增一个“批量导出工单为CSV”的功能模块。 硬性约束:不要修改 app/ 下其他文件的接口签名;导出功能需要支持分页读取,避免内存占用过高; 时间格式统一使用 ISO 8601。这个模板里每一句话都不是废话。“Python 3.10”约束了语法特性,避免它用3.11才有的新特性;“不允许新依赖”杜绝了它顺手写个第三方库;“目录结构”告诉它代码放哪里、日志走哪里;“不修改其他文件接口”锁定了改动边界;“分页读取”直接划定了技术方案的地基。这套东西加起来,比一万句“你要写得专业一点”管用得多。
2.3 角色描述里最容易犯的两个错
第一个错,是角色定得过于宽泛。“你是一名AI编程专家”“你是全栈大神”这种设定基本等于没设定,因为知识域太宽,模型反而不知道该调用哪一套经验。角色越窄,输出的约束性越强。你写“你是专门维护API服务的后端工程师,处理过大量并发问题”,比“你是技术大牛”有效得多。
第二个错,是角色和约束自相矛盾。比如你让它扮演“注重性能的底层开发者”,转头又说“不许用任何高级特性”;或者让它扮演“快速原型开发者”,又要求它写出生产级别的防御性代码。AI这时候会无所适从,只能取一个折中方案,结果就是两头都不靠。角色定义一定要和约束方向一致,你希望它保守稳重建模,就别同时要求它炫技。
我现在的做法是把这么一段角色模板存成备忘录,每次开新任务直接复制改一改。别每次都现场编,编着编着你就会漏掉一些关键约束,而AI的代码风格会随着你漏掉的约束一起跑偏。
3. 技巧二:把“要求”翻译成“验收标准”
3.1 验收标准为什么比功能描述更管用
“我要一个带超时控制的HTTP客户端”和“这个客户端必须在超时的时候抛出我能捕获的异常,在URL非法的时候直接报错”——这两句话在AI眼里是完全不同的信息量。
前者是功能描述,描述的是“做什么”。模型只能推测“超时控制”具体长什么样,随手给你一个socket超时参数就交差了。后者是验收标准,描述的是“怎么验证做对了”。模型拿到的是可检查的行为约束,它写代码的时候会逐条去满足,因为它知道你要的是一组可验证的行为。
这背后的逻辑很简单:大语言模型在训练的时候见过海量的“需求—代码”对,但它并不知道你和它之间这个具体的需求到底是宽松还是严格。你把验收标准写出来,等于告诉了它这次对话里“合格”的定义。它优化目标从“写一个看起来合理的实现”变成了“写一个能通过这些检查的实现”。
3.2 实战示例:让AI写一个带超时控制的HTTP客户端
我用同一个需求做过对比。第一种提问:
用Python写一个带超时控制的HTTP客户端这种问法下,AI通常会给出用requests库的实现,设置个timeout参数就完了。代码大约十行,看着挺干净,但问题一堆:没处理DNS解析异常,没区分超时类型,调用方拿到错误只能靠猜,而且引入了额外依赖。
第二种提问,我加上了验收标准:
请用Python实现一个HTTP客户端模块,验收标准如下: 1. 正常路径:调用 get(url, timeout=5) 发起HTTP GET请求,返回响应体文本;状态码非200时抛出自定义异常 HttpStatusError,异常中携带状态码和响应体内容。 2. 边界条件:url不是合法HTTP地址时,抛出 ValueError;timeout 小于等于0时视为未传,使用默认值10秒。 3. 异常路径:连接超时抛出 HttpTimeoutError,网络不可达抛出 HttpConnectError,这两种异常必须能被调用方单独捕获。 4. 质量底线:仅使用标准库实现,不引入第三方依赖;所有函数带完整类型标注;异常类统一放在 exceptions.py 模块中。这个版本生成的代码,明显不一样。它真的会为不同类型的异常建独立的异常类,会做URL合法性校验,会把超时和网络不可达分开处理,还会主动把异常类拆到exceptions.py里。最关键的是,调用方拿到这个模块,可以针对性地捕获异常做重试或告警,而不是面对一个笼统的Exception发呆。
3.3 验收标准的四个必填字段
我总结了一个验收标准提示词的固定结构,四条写齐,AI基本不会跑偏。完整逻辑是:
- 正常路径:给定输入,期望输出什么。这能保证AI把主流程写完整,而不是写完入口就交差。
- 边界条件:空值、非法值、极端长度、并发重复调用等情况下,应该怎么表现。这是AI最容易偷懒的地方,明确写出来它才会处理。
- 异常路径:外部依赖故障(超时、连不上、返回错误码)时,应该抛什么异常、谁来捕获。这直接决定你的代码在真实环境里能不能扛住故障。
- 质量底线:类型标注、命名风格、依赖限制、测试要求。这决定代码能不能融入你现有的工程规范。
有一个提醒:边界条件和异常路径别写太多,每条路径最多写两三个典型场景就够了。写多了,模型反而会为了凑验收标准而过度设计,把简单模块搞成满屏防御代码的重型机器。
4. 技巧三:先让AI“纸上谈兵”,再让它写代码
4.1 为什么“先说方案”能显著降低返工率
大多数人和AI协作写代码的流程是:提需求→拿到代码→测试→发现不对→再提需求→再拿代码。这个循环的问题在于,来回返工发生在“代码已经生成”之后,每一轮返工都要重新检查一遍实现,成本很高。
而如果让AI先给方案、你再确认,返工发生在“代码还没生成”之前。改方案只需要改几行文字,改代码需要重写几十上百行。这一前一后的成本差距,就是技巧三的核心价值。
更重要的原因是,方案阶段能暴露你需求里的逻辑漏洞。比如你让AI“批量处理文件”,它可能在方案里问:文件重名怎么处理?处理失败要中断还是跳过?你一看方案才发现,这些细节你自己都还没想清楚。方案确认的过程,实际上是在替你做了一次需求评审。
4.2 规划提示词模板与示例过程
我常用的规划提示词长这样:
先不要写任何代码。请先给出解决方案,包括: 1. 整体模块划分和文件结构; 2. 核心函数/类的签名(函数名、参数、返回值); 3. 关键流程的伪代码或步骤描述; 4. 可能的风险点和边界情况。 等我确认方案后,你再开始写实现。注意最后一句“等我确认方案后,你再开始写实现”,这句必须写。如果不加这句,AI经常嘴上说“好的,我先把方案列出来”,结果方案还没列完,代码就已经跟出来了,根本拦不住。
我看过一次典型的对话。需求是“写一个日志清理工具,删除超过30天的日志文件”。AI给的方案里有一条:递归遍历日志目录,逐个查看文件修改时间。我直接在方案阶段就提出了问题:“如果目录下文件数量巨大,逐个检查文件属性会不会太慢?能不能直接用文件名的日期前缀做筛选?”就这一句话,让我省掉了后面至少三轮的代码返工。因为等代码写出来再发现性能问题,就要先读懂它写的整个目录遍历逻辑,再想怎么改,再重新生成,太费劲了。
4.3 规划结果不满意时的追问话术
方案确认阶段,我积累了几条特别好用的追问话术,分享出来供参考:
- “这个方案引入了新的依赖,能否改为使用标准库实现?”——用来收回依赖权限,防止AI在方案阶段又偷偷引入第三方包。
- “请说明超时和重试的具体策略,重试会不会导致重复提交?”——用来逼AI把容错机制想细,避免它含糊地写“加入必要的容错处理”。
- “这个模块的核心接口设计偏复杂了,能不能简化成两个对外函数?”——用来纠正过度设计,让接口保持最小化。
- “如果文件不存在/权限不足/磁盘满了,方案里分别怎么处理?”——用来检查异常路径有没有被它遗忘。
这些追问的共同点是:它们都是针对“方案”而不是针对“代码”。方案上改一句话的成本远低于代码上改一个模块。我实测下来,这样一个“先方案后代码”的流程,能让整体返工率下降一半以上。
5. 三招合体:一个真实需求的完整对照实验
5.1 对照组:普通问答式提问
光说不练没意思,我拿一个真实的内部小需求做了一次对照实验。需求背景是某内部工具需要“批量重命名一批图片文件”,规则是:把文件名里的时间戳格式从xxxx_yyyyMMdd_HHmmss改成xxxx_yyyy-MM-dd_HHmmss,同时要跳过不符合格式的文件。
对照组直接用一句话提问:
写一个Python脚本,批量重命名目录下的图片文件,把文件名里的时间戳从yyyyMMdd改成yyyy-MM-dd格式AI返回的代码大概三十行,核心逻辑用的是正则替换,看起来没什么问题。但实际测试发现三个坑:一是没有跳过不符合格式的文件,前面逻辑写的是“逐一处理所有文件”,有文件不符合格式时正则匹配不到,程序直接报错中断;二是它假设所有文件都在同一个目录下,碰到子目录就傻眼;三是它直接覆盖原文件,没有预览或确认环节,一旦正则写错,文件名就永久破坏了。这结论其实不算意外——我没给它约束,它就默认了一个最理想的场景。
5.2 实验组:三技巧组合提问
实验组用同样的需求,但是把三个技巧全用上。角色定义明确“这是一个生产环境的数据整理脚本,运行环境为 Python 3.10 + Windows/Linux 双平台,不允许安装第三方依赖”;验收标准写清楚“文件名格式不匹配时跳过而不是报错、支持递归子目录、默认输出重命名计划而不实际执行,加 --apply 参数才真正执行”;最后再加一句“先给方案,确认后写代码”。
AI先给出方案:用pathlib.rglob递归查找、用正则的match方法做严格匹配、把重命名拆成“收集计划”和“执行计划”两个阶段。方案里还主动提出一个我没想到的点:修改时间戳格式时,如果目录里已存在同名目标文件,应该跳过重命名并记录日志,防止覆盖。
随后生成的代码里,这些设计全部落地了。跳过不合规文件、递归子目录处理、默认预览打印计划、加--apply才实际执行,全都在。代码量从三十行涨到了六十多行,但没有一行是多余的,全是需求本身的复杂性带来的。
5.3 两组结果对比:差距不在代码量,在可用性
我做了个简单的对比表,列一下两个版本的差异:
| 维度 | 对照组(简单问答) | 实验组(三技巧组合) |
|---|---|---|
| 不合规文件处理 | 程序报错中断 | 跳过并记录 |
| 子目录支持 | 不支持 | 递归支持 |
| 误操作风险 | 直接覆盖原名 | 默认预览,加参数才执行 |
| 同名文件冲突 | 未处理 | 跳过并告警 |
| 平台兼容性 | 未提及 | 明确说明双方平台 |
| 可直接投入使用的程度 | 需要补一堆逻辑 | 基本可用 |
这个对比最能说明问题的是最后一行。对照组看起来代码更短,但那是把工程复杂性藏起来没处理;实验组代码更长,但每一点额外长度都对应着一个实际会发生的情况。所谓即用型代码,说到底不是“写得好”,而是“考虑得全”。
6. 实战中踩过的坑与排查经验
6.1 上下文窗口被撑爆之后
技巧一和技巧二都强调要给足上下文,但给多了也有麻烦。有一次我把项目简介、角色定义、验收标准、历史对话记录全堆在一条提示里,结果AI反而开始“丢”最前面的信息——它后面的生成明显更依赖最近几轮对话,早期的约束渐渐被遗忘了。
后来我总结了一个更稳的做法:把角色定义和项目背景这类长期信息放到提示词最前面,而且控制在一百五十字以内,写成精炼的要点式简介;具体任务的验收标准紧跟其后;历史对话每轮结束后,我会手动把过时的结论删掉,只保留最后确定的方案和约束。如果你的对话已经很长了,不要硬续,而是开一个新对话,把“最终确认的方案摘要”贴进去,再让AI接着干活。
6.2 AI“一本正经编API”怎么办
这是我最常遇到的坑,没有之一。你让它实现一个功能,它在代码里调用了一个看着像标准库、实际上是它编出来的假API。这种跌最容易发生在AI引用不常见的标准库模块时。
比如有一次我让它处理定时任务,它在代码里用了某个我根本没听说过的标准库函数,跑起来果断报错。后来我学乖了,在提示词里加了一条约束:“只能用你确认为标准库且实际存在的API,不确定的API请在方案阶段列出让我确认。”方案阶段让AI把所有要使用的库和关键API列出来,我看到不确定的去文档确认完再让它写代码,就基本杜绝了这个坑。
6.3 提示词越写越长,效果反而变差
我有一段时期走极端,觉得反正AI理解能力强,就把需求写得很详细,连注释怎么写、变量怎么命名都规定死。结果代码生成质量明显下降,原因是约束过多,反而挤掉了模型发挥的空间,它每一行都顾虑重重,生成的代码变得非常别扭,甚至开始自相矛盾。
现在我的原则是:硬约束必须明确,弹性项目不干预。环境版本、依赖范围、接口签名、异常行为这些是硬约束,一定写清楚;但函数内部的实现细节、变量命名风格、注释密度这种,就交给AI自己决定。你越是信任它在细节上的默认选择,它越能在关键处给你省心。
这套流程我磨合了大概两三个星期,最开始也觉得每次写提示词都啰啰嗦嗦很麻烦,但后来发现,一次交代清楚,比来回返工五轮省时间得多。现在我把角色模板、验收标准结构和先方案后代码的流程,直接存成了一份项目级的提示词文档,新任务来了复制改改就能用。如果你也在用AI写代码,别急着追着问更花哨的“咒语”,先把这三件事做到位,你会发现代码质量立刻就不一样了。