林子雨编著《AI编程与智能体开发》(访问教材官网)
4.3 AI编程实践
4.3.1 提示词正确使用案例
1.开发角色:猜数字游戏
## 角色
你是一位注重代码健壮性的 Python 开发者。
## 任务
编写一个猜数字游戏脚本。
## 约束
- 随机生成 1-100 的整数;
- 使用 `while` 循环持续猜测;
- **必须**处理非数字输入,禁止程序崩溃;
- 猜对后必须打印 `Bingo` 并退出。
## 参考
- 使用 `input()` 获取用户输入;
- 使用 `random.randint(1, 100)` 生成目标数字。
## 验收标准
- [ ] 输入非数字(如 'abc')时,提示"无效"并继续循环;
- [ ] 输入 50(假设答案是 50)时,打印 `Bingo`;
- [ ] 输入 60 时,提示 `Too big`。
2.安全角色:密码强度检测
## 角色
你是一位安全审计工程师。
## 任务
编写一个 Python 密码强度检测脚本。
## 约束
- 长度必须在 8 到 16 位之间;
- **必须**同时包含数字和字母;
- **必须**包含特殊字符 `!` 或 `@`;
- 满足所有条件打印 `Strong`,否则打印 `Weak`。
## 参考
- 使用 `str.isdigit()` 和 `str.isalpha()` 检测字符类型。
## 验收标准
- [ ] 输入 `abc123!x` -> 输出 `Strong`;
- [ ] 输入 `abcdefg` -> 输出 `Weak`(缺数字和特殊符);
- [ ] 输入 `12345678` -> 输出 `Weak`(缺字母和特殊符)。
3.运维角色:端口存活检测
## 角色
你是一位初级运维开发工程师。
## 任务
编写检测 `localhost:80` 端口存活的脚本。
## 约束
- 超时设置为 1 秒;
- 如果连接失败,**必须**重试 2 次;
- 最终成功打印 `UP`,失败打印 `DOWN`;
- 使用 `socket` 库。
## 参考
- 使用 `socket.settimeout(1)` 设置超时;
- 使用 `socket.connect_ex()` 检测端口。
## 验收标准
- [ ] 端口存活时,输出 `UP`;
- [ ] 端口关闭时,经历 3 次尝试后输出 `DOWN`;
- [ ] 脚本不能在第一次失败后直接退出。
4.3.2 提示词使用中的常见问题
1.问题一:需求不明确
## 角色
你是一位有 5 年经验的 Python 后端工程师,熟悉 FastAPI + SQLAlchemy 2.0。
## 任务
实现 `POST /api/v1/users/register` 用户注册接口。
## 约束
- 密码必须哈希存储(使用bcrypt);
- 不得修改User数据模型;
- 所有新增代码包含完整类型注解。
## 参考
参照项目中现有的接口规范:
- 路径格式:`/api/v1/{resource}`
- 成功响应:HTTP 201 + `{"user_id": int, "username": str}`
- 错误响应:HTTP 4xx + `{"detail": "ERROR_CODE"}`
## 验收标准
- [ ] 注册成功 → HTTP 201
- [ ] 邮箱重复 → HTTP 400
- [ ] 密码哈希验证
2.问题二:上下文缺失
## 任务
修复 `src/repositories/order_repo.py` 中 `get_orders_with_items` 函数的 N+1 查询问题。
## 约束
- 函数签名(`user_id: int` -> `list[Order]`)不得改变;
- 仅使用 SQLAlchemy 内置的 `selectinload`,不引入新依赖;
- 保持异步模式。
## 问题代码(已诊断)
def get_orders_with_items(user_id: int) -> list[Order]:
orders = session.execute(select(Order).where(Order.user_id == user_id)).scalars().all()
for order in orders:
_ = order.items # ← N+1问题:每个订单触发一次额外查询
return orders
## 验收标准
- **性能目标**:200 个订单的查询次数 ≤ 3 次;
- **功能不变**:返回内容与修改前完全一致;
- **边界**:`user_id=99999`(无订单)时返回 `[]`,不抛异常。
3.问题三:异常处理不完善
## 任务
重写 `send_batch_sms` Celery 任务,实现并发安全的批量短信发送,
支持幂等性保证、重试机制和限流控制。
## 约束
- 不得引入新的第三方依赖(`tenacity` 和 `requests` 已在 requirements.txt);
- 幂等性:发送前必须检查 `msg.status == "SENT"`,避免重复发送。
## 问题代码(仅处理常规路径,存在多处隐患)
@celery.task
def send_batch_sms():
msgs = Session().query(SmsMessage).filter_by(status="PENDING").limit(100).all()
for msg in msgs:
requests.post("https://sms-api.example.com/send", json={...})
msg.status = "SENT"
Session().commit()
## 验收标准(以下每条对应一个生产事故风险)
- [ ] **C1:并发安全**——`with_for_update(skip_locked=True)`
- [ ] **C2:幂等性**——发送前检查 `status == "SENT"`
- [ ] **C3:重试**——HTTP 5xx 重试 3 次,HTTP 4xx 直接标记 FAILED
- [ ] **C4:限流**——循环中加入 `time.sleep(0.02)`,确保 ≤ 50 QPS
- [ ] **C5:最终失败**——3 次重试后状态 = `FAILED`,记录 `error_message`
4.问题四:需求描述不完整
## 任务
实现一套完整的JWT认证中间件,包含Token验证、Token刷新和Token黑名单功能。
一次性实现以下5个功能:
1. Token验证中间件(从Bearer Token提取并验证JWT)
2. 过期处理(捕获 ExpiredSignatureError)
3. 无效处理(捕获 JWTError)
4. 刷新 Token 接口(POST /api/v1/auth/refresh)
5. Token 黑名单 / 注销接口(POST /api/v1/auth/logout)
## 约束
- JWT 算法固定为 **HS256**,禁止支持多种算法;
- **绝对禁止**硬编码密钥(从环境变量 `JWT_SECRET` 读取);
- Redis 操作必须使用已有的 `redis_client`;
- 中间件不得阻塞白名单路径;
- 错误响应格式:`{"code": "ERROR_CODE", "message": "描述"}`。
## 验收标准
- [ ] 有效 Token → HTTP 200
- [ ] 过期 Token → HTTP 401,`code == "token_expired"`
- [ ] 格式错误 Token → HTTP 401,`code == "invalid_token"`
- [ ] 有效 refresh_token → 返回新 access_token 和 refresh_token
- [ ] 已加入黑名单的 refresh_token → HTTP 401
- [ ] logout 后旧 Token → HTTP 401
4.4与AI编程工具协作
4.4.1写给AI的项目说明书
下面是一个完整的AGENTS.md示例:
# 极客书城 API 服务(GeekBooks Backend)
## 项目简介
本项目是"极客书城"在线书店的后端 API 服务,负责用户管理、图书目录、
订单处理和支付集成。服务以 REST API 形式对外提供,供 Web 前端和移动端消费。
## 技术栈
- **语言**:Python 3.12
- **框架**:FastAPI 0.115
- **ORM**:SQLAlchemy 2.0(异步模式,使用 asyncpg 驱动)
- **数据库**:PostgreSQL 15(主库)+ Redis 7(缓存 / 消息队列)
- **任务队列**:Celery 5.3 + Redis(Broker)
- **测试**:pytest + pytest-asyncio + httpx(AsyncClient)
- **代码质量**:Ruff(lint + format)+ mypy(类型检查)
## 目录结构
src/
├── api/ # 路由层:仅做请求参数校验和响应组装,不含业务逻辑
├── services/ # 业务逻辑层:所有业务规则在此实现
├── repositories/ # 数据访问层:封装所有数据库和缓存操作
├── models/ # SQLAlchemy 数据模型(只定义结构,不含逻辑)
├── schemas/ # Pydantic 输入/输出模型(请求体/响应体)
├── core/ # 全局配置、异常定义、依赖注入、中间件
└── tasks/ # Celery 异步任务
## 架构约定(AI 必须遵守)
- 严格遵循三层架构:api → service → repository;
- API 层不得直接访问数据库(禁止在 api/ 目录下 import Session);
- 数据库操作必须封装在 repository 层;
- 所有业务异常继承自 `AppException`;
- ...(其他架构约束)
## 编码规范
- 所有公共函数和类方法必须有中文 docstring;
- 使用 Python 3.12 的类型注解语法;
- 函数长度不超过 50 行;
- 金额字段使用 Decimal 类型,禁止 float;
- ...(其他编码规范)
## 常用命令
- 启动开发服务器:`uvicorn src.main:app --reload --port 8000`
- 运行全部测试:`pytest tests/ -v --asyncio-mode=auto`
- 代码检查和格式化:`ruff check src/ && ruff format src/`
4.4.2限制AI行为的编码规则
下面是一个完整的项目规则文件示例:
---
alwaysApply: true
---
# Python 编码规范(极客书城项目)
## 命名规范
- 变量名和函数名:snake_case(如 `get_user_by_id`);
- 类名:PascalCase(如 `UserService`);
- 常量:UPPER_SNAKE_CASE(如 `MAX_RETRY_COUNT`);
- 私有方法/属性:前缀下划线(如 `_validate_password`)。
## 类型注解
- 所有函数参数和返回值必须有类型注解;
- 使用 Python 3.12 内置泛型语法(`list[str]`、`dict[str, int]`);
- Optional 类型写成 `str | None`,不使用 `Optional[str]`。
## 错误处理
- 禁止裸 `except:` 或 `except Exception:`;
- 必须捕获具体异常类型;
- 业务错误使用自定义异常(继承 AppException)。
## 安全规范
- 禁止字符串拼接构造 SQL;
- 禁止在代码中硬编码密码、API Key 等敏感信息;
- 用户输入必须经过 Pydantic 校验。
...(其他规则)
4.5 AI维护存量项目
4.5.3存量项目维护的四大实践
(1)架构决策记录(ADR)
## 重要架构决策
**为什么订单模块不使用软删除?**
订单数据有财务合规要求,必须保留完整历史,不能物理删除。
→ AI 必须理解:任何涉及订单删除的功能,都必须是软删除或状态标记。
**为什么用户模块有 user_id 和 uuid 两个标识符?**
- user_id:内部使用,int 类型,自增,供数据库 join 使用;
- uuid:对外暴露,string 类型,用于 API 响应和前端交互,防止 ID 枚举攻击。
→ AI 必须理解:不能随意替换这两个字段。
(2)关键模块的职责说明
## 关键模块职责
**UserService(src/services/user_service.py)**
- 负责:用户注册、登录、权限校验、资料修改
- 不负责:订单处理(属于 OrderService)、消息推送(属于 NotificationService)
→ AI 必须理解:不能在 UserService 中直接操作订单数据
(3)技术债说明
## 已知技术债
- [ ] 旧版支付模块(src/payment_v1/)使用同步调用,已计划迁移到 payment_v2
→ 新功能禁止在 payment_v1 上继续开发
- [ ] 缓存层目前使用 Redis 字符串,建议迁移到 Hash 结构(已在 backlog 中)
→ AI 生成缓存代码时,可以参考现有模式,但不需要改进架构
(4)代码审查要点
## Code Review 关注点
**订单模块**
- 必须保留审计日志(谁、什么时候、做了什么修改)
- 金额计算必须使用 Decimal,禁止 float
**用户模块**
- 敏感字段(密码、手机号)不得出现在日志中
2.实践二:保持环境健康
3.实践三:补充代码规范
---
alwaysApply: true
---
# 项目编码规范
## 命名规范(已通过代码审查确认)
- 函数名:snake_case(如 `get_user_by_id`)
- 类名:PascalCase(如 `UserService`)
- 常量:UPPER_SNAKE_CASE(如 `MAX_RETRY_COUNT`)
## 错误处理规范
- 业务错误使用自定义异常(继承 AppException)
- 禁止使用 `raise HTTPException`(在 API 层统一处理)
- 捕获异常后必须记录日志
## 文档规范
- 所有公共函数必须有中文 docstring
- docstring 格式:功能描述 + 参数说明 + 返回值说明
4.实践四:参考现有代码
## 任务
参照以下"用户管理"模块的实现,为"商品管理"创建类似的功能。
## 约束
- 严格遵照参照代码的结构、命名风格和错误处理模式
- 不要引入参照代码中没有的设计模式
## 参照代码
[粘贴 user_service.py 的完整代码]
## 差异说明
1. Product 没有密码字段,去掉所有密码相关逻辑
2. Product 需要额外的库存扣减方法
3. Product 的删除是软删除
4.6故障诊断与修复
4.6.2AI编程的可观测性
OpenTelemetry (简称OTel)是目前最主流的可观测性标准(由CNCF维护),提供统一SDK,支持自动埋点,与Python、Java、Go等主流语言均有良好集成。在提示词中可以直接要求AI集成OTel,具体如下:
## 约束
使用 OpenTelemetry SDK(opentelemetry-sdk + opentelemetry-instrumentation-fastapi)
为服务添加链路追踪:
- 自动捕获所有 FastAPI 路由的 HTTP Span;
- 手动为 create_order 函数添加 custom Span,包含 user_id 和 order_id 属性;
- 通过 OTLP 协议将 Trace 数据导出到 localhost:4317(Jaeger 采集端口)。
4.6.3防御性编程
可以将防御性编程写入规则当中,实例如下:
---
alwaysApply: true
---
## 防御性编程规范
- 所有接受外部输入的函数必须在函数体开头对输入进行有效性校验;
- 禁止 except Exception: 或裸 except:,必须捕获具体异常类型;
- 调用第三方 HTTP 服务必须设置 timeout(httpx 推荐 timeout=10.0);
- 所有外部 IO 操作必须使用上下文管理器;
- 涉及数值边界或唯一性保证的写操作,使用数据库约束或行级锁。
4.7综合案例:待办事项应用
4.7.3第一步:项目初始化
在TRAE中新建一个项目ToDoApp,在空目录下创建AGENTS.md,填入如下内容:
# TodoApp - 待办事项管理应用
## 项目简介
学习用的待办事项管理应用,包含 FastAPI 后端和原生 HTML 前端。
数据存储在内存中(Python list),适合快速原型验证。
## 技术栈
- Python 3.12 + FastAPI + Pydantic v2
- 原生 HTML/CSS/JavaScript(无框架依赖)
- 数据存储:内存中的 Python list
## 项目结构
- main.py:FastAPI 应用入口,包含内存存储和所有 API 路由
- schemas.py:Pydantic 数据模型
- templates/index.html:前端单页应用
## 架构约定
- 后端只负责 API 响应,不含 HTML 渲染逻辑
- 前端通过 fetch 调用后端 API
- 内存存储使用全局 list,id 自增使用 itertools.count
## 常用命令
- 安装依赖:pip install fastapi uvicorn pydantic
- 启动服务:uvicorn main:app --reload
- 访问前端:http://localhost:8000/
创建.trae/rules目录,并在该目录下创建一个名为todo-style.md的Rules文件,填入如下内容:
---
alwaysApply: true
---
# TodoApp 编码规范
## API 响应规范
- 创建成功:HTTP 201;更新成功:HTTP 200;
- 资源不存在:HTTP 404,body 格式 {"detail": "Todo not found"}
## 数据模型
- Todo 使用 Pydantic 模型
- id 为 int,自增生成
- created_at 使用 datetime.now(timezone.utc)
## 前端规范
- 使用原生 JavaScript,不引入任何前端框架
- 所有 API 调用使用 fetch API
4.7.4第二步:后端API开发
将以下提示词输入TRAE的Agent模式,然后TRAE将会根据提示生成main.py和schemas.py文件,这两个文件不用用户写一行代码,全部由AI生成:
## 任务
实现 TodoApp 的后端 API,包含新增、查询和标记完成三个接口。
## 技术栈
- Python 3.12 + FastAPI + Pydantic v2
- 数据存储在内存中(Python list),id 使用 itertools.count 自增
## 文件结构
1. `schemas.py`:定义 TodoCreate 和 TodoResponse 两个 Pydantic 模型
- TodoCreate:title(str,必填)
- TodoResponse:id(int)、title(str)、is_completed(bool)、created_at(datetime)
2. `main.py`:FastAPI 应用入口,包含以下路由
## 接口清单
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /todos | 获取所有待办,返回 {"todos": [...]} |
| POST | /todos | 新增待办,请求体 {"title": "xxx"},返回 HTTP 201 |
| PUT | /todos/{id} | 更新待办,请求体 {"is_completed": true},返回更新后的对象 |
## 约束
- 资源不存在时返回 HTTP 404,body 格式 {"detail": "Todo not found"}
- created_at 使用 datetime.now(timezone.utc)
- main.py 需挂载 templates 目录,根路径 "/" 返回 index.html
## 验收标准
- [ ] POST /todos 创建成功 → HTTP 201,返回完整 Todo 对象
- [ ] GET /todos → 返回所有待办列表
- [ ] PUT /todos/{id} 更新 is_completed → 返回更新后的对象
- [ ] PUT /todos/999(不存在)→ HTTP 404
4.7.5第三步:前端页面开发
将以下提示词输入TRAE的Agent模式,同样,不需要用户创建任何文件,编写任何代码,AI将会自动实现前端的功能:
## 任务
创建 templates/index.html,为 TodoApp 提供可视化界面。
## 技术栈
- 原生 HTML + CSS + JavaScript(单文件实现,无框架依赖)
- API 调用使用原生 fetch
## 页面结构
1. **标题**:顶部显示"待办事项管理"
2. **添加区域**:一个文本输入框 + "添加"按钮
3. **待办列表**:逐条显示所有待办事项,每条包含:
- 标题文字
- 完成复选框(点击后切换完成状态)
- 已完成项显示删除线样式
## API 调用说明
| 操作 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取列表 | GET | /todos | 页面加载时调用 |
| 新增 | POST | /todos | body: {"title": "xxx"} |
| 切换状态 | PUT | /todos/{id} | body: {"is_completed": true/false} |
## 响应格式
// GET /todos响应
{"todos": [{"id": 1, "title": "完成任务", "is_completed": false, "created_at": "2025-01-15T10:30:00"}]}
// POST /todos响应
{"id": 1, "title": "完成任务", "is_completed": false, "created_at": "2025-01-15T10:30:00"}
// 错误响应
{"detail": "Todo not found"}
## CSS 样式要求
- 整体浅色系,白色背景,灰色边框
- 主色调:浅蓝色(#4A90D9),仅用于按钮和标题
- 已完成项:浅灰色文字 + 删除线
- 布局:居中显示,最大宽度 600px
- 字体:无衬线字体(sans-serif)
## JavaScript 功能要求
1. 页面加载时调用 GET /todos 获取列表并渲染
2. 点击"添加"按钮,调用 POST /todos,成功后刷新列表
3. 点击复选框,调用 PUT /todos/{id} 切换完成状态,成功后刷新列表
4. 所有操作失败时在控制台输出错误信息
## 验收标准
- [ ] 页面加载后显示待办列表
- [ ] 输入标题并点击添加,新待办出现在列表中
- [ ] 点击复选框,待办完成状态切换,文字样式变化
4.7.6第四步:运行应用
后端和前端开发完成后,按以下步骤启动应用:
(1)安装依赖,具体命令如下:
pip install fastapi uvicorn pydantic
(2)启动服务,具体命令如下:
cd todoapp
uvicorn main:app --reload
(3)访问应用,打开浏览器访问http://localhost:8000/,即可看到TodoApp界面。
