1. 引言
Python 之所以能成为当下最热门的编程语言之一,很大程度上得益于它在多个领域的全面覆盖。从 Web 后端开发到数据分析与可视化,从网络爬虫到人工智能与大模型应用,Python 几乎无处不在。本文作为「Python 进阶语法」系列的第八篇,将带你系统梳理这四大方向的核心语法与实战要点,帮助你建立完整的知识图谱。
2. Web 后端开发
2.1 主流框架概览
Python Web 后端开发主要围绕三大框架展开:
- Flask:轻量、灵活,适合快速搭建 API 服务和小型应用。
- Django:重量级、全家桶,自带 ORM、Admin 后台、认证体系,适合大型项目。
- FastAPI:基于类型注解,天然支持异步,自动生成 OpenAPI 文档,是当下构建高性能 API 的首选。
| 框架 | 适用场景 | 学习曲线 | 性能特点 | 推荐指数 |
|---|---|---|---|---|
| Flask | 小型应用、快速原型、微服务 | 平缓,上手快 | 同步为主,性能中规中矩 | ⭐⭐⭐⭐ |
| Django | 大型项目、内容管理、全栈一体化 | 较陡,概念多 | 自带 ORM 与缓存,性能均衡 | ⭐⭐⭐⭐ |
| FastAPI | 高性能 API、异步服务、前后端分离 | 中等,需熟悉类型注解 | 原生异步,高并发表现优异 | ⭐⭐⭐⭐⭐ |
除了上述基础特性,三大框架在并发处理、开发效率、社区生态三个维度上差异明显,直接影响选型决策:
- 并发处理 :Flask 默认基于 WSGI,同步阻塞,高并发场景需要借助 Gunicorn + 多进程或引入 Celery 异步任务来弥补;Django 同样以同步为主,虽支持 ASGI 但异步生态相对滞后;FastAPI 基于 ASGI 与
async/await,原生支持异步与协程,配合 Uvicorn 在高并发 I/O 密集型场景下表现最为出色。 - 开发效率:Flask 极简灵活,适合快速原型与微服务,但大型项目需要自行组装组件;Django 自带 ORM、Admin、认证、迁移等全家桶能力,开箱即用,适合快速搭建功能完整的中大型系统;FastAPI 借助类型注解自动生成 OpenAPI 文档与数据校验,前后端联调效率极高,开发体验现代。
- 社区生态:Flask 与 Django 历史悠久、资料丰富、第三方扩展众多,遇到问题容易找到解决方案;FastAPI 虽年轻,但社区增长迅猛,官方文档完善,周边工具(如 Pydantic、SQLModel)持续演进,生态正在快速补齐。
选型建议 :如果是小型项目、微服务或希望高度自定义,优先选择 Flask ;如果是功能复杂、需要快速交付的中大型全栈项目,Django 的「全家桶」能显著降低开发成本;如果核心诉求是高性能 API、异步服务或前后端分离架构,FastAPI 是最佳选择。实际项目中三者也可按需混用,例如用 Django 管理后台 + FastAPI 提供高并发 API。
2.2 FastAPI 快速上手
FastAPI 充分利用了 Python 的类型注解语法,让代码既清晰又高效:
python
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: bool = False
@app.get("/")
def read_root():
return {"message": "Hello World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None):
return {"item_id": item_id, "q": q}
@app.post("/items/")
def create_item(item: Item):
return {"item": item, "price_with_tax": item.price * 1.1}
2.3 异步与并发
Python 3.5+ 引入的 async/await 语法让异步编程变得优雅:
python
import asyncio
async def fetch_data(url: str) -> str:
await asyncio.sleep(1) # 模拟网络请求
return f"Data from {url}"
async def main():
tasks = [fetch_data(f"https://api.example.com/{i}") for i in range(5)]
results = await asyncio.gather(*tasks)
for r in results:
print(r)
asyncio.run(main())
3. 数据分析与可视化
3.1 数据分析三剑客
数据分析领域离不开三个核心库:
- NumPy:提供高性能的多维数组对象与数学运算。
- Pandas:提供 DataFrame 数据结构,是数据清洗与处理的利器。
- Matplotlib / Seaborn:负责数据可视化。
3.2 Pandas 核心操作
python
import pandas as pd
# 创建 DataFrame
df = pd.DataFrame({
"姓名": ["张三", "李四", "王五"],
"年龄": [25, 30, 35],
"城市": ["北京", "上海", "广州"]
})
# 数据筛选
adults = df[df["年龄"] >= 30]
# 分组聚合
grouped = df.groupby("城市")["年龄"].mean()
# 处理缺失值
df.fillna(0, inplace=True)
3.3 数据可视化
python
import matplotlib.pyplot as plt
import seaborn as sns
# 设置中文字体
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
# 折线图
x = [1, 2, 3, 4, 5]
y = [2, 4, 1, 5, 3]
plt.plot(x, y, marker="o")
plt.title("示例折线图")
plt.xlabel("X 轴")
plt.ylabel("Y 轴")
plt.show()
# Seaborn 统计图
sns.set_theme()
tips = sns.load_dataset("tips")
sns.boxplot(x="day", y="total_bill", data=tips)
plt.show()
4. 网络爬虫
4.1 爬虫基础流程
网络爬虫的基本流程可以概括为:发送请求 → 解析响应 → 提取数据 → 存储数据。
4.2 使用 Requests 发送请求
python
import requests
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
# GET 请求
resp = requests.get("https://api.example.com/data", headers=headers, timeout=10)
print(resp.status_code)
print(resp.json())
# POST 请求
payload = {"username": "admin", "password": "123456"}
resp = requests.post("https://api.example.com/login", json=payload)
网络请求往往受网络波动、服务器状态等因素影响,因此异常处理与重试机制是爬虫健壮性的关键。下面是一个带超时、重试与异常捕获的完整示例:
python
import time
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# 1. 配置重试策略:最多重试 3 次,遇到连接错误、超时、5xx 状态码时触发
retry_strategy = Retry(
total=3, # 总重试次数
backoff_factor=1, # 重试间隔:1s、2s、4s 递增
status_forcelist=[500, 502, 503, 504], # 触发重试的 HTTP 状态码
allowed_methods=["GET", "POST"] # 允许重试的请求方法
)
# 2. 将重试策略挂载到 Session 上,统一管理连接池
session = requests.Session()
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("http://", adapter)
session.mount("https://", adapter)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
def fetch_with_retry(url: str, max_attempts: int = 3) -> requests.Response:
"""带重试的请求函数:捕获常见异常并逐次重试"""
for attempt in range(1, max_attempts + 1):
try:
# 设置 timeout:连接超时 5s,读取超时 10s,避免请求无限挂起
resp = session.get(url, headers=headers, timeout=(5, 10))
resp.raise_for_status() # 状态码非 2xx 时抛出 HTTPError
return resp
except requests.exceptions.Timeout as e:
# 超时异常:连接超时或读取超时
print(f"[第 {attempt} 次] 请求超时:{e}")
except requests.exceptions.ConnectionError as e:
# 连接异常:DNS 解析失败、拒绝连接、网络不可达等
print(f"[第 {attempt} 次] 连接失败:{e}")
except requests.exceptions.HTTPError as e:
# HTTP 错误:4xx 客户端错误、5xx 服务器错误
print(f"[第 {attempt} 次] HTTP 错误:{e}")
if resp.status_code < 500:
# 4xx 属于客户端错误,重试无意义,直接抛出
raise
except requests.exceptions.RequestException as e:
# 兜底:捕获所有 requests 相关异常(如 JSON 解析失败等)
print(f"[第 {attempt} 次] 请求异常:{e}")
if attempt < max_attempts:
time.sleep(attempt) # 重试前等待,避免对服务器造成压力
# 重试耗尽仍未成功,抛出最终异常
raise requests.exceptions.RequestException(f"请求失败,已重试 {max_attempts} 次")
# 调用示例
try:
resp = fetch_with_retry("https://api.example.com/data")
print(resp.status_code)
print(resp.json())
except requests.exceptions.RequestException as e:
print(f"最终失败:{e}")
常见异常类型速查:
requests.exceptions.Timeout:请求超时,通常由网络延迟或服务器响应过慢引起。requests.exceptions.ConnectionError:连接层错误,如 DNS 解析失败、目标主机拒绝连接、网络不可达。requests.exceptions.HTTPError:服务器返回了 4xx/5xx 状态码,可通过resp.status_code判断具体原因。requests.exceptions.RequestException:所有 requests 异常的基类,适合作为兜底捕获。
4.3 使用 BeautifulSoup 解析 HTML
python
from bs4 import BeautifulSoup
html = """
<html>
<body>
<div class="article">
<h2>标题一</h2>
<p>内容一</p>
</div>
<div class="article">
<h2>标题二</h2>
<p>内容二</p>
</div>
</body>
</html>
"""
soup = BeautifulSoup(html, "html.parser")
for article in soup.select(".article"):
title = article.find("h2").text
content = article.find("p").text
print(f"标题:{title},内容:{content}")
4.5 实战:爬取新闻列表
将前面学到的 Requests 与 BeautifulSoup 结合起来,完成一个完整的实战案例:抓取新闻列表的标题与链接,支持分页翻页、数据清洗,并最终保存为 CSV 文件。
python
import csv
import time
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
# 1. 请求头:模拟真实浏览器,降低被反爬拦截的概率
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
BASE_URL = "https://news.example.com" # 目标站点(示例域名)
LIST_PATH = "/list" # 列表页路径
def fetch_page(page: int) -> str | None:
"""抓取指定页码的 HTML 源码,失败时返回 None"""
url = f"{BASE_URL}{LIST_PATH}?page={page}"
try:
resp = requests.get(url, headers=headers, timeout=(5, 10))
resp.raise_for_status() # 非 2xx 状态码抛出异常
resp.encoding = resp.apparent_encoding # 自动识别网页编码,避免中文乱码
return resp.text
except requests.exceptions.RequestException as e:
print(f"[第 {page} 页] 请求失败:{e}")
return None
def parse_news(html: str) -> list[dict]:
"""解析 HTML,提取新闻标题与链接,并做数据清洗"""
soup = BeautifulSoup(html, "html.parser")
news_list = []
# 2. 定位新闻条目容器:假设每条新闻在 <li class="news-item"> 中
for item in soup.select("li.news-item"):
a_tag = item.find("a") # 找到标题链接
if not a_tag:
continue
# 3. 提取标题并清洗:去除首尾空白、合并多余空格
title = a_tag.get_text(strip=True)
title = " ".join(title.split())
# 4. 提取链接:相对路径转为绝对 URL
href = a_tag.get("href", "")
link = urljoin(BASE_URL, href)
# 5. 过滤无效数据:跳过空标题或空链接
if title and link:
news_list.append({"title": title, "link": link})
return news_list
def save_to_csv(news_list: list[dict], filename: str = "news.csv") -> None:
"""将新闻数据写入 CSV 文件,UTF-8 编码并带表头"""
with open(filename, "w", newline="", encoding="utf-8-sig") as f:
writer = csv.DictWriter(f, fieldnames=["title", "link"])
writer.writeheader() # 写入表头
writer.writerows(news_list) # 批量写入数据行
print(f"已保存 {len(news_list)} 条新闻到 {filename}")
def crawl_news(max_pages: int = 3) -> list[dict]:
"""主流程:循环翻页抓取,聚合所有页面的新闻"""
all_news = []
for page in range(1, max_pages + 1):
html = fetch_page(page)
if html is None:
continue
page_news = parse_news(html)
print(f"[第 {page} 页] 解析到 {len(page_news)} 条新闻")
all_news.extend(page_news)
# 6. 礼貌抓取:每页之间休眠 1 秒,避免对服务器造成压力
time.sleep(1)
return all_news
# 运行示例:抓取前 3 页新闻并保存
if __name__ == "__main__":
news = crawl_news(max_pages=3)
save_to_csv(news)
关键点说明:
- 分页处理 :通过
?page=N参数循环翻页,max_pages控制抓取深度,避免无限抓取。 - 数据清洗 :用
get_text(strip=True)去除首尾空白,再用" ".join(title.split())合并多余空格;用urljoin把相对链接补全为绝对地址。 - 编码处理 :
resp.apparent_encoding自动识别网页编码,防止中文标题乱码。 - CSV 存储 :使用
utf-8-sig编码写入,Excel 打开时中文不会乱码;newline=""避免 Windows 下出现空行。 - 礼貌抓取 :每页之间
time.sleep(1),遵守爬虫伦理,降低对目标服务器的压力。
4.4 爬虫伦理与合规
4.5 常见反爬策略与应对
实际爬虫开发中,目标网站常通过多种手段限制爬虫访问。下面用一张表格对比三种最常见的反爬手段及对应的 Python 解决方案:
| 反爬手段 | 原理 | 常见表现 | Python 解决方案 |
|---|---|---|---|
| User-Agent 检测 | 服务器校验请求头中的 User-Agent,识别非浏览器请求 | 返回 403、验证码或空数据 | requests 伪装浏览器头部 |
| IP 频率限制 | 统计同一 IP 的请求频率,超限后封禁或限流 | 请求被拒绝、返回 429 | 代理池轮换 IP |
| 动态渲染 | 页面数据由 JavaScript 异步加载,直接请求拿不到内容 | HTML 源码中无目标数据 | Selenium / Playwright 渲染 |
应对 User-Agent 检测:在请求头中伪装成真实浏览器,并定期更换 UA 字符串:
python
import requests
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36"
}
resp = requests.get("https://example.com", headers=headers, timeout=10)
print(resp.status_code)
应对 IP 频率限制:维护一个代理池,每次请求随机轮换 IP,降低单 IP 被封风险:
python
import random
import requests
proxies_pool = [
{"http": "http://proxy1:8080", "https": "http://proxy1:8080"},
{"http": "http://proxy2:8080", "https": "http://proxy2:8080"},
]
proxy = random.choice(proxies_pool)
resp = requests.get("https://example.com", proxies=proxy, timeout=10)
print(resp.status_code)
应对动态渲染:使用 Playwright 驱动无头浏览器,等待页面 JS 执行完成后再提取数据:
python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("https://example.com", wait_until="networkidle")
html = page.content() # 此时已包含 JS 渲染后的完整内容
browser.close()
爬虫开发必须遵守 robots.txt 协议,控制请求频率,尊重目标网站的版权与用户隐私,避免对服务器造成压力。
5. 人工智能 / 大模型应用
5.1 机器学习基础
python
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
# 加载数据
iris = load_iris()
X, y = iris.data, iris.target
# 划分训练集与测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 训练模型
model = RandomForestClassifier(n_estimators=100)
model.fit(X_train, y_train)
# 预测与评估
y_pred = model.predict(X_test)
print(f"准确率:{accuracy_score(y_test, y_pred):.2f}")
5.2 深度学习入门
python
import torch
import torch.nn as nn
# 定义一个简单的神经网络
class SimpleNet(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(784, 128)
self.fc2 = nn.Linear(128, 10)
self.relu = nn.ReLU()
def forward(self, x):
x = self.relu(self.fc1(x))
x = self.fc2(x)
return x
model = SimpleNet()
print(model)
5.3 大模型应用开发
大模型应用开发的核心是提示词工程(Prompt Engineering)与检索增强生成(RAG):
python
from openai import OpenAI
client = OpenAI()
def chat_with_model(prompt: str) -> str:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "你是一个乐于助人的中文助手。"},
{"role": "user", "content": prompt}
],
temperature=0.7
)
return response.choices[0].message.content
# 调用示例
result = chat_with_model("请用一句话介绍 Python 的优势")
print(result)
在实际调用 OpenAI API 时,经常会遇到一些典型错误。下面列出 3 个最常见的问题及对应的排查思路与代码片段:
错误 1:认证失败(AuthenticationError)
现象 :抛出 openai.AuthenticationError,提示 Invalid API key provided 或 Incorrect API key provided。
原因:API Key 缺失、拼写错误、已过期或未正确设置环境变量。
解决方案:检查环境变量是否已正确配置,并确认 Key 有效。
python
import os
from openai import OpenAI
# 1. 优先从环境变量读取,避免硬编码泄露密钥
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
raise ValueError("未检测到 OPENAI_API_KEY,请先设置环境变量")
client = OpenAI(api_key=api_key)
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "你好"}]
)
print(response.choices[0].message.content)
except openai.AuthenticationError as e:
print(f"认证失败:请检查 API Key 是否正确。详情:{e}")
错误 2:速率限制(RateLimitError)
现象 :抛出 openai.RateLimitError,提示 Rate limit reached 或 429 状态码。
原因:请求频率超过账号配额,或并发请求过多触发了限流。
解决方案:降低请求频率,或加入指数退避重试机制。
python
import time
from openai import OpenAI
client = OpenAI()
def chat_with_retry(prompt: str, max_retries: int = 3) -> str:
"""带指数退避重试的对话函数,应对速率限制"""
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
except openai.RateLimitError as e:
wait_time = 2 ** attempt # 指数退避:1s、2s、4s
print(f"触发速率限制,{wait_time} 秒后重试(第 {attempt + 1} 次)")
time.sleep(wait_time)
raise RuntimeError("重试多次仍被限流,请稍后再试或降低请求频率")
# 调用示例
print(chat_with_retry("请用一句话介绍 Python"))
错误 3:上下文超长(InvalidRequestError)
现象 :抛出 openai.BadRequestError 或 openai.InvalidRequestError,提示 maximum context length 或 token limit。
原因 :messages 中的总 token 数超过了模型的最大上下文窗口(如 gpt-4o-mini 为 128K)。
解决方案:对历史消息做截断,只保留最近若干轮对话。
python
from openai import OpenAI
client = OpenAI()
MAX_TOKENS = 8000 # 预留安全余量,避免触顶
def trim_history(history: list[dict], max_tokens: int = MAX_TOKENS) -> list[dict]:
"""按 token 估算截断历史消息,保留最近的对话"""
# 简单估算:1 个汉字约 1.5 token,1 个英文单词约 1.3 token
def estimate_tokens(text: str) -> int:
return int(len(text) * 1.5)
trimmed = []
total = 0
# 从最新消息往前累加,直到接近上限
for msg in reversed(history):
cost = estimate_tokens(msg["content"])
if total + cost > max_tokens:
break
trimmed.append(msg)
total += cost
# 恢复正序,并确保 system 指令始终保留在最前
trimmed.reverse()
if trimmed and trimmed[0]["role"] != "system":
trimmed.insert(0, {"role": "system", "content": "你是一个乐于助人的中文助手。"})
return trimmed
# 模拟一段很长的对话历史
history = [{"role": "user", "content": "问题" + "很长" * 2000} for _ in range(10)]
history = trim_history(history)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=history
)
print(response.choices[0].message.content)
统一异常处理:整合三种错误
在实际项目中,与其为每种错误单独写 try-except,不如封装一个统一的异常处理函数,把认证失败、速率限制、上下文超长三类错误集中处理,并统一记录日志,让代码更健壮、更易维护:
python
import logging
import time
from openai import OpenAI
# 1. 配置日志:记录错误详情,便于线上排查
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
client = OpenAI()
MAX_TOKENS = 8000 # 预留安全余量,避免触顶
def estimate_tokens(text: str) -> int:
"""简单估算 token 数:1 个汉字约 1.5 token,1 个英文单词约 1.3 token"""
return int(len(text) * 1.5)
def trim_history(history: list[dict], max_tokens: int = MAX_TOKENS) -> list[dict]:
"""按 token 估算截断历史消息,保留最近的对话,并确保 system 指令在最前"""
trimmed = []
total = 0
for msg in reversed(history):
cost = estimate_tokens(msg["content"])
if total + cost > max_tokens:
break
trimmed.append(msg)
total += cost
trimmed.reverse()
if trimmed and trimmed[0]["role"] != "system":
trimmed.insert(0, {"role": "system", "content": "你是一个乐于助人的中文助手。"})
return trimmed
def chat_with_unified_retry(prompt: str, history: list[dict] | None = None,
max_retries: int = 3) -> str:
"""统一的对话函数:整合认证失败、速率限制、上下文超长三类错误处理"""
messages = history or [{"role": "user", "content": prompt}]
for attempt in range(max_retries):
try:
# 2. 正常调用:携带完整上下文
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
temperature=0.7
)
return response.choices[0].message.content
except openai.AuthenticationError as e:
# 3. 认证失败:Key 错误,重试无意义,直接抛出并记录日志
logger.error("认证失败:请检查 OPENAI_API_KEY 是否正确。详情:%s", e)
raise
except openai.RateLimitError as e:
# 4. 速率限制:指数退避重试,等待 1s、2s、4s
wait_time = 2 ** attempt
logger.warning("触发速率限制,%.0f 秒后重试(第 %d 次)", wait_time, attempt + 1)
time.sleep(wait_time)
except (openai.BadRequestError, openai.InvalidRequestError) as e:
# 5. 上下文超长:截断历史后重试一次
logger.warning("上下文超长,正在截断历史后重试:%s", e)
messages = trim_history(messages)
if attempt == max_retries - 1:
raise
raise RuntimeError("重试多次仍失败,请检查网络或稍后再试")
# 6. 调用示例:传入一段较长的对话历史,验证统一异常处理
history = [{"role": "user", "content": "问题" + "很长" * 2000} for _ in range(10)]
try:
answer = chat_with_unified_retry("请用一句话介绍 Python", history=history)
print(answer)
except Exception as e:
logger.error("最终失败:%s", e)
处理策略说明:
- 认证失败(AuthenticationError) :属于配置性错误,重试无意义,直接抛出并记录
error级别日志,提醒开发者检查 API Key。 - 速率限制(RateLimitError) :属于临时性限流,采用指数退避 (1s、2s、4s)自动重试,并记录
warning日志。 - 上下文超长(InvalidRequestError) :属于输入过长,先调用
trim_history截断历史,再重试一次;若仍失败则抛出,避免无限循环。
小结:遇到 OpenAI API 报错时,先看异常类型再对症下药------认证失败检查 Key,速率限制做退避重试,上下文超长则截断历史。掌握这三点,就能让大模型应用更健壮。
为了帮助你更清晰地理解两者的区别与联系,下面用一张表格进行对比:
| 维度 | 提示词工程(Prompt Engineering) | 检索增强生成(RAG) |
|---|---|---|
| 定义 | 通过精心设计输入提示词,引导大模型输出更准确、更符合预期的结果 | 先从外部知识库检索相关内容,再将其作为上下文拼接给大模型,从而生成更可靠的回答 |
| 核心思想 | 挖掘并激发模型已有的知识,让模型"想得更对" | 为模型"外挂"知识库,让模型"知道得更多",弥补其知识盲区与时效性不足 |
| 适用场景 | 通用问答、文本改写、代码生成、创意写作等无需外部知识的任务 | 企业知识库问答、私有文档检索、实时信息查询、客服机器人等依赖特定知识的场景 |
| 优点 | 实现简单、成本低、迭代快,无需额外基础设施 | 答案可溯源、能引用最新或私有知识、有效缓解模型幻觉 |
| 缺点 | 受限于模型自身知识,无法回答训练数据之外或过时的问题 | 需要搭建向量数据库与检索链路,架构更复杂、维护成本更高 |
| 典型工具 | LangChain 的 PromptTemplate、OpenAI 的 messages 参数、各类提示词模板库 | LangChain、LlamaIndex、向量数据库(如 Chroma、FAISS、Milvus) |
两者并非互斥,实际项目中常组合使用:先用提示词工程设计好系统指令与输出格式,再用 RAG 注入检索到的上下文,最终让大模型给出既准确又规范的答案。
5.4 RAG 应用架构
#mermaid-svg-9M3dU9i1gt3ZTzOh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9M3dU9i1gt3ZTzOh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9M3dU9i1gt3ZTzOh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9M3dU9i1gt3ZTzOh .error-icon{fill:#552222;}#mermaid-svg-9M3dU9i1gt3ZTzOh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9M3dU9i1gt3ZTzOh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9M3dU9i1gt3ZTzOh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9M3dU9i1gt3ZTzOh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9M3dU9i1gt3ZTzOh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9M3dU9i1gt3ZTzOh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9M3dU9i1gt3ZTzOh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9M3dU9i1gt3ZTzOh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9M3dU9i1gt3ZTzOh .marker.cross{stroke:#333333;}#mermaid-svg-9M3dU9i1gt3ZTzOh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9M3dU9i1gt3ZTzOh p{margin:0;}#mermaid-svg-9M3dU9i1gt3ZTzOh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9M3dU9i1gt3ZTzOh .cluster-label text{fill:#333;}#mermaid-svg-9M3dU9i1gt3ZTzOh .cluster-label span{color:#333;}#mermaid-svg-9M3dU9i1gt3ZTzOh .cluster-label span p{background-color:transparent;}#mermaid-svg-9M3dU9i1gt3ZTzOh .label text,#mermaid-svg-9M3dU9i1gt3ZTzOh span{fill:#333;color:#333;}#mermaid-svg-9M3dU9i1gt3ZTzOh .node rect,#mermaid-svg-9M3dU9i1gt3ZTzOh .node circle,#mermaid-svg-9M3dU9i1gt3ZTzOh .node ellipse,#mermaid-svg-9M3dU9i1gt3ZTzOh .node polygon,#mermaid-svg-9M3dU9i1gt3ZTzOh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9M3dU9i1gt3ZTzOh .rough-node .label text,#mermaid-svg-9M3dU9i1gt3ZTzOh .node .label text,#mermaid-svg-9M3dU9i1gt3ZTzOh .image-shape .label,#mermaid-svg-9M3dU9i1gt3ZTzOh .icon-shape .label{text-anchor:middle;}#mermaid-svg-9M3dU9i1gt3ZTzOh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9M3dU9i1gt3ZTzOh .rough-node .label,#mermaid-svg-9M3dU9i1gt3ZTzOh .node .label,#mermaid-svg-9M3dU9i1gt3ZTzOh .image-shape .label,#mermaid-svg-9M3dU9i1gt3ZTzOh .icon-shape .label{text-align:center;}#mermaid-svg-9M3dU9i1gt3ZTzOh .node.clickable{cursor:pointer;}#mermaid-svg-9M3dU9i1gt3ZTzOh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9M3dU9i1gt3ZTzOh .arrowheadPath{fill:#333333;}#mermaid-svg-9M3dU9i1gt3ZTzOh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9M3dU9i1gt3ZTzOh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9M3dU9i1gt3ZTzOh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9M3dU9i1gt3ZTzOh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9M3dU9i1gt3ZTzOh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9M3dU9i1gt3ZTzOh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9M3dU9i1gt3ZTzOh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9M3dU9i1gt3ZTzOh .cluster text{fill:#333;}#mermaid-svg-9M3dU9i1gt3ZTzOh .cluster span{color:#333;}#mermaid-svg-9M3dU9i1gt3ZTzOh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9M3dU9i1gt3ZTzOh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9M3dU9i1gt3ZTzOh rect.text{fill:none;stroke-width:0;}#mermaid-svg-9M3dU9i1gt3ZTzOh .icon-shape,#mermaid-svg-9M3dU9i1gt3ZTzOh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9M3dU9i1gt3ZTzOh .icon-shape p,#mermaid-svg-9M3dU9i1gt3ZTzOh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9M3dU9i1gt3ZTzOh .icon-shape .label rect,#mermaid-svg-9M3dU9i1gt3ZTzOh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9M3dU9i1gt3ZTzOh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9M3dU9i1gt3ZTzOh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9M3dU9i1gt3ZTzOh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户提问
向量化
向量数据库检索
拼接上下文
大模型生成回答
返回结果
下面是一个基于 LangChain + Chroma 的完整 RAG 实现,覆盖从文档加载到最终回答的全流程:
python
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
# 1. 文档加载:读取本地文本文件
loader = TextLoader("knowledge_base.txt", encoding="utf-8")
documents = loader.load()
# 2. 文本切分:按语义边界切分为小块,便于向量化与检索
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块最大字符数
chunk_overlap=50 # 相邻块重叠,避免切断语义
)
chunks = text_splitter.split_documents(documents)
print(f"共切分为 {len(chunks)} 个文本块")
# 3. 向量化存储:将文本块转为向量并写入 Chroma 向量数据库
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db" # 本地持久化目录
)
# 4. 持久化:显式调用 persist() 将向量库写入磁盘,确保重启后数据不丢失
vectorstore.persist()
print("向量数据库已持久化到 ./chroma_db")
# 5. 检索器构建:将向量库封装为检索器,按相似度召回最相关的文本块
retriever = vectorstore.as_retriever(
search_type="similarity", # 相似度检索
search_kwargs={"k": 3} # 召回 Top-3 文本块
)
# 6. 拼接上下文调用大模型:构建 RAG 问答链
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.3)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=retriever,
chain_type="stuff", # 将检索到的文档直接拼接进提示词
return_source_documents=True # 返回引用来源,便于溯源
)
# 7. 发起提问,模型基于检索到的知识作答
question = "公司年假政策是怎样的?"
result = qa_chain.invoke({"query": question})
print("回答:", result["result"])
print("\n引用来源:")
for doc in result["source_documents"]:
print("-", doc.page_content[:80], "...")
- 文档加载 :
TextLoader读取本地文本;生产环境可替换为PyPDFLoader、WebBaseLoader等加载 PDF、网页等不同来源。 - 文本切分 :
RecursiveCharacterTextSplitter按段落、句子等语义边界递归切分,chunk_overlap保留上下文衔接,避免关键信息被切断。 - 向量化存储 :
OpenAIEmbeddings将文本转为高维向量,Chroma.from_documents一次性完成向量化并写入本地向量库,persist_directory实现持久化。 - 相似度检索 :
as_retriever(search_kwargs={"k": 3})召回与问题最相关的 Top-3 文本块,作为大模型的参考上下文。 - 拼接上下文调用大模型 :
RetrievalQA自动完成「检索 → 拼接上下文 → 调用大模型」的串联,return_source_documents=True可返回引用来源,便于答案溯源。
6. 综合实战:构建一个智能问答 API
将上述知识串联起来,构建一个基于 FastAPI + 大模型的智能问答服务:
python
from fastapi import FastAPI
from pydantic import BaseModel
from openai import OpenAI
app = FastAPI()
client = OpenAI()
# 1. 请求体设计:携带会话 ID 与用户提问
class ChatRequest(BaseModel):
session_id: str # 会话 ID,用于区分不同用户的对话
question: str # 用户本次提问的内容
# 2. 对话历史存储:使用内存字典保存每个会话的消息记录
# 生产环境可替换为 Redis 或数据库,实现持久化
conversations: dict[str, list[dict]] = {}
def get_history(session_id: str) -> list[dict]:
"""获取指定会话的历史消息,若不存在则初始化空列表"""
if session_id not in conversations:
conversations[session_id] = [
{"role": "system", "content": "你是一个乐于助人的中文助手。"}
]
return conversations[session_id]
@app.post("/chat")
def chat(req: ChatRequest):
# 3. 取出该会话的历史消息,追加用户提问
history = get_history(req.session_id)
history.append({"role": "user", "content": req.question})
# 4. 调用大模型生成回答,携带完整上下文
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=history,
temperature=0.7
)
answer = response.choices[0].message.content
# 5. 将模型回答追加到历史,供下一轮对话使用
history.append({"role": "assistant", "content": answer})
return {"session_id": req.session_id, "answer": answer}
7. 总结
本文系统梳理了 Python 在四大核心领域的进阶语法与应用:
- Web 后端开发:掌握 FastAPI 的类型注解与异步特性。
- 数据分析与可视化:熟练运用 Pandas 与 Matplotlib 处理数据。
- 网络爬虫:理解请求、解析、提取、存储的完整链路。
- 人工智能 / 大模型应用:从传统机器学习到提示词工程与 RAG。
Python 的生态优势在于各领域之间的无缝衔接------你可以用爬虫采集数据,用 Pandas 清洗分析,用 Matplotlib 可视化,最后用 FastAPI 将模型能力封装成服务。掌握这条完整链路,你就能真正发挥 Python 的生产力。
8. 参考资料
以下是本文涉及的核心库与框架的官方文档链接,供你进一步深入学习:
- FastAPI :https://fastapi.tiangolo.com/ ------ 官方文档,涵盖类型注解、异步接口、依赖注入与 OpenAPI 文档生成等完整教程。
- Pandas :https://pandas.pydata.org/docs/ ------ 官方文档,包含 DataFrame 操作、数据清洗、分组聚合与时间序列处理等详细说明。
- BeautifulSoup :https://www.crummy.com/software/BeautifulSoup/bs4/doc/ ------ 官方文档,介绍 HTML/XML 解析、选择器与遍历 API 的用法。
- scikit-learn :https://scikit-learn.org/stable/ ------ 官方文档,涵盖数据预处理、模型训练、评估与调参等机器学习全流程。
- PyTorch :https://pytorch.org/docs/ ------ 官方文档,包含张量操作、神经网络模块、自动求导与模型训练等深度学习内容。
- OpenAI :https://platform.openai.com/docs/ ------ 官方文档,介绍大模型 API 调用、提示词工程与对话补全等接口用法。
9. 总结与参考资料
9.1 全文总结
本文系统梳理了 Python 在四大核心领域的进阶语法与应用。Web 后端开发 方面,重点掌握 FastAPI 的类型注解、异步特性与三大框架的选型思路;数据分析与可视化 方面,熟练运用 Pandas 进行数据清洗与聚合,配合 Matplotlib / Seaborn 完成可视化呈现;网络爬虫 方面,理解「发送请求 → 解析响应 → 提取数据 → 存储数据」的完整链路,并重视异常处理、重试机制与爬虫伦理;人工智能 / 大模型应用方面,从传统机器学习、深度学习入门,进阶到提示词工程、RAG 检索增强生成与 OpenAI API 的健壮调用。建议的学习路径是:先夯实 Web 与数据分析基础,再通过爬虫打通数据采集,最后将模型能力封装为服务,形成完整闭环。
9.2 参考资料
官方文档
- FastAPI :https://fastapi.tiangolo.com/ ------ 官方文档,涵盖类型注解、异步接口、依赖注入与 OpenAPI 文档生成等完整教程。
- Pandas :https://pandas.pydata.org/docs/ ------ 官方文档,包含 DataFrame 操作、数据清洗、分组聚合与时间序列处理等详细说明。
- Requests :https://requests.readthedocs.io/ ------ 官方文档,介绍 HTTP 请求、会话管理、异常处理与重试机制等用法。
- BeautifulSoup :https://www.crummy.com/software/BeautifulSoup/bs4/doc/ ------ 官方文档,介绍 HTML/XML 解析、选择器与遍历 API 的用法。
- scikit-learn :https://scikit-learn.org/stable/ ------ 官方文档,涵盖数据预处理、模型训练、评估与调参等机器学习全流程。
- PyTorch :https://pytorch.org/docs/ ------ 官方文档,包含张量操作、神经网络模块、自动求导与模型训练等深度学习内容。
- OpenAI :https://platform.openai.com/docs/ ------ 官方文档,介绍大模型 API 调用、提示词工程与对话补全等接口用法。
- LangChain :https://python.langchain.com/docs/ ------ 官方文档,涵盖文档加载、文本切分、向量检索与 RAG 应用构建等完整指南。
推荐书籍
- 《Python 编程:从入门到实践(第 3 版)》(Eric Matthes 著)------ 系统讲解 Python 基础与 Web 应用开发,适合建立扎实的编程功底。
- 《利用 Python 进行数据分析(第 2 版)》(Wes McKinney 著)------ Pandas 作者亲著,深入讲解 NumPy、Pandas 与数据清洗、聚合、可视化的实战技巧。
- 《Python 网络数据采集》(Ryan Mitchell 著)------ 全面覆盖 Requests、BeautifulSoup、Scrapy 等爬虫工具,并强调爬虫伦理与合规。
- 《机器学习实战:基于 Scikit-Learn、Keras 和 TensorFlow(第 3 版)》(Aurélien Géron 著)------ 从传统机器学习到深度学习的系统实战指南,与本文第 5 章内容高度衔接。