📚前言
📒FDE系列内容总纲:
🚄前置课程列表:
见文档结尾附录。
🚀阶段2·Day 35:Python + SQL --- 工单接入 MySQL + 本周收官
FDE 学习系列教程 · 第二阶段 · 第 3 周 · Day 5 预计时长:3 小时 | 难度:★★★★☆ | 前置知识:Day 31-34 全部内容
📌 一句话目标:装好 MySQL,用 SQLAlchemy 和 pandas 在 Python 里读写数据库,搭一条"脏 CSV → 清洗 → MySQL"管道,并把第 2 周的工单 API 从内存升级为 MySQL 持久化。
🧑🤝🧑 开场:从"玩具"到"真家伙"
兄弟,前四天我们都在 SQLite 上练。它轻便、零安装,是最好的训练场。但它有个天花板:不支持多人高并发,不适合当生产服务器。
客户现场跑的是 MySQL------真正的企业级数据库,作为一个服务 7×24 小时跑在服务器上,成百上千个请求同时来都扛得住。
今天完成三级跳:
Day31-34 今天 最终成果
┌──────────┐ ┌──────────────┐ ┌────────────────┐
│ SQLite │ ───► │ MySQL 服务 │ ───► │ FastAPI 工单API │
│ 单文件 │ │ SQLAlchemy │ │ 数据持久化 │
│ 自己练 │ │ pandas │ │ 重启不丢 │
└──────────┘ └──────────────┘ └────────────────┘
今天内容多,遇到安装报错别烦躁------装数据库本身就是 FDE 的必备技能,客户服务器上你也得这么干。一步步来。
🖥️ 一、安装 MySQL(Windows)
安装步骤
-
打开 https://dev.mysql.com/downloads/installer/ ,下载 MySQL Installer for Windows(选体积较大的那个完整版 MSI,约 400MB,组件全)
-
运行安装程序,安装类型选 "Server only"(只装服务器即可,体积小;想要图形界面可选 Full)
-
一路 Next,到配置环节:
-
Config Type 选
Development Computer(开发机) -
端口(Port)保持 3306,勾上"开机自启"
-
认证方式选推荐的
Use Strong Password Encryption
-
-
设置 root 密码 :学习阶段建议设成好记的,比如
fde2026(生产环境务必用强密码!) -
点 Execute 应用配置 → Finish
验证安装成功
打开开始菜单里的 MySQL Command Line Client ,输入刚才的密码,看到 mysql> 提示符就成了:
Enter password: ********
Welcome to the MySQL monitor.
mysql>
⚠️ 两个信息务必记牢,后面 Python 连接全靠它们:
用户名
root,密码fde2026(你自己设的)端口
3306装不上的常见原因:① 3306 端口被别的程序占了(之前装过 MySQL/MariaDB)② 缺少 Visual C++ 运行库(按提示装一个即可)。
🖥️ 二、建库建表
在 MySQL Command Line 里逐段执行(注意 MySQL 的语法和 SQLite 略有不同):
-- ① 创建数据库(指定 utf8mb4 字符集,才能正确存中文和 emoji)
CREATE DATABASE IF NOT EXISTS fde_tickets
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE fde_tickets;
-- ② 工程师表
CREATE TABLE engineers (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
phone VARCHAR(20),
department VARCHAR(50),
title VARCHAR(50) DEFAULT '工程师',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- ③ 设备表(DECIMAL 定点数存温度,比浮点精确)
CREATE TABLE devices (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
type VARCHAR(20) NOT NULL,
temperature DECIMAL(5,1) DEFAULT 0,
vibration DECIMAL(4,1) DEFAULT 0,
is_running BOOLEAN DEFAULT TRUE,
engineer_id INT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (engineer_id) REFERENCES engineers(id)
);
-- ④ 工单表
CREATE TABLE tickets (
id INT AUTO_INCREMENT PRIMARY KEY,
device_id INT NOT NULL,
title VARCHAR(200) NOT NULL,
priority VARCHAR(10) DEFAULT '中',
status VARCHAR(20) DEFAULT '待处理',
reporter_id INT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (device_id) REFERENCES devices(id),
FOREIGN KEY (reporter_id) REFERENCES engineers(id)
);
-- 看一眼表建好了没
SHOW TABLES;
SQLite → MySQL 数据类型对照
| 含义 | SQLite | MySQL |
|---|---|---|
| 整数 | INTEGER |
INT / BIGINT |
| 小数 | REAL |
DECIMAL(5,1) / FLOAT / DOUBLE |
| 字符串 | TEXT |
VARCHAR(50) / TEXT |
| 布尔 | INTEGER(0/1) |
BOOLEAN / TINYINT(1) |
| 时间 | TEXT |
DATETIME / TIMESTAMP |
| 自增主键 | AUTOINCREMENT |
AUTO_INCREMENT |
💡 DECIMAL(5,1) 是啥意思? 总共 5 位数字,小数部分占 1 位,所以整数部分最多 4 位------能存
-9999.9到9999.9。温度用定点数而非 FLOAT,是为了避免浮点误差(0.1+0.2≠0.3 的老问题)。涉及金额必须用 DECIMAL。
🖥️ 三、安装 Python 库
在你的项目虚拟环境里:
pip install sqlalchemy pymysql pandas
三个库分工明确:
| 库 | 角色 | 大白话 |
|---|---|---|
sqlalchemy |
ORM / 数据库工具包 | Python 和数据库之间的"万能翻译官" |
pymysql |
MySQL 驱动 | 让 Python 能说 MySQL 的"方言" |
pandas |
数据分析库 | 一张表在 Python 里变成强大的 DataFrame |
你的 Python 代码
│
▼
SQLAlchemy(统一接口,换数据库只改连接串)
│
▼
PyMySQL(MySQL 专用驱动)
│
▼
MySQL 服务器(3306 端口)
💡 连接串(URL)是关键,格式背下来:
mysql+pymysql://用户名:密码@主机:端口/数据库名?charset=utf8mb4 mysql+pymysql://root:fde2026@localhost:3306/fde_tickets?charset=utf8mb4
mysql+pymysql的意思是"用 pymysql 驱动连 MySQL"。charset=utf8mb4保证中文不乱码。
🖥️ 四、SQLAlchemy 连接与操作
新建 07_sqlalchemy.py:
"""
SQLAlchemy 操作 MySQL
文件:07_sqlalchemy.py
"""
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
# ① 创建引擎(整个程序通常只创建一次,它内部管连接池)
engine = create_engine(
"mysql+pymysql://root:fde2026@localhost:3306/fde_tickets?charset=utf8mb4",
echo=True, # echo=True 打印实际执行的 SQL,学习时强烈建议开
pool_pre_ping=True # 连接前探活,避免用到断开的旧连接
)
# ② 用 with 管理连接(自动关闭,不用手写 close)
with engine.connect() as conn:
# 插入工程师 ------ 参数用 :名字 占位(SQLAlchemy 风格,防注入)
conn.execute(text("""
INSERT INTO engineers (name, phone, department, title)
VALUES (:name, :phone, :dept, :title)
"""), [
{"name": "李工", "phone": "13800001111", "dept": "一车间", "title": "高级工程师"},
{"name": "王工", "phone": "13800002222", "dept": "二车间", "title": "工程师"},
{"name": "赵工", "phone": "13800003333", "dept": "一车间", "title": "工程师"},
])
conn.commit()
# 查询
result = conn.execute(text("SELECT id, name, department FROM engineers"))
print("\n工程师列表:")
for row in result:
print(f" {row.id}. {row.name} | {row.department}")
运行:
python 07_sqlalchemy.py
echo=True 会让你看到 SQLAlchemy 实际发出的 SQL 语句------这是学习"Python 代码如何变成 SQL"的最佳窗口。熟悉后在生产代码里关掉(echo=False)。
📌 参数占位符的演变:
SQLite 原生驱动:
?MySQL 原生驱动(pymysql):
%sSQLAlchemy 统一用
:名字(命名参数),不管底层啥数据库都一样这就是用 SQLAlchemy 的一大好处:换数据库时业务代码几乎不动,只改连接串。
pandas 读写数据库(爽到飞起)
在同一文件追加:
import pandas as pd
# 读:一句 SQL → DataFrame(带表头的二维表,类似 Excel)
df = pd.read_sql("SELECT * FROM engineers", engine)
print("\npandas 读出来的:")
print(df)
# 写:DataFrame → 数据库表,一行搞定
new_devices = pd.DataFrame([
{"name": "注塑机A1", "type": "注塑", "temperature": 65.0,
"vibration": 8.0, "is_running": True, "engineer_id": 1},
{"name": "注塑机A2", "type": "注塑", "temperature": 82.0,
"vibration": 12.0, "is_running": True, "engineer_id": 2},
])
new_devices.to_sql("devices", engine, if_exists="append", index=False)
print(f"\n✅ pandas 写入 {len(new_devices)} 条设备")
to_sql 的 if_exists 三种模式必须分清:
| 参数值 | 行为 | 什么时候用 |
|---|---|---|
fail |
表已存在就报错(默认,最安全) | 防止误覆盖 |
replace |
先 DROP 整表再建(数据全没!) | 临时表、整表重灌 |
append |
往现有表追加数据 | 增量导入(最常用) |
⚠️
replace是"删表重建",不是更新!对着生产表手滑用了 replace,眼泪能流一升。日常导入用append。
🖥️ 五、数据管道:脏 CSV → pandas 清洗 → MySQL
把 Day 34 的清洗脚本升级成 MySQL 版本。新建 08_pipeline.py:
"""
数据管道:脏 CSV → pandas 清洗 → MySQL 持久化
文件:08_pipeline.py
"""
import pandas as pd
from sqlalchemy import create_engine
import logging
logging.basicConfig(level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s")
log = logging.getLogger(__name__)
engine = create_engine(
"mysql+pymysql://root:fde2026@localhost:3306/fde_tickets?charset=utf8mb4"
)
def load_and_clean(csv_path):
"""读 CSV 并清洗,全程向量化操作,比手写循环快得多"""
df = pd.read_csv(csv_path)
log.info(f"原始数据:{len(df)} 行")
# ① 标准化:设备名去空格→大写→去内部空格;负责人去空格
df["device_name"] = df["device_name"].astype(str).str.strip()\
.str.upper().str.replace(" ", "")
df["owner_name"] = df["owner_name"].astype(str).str.strip()
# ② 温度:中文数字映射 → 转数字(转不了的变 NaN,对应数据库 NULL)
cn_map = {"八十二": "82", "九十": "90", "九十一": "91"}
df["temperature"] = df["temperature"].astype(str).str.strip().replace(cn_map)
df["temperature"] = pd.to_numeric(df["temperature"], errors="coerce")
# errors="coerce" 是灵魂:无法转换的变 NaN 而不是报错
# ③ 手机号:去横杠空格;pandas 把空读成 NaN(字符串'nan'),还原成 None
df["phone"] = df["phone"].astype(str).str.replace("-", "", regex=False)\
.str.replace(" ", "", regex=False)
df.loc[df["phone"].isin(["nan", "None", ""]), "phone"] = None
# ④ 去重
before = len(df)
df = df.drop_duplicates(subset=["device_name", "owner_name"])
log.info(f"去重:{before} → {len(df)} 行(删除 {before-len(df)} 条)")
return df
def save_to_mysql(df, table_name):
df.to_sql(table_name, engine, if_exists="append", index=False)
log.info(f"✅ 写入 {table_name} 表 {len(df)} 条")
# ===== 跑管道 =====
df = load_and_clean("dirty_data.csv")
print(df) # 直接打印 DataFrame 检查清洗效果
save_to_mysql(df, "devices_clean")
# 验证
cnt = pd.read_sql("SELECT COUNT(*) AS c FROM devices_clean", engine)
log.info(f"devices_clean 表现共 {cnt.iloc[0,0]} 条")
💡 对比 Day 34 的纯 Python 版本,pandas 的
str.strip()、to_numeric(errors='coerce')、drop_duplicates()都是向量化操作------不用自己写 for 循环,一行顶十行,处理几万行 CSV 速度快几十倍。这就是为什么数据分析人人爱 pandas。
⚠️ 第一次跑前,先在 MySQL 里建devices_clean表(列名要和 DataFrame 对得上),或用to_sql(..., if_exists='replace')让 pandas 自动建表(学习阶段图省事可以,生产环境建议手动建表好控制类型)。
🖥️ 六、重头戏:工单 API 接入 MySQL(持久化)
回到第 2 周的 FastAPI 工单项目。当时数据存在内存列表里,重启就没。今天把数据层换成 MySQL。
还记得 Day 26 学的分层架构吗?现在它开始回报你了------我们只替换数据层,接口层一行不用改。
分层架构的回报:
┌─────────────────────────┐
│ 接口层 main.py(路由) │ ← 完全不用改!
│ @app.get("/tickets") │
└───────────┬─────────────┘
│ 调用
┌───────────▼─────────────┐
│ 数据层 data_store.py │ ← 只换这一层
│ 旧:内存 TICKETS 列表 │
│ 新:MySQL 增删改查 │
└─────────────────────────┘
新建 data_store.py:
"""
数据层:MySQL 版本(替换原来的内存列表)
文件:data_store.py
"""
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
from contextlib import contextmanager
engine = create_engine(
"mysql+pymysql://root:fde2026@localhost:3306/fde_tickets?charset=utf8mb4",
pool_pre_ping=True
)
SessionLocal = sessionmaker(bind=engine)
@contextmanager
def get_db():
"""数据库会话上下文管理器:自动提交/回滚/关闭"""
session = SessionLocal()
try:
yield session
session.commit() # 没出异常 → 提交
except Exception:
session.rollback() # 出异常 → 回滚(保证不留半截脏数据)
raise
finally:
session.close() # 无论如何都关闭,归还连接给连接池
# ===== CRUD =====
def list_tickets(status=None, priority=None):
"""动态拼条件查工单列表"""
with get_db() as db:
sql = "SELECT * FROM tickets WHERE 1=1" # 1=1 方便后面无脑 AND
params = {}
if status:
sql += " AND status = :status"
params["status"] = status
if priority:
sql += " AND priority = :priority"
params["priority"] = priority
sql += " ORDER BY created_at DESC"
result = db.execute(text(sql), params)
return [dict(row._mapping) for row in result]
def get_ticket(ticket_id):
with get_db() as db:
result = db.execute(
text("SELECT * FROM tickets WHERE id = :id"), {"id": ticket_id}
)
row = result.fetchone()
return dict(row._mapping) if row else None
def create_ticket(data):
with get_db() as db:
db.execute(text("""
INSERT INTO tickets (device_id, title, priority, status, reporter_id)
VALUES (:device_id, :title, :priority, '待处理', :reporter_id)
"""), data)
new_id = db.execute(text("SELECT LAST_INSERT_ID() AS id")).fetchone()[0]
return get_ticket(new_id)
def update_ticket(ticket_id, data):
with get_db() as db:
sets, params = [], {"id": ticket_id}
for key, val in data.items():
if val is not None:
sets.append(f"{key} = :{key}")
params[key] = val
if sets:
db.execute(text(f"UPDATE tickets SET {', '.join(sets)} WHERE id=:id"),
params)
return get_ticket(ticket_id)
def delete_ticket(ticket_id):
with get_db() as db:
result = db.execute(text("DELETE FROM tickets WHERE id=:id"),
{"id": ticket_id})
return result.rowcount > 0
几个关键设计点
1. @contextmanager 上下文管理器------数据库操作的安全护栏
with get_db() as db: 进入时:自动开一个会话
db.execute(INSERT) 正常 → commit() 提交
db.execute(UPDATE) 异常 → rollback() 回滚
退出时:close() 一定执行(哪怕报错)
这保证了:连接不泄漏、出错不留半成品。比每次手写 try/finally 清爽。
2. WHERE 1=1 是动态拼 SQL 的经典技巧
因为查询条件是可选的(用户可能只传 status,也可能 status/priority 都传),写死 WHERE 会很麻烦。用 WHERE 1=1 打底,后面每个条件直接 AND ... 往上拼即可。
3. 列名不能用参数占位符
:参数 只能占位"值",不能占位"列名"。所以 update_ticket 里列名用 f-string 拼、值用 :参数 传。这里列名来自你自己的代码(白名单内),安全;绝不能把用户输入直接拼进 SQL。
接口层 main.py 几乎不变
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import data_store # ← 关键:只改这一行的 import(原来可能是内存版)
app = FastAPI(title="工单 API(MySQL 版)")
class TicketIn(BaseModel):
device_id: int
title: str
priority: str = "中"
reporter_id: int | None = None
@app.get("/tickets")
def list_tickets(status: str | None = None, priority: str | None = None):
return data_store.list_tickets(status, priority)
@app.post("/tickets", status_code=201)
def create_ticket(t: TicketIn):
return data_store.create_ticket(t.model_dump())
@app.get("/tickets/{ticket_id}")
def get_ticket(ticket_id: int):
t = data_store.get_ticket(ticket_id)
if not t:
raise HTTPException(404, "工单不存在")
return t
@app.delete("/tickets/{ticket_id}", status_code=204)
def delete_ticket(ticket_id: int):
if not data_store.delete_ticket(ticket_id):
raise HTTPException(404, "工单不存在")
见证奇迹的时刻
uvicorn main:app --reload
-
用 Swagger(http://localhost:8000/docs)创建 2 张工单
-
关掉 uvicorn 服务(Ctrl+C)
-
重新启动
uvicorn main:app --reload -
再查
GET /tickets------数据还在!
这就是持久化。在 MySQL Command Line 里也能直接查到:
USE fde_tickets;
SELECT * FROM tickets;
📌 这一刻你应该体会到分层架构的价值:换数据层(内存→MySQL),接口层、Pydantic 模型、文档全部零修改。以后要从 MySQL 换成 PostgreSQL?改个连接串的事。这就是 Day 26 埋的伏笔在今天开花结果。
📝 本周复习:知识地图
SQL 与数据处理(Day 31-35)
│
├─ 基础 CRUD(Day 31)
│ ├─ SQLite 上手 + DBeaver 可视化
│ ├─ SELECT / WHERE / ORDER BY / LIMIT
│ ├─ INSERT / UPDATE / DELETE(写操作必加 WHERE!)
│ ├─ 主键、数据类型、? 占位符防注入
│ └─ commit 落盘
│
├─ 多表查询(Day 32)
│ ├─ 为什么拆表:消除重复,一处改处处生效
│ ├─ 主键 / 外键 / 表关系(1:N)
│ ├─ INNER JOIN(交集)/ LEFT JOIN(左全保留补 NULL)
│ ├─ 聚合 COUNT/SUM/AVG/MAX/MIN + GROUP BY
│ ├─ HAVING 过滤组(WHERE 过滤行)
│ └─ 执行顺序 FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY→LIMIT
│
├─ 进阶查询(Day 33)
│ ├─ 子查询 / CTE(WITH,把复杂查询拆成流水线)
│ ├─ ROW_NUMBER / RANK / DENSE_RANK 的区别
│ ├─ PARTITION BY:分组但不压扁行
│ ├─ 组内 TopN 模板:CTE + ROW_NUMBER + WHERE rn<=N
│ └─ SUM/AVG OVER(PARTITION BY):每行带组统计
│
├─ 数据清洗(Day 34)
│ ├─ 四类脏数据:重复 / 缺失 / 格式不一致 / 类型异常
│ ├─ 顺序:先标准化 → 再去重 → 后补缺转类型
│ ├─ TRIM/UPPER/REPLACE/CAST/COALESCE
│ ├─ 脱敏 SUBSTR+拼接;原始数据只读不覆盖
│ └─ 全程日志留痕
│
└─ Python + SQL(Day 35)
├─ MySQL 安装 + 建库建表(utf8mb4 / DECIMAL)
├─ 连接串 mysql+pymysql://user:pwd@host:3306/db
├─ SQLAlchemy engine / text(:命名参数) / 上下文管理器
├─ pandas read_sql() / to_sql(append/replace/fail)
├─ 数据管道:脏 CSV → pandas 清洗 → MySQL
└─ 工单 API 接入 MySQL,分层架构接口层零修改
📋 本周验收清单
| 序号 | 验收项 | 达标标准 | 自测方式 |
|---|---|---|---|
| 1 | 基础查询 | 熟练写 SELECT+WHERE+ORDER BY+LIMIT | Day31 练习 1 全对 |
| 2 | 增删改 | 会 INSERT/UPDATE/DELETE,且记得加 WHERE | 能说出忘加 WHERE 的后果 |
| 3 | 多表 JOIN | 能独立写三表关联 | Day32 练习 1 跑通 |
| 4 | 分组统计 | GROUP BY + HAVING 用对 | 能讲清 WHERE/HAVING 区别 |
| 5 | 窗口函数 | 写出分组 TopN | Day33 练习 3 跑通 |
| 6 | CTE | 用 WITH 把复杂查询分段 | Day33 练习 4 跑通 |
| 7 | 数据清洗 | 脏 CSV → 干净数据入库 | 9 行洗成 6 行且无报错 |
| 8 | 脱敏 | 手机号/身份证打码 | Day34 练习 3 正确 |
| 9 | Python+SQL | SQLAlchemy + pandas 连 MySQL | 脚本能读写真实 MySQL |
| 10 | 数据管道 | CSV→清洗→MySQL 一键跑通 | 08_pipeline.py 成功 |
| 11 | API 持久化 | 工单 API 重启数据不丢 | 重启后数据仍在 |
全绿了吗? 有 1-2 项不踏实很正常,回看对应那天的实操再敲一遍。SQL 这东西,手上敲过和眼睛看过是两种技能。
🎉 本周收官:你获得了什么
这一周,你完成了从"数据在内存里裸奔"到"企业级数据处理"的跨越:
-
你能在数据库里设计表、写各种查询,包括多表 JOIN、分组统计、窗口排名
-
你能把客户给的脏 CSV 洗成干净数据,还知道怎么脱敏、怎么留痕
-
你能用 Python(SQLAlchemy + pandas)操作真正的 MySQL
-
你的工单 API 接上了数据库,重启不丢数据,有了生产应用的雏形
你现在手里的完整数据能力栈: 数据源 清洗加工 存储 对外服务┌────────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐
│ 脏 CSV │→│ pandas │→│ MySQL │ ←── │ FastAPI │
│ 设备日志 │ │ 标准化 │ │ 三表关联 │ │ 工单 API │
│ 客户 Excel│ │ 去重补缺 │ │ 索引/外键 │ │ Swagger │
└────────┘ └──────────┘ └─────────┘ └──────────┘
这套"数据进来 → 清洗 → 入库 → 对外提供 API"的链路,就是无数企业系统的骨架。FDE 在客户现场做的数据对接,本质都是它的变体。
🔭 下阶段预告
第 3 周拿下数据,第 4 周要攻克部署环境。客户的服务器 90% 是 Linux------没有图形界面、没有资源管理器,全靠命令行。
下周你会:
-
在 Windows 上用 WSL2 装一个 Ubuntu,拥有本地 Linux 环境
-
掌握文件操作、权限、进程管理、文本三剑客(grep/awk/sed)
-
写 Shell 脚本把重复操作自动化(自动备份、健康检查)
-
用 nohup、crontab 让服务后台常驻、定时执行
你的工单 API 现在跑得好好的,但总不能一直占着你的终端窗口。下周教你怎么把它"扔到服务器上一直跑"。周末好好休息,下周进入部署工程师的世界!
🌍附录:前置课程列表
阶段一:
【FDE系列】阶段1Day 1:AI 层级关系 --- 四个嵌套的圈-CSDN博客
【FDE系列】阶段1Day 2:AI 三阶段发展史 --- 会认 → 会判断 → 会创造-CSDN博客
【FDE系列】阶段1Day 3:符号 AI vs 机器学习 --- 两条路线的本质区别-CSDN博客
【FDE系列】阶段1Day 4:Transformer 的历史意义 --- 2017 年的分水岭-CSDN博客
【FDE系列】阶段1Day 5:本周复习与自测 --- 检验你的 AI 认知地基-CSDN博客
【FDE系列】阶段1Day 6:Transformer 架构 --- 一张图纸盖出千千万万栋楼-CSDN博客
【FDE系列】阶段1Day 7:LLM 本质 --- 文字接龙机器-CSDN博客
【FDE系列】阶段1Day 8:Token --- 模型眼中的最小单位-CSDN博客
【FDE系列】阶段1Day 9:AI 幻觉 --- 为什么会一本正经地胡说八道-CSDN博客
【FDE系列】阶段1Day 10:上下文窗口 --- 模型的记忆力上限 + 本周复习-CSDN博客
【FDE系列】阶段1Day 11:Prompt --- 给模型立规矩-CSDN博客
【FDE系列】阶段1Day 12:Memory --- 让模型记住上下文
【FDE系列】阶段1Day 13:RAG --- 给模型配图书管理员-CSDN博客
【FDE系列】阶段1Day 14:Tool Use --- 让模型动手操作-CSDN博客
【FDE系列】阶段1Day 15:MCP --- 统一的工具接口标准 + 第三周复习-CSDN博客
【FDE系列】阶段1Day 16:什么是 FDE --- 把 AI 变成客户结果的人-CSDN博客
【FDE系列】阶段1Day 17:FDE vs 传统实施 --- 三大本质区别-CSDN博客
【FDE系列】阶段1Day 18:FDE 三重身份 + C6 胜任力模型-CSDN博客
【FDE系列】阶段1Day 19:七阶段行动路径 + 行业经验的价值-CSDN博客
【FDE系列】阶段1Day 20:阶段总结与产出物 --- 第一阶段收官-CSDN博客
阶段二:
【FDE系列】阶段2:Day 21:Python 环境搭建 --- 写出你的第一行代码-CSDN博客
【FDE系列】阶段2:Day 22:变量、数据类型、条件判断 --- Python 的"记忆"和"判断"-CSDN博客
【FDE系列】阶段2:Day 23:循环与函数 --- 让代码跑 100 遍、把逻辑打包复用-CSDN博客
【FDE系列】阶段2:Day 24:数据结构 --- 列表、字典、集合、元组-CSDN博客
【FDE系列】阶段2:Day 25:文件读写与 JSON --- 让程序连通外部数据(第一周收官)-CSDN博客
【FDE系列】阶段2:Day 26:模块化编程 --- 把代码拆成"抽屉柜"-CSDN博客
【FDE系列】阶段2:Day 27:异常处理与日志 --- 让程序"摔不烂、查得到"-CSDN博客
【FDE系列】阶段2:Day 28:FastAPI 入门 --- 把你的函数变成 API 服务-CSDN博客
【FDE系列】阶段2:Day 29:FastAPI 进阶 --- Pydantic 模型与完整 CRUD 实战-CSDN博客
【FDE系列】阶段2:Day 30:生产代码规范 --- 测试、类型注解、配置管理(第二周收官)-CSDN博客
【FDE系列】阶段2:Day 31:SQL 基础 --- 增删改查一把梭-CSDN博客
【FDE系列】阶段2:Day 32:多表查询 --- JOIN 与聚合-CSDN博客