大模型项目:邮件发送与验证码验证功能实现
邮件发送与验证码验证功能实现
今天的课程将前面所学的 FastAPI 知识串联,实现一个完整的邮件发送 + 验证码验证功能。涉及:环境统一管理、pymysql 数据库操作、Redis 缓存集成、SMTP 邮件发送,以及 MVC 分层架构的完整实践。
一、功能概述
1. 业务流程
用户输入邮箱号 → 点击发送按钮
│
▼
① 服务器接收请求(Controller)
│
▼
② 验证邮箱是否注册(Dao → MySQL)
│
├── 未注册 → 返回"邮箱号不存在"
│
└── 已注册 → ③ 生成 4 位验证码
│
▼
④ 发送邮件(SMTP)
│
▼
⑤ 验证码存入 Redis(60 秒过期)
│
▼
⑥ 用户输入验证码 → 点击验证
│
▼
⑦ 服务器比对验证码(Service → Redis)
│
├── 一致 → 验证成功,删除 Redis 中的验证码
│
└── 不一致/过期 → 验证失败
2. 涉及技术栈
| 技术 | 用途 | 对应的 Python 库 |
|---|---|---|
| FastAPI | Web 服务器框架 | fastapi + uvicorn |
| MySQL | 用户数据持久化(存储用户信息) | pymysql |
| Redis | 验证码缓存(带过期时间) | redis |
| SMTP | 发送邮件 | smtplib + email |
| python-dotenv | 环境变量管理 | python-dotenv |
二、环境统一管理 — .env 文件
1. 为什么需要 .env?
项目中涉及大量配置信息(数据库连接、邮箱授权码、Redis 地址等),直接写在代码中会导致:
- 安全风险:API Key、密码等敏感信息暴露在代码中,Git 提交后难以收回
- 修改困难:换一台机器部署要改多处代码
- 环境隔离:开发/测试/生产环境无法使用不同的配置
解决方案:将配置信息统一写入 .env 文件,代码中通过 os.getenv() 读取。
2. .env 文件示例
在项目根目录下创建 .env 文件:
# 发件方邮箱号
SENDER_EMAIL="xxx@qq.com"
# 邮箱授权码(非登录密码)
SENDER_EMAIL_PASSWORD="xxxxx"
# QQ 邮箱 SMTP 服务器地址
SMTP_HOST="smtp.qq.com"
# SMTP 端口号(TLS:587 / SSL:465)
SMTP_PORT="587"
# MySQL 连接信息
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
MYSQL_USER="root"
MYSQL_PASSWORD="xxxx"
MYSQL_DATABASE="xiangmu_one"
MYSQL_CHARSET="utf8mb4"
# Redis 连接信息
REDIS_HOST="localhost"
REDIS_PORT="6379"
REDIS_PASSWORD=""
REDIS_DB="0"
关键点:
.env文件使用key=value格式,key 通常全大写(常量命名规范)- 邮箱授权码(
SENDER_EMAIL_PASSWORD)不是 QQ 邮箱的登录密码,需要在 QQ 邮箱设置中生成 - **
.env 文件不要提交到 Git**,务必在.gitignore中添加.env`
3. 读取 .env 配置
from dotenv import load_dotenv
import os
# 加载 .env 文件(默认在当前目录查找)
load_dotenv()
# 读取环境变量
sender = os.getenv("SENDER_EMAIL")
sender_pwd = os.getenv("SENDER_EMAIL_PASSWORD")
关键点:
load_dotenv()将.env中的键值对加载到os.environ中os.getenv(key)从环境变量中读取值,不存在返回None- 可以在所有需要配置的模块中分别调用
load_dotenv()
三、pymysql 操作数据库
1. pymysql 查询 — 无参数
import pymysql
# 建立连接
conn = pymysql.connect(
host="localhost",
port=3306,
user="root",
password="root",
database="xiangmu_one",
charset="utf8mb4",
# 以字典形式返回查询结果
cursorclass=pymysql.cursors.DictCursor,
)
# 获取游标对象
cur = conn.cursor()
# 编写 SQL 语句
sql = "SELECT * FROM users;"
# 执行 SQL
cur.execute(sql)
# 获取查询结果
results = cur.fetchall()
print(results)
# 关闭连接
cur.close()
conn.close()
2. pymysql 查询 — 带参数
涉及变量时,使用 %s 作为占位符,执行时传值替换:
# 编写 SQL 语句,用 %s 占位
sql = "SELECT * FROM users WHERE email=%s;"
# 执行 SQL,值放在列表中按顺序替换 %s
cur.execute(sql, ["12345678@qq.com"])
# 获取结果
results = cur.fetchall()
关键点:
- 使用
%s占位符避免 SQL 注入风险 - 传参时必须把值放在列表或元组中:
cur.execute(sql, [value]) cursorclass=pymysql.cursors.DictCursor让查询结果以字典格式返回,便于通过字段名取值fetchall()返回列表,列表中每个元素是一行数据
3. 封装 MySQL 工具类
将数据库连接和关闭操作封装到 common/MySQLUtil.py,避免每个模块重复写连接代码:
# common/MySQLUtil.py
import pymysql
import os
from dotenv import load_dotenv
# 加载.env文件中的数据
load_dotenv()
# 获取连接
def get_mysql_conn():
return pymysql.connect(
# IP地址
host=os.getenv("MYSQL_HOST"),
# 端口号
port=int(os.getenv("MYSQL_PORT")),
# 数据库账户
user=os.getenv("MYSQL_USER"),
# 数据库账户对应的密码
password=os.getenv("MYSQL_PASSWORD"),
# 数据库名称
database=os.getenv("MYSQL_DATABASE"),
# 字符集
charset=os.getenv("MYSQL_CHARSET"),
# 以 dict 的方式返回查询结果
cursorclass=pymysql.cursors.DictCursor,
)
# 关闭连接
def close_mysql_conn(cursor, conn):
cursor.close()
conn.close()
关键点:
- 配置文件读取通过
.env集中管理,get_mysql_conn()自动读取 - 连接信息可以随时修改
.env文件,无需改动代码 - 工具函数放在
common包下,供所有模块共享 - 关闭的顺序一定是先开后关,后开先关
四、Redis 集成 — 验证码存储
验证码需要设置过期时间(60 秒),传统数据库不适合这种"自动过期"场景,Redis 的 EX 参数天然支持。
1. 封装 Redis 工具类
# common/RedisUtil.py
import os
from dotenv import load_dotenv
import redis
load_dotenv()
# 获取连接
def get_redis_conn():
return redis.Redis(
host=os.getenv("REDIS_HOST"),
port=int(os.getenv("REDIS_PORT")),
password=os.getenv("REDIS_PASSWORD"),
db=int(os.getenv("REDIS_DB")),
# 如果redis无法存入数据,添加下面的配置protocol=2 3 中的一个,应该是2
protocol=2,
)
# 关闭连接
def close_redis_conn(conn):
conn.close()
2. Redis 操作说明
# 获取连接
r = RedisUtil.get_redis_conn()
# redis存入数据通过key,value格式 --- 取值通过key
# 存入数据,60 秒后自动过期
r.set(email, code, ex=60)
# 读取数据(返回 bytes 类型)
stored_code = r.get(email)
# 删除数据
r.delete(email)
# 关闭连接
RedisUtil.close_redis_conn(r)
关键点:
r.set(key, value, ex=60):存储 key-value 并设置 60 秒过期时间,到期自动删除r.get(key):根据 key 获取 value,不存在返回None,存在返回 bytes 类型,需要.decode("utf-8")转字符串r.delete(key):手动删除 key(验证成功后清理验证码,实现一次性使用)- Redis 天然支持过期机制,非常适合验证码、Session、限流等场景
五、数据库层 — UsersDao
Dao(Data Access Object)层只负责操作数据库,不做逻辑处理。
# users/dao/UsersDao.py
from common import MySQLUtil
# 验证邮箱是否存在
def check_email(email):
# 获取连接
conn = MySQLUtil.get_mysql_conn()
# 获取游标对象
cur = conn.cursor()
# 编写SQL语句
sql = "SELECT * FROM users WHERE email=%s;"
# 执行SQL语句
cur.execute(sql, [email])
# 获取查询结果
results = cur.fetchall()
# 关闭连接
MySQLUtil.close_mysql_conn(cur, conn)
# 返回结果
return results
关键点:
- Dao 层方法职责单一:只做数据库的增删改查,不做业务判断
check_email直接返回查询结果(原始数据),由上层(Service)决定如何使用fetchall()返回的是列表,若查到数据则列表有元素,否则为空列表
六、业务层 — UsersService
Service 层实现具体的业务逻辑,是项目的核心——调用 Dao 获取数据、处理判断、协调多个组件。
1. 发送邮件功能
# users/service/UsersService.py
import random
from email.mime.text import MIMEText
import smtplib
import os
from dotenv import load_dotenv
from users.dao import UsersDao
from common import RedisUtil
load_dotenv()
def send_email(email):
"""
发送验证码邮件
流程:验证邮箱 → 生成验证码 → 发送邮件 → 存入 Redis
"""
# 1、验证邮箱号是否属于注册过的用户
flag = False
results = UsersDao.check_email(email)
# fetchall() 总是返回 list,需要判断 list 是否有数据
if results and len(results) > 0:
flag = True
# 2、根据结果判定是否需要发邮件
if not flag:
# 不发邮件
return {
"code": 500,
"msg": "邮箱号不存在",
"data": None,
}
# 发邮件
# 随机生成4位数验证码
code = ""
for i in range(4):
# 随机生成一个0-9的数字
code += str(int(random.random() * 10))
# 配置发送信息
sender = os.getenv("SENDER_EMAIL") # 发送方
sender_pwd = os.getenv("SENDER_EMAIL_PASSWORD") # 发送方授权码
subject = "你的验证码来咯~~~" # 邮件主题
content = f"你的验证码为:{code}, 过期时间为:60s"
# 创建邮件对象 --- 写发送邮件的信息在这个对象里面
message = MIMEText(content, "plain", "utf-8")
# 添加内容在message中
message["From"] = sender
message["To"] = email
message["Subject"] = subject
# 发送邮件
try:
# 构建发送邮件的对象
smtp = smtplib.SMTP(
host=os.getenv("SMTP_HOST"),
port=int(os.getenv("SMTP_PORT")),
)
# smtp.set_debuglevel(1) # ← 开启调试,打印完整的 SMTP 对话
# 开启邮件发送服务 TLS
smtp.starttls()
# 验证发送方和发送方的授权码是否能对上
smtp.login(sender, sender_pwd)
# 发送邮件 -- sendmail 发送邮件的方法:发送方,接收方,邮件对象
smtp.sendmail(sender, email, message.as_string())
# 发送成功后退出
smtp.quit()
# 把验证码存入到redis中
r = RedisUtil.get_redis_conn()
# redis存入数据通过key,value格式 --- 取值通过key
r.set(email, code, ex=60) # 60秒后过期,key:email value:code
# 关闭连接
RedisUtil.close_redis_conn(r)
return {
"code": 200,
"msg": "发送成功",
"data": None,
}
except Exception as e:
print(f"邮件发送失败:{e}")
return {
"code": 500,
"msg": "发送失败",
"data": None,
}
关键点:
MIMEText(content, "plain", "utf-8"):创建纯文本邮件对象smtplib.SMTP(host, port):连接到邮箱的 SMTP 服务器smtp.starttls():开启 TLS 加密传输(端口 587),确保通信安全smtp.login(sender, sender_pwd):使用邮箱号和授权码登录 SMTP 服务器smtp.sendmail(sender, email, message.as_string()):发送邮件- 授权码 ≠ 登录密码,需要在 QQ 邮箱 → 设置 → 账户 → 生成授权码
- 发送成功后验证码存入 Redis,key 为邮箱号,value 为验证码,60 秒自动过期
2. 发送邮件完整流程图
send_email(email)
│
├── UsersDao.check_email(email)
│ │
│ └── MySQL:SELECT * FROM users WHERE email=?
│ │
│ ├── 无记录 → return {"code": 500, "msg": "邮箱号不存在"}
│ │
│ └── 有记录 → 继续执行
│
├── 生成 4 位验证码(random)
│
├── 构建邮件对象(MIMEText)
│ │
│ └── smtplib.SMTP → starttls → login → sendmail → quit
│
└── Redis 存储验证码
│
└── r.set(email, code, ex=60)
3. 验证码验证功能
def verify_email(email, code):
"""
验证用户输入的验证码是否正确
:param email: 用户邮箱号
:param code: 用户输入的验证码
:return: {"code": 状态码, "msg": 提示信息, "data": None}
"""
# 1、从 Redis 中获取该邮箱对应的验证码
r = RedisUtil.get_redis_conn()
stored_code = r.get(email)
# 2、判定验证码是否存在
if stored_code is None:
# 验证码不存在(已过期或未发送)
RedisUtil.close_redis_conn(r)
return {
"code": 500,
"msg": "验证码已过期或未发送,请重新获取",
"data": None,
}
# Redis 返回的是 bytes,需要解码为字符串
stored_code = stored_code.decode("utf-8") if isinstance(stored_code, bytes) else stored_code
# 3、比对验证码
if stored_code == code:
# 验证成功,删除 Redis 中的验证码(一次性使用)
r.delete(email)
RedisUtil.close_redis_conn(r)
return {
"code": 200,
"msg": "验证成功",
"data": None,
}
else:
RedisUtil.close_redis_conn(r)
return {
"code": 500,
"msg": "验证码错误,请重新输入",
"data": None,
}
关键点:
r.get(email)返回bytes类型(如b'1234'),需使用.decode("utf-8")转为字符串- 验证码有过期机制:60 秒后 Redis 自动删除,此时
r.get()返回None - 验证成功后立即删除 Redis 中的验证码,实现一次性使用,防止重复验证
- 验证码错误时不清除 Redis 数据,用户可重新输入
七、接口层 — UsersController
Controller 层定义接口,负责接收客户端请求、调用 Service 处理、返回响应。
1. 发送邮件接口(GET 请求)
# users/controller/UsersController.py
from fastapi import APIRouter
from users.service import UsersService
from pydantic import BaseModel, Field
# 子路由对象
users_router = APIRouter()
@users_router.get(
# 请求路径
path="/sendEmail",
# 接口简短摘要,显示在 Swagger UI 的接口列表中
summary="发送邮件",
# 接口详细描述,显示在 Swagger UI 的接口详情中
description="""
给用户输入的邮箱号发送验证码
访问路径:http://localhost:8001/users/sendEmail
请求参数:
email:字符串类型,用户输入的邮箱号
返回值:
{
"code": 状态码,成功200、失败500,int
"msg": 提示信息,字符串
"data": None,数据内容,Object
}
""",
)
def send_email(email: str):
"""接收客户端邮箱号 → 调用 Service 发送邮件"""
# 调用服务层方法 --- 服务层方法的返回值在这里就是直接返回给客户端请求
return UsersService.send_email(email)
2. 验证码验证接口(POST 请求)
定义一个数据模型类来接收 JSON 格式的请求体:
from pydantic import BaseModel, Field
# 定义接收验证数据的模型类
class VerifyEmailRequest(BaseModel):
"""接收验证码验证请求的 JSON 数据"""
email: str = Field(..., title="用户邮箱号", description="接收验证码的邮箱地址")
code: str = Field(..., title="验证码", description="用户输入的4位数字验证码")
@users_router.post(
path="/verifyEmail",
summary="验证邮箱验证码",
description="""
验证用户输入的邮箱验证码是否正确
访问路径:http://localhost:8001/users/verifyEmail
请求参数(JSON格式):
email:字符串类型,用户输入的邮箱号
code:字符串类型,用户输入的验证码
返回值:
{
"code": 状态码,成功200、失败500,int
"msg": 提示信息,字符串
"data": None,数据内容,Object
}
""",
)
def verify_email(request: VerifyEmailRequest):
"""接收邮箱号和验证码 → 调用 Service 验证"""
# 调用服务层方法验证验证码
return UsersService.verify_email(request.email, request.code)
关键点:
- 发邮件用 GET + 表单参数(key=value),直接通过形参
email: str接收 - 验证验证码用 POST + JSON 请求体,定义
VerifyEmailRequest类(继承BaseModel)来接收 Field(..., title="xxx")中的...表示必填字段- 接口中不写业务逻辑,直接调用 Service 层方法,返回值就是 Service 返回的字典
3. 请求方式对比
| 接口 | 请求方式 | 参数传递方式 | 接收方式 | 原因 |
|---|---|---|---|---|
/sendEmail | GET | URL 查询参数(k=v) | 直接形参 email: str | 简单查询,不涉及敏感数据 |
/verifyEmail | POST | JSON 请求体 | VerifyEmailRequest 数据类 | 验证操作涉及状态变更,不宜用 GET |
八、main.py 注册与启动
1. 完整 main.py
from fastapi import FastAPI
# 启动项目和关闭项目分别执行一些内容
from contextlib import asynccontextmanager
@asynccontextmanager
async def start_end_run(app):
"""
app:FastAPI 对象
yield 之前的内容:启动项目执行
yield 之后的内容:关闭项目执行
如果想实现一些变量的初始化操作,可以把变量写入到 app.state 属性中,格式如下:
app.state.变量名 = 初始化值
如果某个接口中需要使用,就用 request 对象取出来,格式如下
变量名2 = request.app.state.变量名
"""
# app.state.username = "cc"
print("启动项目")
yield
print("关闭项目")
# 创建FastAPI对象
app = FastAPI(lifespan=start_end_run)
# 导入子路由对象
from users.controller.UsersController import users_router
# 注册子路由
app.include_router(
router=users_router, # 引入子路由对象
prefix="/users", # 配置访问子路由接口的前缀,默认"",推荐写为模块的包名做区分
tags=["users"], # 配置swaggerUI中的模块名称
)
# 静态资源配置
from fastapi.staticfiles import StaticFiles
app.mount(
"/static", # 静态资源访问的前缀 --- 请求路径
StaticFiles(directory="static"), # 静态资源目录 --- 放行文件夹
name="static", # 静态资源访问的模块名称
)
# 启动服务
if __name__ == "__main__":
# 导入uvicorn包来写命令启动fastapi服务器项目
import uvicorn as uv
# 配置启动
uv.run(
# 启动项目的文件,即FastAPI()对象所在的文件
app="main:app", # 配置启动的项目文件 --- main.py中的app对象
host="localhost", # 配置启动的服务器地址
port=8001, # 配置启动的服务器端口
reload=False, # 配置关闭自动重启
)
2. 启动验证
# 方式一:命令行启动
python main.py
# 方式二:uvicorn 直接启动
uvicorn main:app --reload --host localhost --port 8001
启动后在浏览器中基于自己的网页访问 Swagger UI 测试页面:
http://localhost:8000/docs
九、Swagger UI 接口测试
FastAPI 自动集成了 Swagger UI,不需要 Postman 等第三方工具。
1. 测试发送邮件接口
在 Swagger UI 中找到 /users/sendEmail 接口:
- 点击接口名称展开
- 点击 Try it out 按钮
- 在
email参数框中输入已注册的邮箱号 - 点击 Execute
- 查看返回结果
成功响应:
{
"code": 200,
"msg": "发送成功",
"data": null
}
失败响应(邮箱未注册):
{
"code": 500,
"msg": "邮箱号不存在",
"data": null
}
2. 测试验证码验证接口
找到 /users/verifyEmail 接口:
- 点击 Try it out
- 在请求体 JSON 中输入邮箱号和收到的验证码:
{
"email": "2584744108@qq.com",
"code": "1234"
}
- 点击 Execute
- 查看返回结果
验证成功:
{
"code": 200,
"msg": "验证成功",
"data": null
}
验证码错误:
{
"code": 500,
"msg": "验证码错误,请重新输入",
"data": null
}
验证码已过期:
{
"code": 500,
"msg": "验证码已过期或未发送,请重新获取",
"data": null
}
十、完整 MVC 分层架构回顾
main.py (FastAPI 实例 + 子路由注册)
│
▼
┌─────────────────────────────────────────────────┐
│ Controller 层(接口层) │
│ users/controller/UsersController.py │
│ 职责:接收请求、调用 Service、返回响应 │
│ 定义:@users_router.get/post("路径") │
│ 参数:GET 用形参,POST 用 BaseModel 数据类 │
│ 返回:字典格式(自动转 JSON) │
└───────────────────────┬─────────────────────────┘
│ 调用
▼
┌─────────────────────────────────────────────────┐
│ Service 层(业务层) │
│ users/service/UsersService.py │
│ 职责:实现具体业务逻辑 │
│ 功能:验证邮箱、生成验证码、发送邮件、比对验证码 │
│ 调用:Dao 获取数据 + Redis 存取验证码 │
└──────────┬──────────────────────┬────────────────┘
│ 调用 │ 调用
▼ ▼
┌──────────────────┐ ┌──────────────────────┐
│ Dao 层(数据层) │ │ Redis 缓存 │
│ users/dao/ │ │ common/RedisUtil.py │
│ UsersDao.py │ │ 验证码存取 + 过期 │
│ MySQL 查询用户 │ │ r.set/get/delete │
└──────────────────┘ └──────────────────────┘
│
▼
┌──────────────────┐
│ MySQL 数据库 │
│ users 表 │
│ 字段:user_id, │
│ username, email, │
│ create_time │
└──────────────────┘
各层核心职责总结:
| 层级 | 包路径 | 核心任务 | 谁调用它 |
|---|---|---|---|
| Controller | controller/ | 定义接口、接收参数、调用 Service、返回响应 | 客户端(HTTP 请求) |
| Service | service/ | 业务逻辑处理、协调多个组件 | Controller |
| Dao | dao/ | 只做数据库增删改查,不做逻辑判断 | Service |
| Utils | common/ | 抽取公共工具代码(MySQL 连接、Redis 连接等) | 各层共用 |
十一、课后实践(额外作业)
📝 任务要求
- 启动服务器:运行
python main.py,确保服务器正常启动自己的端口 - 使用 Swagger UI 测试:访问
http://localhost:8001/docs - 测试发送邮件接口:
- 接口路径:
GET /users/sendEmail?email=你的邮箱号 - 验证:邮箱是否收到验证码邮件
- 验证:输入未注册的邮箱号,观察返回的错误信息
- 接口路径:
- 测试验证码验证接口:
- 接口路径:
POST /users/verifyEmail - 请求体:
{"email": "你的邮箱号", "code": "收到的验证码"} - 验证:输入正确的验证码 → 验证成功
- 验证:输入错误的验证码 → 验证码错误
- 验证:等待 60 秒后再次验证 → 验证码过期
- 接口路径:
- (扩展)编写前端页面:实现一个简单的 HTML 页面,包含邮箱输入框、发送按钮、验证码输入框和验证按钮,通过 AJAX 调用后端接口
🔧 准备工作检查清单
- MySQL 已启动,
xiangmu_one数据库已创建 -
users表中已插入测试数据(至少有一条真实邮箱记录) - Redis 已启动(默认端口 6379)
-
.env文件配置正确(邮箱号、授权码、数据库信息) - 已安装依赖:
pip install fastapi uvicorn pymysql redis python-dotenv - QQ 邮箱已开启 SMTP 服务并生成授权码
⚠️ 常见问题
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 邮件发送失败 | 授权码错误 | 检查 QQ 邮箱生成的授权码,确认未过期 |
| 邮件发送失败 | SMTP 未开启 | QQ 邮箱 → 设置 → 账户 → 开启 POP3/SMTP 服务 |
| 验证码验证失败 | Redis 未启动 | 启动 Redis 服务:redis-server 或检查 Windows 服务 |
| 接口返回 422 | 参数名不一致 | 检查形参名是否与请求参数的 key 一致 |
| 数据库查询不到用户 | MySQL 未启动或表结构不对 | 确认 users 表存在且有 email 字段 |
核心要点
- 环境配置统一管理:
.env文件集中管理所有配置,python-dotenv加载到环境变量,代码和配置分离 - MVC 分层思想:Controller 收请求 → Service 做逻辑 → Dao 查数据,职责分明、降低耦合
- 验证码流程:生成 → 发邮件 → Redis 存(带过期) → 比对 → 验证成功删除(一次性)
- Redis 过期机制:
r.set(key, value, ex=60)天然适合验证码场景,到期自动清理 - 接口设计规范:
- 简单查询(发邮件)→ GET + k=v 参数
- 状态变更(验证码验证)→ POST + JSON 请求体
- 统一返回格式:所有接口返回
{"code": 状态码, "msg": 提示信息, "data": 数据},方便前端统一处理 - 同步开发流程:后端定义好接口和返回值格式后,前端可以同步开始页面开发,双方约定好接口规范即可并行推进
最终思考:今天的邮件验证码功能是 Web 开发中非常经典的功能组合。通过这个实战,完整实践了 FastAPI + MySQL + Redis + SMTP 的四端联动,理解了项目从"需求分析 → 流程设计 → 分层编码 → 接口测试"的完整开发链路。这也是之后 RAG 对话系统开发的基础框架。
更多推荐
所有评论(0)