09|实战:用提示词驱动代码生成与调试
凌晨两点,手机震动把你从睡梦中惊醒。监控系统发来告警:订单服务的支付回调接口返回500错误,每分钟影响数百笔交易。你打开笔记本电脑,面对的是一个同事三个月前写的模块——变量命名晦涩、没有注释、逻辑嵌套了五六层。这时候,你的AI助手可能是最好的”深夜搭档”。
一、代码生成的提示词设计原则
很多人让AI写代码时,像在餐厅对服务员说”给我来点吃的”——这样得到的结果自然不可控。写代码类的提示词,就像给施工队下发图纸,每一个关键参数都不能省略。
核心原则:让AI知道”用什么材料盖什么楼”。
一个高质量的代码生成提示词,通常需要包含以下要素:
┌───────────────────────────────────────────────┐
│ 编程语言与版本:Python 3.11 / TypeScript 5.x │
│ 框架与库:FastAPI / Express / Spring Boot │
│ 代码风格:函数式 / 面向对象 / RESTful │
│ 输入输出:函数签名、接口定义、数据结构 │
│ 质量要求:错误处理、日志记录、类型标注 │
│ 约束条件:性能要求、安全要求、兼容性要求 │
└───────────────────────────────────────────────┘
来看一组对比:
模糊的提示词:
帮我写一个用户注册的接口。
AI可能返回任何语言、任何框架的代码,甚至可能只给你一段伪代码。
精确的提示词:
用 Python 3.11 + FastAPI 框架编写一个用户注册的 API 端点。
技术要求:
- 路由:POST /api/v1/users/register
- 请求体:包含 username(字符串,3-20字符)、email(合法邮箱格式)、password(至少8位,包含大小写字母和数字)
- 使用 Pydantic v2 做参数校验
- 密码用 bcrypt 加密后存储
- 返回格式:{"code": 0, "message": "success", "data": {"user_id": "xxx"}}
- 包含完整的异常处理和日志记录
- 添加类型标注和文档字符串
两个提示词的差距,就像”画个房子”和”画一栋三层带阳台的江南风格民居”的区别。
二、实战案例1:从需求到可运行的REST API
假设你接到一个任务:为内部资产管理系统开发一个设备借用记录的查询接口。我们来看如何用提示词一步步把它做出来。
第一步:先让AI理解需求并给出方案。
我正在开发一个内部资产管理系统,使用 Python 3.11 + FastAPI + SQLAlchemy 2.0(异步模式)+ PostgreSQL。
现在需要实现一个设备借用记录的查询接口,需求如下:
1. 支持按借用人姓名、设备编号、借用日期范围进行筛选(所有条件均可选)
2. 支持分页查询,默认每页20条
3. 返回结果按借用时间倒序排列
4. 每条记录需要包含:记录ID、设备名称、设备编号、借用人、借用时间、预计归还时间、实际归还时间、状态
请先分析这个需求,列出你的技术方案,然后再写代码。
注意最后一句”请先分析需求再写代码”——这是代码类提示词中一个非常重要的技巧。它迫使AI先梳理思路,而不是直接生成可能考虑不周的代码。
AI可能会这样回应:
## 技术方案分析
1. **数据模型**:需要一个 DeviceLoan 表,包含设备信息、借用人信息和时间字段
2. **查询设计**:使用动态条件拼接,避免 N 个 if-else 判断
3. **分页实现**:采用 offset + limit 方案,返回总数以便前端计算页码
4. **接口设计**:GET /api/v1/device-loans?borrower=张三&page=1&size=20
## 代码实现
...
第二步:如果生成的代码不完整,追问补全。
代码整体不错。请补充以下内容:
1. 添加一个枚举类定义借用状态(借出中、已归还、逾期未还)
2. 为查询接口添加响应模型(Pydantic schema),不要直接返回 ORM 对象
3. 添加接口的 OpenAPI 文档描述(summary 和 description)
这种”先生成框架,再逐步补全”的工作模式,就像盖房子先搭骨架再砌墙,比一次性要求AI生成完美代码更可靠。
三、实战案例2:让AI当代码审查员
回到开头的深夜故障场景。你打开出问题的支付回调处理函数,发现代码是这样的:
⚠️ 反面教材:以下代码包含多个严重问题(SQL注入、缺少异常处理等),仅用于演示代码审查场景,切勿在实际项目中使用。
def handle_callback(data):
d = json.loads(data)
if d['status'] == 'success':
order = db.query(f"SELECT * FROM orders WHERE order_no='{d['order_no']}'")
if order:
db.execute(f"UPDATE orders SET status='paid' WHERE order_no='{d['order_no']}'")
db.execute(f"UPDATE orders SET paid_at='{d['paid_at']}' WHERE order_no='{d['order_no']}'")
send_notification(order['user_id'], 'Your payment is confirmed')
return {'code': 0}
else:
return {'code': -1}
else:
return {'code': -1}
这段代码”能跑”,但暗藏杀机。让我们用提示词请AI来做一次代码审查:
请以资深后端工程师的视角审查以下 Python 代码。这是一个支付回调处理函数,
目前线上报500错误。请从以下角度逐一分析:
1. 安全隐患
2. 异常处理缺陷
3. 数据一致性问题
4. 性能问题
5. 代码可维护性
对于每个发现的问题,请说明:
- 问题是什么
- 为什么这是个问题(可能导致什么后果)
- 建议如何修复
代码如下:
```python
def handle_callback(data):
d = json.loads(data)
...(完整代码)
AI的审查结果通常会非常全面:
## 审查结果
### 1. 安全隐患
**SQL注入漏洞(严重)**
- 问题:使用字符串拼接构造SQL查询,如 f"SELECT * FROM orders WHERE order_no='{d['order_no']}'"
- 后果:攻击者可以通过构造恶意的 order_no 值执行任意SQL,例如删库或窃取数据
- 修复:使用参数化查询或 ORM 的查询方法
### 2. 异常处理缺陷
**未捕获 JSON 解析异常**
- 问题:json.loads(data) 如果收到非法JSON会抛出 ValueError,导致500错误
- 后果:这很可能就是线上500错误的直接原因——如果支付平台偶尔发送格式异常的回调
- 修复:用 try-except 包裹,并记录异常日志
**未处理字典键不存在的情况**
- 问题:直接使用 d['status']、d['order_no'] 等,如果键不存在会抛出 KeyError
- 修复:使用 d.get('status') 或先做数据校验
### 3. 数据一致性问题
**两次 UPDATE 非原子操作**
- 问题:status 和 paid_at 的更新分两条SQL执行,如果第一条成功第二条失败,数据会处于不一致状态
- 修复:合并为一条UPDATE语句,或使用数据库事务
...
关键技巧:在提示词中明确审查维度。 如果你只说”帮我审查一下这段代码”,AI可能只关注最明显的问题。通过列出审查清单,你把AI变成了一个按照检查表逐项排查的专业审计员。
四、实战案例3:代码重构——拆解面条代码
下面是一段典型的”面条代码”——所有逻辑堆在一个函数里,嵌套层级深、职责混乱:
def process_monthly_report(dept_id, year, month):
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute(f"SELECT * FROM employees WHERE department_id={dept_id}")
employees = cursor.fetchall()
result = []
for emp in employees:
cursor.execute(f"SELECT * FROM attendance WHERE emp_id={emp['id']} AND year={year} AND month={month}")
records = cursor.fetchall()
late_count = 0
absence_count = 0
overtime_hours = 0
for r in records:
if r['check_in_time'] and r['check_in_time'] > '09:30':
late_count += 1
if r['status'] == 'absent':
absence_count += 1
if r['overtime']:
overtime_hours += r['overtime']
cursor.execute(f"SELECT * FROM salary WHERE emp_id={emp['id']} AND year={year} AND month={month}")
salary = cursor.fetchone()
if salary:
base = salary['base_salary']
deduction = late_count * 50 + absence_count * 200
bonus = overtime_hours * 80
final_salary = base - deduction + bonus
else:
final_salary = 0
result.append({'name': emp['name'], 'late': late_count, 'absence': absence_count, 'overtime': overtime_hours, 'salary': final_salary})
conn.close()
return result
用以下提示词请求重构:
请将下面这段 Python 函数重构为清晰、可维护的代码。要求:
1. 遵循单一职责原则:将数据查询、业务计算、结果组装拆分为独立函数
2. 消除 SQL 注入风险:使用参数化查询
3. 使用 dataclass 或 Pydantic 定义数据结构,替代裸字典
4. 添加类型标注
5. 用上下文管理器管理数据库连接
6. 保持原有的业务逻辑不变
请先说明你的重构思路,然后给出完整代码。
原始代码:
(粘贴上面的代码)
AI会把一个80行的巨型函数拆解成多个职责清晰的小函数,加上数据类定义和类型标注,代码可读性会有质的提升。
重构类提示词的要点:
- 明确告诉AI”保持业务逻辑不变”,否则AI可能在重构过程中”自作主张”修改业务规则
- 列出具体的重构原则,而不是笼统地说”重构一下”
- 要求AI先说明思路,这样你能在看代码之前就判断方向是否正确
五、实战案例4:自动生成单元测试
已有代码但没有测试,是技术债务中最常见的一种。手动补测试枯燥且容易遗漏边界情况。让AI来做这件事,效率和覆盖度都会大幅提升。
假设我们有以下函数需要编写测试:
from datetime import date
from typing import Optional
def calculate_membership_fee(
join_date: date,
membership_type: str,
referral_code: Optional[str] = None,
is_student: bool = False
) -> float:
"""计算会员年费。"""
base_fees = {"basic": 99.0, "standard": 199.0, "premium": 399.0}
if membership_type not in base_fees:
raise ValueError(f"未知的会员类型: {membership_type}")
fee = base_fees[membership_type]
# 学生享受六折优惠
if is_student:
fee *= 0.6
# 老会员(加入超过2年)享受八折优惠
days_since_join = (date.today() - join_date).days
if days_since_join > 730:
fee *= 0.8
# 推荐码减免30元
if referral_code and referral_code.startswith("REF-"):
fee = max(fee - 30, 0)
return round(fee, 2)
提示词这样写:
请为以下 Python 函数编写完整的单元测试。
要求:
1. 使用 pytest 框架
2. 测试用例需要覆盖以下场景:
- 正常路径:每种会员类型的基础费用计算
- 学生折扣
- 老会员折扣
- 推荐码减免
- 多种优惠叠加的情况
- 边界条件:刚好2年的会员、刚好超过2年的会员
- 异常路径:无效的会员类型
- 边界值:优惠后费用不低于0
3. 使用 @pytest.fixture 组织测试数据
4. 使用 @pytest.mark.parametrize 减少重复代码
5. 用 freezegun 或 mock 固定 date.today() 的返回值,确保测试不受运行日期影响
6. 每个测试方法的命名要清晰表达测试意图
被测函数如下:
(粘贴代码)
这个提示词的价值在于:你把一个资深工程师在写测试时会考虑的所有维度,都列成了清单交给AI。 AI很擅长按照清单逐项生成内容,它生成的测试会覆盖到手写测试时容易忽略的边界条件。
六、代码类提示词的特殊技巧
6.1 提供接口定义作为约束
当你需要AI生成的代码与已有系统对接时,把接口定义”喂”给它是最有效的约束手段:
请基于以下 TypeScript 接口定义,实现对应的数据校验中间件。
接口定义:
interface CreateProjectRequest {
name: string; // 1-50个字符
description?: string; // 可选,最多500字符
budget: number; // 正数,最多两位小数
start_date: string; // ISO 8601 格式
team_members: string[]; // 至少1人,最多20人
}
请用 zod 库实现校验逻辑,校验失败时返回具体哪个字段不合法。
接口定义就像建筑图纸上的尺寸标注——它不告诉施工队怎么建,但明确限定了最终成果必须满足的规格。
6.2 用注释引导生成方向
在代码中嵌入注释,让AI”填空”:
class OrderService:
def __init__(self, db_session, cache_client, notification_service):
self.db = db_session
self.cache = cache_client
self.notifier = notification_service
async def cancel_order(self, order_id: str, reason: str) -> bool:
# 1. 从数据库查询订单,如果不存在则抛出 OrderNotFoundError
# 2. 检查订单状态,只有"待支付"和"待发货"状态的订单可以取消
# 3. 更新订单状态为"已取消",记录取消原因和取消时间
# 4. 如果订单已支付,调用退款服务发起退款
# 5. 清除该订单的缓存
# 6. 发送取消通知给用户
# 7. 返回操作结果
pass
然后告诉AI:
请根据注释中的步骤说明,实现 cancel_order 方法的完整逻辑。
要求:每个步骤都要有异常处理,使用 async/await,
退款失败不应阻塞取消流程但需要记录日志以便后续处理。
这种方式的好处是:你掌控了代码的架构和流程,AI只负责填充实现细节。就像主厨定好菜谱和工序,让帮厨来切配。
6.3 要求AI先分析再编码
这个技巧在前面的实战案例中已经多次出现。它的核心价值在于:强制AI在写代码前完成”设计评审”,从而减少遗漏边界条件的概率。如果你只记住一条代码生成的提示词技巧,就记住这条。
七、调试场景:带着报错信息找AI排查
当线上或开发中遇到错误时,AI是一个极其高效的排查助手。关键在于给它足够的上下文:
我的 FastAPI 应用启动后,调用 /api/v1/tasks 接口时报以下错误:
错误信息:
sqlalchemy.exc.InvalidRequestError: Entity namespace for "Task" has no property "assignee_name"
相关代码:
# models.py
class Task(Base):
__tablename__ = "tasks"
id = Column(Integer, primary_key=True)
title = Column(String(200))
assignee_id = Column(Integer, ForeignKey("users.id"))
assignee = relationship("User", back_populates="tasks")
# schemas.py
class TaskResponse(BaseModel):
id: int
title: str
assignee_name: str
# routes.py
@router.get("/tasks")
async def list_tasks(db: AsyncSession = Depends(get_db)):
result = await db.execute(
select(Task).options(joinedload(Task.assignee_name))
)
return result.scalars().all()
环境:Python 3.11, FastAPI 0.109, SQLAlchemy 2.0(异步模式)
请分析错误原因并给出修复方案。
调试类提示词的三要素:
- 完整的错误信息:包括异常类型和完整的traceback
- 相关代码:不要只贴出错的那一行,要贴出前后相关的上下文
- 环境信息:语言版本、框架版本、操作系统等
这就像去医院看病——你不能只告诉医生”我肚子疼”,还得说清楚什么时候开始疼、吃了什么、疼的具体位置。信息越完整,诊断越准确。
八、代码提示词的质量保障
生成代码只是第一步,确保代码质量同样重要。以下是几个实用的质量保障策略:
策略1:要求AI解释关键决策
请在代码的关键位置用注释说明你的设计决策,特别是:
- 为什么选择这个数据结构
- 这段逻辑处理了什么边界情况
- 时间/空间复杂度是多少
策略2:要求添加防御性代码
请确保代码包含以下防御措施:
1. 所有外部输入都经过校验
2. 数据库操作使用事务
3. 网络请求设置超时时间
4. 关键操作记录日志
5. 敏感信息不出现在日志或错误消息中
策略3:让AI自检
请回顾你刚才生成的代码,检查以下几点:
1. 是否有资源未正确释放(数据库连接、文件句柄等)
2. 是否有并发安全问题
3. 是否有硬编码的配置值应该提取为常量或环境变量
4. 是否符合 PEP 8 规范
如有问题,请直接给出修正后的代码。
这个”自检”技巧非常有用。AI在第一次生成时可能会遗漏某些问题,但当你明确要求它回头检查时,它往往能找出自己的疏漏。
九、本章要点回顾
代码生成的提示词金字塔:
┌───────────┐
│ 质量保障 │ ← 让AI解释决策、自检、补全测试
├───────────┤
│ 约束条件 │ ← 接口定义、注释引导、先分析再编码
├───────────┤
│ 具体需求 │ ← 功能描述、输入输出、业务规则
├───────────┤
│ 技术栈 │ ← 语言、框架、版本、代码风格
└───────────┘
- 代码提示词必须明确技术栈:语言版本、框架、代码风格缺一不可
- 先分析后编码:让AI先理解需求再动手,效果远好于直接生成
- 审查清单法:通过明确的审查维度,让AI变成严格的代码审查员
- 填空式生成:用注释框定流程,让AI填充实现细节,你掌控架构
- 调试三要素:错误信息 + 相关代码 + 环境信息,信息越全诊断越准
- 自检闭环:让AI回头审视自己的输出,找出遗漏的问题
思考与实践
-
选择你日常工作中最近写过的一段代码(30行以上),构造一个提示词让AI对其进行代码审查。对比AI的审查结果和你自己的判断,看看有哪些发现是你没有想到的。
-
找一段你项目中没有测试的函数,用本章的方法让AI生成单元测试。跑一下这些测试,看看通过率如何,有没有测试本身就有bug的情况。
-
尝试用”注释引导法”让AI实现一个你正在开发的功能:先自己写好架构和注释,然后让AI填充实现。对比这种方式和直接让AI从零生成的效果差异。
购买课程解锁全部内容
告别答非所问:12 章掌握提示词工程
¥39.90