1. 被误解的“基本功”:为什么 Prompt 不是终点
这两年跟不少同行聊 AI 编程,发现一个特别普遍的现象:很多人把“会写 Prompt”当成了核心竞争力,甚至觉得只要提示词写得够花哨,AI 就能自动把活干完。我一开始也走过这个弯路,花了不少时间研究各种提示词模板、角色设定、思维链格式,结果在实际项目里该翻车还是翻车。后来才慢慢想明白一件事:Prompt 只是你和模型之间的接口,真正决定输出质量的,是你对问题的拆解能力、对上下文的组织能力,以及对结果的验证能力。
打个比方,Prompt 就像你跟装修师傅沟通时说的话。话说得清楚当然重要,但如果你自己都不知道想要什么风格、水电怎么走、预算怎么分配,那话说得再漂亮,最后装出来的房子大概率也不是你想要的。AI 编程也是这个道理——模型再强,它也只是执行者,真正的“设计图纸”得你自己出。
那什么才是 AI 编程的真正基本功?我总结下来是四样东西:问题拆解、上下文管理、结果验证、以及工程化思维。这四样东西,跟你会不会写 Prompt 关系不大,但跟你是不是一个合格的工程师关系极大。下面我逐个拆开讲,结合我自己的实操经验,把每个环节的细节和坑都摊开来说。
1.1 一个真实的翻车案例
先说个我自己的教训。之前接了一个需求,要给一个内部工具加一个“数据导出”功能,支持导出成 CSV 和 Excel 两种格式。我当时觉得这活儿简单,直接给 AI 甩了一句:“帮我写一个数据导出功能,支持 CSV 和 Excel。”结果 AI 给出来的代码,CSV 部分还行,Excel 部分用了一个我没听说过的库,而且导出逻辑里把整个数据集一次性加载到内存,完全没有分页处理。
问题出在哪?不是 Prompt 写得不好,是我自己没想清楚几个关键点:数据量有多大?需不需要流式导出?Excel 格式有没有特殊要求(比如单元格样式、多 sheet)?这些我都没定义,AI 只能猜,猜出来的结果自然不能用。
后来我重新梳理了需求,把问题拆成几个子问题:数据源是什么、导出触发方式是什么、目标格式的具体要求、性能约束是什么。然后针对每个子问题分别跟 AI 沟通,最后再让它把各部分组装起来。这次出来的代码质量明显不一样,基本一次通过。
这个经历让我意识到,AI 编程的核心不是“怎么问”,而是“问什么”。你得先有能力把一个大问题拆成若干个小问题,每个小问题都有明确的输入、输出和约束条件,然后才能指望 AI 帮你高效解决。
2. 基本功之一:问题拆解能力
问题拆解听起来像句废话,谁不会拆问题?但实际操作中,我发现很多人拆问题的粒度太粗,或者拆完之后子问题之间还有隐含依赖没理清楚。AI 编程场景下,拆解的质量直接决定了你后续跟 AI 交互的效率。
2.1 拆解的粒度怎么把握
我的经验是:每个子问题应该是一个“可独立验证”的单元。什么意思?就是你把这个子问题交给 AI 之后,它给出的结果你能单独跑起来、单独测试、单独判断对错。如果一个子问题还需要依赖另一个子问题的输出才能验证,那说明拆得还不够细。
举个例子,你要做一个“用户登录”功能。粗拆可能是:前端页面、后端接口、数据库查询。但这个粒度太粗了,AI 给你的代码你没法直接验证。细拆应该是:
- 数据库表结构设计(字段、类型、索引)
- 密码加密与校验逻辑(用什么算法、盐值怎么处理)
- 登录接口的请求/响应格式定义
- 前端表单的字段校验规则
- 登录态的管理方式(token 还是 session)
每个子问题都可以单独拿出来让 AI 生成代码,而且生成之后你能立刻写个测试用例验证。这样一步步推进,最后组装起来的时候,出问题的概率会小很多。
2.2 拆解时容易忽略的“隐性依赖”
拆解的时候有个坑特别容易踩:子问题之间的隐性依赖。比如你让 AI 先生成数据库查询代码,再生成接口代码,但接口代码里用到的字段名跟数据库查询返回的字段名对不上。这种问题在粗粒度拆解时经常出现,因为 AI 不知道你前面生成了什么。
解决办法是在拆解阶段就把接口契约定下来。比如你先定义一个数据模型:
# 用户登录相关的数据模型定义 class LoginRequest: username: str password: str class LoginResponse: token: str expires_at: int user_id: str然后把这个模型定义作为上下文,分别让 AI 生成数据库查询、接口逻辑、前端调用代码。这样各个部分之间的字段名、类型都能对齐,组装的时候基本不会出现“对不上”的问题。
注意:拆解阶段花的时间,会在后续组装和调试阶段成倍省回来。我自己的经验是,拆解时间占总时间的 20% 左右比较合理,低于这个比例后面大概率要返工。
2.3 拆解后的优先级排序
拆完之后还有个步骤:排优先级。不是所有子问题都一样重要,有些是核心路径,有些是边缘情况。我的做法是先搞定核心路径,让整个流程能跑通,然后再逐个补充边缘情况。
比如做数据导出功能,核心路径是“查询数据 → 格式化 → 写入文件 → 下载”。边缘情况包括:数据量为零怎么处理、导出过程中用户取消怎么办、文件名冲突怎么解决。先把核心路径跑通,你就能看到一个可用的版本,然后再让 AI 帮你补充边缘情况的处理逻辑。这样每一步都有正反馈,不至于一开始就陷在细节里出不来。
3. 基本功之二:上下文管理能力
跟 AI 协作编程,上下文管理是另一个容易被低估的能力。很多人觉得上下文就是“把代码贴给 AI”,但实际上,上下文的组织方式、裁剪策略、更新时机,都会直接影响 AI 的输出质量。
3.1 上下文不是越多越好
我见过有人把整个项目的代码都贴给 AI,觉得这样 AI 就能“理解全局”。但实际上,上下文太长会导致两个问题:一是模型注意力被分散,关键信息反而被淹没;二是 token 消耗大,成本高不说,还可能触发长度限制。
我的做法是:只给当前子问题相关的上下文。比如我在写一个 API 接口,我只需要给 AI 看:这个接口的路由定义、相关的数据模型、以及它依赖的服务层方法签名。不需要把整个项目的代码都塞进去。
具体操作上,我会维护一个“上下文清单”,每次跟 AI 交互前,先想清楚这次需要哪些信息:
| 上下文类型 | 是否必需 | 说明 |
|---|---|---|
| 当前子问题的需求描述 | 必需 | 明确输入输出和约束 |
| 相关的数据模型定义 | 必需 | 保证字段名和类型对齐 |
| 依赖的方法签名 | 必需 | 知道能调用哪些方法 |
| 相邻模块的代码 | 可选 | 需要风格对齐时才给 |
| 整个项目的代码 | 不需要 | 信息过载,反而干扰 |
3.2 上下文的更新时机
上下文不是一次给完就完事了,随着子问题的推进,上下文需要动态更新。比如你刚让 AI 生成了一个工具函数,接下来要写调用这个函数的代码,那你就需要把刚才生成的函数签名加到上下文里。
我习惯用一个小技巧:每次跟 AI 交互后,把关键产出(函数签名、数据模型、接口定义)摘出来,存到一个单独的文档里。下次交互时,直接把这个文档作为上下文的一部分。这样既能保证信息不丢失,又不会把无关的代码带进来。
3.3 用“契约”代替“代码”作为上下文
还有一个进阶技巧:尽量用接口契约而不是具体实现作为上下文。比如你要让 AI 写一个调用数据库的方法,你不需要把数据库连接的具体代码给它看,只需要告诉它“有一个方法叫query_users,接收一个user_id参数,返回一个User对象”。这样 AI 生成的代码会更干净,不会跟具体的实现细节耦合。
这个思路其实跟微服务架构里的“面向接口编程”是一个道理。AI 不需要知道底层怎么实现的,它只需要知道能调用什么、返回什么。这样生成的代码可测试性也更好,因为你可以很方便地 mock 掉依赖。
4. 基本功之三:结果验证能力
AI 生成的代码,永远不要直接信。这不是说 AI 能力不行,而是因为 AI 没有你的业务上下文,它不知道哪些边界情况需要处理,也不知道你的代码规范是什么。所以验证环节是必须的,而且验证能力本身就是一个核心基本功。
4.1 验证的三个层次
我把验证分成三个层次:语法验证、逻辑验证、边界验证。
语法验证最简单,代码能不能跑起来、有没有明显的语法错误。这个大部分 IDE 都能帮你做,AI 生成的代码一般语法问题不大。
逻辑验证是看代码的逻辑是否符合你的预期。比如你让 AI 写一个“计算订单总价”的函数,你得检查它有没有把折扣、税费、运费都算进去,计算顺序对不对。这个层次需要你自己对业务逻辑非常清楚,否则你根本不知道 AI 写得对不对。
边界验证是最容易被忽略的。比如输入为空、输入超长、数值溢出、并发冲突这些情况,AI 默认生成的代码往往不会处理。你需要主动构造这些边界条件去测试,发现问 题再让 AI 补充处理逻辑。
4.2 用测试用例驱动验证
我的习惯是:在让 AI 生成代码之前,先想好测试用例。比如我要一个“判断字符串是否为合法邮箱”的函数,我会先列出几个测试用例:
# 测试用例设计 test_cases = [ ("user@example.com", True), # 正常邮箱 ("user@.com", False), # 域名不完整 ("@example.com", False), # 缺少用户名 ("user@example", False), # 缺少顶级域名 ("user name@example.com", False), # 包含空格 ("", False), # 空字符串 ]然后把这些测试用例一起给 AI,让它生成能通过这些用例的代码。这样 AI 的输出就有了明确的验证标准,你也能快速判断它写得对不对。
4.3 验证过程中的常见陷阱
验证的时候有几个坑我踩过,这里列出来供参考:
- 只验证正常路径:只测了输入合法的情况,没测异常输入。结果上线后遇到脏数据直接崩了。
- 验证环境跟生产环境不一致:本地测试用的是小数据集,生产环境数据量大,性能问题没暴露出来。
- 过度依赖 AI 的自我验证:让 AI 自己检查代码有没有问题,它往往会说“没问题”,但实际上问题还在。验证必须由你自己来做。
提示:验证环节的时间投入不要省。我自己的比例是:生成代码占 30%,验证和调试占 70%。这个比例看起来夸张,但实际做下来,前期验证充分的话,后期返工的时间会大幅减少。
5. 基本功之四:工程化思维
最后一个基本功是工程化思维。AI 编程很容易让人陷入“能跑就行”的状态,因为生成代码太快了,快到你来不及思考架构和可维护性。但代码是要给人看的,也是要长期维护的,所以工程化思维不能丢。
5.1 代码风格的一致性
AI 生成的代码风格可能跟你项目现有的风格不一致。比如你项目里用的是 4 空格缩进,AI 给你生成的是 2 空格;你项目里用驼峰命名,AI 给你生成的是下划线命名。这些细节看起来小,但积累多了会让代码库变得混乱。
解决办法是在上下文里明确告诉 AI 你的代码规范。比如:
请遵循以下代码规范: - 缩进使用 4 个空格 - 变量和函数名使用驼峰命名法 - 类名使用大驼峰命名法 - 常量使用全大写下划线分隔 - 每个函数不超过 50 行 - 公共方法必须写文档注释把这些规范作为系统提示的一部分,每次交互都带上,AI 生成的代码风格就会一致很多。
5.2 模块划分与职责单一
AI 生成代码时,倾向于把所有逻辑写在一个函数里。比如你让它写一个“处理用户注册”的功能,它可能把参数校验、密码加密、数据库写入、发送邮件全塞在一个函数里。这种代码能跑,但不好维护。
你需要主动引导 AI 做模块划分。比如你可以这样拆:
validate_registration_params(params):只负责参数校验hash_password(password):只负责密码加密create_user_in_db(user_data):只负责数据库写入send_welcome_email(user_email):只负责发送邮件
每个函数只做一件事,然后在一个主流程里把它们串起来。这样代码的可读性和可测试性都会好很多。
5.3 错误处理与日志
AI 生成的代码往往对错误处理比较敷衍,要么直接抛异常,要么吞掉异常什么都不做。但在生产环境里,错误处理和日志是必不可少的。
我的做法是:在让 AI 生成代码时,明确要求它加上错误处理和日志。比如:
import logging logger = logging.getLogger(__name__) def create_user_in_db(user_data): try: # 数据库写入逻辑 result = db.users.insert_one(user_data) logger.info(f"用户创建成功: {user_data['username']}") return result except DuplicateKeyError: logger.warning(f"用户名已存在: {user_data['username']}") raise ValueError("用户名已被占用") except Exception as e: logger.error(f"用户创建失败: {str(e)}") raise这样生成的代码,出问题的时候你能快速定位,而不是两眼一抹黑。
6. 实操流程:从需求到上线的完整链路
前面讲了四个基本功,这一节我把它们串起来,展示一个完整的实操流程。假设我们要做一个“文件上传与解析”的功能,支持上传 CSV 文件并解析成结构化数据。
6.1 第一步:需求拆解
先把需求拆成子问题:
- 文件上传接口:接收文件、校验格式、保存到临时目录
- CSV 解析逻辑:读取文件、解析表头、逐行解析数据
- 数据校验:检查必填字段、数据类型、数值范围
- 数据入库:将解析后的数据写入数据库
- 错误处理:解析失败时返回明确的错误信息
每个子问题都可以独立开发和验证。
6.2 第二步:定义接口契约
在写代码之前,先把数据模型和接口定义好:
# 数据模型 class UploadedFile: filename: str content_type: str size: int temp_path: str class ParsedRow: row_number: int data: dict errors: list class ParseResult: total_rows: int success_rows: int failed_rows: list这些契约定义好之后,后续每个子问题的开发都围绕这些契约来,保证各部分能对接上。
6.3 第三步:逐个实现子问题
以 CSV 解析逻辑为例,我会这样跟 AI 沟通:
请实现一个 CSV 解析函数,要求: - 输入:文件路径(字符串) - 输出:ParseResult 对象 - 使用 Python 标准库 csv 模块 - 第一行作为表头 - 每行数据解析后,检查必填字段是否为空 - 如果某行解析失败,记录行号和错误信息,继续解析下一行 - 不要因为单行失败而中断整个解析过程AI 生成代码后,我会用几个测试文件验证:正常文件、空文件、只有表头的文件、包含脏数据的文件。验证通过后再进入下一个子问题。
6.4 第四步:集成与联调
所有子问题都实现完之后,把它们组装起来。这时候重点检查:
- 各模块之间的数据传递是否正确
- 错误处理是否覆盖了所有失败路径
- 日志是否足够定位问题
- 性能是否满足要求(比如大文件上传时内存占用)
集成阶段最容易出现的问题是“接口对不上”,但因为前面已经定义了契约,这类问题会少很多。
6.5 第五步:上线前的检查清单
上线前我会过一遍这个清单:
| 检查项 | 检查内容 |
|---|---|
| 功能完整性 | 所有需求点是否都已实现 |
| 边界处理 | 空文件、超大文件、格式错误文件是否都有处理 |
| 错误提示 | 用户能否看懂错误信息 |
| 日志记录 | 关键操作是否有日志 |
| 性能表现 | 大文件上传和解析是否在可接受范围内 |
| 安全性 | 文件类型校验、大小限制、路径穿越防护 |
这个清单看起来简单,但每次过一遍都能发现几个遗漏的点。
7. 常见问题与排查技巧实录
在实际操作中,我遇到过不少典型问题,这里整理成速查表,方便大家参考。
7.1 AI 生成的代码跑不起来怎么办
这是最常见的问题。排查思路是:
- 看报错信息:Python 的报错信息通常很明确,直接看最后一行。
- 检查依赖:AI 可能用了你没安装的库,或者用了不同版本的 API。
- 检查上下文:AI 可能假设了一些不存在的变量或方法,检查它引用的东西是否真的存在。
- 简化问题:把代码拆成更小的片段,逐个运行,定位到具体哪一段出问题。
提示:如果 AI 生成的代码反复跑不起来,不要一直让它“修复”,而是把报错信息完整贴给它,并告诉它你的运行环境(Python 版本、已安装的库)。信息越完整,它修复的成功率越高。
7.2 AI 生成的代码逻辑不对怎么办
逻辑不对通常是因为需求描述不够清晰。我的做法是:
- 把需求拆成更细的步骤,逐步跟 AI 确认
- 提供具体的输入输出示例,让 AI 照着示例写
- 如果还是不对,自己先写伪代码,让 AI 把伪代码翻译成具体语言的代码
7.3 代码风格不一致怎么办
前面提过,在上下文里明确代码规范。如果已经生成了不一致的代码,可以让 AI 帮你统一格式化,或者用项目的 lint 工具自动修复。
7.4 性能不达标怎么办
AI 生成的代码往往不是性能最优的。如果性能不达标,先定位瓶颈在哪:是数据库查询慢、还是循环太多、还是内存占用高。定位到具体问题后,再针对性地让 AI 优化。
比如数据库查询慢,可能是没有加索引,或者查询了不必要的字段。你可以让 AI 帮你分析查询语句,给出优化建议。
7.5 常见问题速查表
| 问题现象 | 可能原因 | 解决思路 |
|---|---|---|
| 代码跑不起来 | 依赖缺失、API 版本不对 | 检查报错信息,确认环境 |
| 逻辑不符合预期 | 需求描述不清晰 | 补充输入输出示例,拆细需求 |
| 风格不一致 | 未指定代码规范 | 在上下文中加入规范说明 |
| 性能差 | 算法效率低、缺少索引 | 定位瓶颈,针对性优化 |
| 边界情况崩溃 | 未处理异常输入 | 补充边界测试用例 |
| 集成时对不上 | 接口契约未定义 | 提前定义数据模型和接口 |
8. 我个人的一些实操心得
最后分享几个我在实际项目中总结的小技巧,都是踩过坑之后才明白的。
第一,不要一次性让 AI 生成太多代码。我试过让 AI 一次性生成一个完整模块,结果代码量太大,它自己都顾此失彼,前面定义的变量后面忘了用。后来改成每次只生成一个函数或一个类,质量明显提升。
第二,把 AI 当成一个“很聪明但很健忘的同事”。它能力很强,但记不住你之前说过什么。所以每次交互都要把必要的上下文带上,不要指望它记得你上一轮说了什么。
第三,验证环节不要偷懒。我见过有人直接复制 AI 生成的代码到生产环境,结果出了事故。AI 生成的代码一定要经过测试,尤其是边界情况和异常路径。
第四,保持自己的判断力。AI 有时候会给出看起来合理但实际上有问题的方案。比如它可能推荐一个已经不维护的库,或者用一个有安全隐患的写法。你需要有能力判断这些方案是否靠谱。
第五,持续积累自己的“代码片段库”。跟 AI 协作久了,你会发现某些场景反复出现,比如参数校验、错误处理、日志记录。把这些常用逻辑整理成自己的代码片段库,下次直接复用,不用每次都让 AI 重新生成。
这些心得听起来简单,但真正做到需要刻意练习。AI 编程的效率提升是实实在在的,但前提是你得把基本功练扎实。Prompt 只是表面功夫,真正决定你上限的,还是那些传统的工程能力:拆解问题、管理上下文、验证结果、保持工程化思维。这些东西,AI 替代不了,也帮你省不了。