Skip to content

AI写代码:从需求到实现

学会让AI帮你写代码,是AI编程最核心的技能。本文将教你如何从需求描述开始,一步步引导AI生成高质量的代码。

为什么需要学习这个技能?

你可能会想:"不就是描述需求让AI写代码吗?"

实际上,怎么描述需求决定了代码的质量:

❌ 差的需求描述
"帮我写个登录功能"

✅ 好的需求描述
"用FastAPI写一个用户登录API:
- 接收用户名和密码
- 验证用户身份
- 返回JWT token
- 包含错误处理
- 添加类型提示"

好的描述能生成直接可用的代码,差的描述只能得到模糊的框架。

从需求到代码的完整流程

┌─────────────────────────────────────────────────────┐
│ Step 1: 梳理需求                                     │
│        把想法变成清晰的功能描述                       │
├─────────────────────────────────────────────────────┤
│ Step 2: 明确技术约束                                 │
│        语言、框架、库、代码规范                       │
├─────────────────────────────────────────────────────┤
│ Step 3: 描述给AI                                     │
│        用结构化的方式让AI理解需求                     │
├─────────────────────────────────────────────────────┤
│ Step 4: 审查AI输出                                   │
│        验证功能正确性、检查代码质量                   │
├─────────────────────────────────────────────────────┤
│ Step 5: 迭代优化                                     │
│        根据测试结果让AI改进代码                      │
└─────────────────────────────────────────────────────┘

Step 1:梳理需求

把模糊的想法变成具体的功能点

模糊的想法:
"我想做一个文件上传功能"

具体的功能点:
1. 用户可以上传文件(图片、PDF、Word文档)
2. 文件大小限制10MB
3. 支持拖拽上传和点击选择
4. 上传后显示预览
5. 上传成功返回文件URL
6. 失败时显示错误提示

明确输入输出

输入:
- 文件(multipart/form-data)
- 文件类型限制:jpg, png, pdf, doc, docx
- 文件大小限制:10MB

输出:
- 成功:{"url": "https://...", "filename": "xxx"}
- 失败:{"error": "错误原因"}

Step 2:明确技术约束

技术栈

后端:
- 语言:Python 3.11
- 框架:FastAPI
- 文件存储:本地存储或阿里云OSS

前端:
- 框架:React + TypeScript
- UI组件:Ant Design
- 请求库:axios

代码规范

- 使用类型提示
- 遵循PEP 8规范
- 函数必须有文档字符串
- 错误使用自定义异常

Step 3:描述给AI

使用结构化的提示词

请帮我用FastAPI实现一个文件上传API。

【功能需求】
1. 接收用户上传的文件
2. 验证文件类型(只允许jpg、png、pdf、doc、docx)
3. 验证文件大小(不超过10MB)
4. 保存文件到本地storage目录
5. 返回文件访问URL

【技术要求】
- Python 3.11 + FastAPI
- 使用类型提示
- 包含错误处理
- 包含文档字符串

【接口规范】
POST /api/upload
Content-Type: multipart/form-data

请求:
- file: 文件

响应(成功):
{
  "success": true,
  "url": "/files/xxx.pdf",
  "filename": "document.pdf",
  "size": 1024000
}

响应(失败):
{
  "success": false,
  "error": "文件类型不支持"
}

AI生成的代码

python
from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.responses import FileResponse
from pathlib import Path
import uuid
import os
from typing import Optional

app = FastAPI()

# 配置
UPLOAD_DIR = Path("storage")
UPLOAD_DIR.mkdir(exist_ok=True)
MAX_FILE_SIZE = 10 * 1024 * 1024  # 10MB
ALLOWED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".pdf", ".doc", ".docx"}


def validate_file(filename: str, file_size: int) -> Optional[str]:
    """验证文件是否符合要求
    
    Args:
        filename: 文件名
        file_size: 文件大小(字节)
        
    Returns:
        错误信息,如果验证通过则返回None
    """
    # 检查文件扩展名
    ext = Path(filename).suffix.lower()
    if ext not in ALLOWED_EXTENSIONS:
        return f"不支持的文件类型:{ext}"
    
    # 检查文件大小
    if file_size > MAX_FILE_SIZE:
        return f"文件大小超过限制(最大10MB)"
    
    return None


@app.post("/api/upload")
async def upload_file(file: UploadFile = File(...)):
    """文件上传接口
    
    Args:
        file: 上传的文件
        
    Returns:
        上传结果,包含文件URL
    """
    # 读取文件内容以获取大小
    content = await file.read()
    file_size = len(content)
    
    # 验证文件
    error = validate_file(file.filename, file_size)
    if error:
        raise HTTPException(status_code=400, detail=error)
    
    # 生成唯一文件名
    ext = Path(file.filename).suffix.lower()
    unique_filename = f"{uuid.uuid4()}{ext}"
    file_path = UPLOAD_DIR / unique_filename
    
    # 保存文件
    with open(file_path, "wb") as f:
        f.write(content)
    
    return {
        "success": True,
        "url": f"/files/{unique_filename}",
        "filename": file.filename,
        "size": file_size
    }


@app.get("/files/{filename}")
async def get_file(filename: str):
    """获取上传的文件"""
    file_path = UPLOAD_DIR / filename
    if not file_path.exists():
        raise HTTPException(status_code=404, detail="文件不存在")
    return FileResponse(file_path)

Step 4:审查AI输出

检查清单

[ ] 功能是否完整?
    - 文件上传 ✓
    - 类型验证 ✓
    - 大小验证 ✓
    - 文件保存 ✓
    - 返回URL ✓

[ ] 代码质量如何?
    - 类型提示 ✓
    - 文档字符串 ✓
    - 错误处理 ✓
    - 代码规范 ✓

[ ] 有没有安全隐患?
    - 文件名安全?需要改进(可能包含恶意路径)
    - 文件内容验证?缺失

[ ] 有没有性能问题?
    - 大文件处理?一次性读入内存,需要改进

发现的问题

  1. 文件名安全:没有对原始文件名进行安全处理
  2. 内存问题:大文件一次性读入内存
  3. 文件内容验证:没有验证文件实际类型(可能伪装扩展名)

Step 5:迭代优化

让AI改进代码

上面的代码有以下问题需要改进:

1. 文件名安全:原始文件名可能包含恶意路径,需要清洗
2. 内存问题:大文件应该流式写入,不要一次性读入内存
3. 文件类型验证:通过文件头验证真实类型,不只是检查扩展名

请改进代码解决这些问题。

AI改进后的代码

python
from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.responses import FileResponse
from pathlib import Path
import uuid
import os
import magic  # python-magic库,用于检测文件真实类型
from typing import Optional

app = FastAPI()

# 配置
UPLOAD_DIR = Path("storage")
UPLOAD_DIR.mkdir(exist_ok=True)
MAX_FILE_SIZE = 10 * 1024 * 1024  # 10MB
ALLOWED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".pdf", ".doc", ".docx"}
ALLOWED_MIME_TYPES = {
    "image/jpeg", "image/png", 
    "application/pdf",
    "application/msword", 
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
}
CHUNK_SIZE = 1024 * 1024  # 1MB chunks


def sanitize_filename(filename: str) -> str:
    """清洗文件名,移除危险字符
    
    Args:
        filename: 原始文件名
        
    Returns:
        安全的文件名
    """
    # 只保留文件名的最后部分(移除路径)
    filename = Path(filename).name
    # 移除危险字符
    safe_chars = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_")
    filename = "".join(c if c in safe_chars else "_" for c in filename)
    return filename


def validate_file_type(file_header: bytes) -> Optional[str]:
    """通过文件头验证真实文件类型
    
    Args:
        file_header: 文件头字节
        
    Returns:
        错误信息,如果验证通过则返回None
    """
    mime = magic.Magic(mime=True)
    detected_type = mime.from_buffer(file_header)
    
    if detected_type not in ALLOWED_MIME_TYPES:
        return f"不支持的文件类型:{detected_type}"
    
    return None


@app.post("/api/upload")
async def upload_file(file: UploadFile = File(...)):
    """文件上传接口(流式处理,支持大文件)
    
    Args:
        file: 上传的文件
        
    Returns:
        上传结果,包含文件URL
    """
    # 生成唯一文件名
    ext = Path(file.filename).suffix.lower()
    if ext not in ALLOWED_EXTENSIONS:
        raise HTTPException(status_code=400, detail=f"不支持的文件扩展名:{ext}")
    
    unique_filename = f"{uuid.uuid4()}{ext}"
    file_path = UPLOAD_DIR / unique_filename
    
    # 流式读取和写入
    total_size = 0
    first_chunk = True
    file_header = b""
    
    with open(file_path, "wb") as f:
        while chunk := await file.read(CHUNK_SIZE):
            # 保存第一个块用于类型检测
            if first_chunk:
                file_header = chunk[:1024]  # 前1KB足够检测类型
                error = validate_file_type(file_header)
                if error:
                    os.remove(file_path)  # 删除已写入的部分
                    raise HTTPException(status_code=400, detail=error)
                first_chunk = False
            
            # 检查文件大小
            total_size += len(chunk)
            if total_size > MAX_FILE_SIZE:
                os.remove(file_path)
                raise HTTPException(status_code=400, detail="文件大小超过限制(最大10MB)")
            
            f.write(chunk)
    
    return {
        "success": True,
        "url": f"/files/{unique_filename}",
        "filename": sanitize_filename(file.filename),
        "size": total_size
    }


@app.get("/files/{filename}")
async def get_file(filename: str):
    """获取上传的文件"""
    # 防止路径遍历攻击
    filename = Path(filename).name
    file_path = UPLOAD_DIR / filename
    
    if not file_path.exists():
        raise HTTPException(status_code=404, detail="文件不存在")
    
    return FileResponse(file_path)

代码生成的最佳实践

实践一:分层描述

不要一次性描述所有需求,分层描述更容易得到好的结果:

第1层:核心功能
"写一个文件上传API"

第2层:添加约束
"添加文件类型和大小限制"

第3层:添加安全措施
"防止恶意文件上传"

第4层:优化性能
"支持大文件流式处理"

实践二:提供示例

给出期望的输入输出示例:

【示例】
请求:
POST /api/upload
file: document.pdf (2MB)

响应:
{
  "success": true,
  "url": "/files/abc123.pdf",
  "filename": "document.pdf",
  "size": 2097152
}

实践三:说明边界情况

【边界情况处理】
1. 文件为空 → 返回错误"请选择文件"
2. 文件类型不支持 → 返回错误"不支持的文件类型"
3. 文件过大 → 返回错误"文件大小超过限制"
4. 上传失败 → 返回错误"上传失败,请重试"

小结

从需求到代码的核心要点:

步骤关键动作
梳理需求把模糊想法变成具体功能点
明确约束技术栈、代码规范、接口规范
描述给AI结构化、详细、有示例
审查输出功能完整性、代码质量、安全、性能
迭代优化针对问题逐个改进

黄金法则

不要期望AI一次就生成完美代码。把它当作一个可以快速迭代的助手,通过多轮对话逐步完善代码质量。

下一步

学会了让AI写代码后,让我们继续学习 AI代码审查与重构,让AI帮你提升代码质量。