从零搭建大模型与智能体平台 - 完整技术详解
本文档系统讲解从底层大语言模型到上层智能体应用的完整技术栈。
逐行注释版:每行代码、每个关键字、每个Python语法都标注了详细作用和使用方法。
📑 目录
一、大语言模型基础
1.1 什么是大语言模型
大语言模型(LLM) 是基于深度学习的自然语言处理模型,具备以下特点:
| 特点 | 说明 |
|---|---|
| 规模巨大 | 参数量从数十亿到数千亿 |
| 预训练 | 在大规模文本上自监督学习 |
| 通用性 | 一个模型处理多种任务 |
| 涌现能力 | 规模到一定程度后出现新能力 |
1.2 Transformer架构
Transformer是所有现代LLM的基础架构。
整体结构:
输入文本
↓
[Tokenizer] → token IDs
↓
[Embedding] → 向量
↓
[Transformer Block] × N
├─ Multi-Head Self-Attention
├─ Feed-Forward Network
├─ Layer Norm
└─ Residual Connection
↓
[Output Layer] → 词汇表概率分布
↓
采样 → 输出token
1.2.1 自注意力机制(逐行详解)
python
import torch # PyTorch深度学习框架
import torch.nn.functional as F # PyTorch函数式API(softmax、relu等)
import math # 数学函数库(用sqrt)
def self_attention(Q, K, V, mask=None):
"""
缩放点积注意力机制
Args:
Q: 查询矩阵,shape=[batch, seq_len, d_k]
K: 键矩阵,shape=[batch, seq_len, d_k]
V: 值矩阵,shape=[batch, seq_len, d_v]
mask: 掩码,shape=[batch, seq_len, seq_len]
Returns:
加权求和后的输出,shape=[batch, seq_len, d_v]
"""
d_k = Q.size(-1) # 获取Q最后一维大小,即每个头的维度
# ========== 步骤1:计算注意力分数 ==========
# torch.matmul: 矩阵乘法
# K.transpose(-2, -1): 交换K的最后两维(seq_len × d_k → d_k × seq_len)
# /math.sqrt(d_k): 缩放因子,防止点积过大导致softmax梯度消失
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k)
# ========== 步骤2:应用掩码(可选)==========
# masked_fill: 用值填充满足条件的元素
# mask == 0: 掩码为0的位置
# -1e9: 负无穷大,softmax后概率接近0
if mask is not None: # 如果传入了掩码
scores = scores.masked_fill(mask == 0, -1e9)
# ========== 步骤3:softmax归一化 ==========
# F.softmax: softmax函数,把分数转为概率分布
# dim=-1: 对最后一维做softmax(每个query对所有key的概率)
attention_weights = F.softmax(scores, dim=-1)
# ========== 步骤4:加权求和 ==========
# 用注意力权重对V加权求和
# shape: [batch, seq_len, d_v]
output = torch.matmul(attention_weights, V)
return output # 返回注意力输出
# 关键概念详解:
# Q(Query)查询:当前token的"查询向量",代表"我在找什么"
# K(Key)键:所有token的"键向量",代表"我是什么"
# V(Value)值:所有token的"值向量",代表"我提供什么信息"
#
# 为什么要除以sqrt(d_k)?
# - 当d_k=64时,点积的方差约为64
# - 不缩放:softmax输入值很大,梯度接近0(梯度消失)
# - 除以8:方差变为1,softmax梯度健康
关键语法详解:
| 语法 | 作用 |
|---|---|
import torch |
导入PyTorch深度学习框架 |
torch.nn.functional |
函数式API模块 |
def |
定义函数关键字 |
Q, K, V, mask=None |
位置参数+默认参数(mask默认为None) |
"""...""" |
三引号文档字符串 |
Q.size(-1) |
获取tensor的最后一维大小 |
torch.matmul(A, B) |
矩阵乘法 |
.transpose(-2, -1) |
交换最后两个维度(-1表示最后一维,-2表示倒数第二维) |
math.sqrt(d_k) |
求平方根 |
if ... is not None |
判断不是None(区别于 if mask:) |
.masked_fill(cond, value) |
条件填充:满足cond的位置填value |
F.softmax(x, dim=-1) |
softmax函数,转概率分布 |
dim=-1 |
-1表示最后一维(更通用,比写具体数字好) |
1.2.2 多头注意力(逐行详解)
python
class MultiHeadAttention(torch.nn.Module):
"""
多头注意力机制
将Q/K/V拆成多个头并行计算,每个头关注不同的特征子空间
"""
def __init__(self, d_model, num_heads):
"""
初始化多头注意力
Args:
d_model: 模型维度(如512)
num_heads: 注意力头数(如8)
"""
super().__init__() # 调用父类nn.Module的__init__
assert d_model % num_heads == 0 # 断言:维度必须能整除头数
# 保存为实例属性
self.num_heads = num_heads # 头数
self.d_model = d_model # 模型维度
self.d_k = d_model // num_heads # 每个头的维度(整数除法)
# ========== 定义4个线性变换层 ==========
# torch.nn.Linear(in_features, out_features, bias=True)
# 实现 y = x·W + b
self.W_q = torch.nn.Linear(d_model, d_model) # Q的线性投影
self.W_k = torch.nn.Linear(d_model, d_model) # K的线性投影
self.W_v = torch.nn.Linear(d_model, d_model) # V的线性投影
self.W_o = torch.nn.Linear(d_model, d_model) # 输出的线性投影
def forward(self, x, mask=None):
"""
前向传播
Args:
x: 输入张量,shape=[batch_size, seq_len, d_model]
mask: 注意力掩码
"""
batch_size = x.size(0) # 第0维是batch_size(一次处理的样本数)
# ========== 步骤1:线性投影 + 分头 ==========
# .view: 重塑tensor形状(要求内存连续)
# -1表示该维度自动计算
# transpose(1, 2): 交换第1、2维
Q = self.W_q(x).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
K = self.W_k(x).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
V = self.W_v(x).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
# Q/K/V shape: [batch, num_heads, seq_len, d_k]
# ========== 步骤2:计算注意力 ==========
# 每个头独立计算自注意力
attn = self_attention(Q, K, V, mask)
# attn shape: [batch, num_heads, seq_len, d_k]
# ========== 步骤3:合并多头 ==========
# transpose(1, 2): 交换回 [batch, seq_len, num_heads, d_k]
# .contiguous(): 让tensor在内存中连续存储(view前必须)
# .view: 合并num_heads和d_k为d_model
attn = attn.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
# attn shape: [batch, seq_len, d_model]
# ========== 步骤4:输出投影 ==========
return self.W_o(attn) # 最后的线性变换
# 使用示例
attention = MultiHeadAttention(d_model=512, num_heads=8)
input_tensor = torch.randn(32, 100, 512) # [batch=32, seq=100, dim=512]
output = attention(input_tensor)
# output shape: [32, 100, 512]
关键语法详解:
| 语法 | 作用 |
|---|---|
class X(torch.nn.Module): |
继承PyTorch模型基类 |
def __init__(self, ...): |
构造函数 |
super().__init__() |
调用父类初始化(必须) |
assert 条件 |
断言,条件为假时抛AssertionError |
d_model % num_heads == 0 |
取模运算 |
d_model // num_heads |
整数除法(向下取整) |
self.xxx = ... |
定义实例属性 |
torch.nn.Linear(in, out) |
全连接层 y = x·W + b |
def forward(self, x): |
PyTorch前向传播方法(约定名称) |
x.size(0) |
获取第0维大小 |
.view(a, b, c) |
改变tensor形状,-1表示自动计算 |
.transpose(1, 2) |
交换两个维度(不复制数据) |
.contiguous() |
转连续存储(view前必须) |
torch.randn(...) |
生成正态分布随机tensor |
1.3 Tokenization
python
from transformers import AutoTokenizer
# 加载预训练tokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt2")
# 编码:文本 → token IDs
text = "Hello, world!"
tokens = tokenizer.encode(text)
print(tokens) # [15496, 11, 995, 0]
# 解码:token IDs → 文本
decoded = tokenizer.decode(tokens)
print(decoded) # "Hello, world!"
# 批量编码(带特殊token)
batch = tokenizer(["Hello", "World"], padding=True, return_tensors="pt")
# padding=True: 自动填充到等长
# return_tensors="pt": 返回PyTorch tensor
逐行详解:
| 语法 | 作用 |
|---|---|
from transformers import AutoTokenizer |
从HuggingFace transformers库导入 |
AutoTokenizer.from_pretrained(...) |
根据模型名自动加载对应的tokenizer |
tokenizer.encode(text) |
文本 → token ID列表 |
tokenizer.decode(tokens) |
token ID列表 → 文本 |
tokenizer([...], padding=True, return_tensors="pt") |
批量编码+填充+返回tensor |
padding=True |
短句自动填充到和最长句一样 |
return_tensors="pt" |
"pt"=PyTorch,"tf"=TensorFlow,"np"=NumPy |
1.4 位置编码
现代LLM主要使用 RoPE(Rotary Position Embedding),Llama、Qwen都采用此方案。
python
# 概念示意(实际实现更复杂)
def apply_rope(x, position_ids):
"""
RoPE:通过旋转让位置信息融入注意力分数
核心思想:每对相邻维度作为一个复数,做旋转
旋转角度与位置成正比
"""
# x shape: [batch, seq, num_heads, head_dim]
# position_ids shape: [batch, seq]
# 计算每个位置对应的旋转角度
freqs = torch.outer(position_ids.float(), 1.0 / (10000 ** (torch.arange(0, head_dim, 2).float() / head_dim)))
# torch.outer: 计算外积
# 10000 ** (...): 频率衰减因子
# 生成旋转矩阵
sin = freqs.sin() # 形状: [seq, head_dim/2]
cos = freqs.cos()
# 应用旋转...
return rotated_x
为什么需要位置编码:
- Transformer本身是置换不变的(打乱token顺序输出不变)
- 必须注入位置信息才能理解语序
- RoPE的优势:相对位置编码 + 长度外推性好
二、模型训练与微调
2.1 预训练
训练目标:Next Token Prediction(下一个token预测)
python
# 训练数据示例
texts = [
"今天天气很好,适合出去",
"机器学习是人工智能的子集",
"深度学习使用神经网络"
]
# 训练目标:给定前面的token,预测下一个token
# "今天" → "天气"
# "今天天气" → "很好"
# ...
2.2 微调方法详解
2.2.1 DeepSpeed配置(逐行详解)
python
import deepspeed # 微软的分布式训练框架
ds_config = {
"train_batch_size": 32, # 全局batch size(所有GPU的micro-batch总和)
"gradient_accumulation_steps": 4, # 梯度累积步数(每4个micro-batch更新一次)
"fp16": { # 半精度训练配置
"enabled": True # 启用FP16混合精度(节省50%显存)
},
"zero_optimization": { # ZeRO显存优化配置
"stage": 3, # ZeRO阶段3:分片优化器+梯度+参数
"offload_optimizer": { # 把优化器状态卸载到CPU
"device": "cpu" # 卸载到CPU内存
},
"offload_param": { # 把参数也卸载到CPU
"device": "cpu"
}
}
}
# 初始化DeepSpeed引擎
model_engine, optimizer, _, scheduler = deepspeed.initialize(
model=model, # 要训练的模型
config=ds_config # 配置字典
)
# 返回值说明:
# model_engine: 包装后的模型(分布式、混合精度)
# optimizer: 优化器
# _: 第二个返回值未使用(下划线表示忽略)
# scheduler: 学习率调度器
逐项解释:
| 配置项 | 作用 | 推荐值 |
|---|---|---|
train_batch_size |
全局batch_size = micro_batch × grad_accum × GPU数 | 32-128 |
gradient_accumulation_steps |
累计多少个micro-batch再更新一次 | 4-8 |
fp16.enabled |
是否使用FP16混合精度 | True(省显存) |
zero_optimization.stage |
ZeRO分片级别(0-3) | 显存不够时调高 |
offload_optimizer |
把优化器状态(如Adam动量)卸载到CPU | 显存紧张时启用 |
offload_param |
把模型参数卸载到CPU | 显存紧张时启用 |
ZeRO各阶段显存节省:
7B模型(FP16)= 14GB
Adam优化器状态 = 28GB(参数+梯度+动量)
ZeRO-0: 14 + 28 = 42GB
ZeRO-1: 14 + 28/N = 节省优化器状态
ZeRO-2: 14 + 14/N + 14/N = 再节省梯度
ZeRO-3: 14/N + 14/N + 14/N = 全部分片
N=8卡时,每卡只需 ~1.75GB
2.2.2 LoRA(逐行详解)
python
from peft import LoraConfig, get_peft_model, TaskType
# LoRA配置
lora_config = LoraConfig(
r=8, # 秩(rank),越小越省显存
lora_alpha=32, # 缩放因子 ΔW·(alpha/r)
target_modules=["q_proj", "v_proj"], # 应用LoRA的模块名
lora_dropout=0.05, # LoRA层的dropout(防过拟合)
bias="none", # 是否训练bias("none"/"all"/"lora_only")
task_type=TaskType.CAUSAL_LM # 任务类型:因果语言模型
)
# 把原模型包装为PEFT模型
model = get_peft_model(model, lora_config)
model.print_trainable_parameters() # 打印可训练参数统计
# 输出示例: trainable params: 2,097,152 || all params: 7,244,179,968 || trainable%: 0.029
LoRA原理:
python
# 原始权重 W (d×d) 冻结
# 增量 ΔW = A·B (A: d×r, B: r×d, r<<d)
# 前向: y = (W + ΔW)x = Wx + ABx
#
# 参数量对比:
# 原始: d × d = 4096 × 4096 = 16,777,216
# LoRA: d × r + r × d = 4096×8 + 8×4096 = 65,536
# 压缩比: 65,536 / 16,777,216 ≈ 0.39%
参数详解:
| 参数 | 作用 | 推荐值 |
|---|---|---|
r |
低秩矩阵的秩 | 4-64,越小越省显存但表达能力下降 |
lora_alpha |
缩放因子 | 通常设为 2*r |
target_modules |
应用LoRA的层 | 一般选Q和V的投影层 |
lora_dropout |
防止过拟合 | 0.05-0.1 |
bias |
bias训练策略 | "none"最常用 |
task_type |
任务类型 | CAUSAL_LM / SEQ_2_SEQ_LM等 |
2.2.3 QLoRA(逐行详解)
python
from transformers import BitsAndBytesConfig, AutoModelForCausalLM
# 4-bit量化配置
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, # 启用4-bit量化加载
bnb_4bit_quant_type="nf4", # 量化类型:NormalFloat 4
bnb_4bit_compute_dtype=torch.float16, # 计算时转回FP16
bnb_4bit_use_double_quant=True, # 二次量化(更省显存)
bnb_4bit_quant_storage=torch.uint8 # 量化参数存储类型
)
# 加载量化模型
model = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen2.5-7B", # 模型路径或HF模型ID
quantization_config=bnb_config, # 应用量化配置
device_map="auto" # 自动分配模型到可用设备
)
逐行详解:
| 语法 | 作用 |
|---|---|
BitsAndBytesConfig(...) |
bitsandbytes库的量化配置类 |
load_in_4bit=True |
是否启用4-bit量化 |
bnb_4bit_quant_type="nf4" |
量化类型(NormalFloat 4) |
bnb_4bit_compute_dtype=torch.float16 |
计算时的数据类型 |
bnb_4bit_use_double_quant=True |
二次量化(对量化常数也量化) |
AutoModelForCausalLM.from_pretrained(...) |
加载因果语言模型 |
device_map="auto" |
自动分配到GPU/CPU |
QLoRA三件套:
- 4-bit量化:把模型权重从FP16压缩到INT4
- LoRA:在量化基础上加可训练的低秩增量
- Double Quant:对量化常数也做量化,再省1-2GB
显存对比:
| 方法 | 7B模型显存 |
|---|---|
| FP16 全量 | 14 GB |
| FP16 + LoRA | 14 GB + 0.1 GB |
| INT8 + LoRA | 7 GB + 0.1 GB |
| INT4 + LoRA(QLoRA) | 4 GB + 0.1 GB |
2.3 RLHF对齐
三步流程:
SFT(监督微调)→ RM(奖励模型)→ PPO(强化学习)
python
from trl import PPOTrainer, PPOConfig
# PPO配置
ppo_config = PPOConfig(
model_name="sft_model", # SFT后的模型
learning_rate=1.41e-5, # 学习率(比SFT小)
batch_size=16, # 批大小
mini_batch_size=4 # 小批大小
)
# 创建PPO训练器
ppo_trainer = PPOTrainer(
config=ppo_config, # 配置
model=sft_model, # 策略模型
ref_model=ref_model, # 参考模型(防止偏离太远)
tokenizer=tokenizer, # 分词器
reward_model=reward_model # 奖励模型
)
# 训练循环
for prompt in prompts:
response = ppo_trainer.generate(prompt) # 生成回答
reward = reward_model(prompt, response) # 计算奖励
stats = ppo_trainer.step(prompt, response, reward) # 优化
三、推理服务搭建
3.1 推理框架对比
| 框架 | 特点 | 适用场景 |
|---|---|---|
| vLLM | 高吞吐,PagedAttention | 生产级服务 |
| TGI | HuggingFace官方 | 快速部署 |
| SGLang | 结构化生成 | 复杂prompt |
| llama.cpp | CPU/GPU混合 | 本地部署 |
| Ollama | 一键运行 | 个人使用 |
| Triton | NVIDIA官方 | 极致性能 |
3.2 vLLM部署(逐行详解)
python
from vllm import LLM, SamplingParams
# ========== 初始化LLM推理引擎 ==========
llm = LLM(
model="Qwen/Qwen2.5-7B-Instruct", # 模型路径或HF ID
tensor_parallel_size=2, # 张量并行度(用2块GPU)
gpu_memory_utilization=0.9, # 显存利用率上限(90%)
max_model_len=4096, # 最大上下文长度(token数)
dtype="float16", # 数据类型(fp16/bf16)
trust_remote_code=True # 是否信任远程代码(自定义模型用)
)
# ========== 配置采样参数 ==========
sampling_params = SamplingParams(
temperature=0.7, # 温度:0=贪婪,1=随机,越大越发散
top_p=0.9, # 核采样:只采样累积概率达90%的token
top_k=50, # Top-K:只从概率最高的50个中采样
max_tokens=2048, # 最大生成token数
repetition_penalty=1.1, # 重复惩罚(>1抑制重复)
stop=["<|endoftext|>"] # 停止符列表
)
# ========== 执行推理 ==========
prompts = ["什么是机器学习?"]
outputs = llm.generate(prompts, sampling_params)
# 遍历结果
for output in outputs:
print(output.outputs[0].text) # 生成的文本
print(f"生成了 {len(output.outputs[0].token_ids)} 个token")
SamplingParams详解:
| 参数 | 作用 | 推荐值 |
|---|---|---|
temperature |
控制随机性,0=确定,1=随机 | 0.7-1.0 |
top_p |
核采样阈值 | 0.9-0.95 |
top_k |
只采样概率最高的k个 | 50 |
max_tokens |
生成上限 | 2048 |
repetition_penalty |
重复惩罚(>1抑制重复) | 1.05-1.2 |
stop |
遇到这些字符串就停止 | 模型特殊token |
vLLM为什么快:
- PagedAttention:KV Cache分页管理,类似OS虚拟内存
- Continuous Batching:动态插入新请求,GPU不空转
- Prefix Caching:相同前缀只计算一次
3.3 OpenAI兼容API(逐行详解)
python
from fastapi import FastAPI # FastAPI Web框架
from pydantic import BaseModel # 数据验证基类
from vllm import LLM, SamplingParams
# 创建FastAPI应用
app = FastAPI() # 应用实例
llm = LLM(model="Qwen/Qwen2.5-7B-Instruct")
# ========== 定义请求体数据模型 ==========
class ChatRequest(BaseModel):
"""
Pydantic自动验证:
- 类型不匹配返回422错误
- 自动生成OpenAPI文档
- IDE智能提示
"""
model: str # 必填:模型名
messages: list # 必填:消息列表
temperature: float = 0.7 # 可选:温度,默认0.7
max_tokens: int = 2048 # 可选:最大token数
# ========== 工具函数 ==========
def format_messages(messages):
"""
把OpenAI格式的messages转为Qwen格式的prompt
Qwen的chat template格式:
<|im_start|>system\n{content}<|im_end|>\n
<|im_start|>user\n{content}<|im_end|>\n
<|im_start|>assistant\n
"""
prompt = "" # 初始化空字符串
for msg in messages: # 遍历每条消息
role = msg["role"] # 角色:system/user/assistant
content = msg["content"] # 内容
prompt += f"<|im_start|>{role}\n{content}<|im_end|>\n" # 拼接
prompt += "<|im_start|>assistant\n" # 引导assistant开始生成
return prompt
# ========== 定义API路由 ==========
@app.post("/v1/chat/completions") # POST路由装饰器
async def chat_completion(request: ChatRequest):
"""
OpenAI兼容的聊天补全接口
请求示例:
{
"model": "qwen",
"messages": [{"role": "user", "content": "你好"}],
"temperature": 0.7
}
"""
# 把messages转为prompt字符串
prompt = format_messages(request.messages)
# 配置采样参数
sampling_params = SamplingParams(
temperature=request.temperature,
max_tokens=request.max_tokens
)
# 调用LLM生成
outputs = llm.generate([prompt], sampling_params)
response_text = outputs[0].outputs[0].text # 提取生成的文本
# 返回OpenAI格式的响应
return {
"id": "chatcmpl-xxx",
"object": "chat.completion",
"created": 1234567890,
"model": request.model,
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": response_text
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 20,
"total_tokens": 30
}
}
逐行详解:
| 语法 | 作用 |
|---|---|
from fastapi import FastAPI |
导入FastAPI Web框架 |
app = FastAPI() |
创建应用实例 |
class X(BaseModel): |
继承Pydantic的BaseModel做数据验证 |
field: type |
必填字段类型注解 |
field: type = default |
可选字段(带默认值) |
@app.post("/path") |
装饰器:注册POST路由 |
async def func(request: X): |
异步处理函数,参数自动验证 |
return {...} |
返回dict自动转JSON |
for msg in messages: |
遍历列表 |
msg["key"] |
字典取值 |
f"...{var}..." |
f-string嵌入变量 |
3.4 推理优化技术
优化手段:
- 量化:FP16 → INT4,显存减少50-75%
- Flash Attention:加速注意力计算
- Continuous Batching:vLLM核心技术,吞吐提升3-10倍
- KV Cache优化:减少重复计算
四、智能体原理
4.1 AI Agent定义
AI Agent = LLM + 记忆 + 工具 + 规划
传统LLM: 输入 → 输出
Agent: 输入 → 思考 → 行动 → 观察 → ... → 输出
4.2 核心能力
| 能力 | 说明 |
|---|---|
| 推理 | 理解任务,拆解步骤 |
| 规划 | 制定执行计划 |
| 记忆 | 短期/长期记忆 |
| 工具使用 | 调用外部API/函数 |
| 反思 | 评估自己的输出 |
| 协作 | 多Agent配合 |
4.3 ReAct模式
Re asoning + Acting,交替进行思考和行动。
Thought 1: 我需要查询北京天气
Action 1: get_weather("北京")
Observation 1: 晴,25度
Thought 2: 用户想看明天是否适合出游
Action 2: get_weather("北京", date="明天")
Observation 2: 多云,22度
Thought 3: 根据天气给出建议
Final Answer: 明天北京多云,气温22度,适合出游
4.4 Function Calling
工作流程:
1. 用户提问
2. LLM分析,判断需要调用工具
3. 返回结构化调用请求
4. 程序执行函数
5. 将结果反馈给LLM
6. LLM基于结果生成最终回答
工具定义:
python
tools = [{
"type": "function", # 类型:function
"function": {
"name": "get_weather", # 函数名
"description": "查询指定城市的天气", # 函数描述(LLM靠这个判断何时调用)
"parameters": { # 参数定义(JSON Schema格式)
"type": "object",
"properties": {
"city": { # 参数名
"type": "string", # 参数类型
"description": "城市名" # 参数描述
}
},
"required": ["city"] # 必填参数列表
}
}
}]
4.5 RAG(检索增强生成)
RAG架构:
用户问题
↓
[向量化] → 问题向量
↓
[向量检索] → 从知识库找相关文档
↓
[Prompt组装] = 系统提示 + 检索内容 + 用户问题
↓
[LLM生成] → 基于事实的回答
完整实现(逐行详解):
python
from langchain.document_loaders import PyPDFLoader # PDF加载器
from langchain.text_splitter import RecursiveCharacterTextSplitter # 文本分片器
from langchain.embeddings import OpenAIEmbeddings # OpenAI向量模型
from langchain.vectorstores import Chroma # Chroma向量数据库
# ========== 1. 文档加载 ==========
loader = PyPDFLoader("document.pdf") # 创建PDF加载器
documents = loader.load() # 加载PDF,返回Document列表
# ========== 2. 文本分片 ==========
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每片500字符
chunk_overlap=50 # 相邻片段重叠50字符
)
chunks = text_splitter.split_documents(documents) # 切分文档
# ========== 3. 向量化 + 存储 ==========
embeddings = OpenAIEmbeddings() # OpenAI向量模型
vectorstore = Chroma.from_documents(
documents=chunks, # 文档列表
embedding=embeddings # 向量化函数
)
# ========== 4. 检索 ==========
retriever = vectorstore.as_retriever(
search_kwargs={"k": 5} # 返回top 5相关文档
)
relevant_docs = retriever.get_relevant_documents("用户问题")
# ========== 5. 生成 ==========
from langchain.chains import RetrievalQA # RAG问答链
from langchain.llms import OpenAI # OpenAI LLM
qa_chain = RetrievalQA.from_chain_type(
llm=OpenAI(), # LLM
retriever=retriever # 检索器
)
answer = qa_chain.run("用户问题") # 执行问答
4.6 记忆系统
三种记忆类型:
- 短期记忆:对话历史管理,按窗口大小保留
- 长期记忆:向量数据库存储关键信息
- 摘要记忆:LLM自动总结历史
python
class ShortTermMemory:
"""短期记忆:保存最近N条对话"""
def __init__(self, max_messages=20):
"""
Args:
max_messages: 最多保留的消息数
"""
self.messages = [] # 消息列表
self.max_messages = max_messages # 最大消息数
def add(self, role, content):
"""添加一条消息"""
self.messages.append({"role": role, "content": content})
# 超过上限时只保留最近的N条
if len(self.messages) > self.max_messages:
self.messages = self.messages[-self.max_messages:] # 切片取末尾
def get(self):
"""获取所有消息"""
return self.messages
逐行详解:
| 语法 | 作用 |
|---|---|
class X: |
定义类 |
def __init__(self, ...): |
构造函数 |
self.messages = [] |
初始化实例属性为空列表 |
self.max_messages = max_messages |
保存参数为实例属性 |
self.messages.append({...}) |
列表追加元素 |
len(self.messages) |
列表长度 |
self.messages[-self.max_messages:] |
列表切片,负数表示从末尾数 |
[-N:] |
切片:取末尾N个元素 |
return |
函数返回值(None时省略) |
五、从零搭建Agent平台
5.1 技术选型
┌─────────────────────────────────────┐
│ 前端:Vue 3 + Element Plus │
└──────────────┬──────────────────────┘
│ HTTP/WebSocket
┌──────────────▼──────────────────────┐
│ 后端:FastAPI + Python 3.10+ │
├─────────────────────────────────────┤
│ 业务层:Agent / Skills / RAG / etc │
├─────────────────────────────────────┤
│ 基础设施:DB / Vector DB / LLM API │
└─────────────────────────────────────┘
5.2 项目结构
ai-platform/
├── backend/
│ ├── main.py # FastAPI入口
│ ├── core/
│ │ ├── config.py # 配置
│ │ └── llm_client.py # LLM客户端
│ ├── agents/
│ │ ├── base.py # Agent基类
│ │ ├── react_agent.py # ReAct Agent
│ │ └── multi_agent.py # 多Agent协作
│ ├── skills/
│ │ ├── base.py # Skill基类
│ │ └── registry.py # 注册表
│ ├── rag/
│ │ ├── loader.py # 文档加载
│ │ ├── splitter.py # 文本分片
│ │ ├── embedder.py # 向量化
│ │ └── retriever.py # 检索
│ ├── memory/ # 记忆系统
│ ├── tools/ # 工具实现
│ ├── db/ # 数据库
│ └── api/ # API路由
├── frontend/ # 前端
└── docker-compose.yml
5.3 LLM客户端封装(逐行详解)
python
import httpx # 异步HTTP客户端(类似requests但支持async)
from typing import List, Dict, Optional # 类型提示
class LLMClient:
"""统一的LLM客户端,支持多家模型"""
def __init__(self, base_url: str, api_key: str, model: str):
"""
初始化LLM客户端
Args:
base_url: API基础URL,如 "https://api.openai.com/v1"
api_key: API密钥
model: 模型名称,如 "gpt-3.5-turbo"
"""
self.base_url = base_url # 保存为实例属性
self.api_key = api_key
self.model = model
self.client = httpx.AsyncClient(timeout=60) # 异步HTTP客户端,超时60秒
async def chat(
self,
messages: List[Dict], # 消息列表
tools: Optional[List[Dict]] = None, # 可选工具列表
temperature: float = 0.7, # 温度参数
max_tokens: int = 2048 # 最大token数
) -> Dict:
"""
调用聊天补全API
Args:
messages: OpenAI格式的消息列表
tools: Function Calling工具列表
temperature: 温度(0=确定,1=随机)
max_tokens: 最大生成token数
Returns:
OpenAI格式的响应字典
"""
# 构造请求体
payload = {
"model": self.model, # 模型名
"messages": messages, # 消息列表
"temperature": temperature, # 温度
"max_tokens": max_tokens # 最大token数
}
# 如果有工具,加入请求体
if tools: # tools不为空时
payload["tools"] = tools # 添加工具定义
# 发送POST请求
response = await self.client.post( # await等待异步响应
f"{self.base_url}/chat/completions", # 完整URL
headers={"Authorization": f"Bearer {self.api_key}"}, # 认证头
json=payload # httpx自动序列化dict为JSON
)
response.raise_for_status() # 非2xx状态码抛异常
return response.json() # 解析JSON响应并返回
async def embed(self, texts: List[str]) -> List[List[float]]:
"""
调用Embedding API
Args:
texts: 文本列表
Returns:
向量列表,每个向量是float列表
"""
response = await self.client.post(
f"{self.base_url}/embeddings",
headers={"Authorization": f"Bearer {self.api_key}"},
json={
"model": "text-embedding-ada-002", # Embedding模型
"input": texts # 输入文本列表
}
)
data = response.json() # 解析JSON
# 提取embedding列表
return [item["embedding"] for item in data["data"]]
# 列表推导式:遍历data["data"],取每个item的"embedding"字段
逐行详解:
| 语法 | 作用 |
|---|---|
import httpx |
导入异步HTTP库 |
from typing import ... |
导入类型提示 |
class LLMClient: |
定义类 |
def __init__(self, ...): |
构造函数 |
base_url: str |
参数类型注解 |
self.xxx = xxx |
保存为实例属性 |
httpx.AsyncClient(timeout=60) |
创建异步HTTP客户端 |
async def |
定义异步函数 |
messages: List[Dict] |
参数+类型注解 |
Optional[List[Dict]] = None |
可选参数,默认None |
-> Dict |
返回类型注解 |
payload = {...} |
字典字面量 |
if tools: |
条件判断(真值检查) |
await |
等待异步操作完成 |
f"..." |
f-string嵌入变量 |
response.raise_for_status() |
非2xx抛HTTPError |
response.json() |
解析JSON为dict |
[... for item in ...] |
列表推导式 |
5.4 ReAct Agent实现(逐行详解)
python
import json # JSON解析库
from agents.base import BaseAgent # Agent基类
from skills.registry import SkillRegistry # 技能注册表
class ReActAgent(BaseAgent):
"""
ReAct模式Agent
Reasoning + Acting 交替进行
"""
def __init__(self, llm, system_prompt, skills=None):
"""
初始化ReAct Agent
Args:
llm: LLM客户端
system_prompt: 系统提示词
skills: 可用技能列表
"""
super().__init__(llm, system_prompt) # 调用父类初始化
self.skills = skills or [] # 兜底空列表(or运算符)
self.registry = SkillRegistry() # 创建技能注册表
self.max_iterations = 10 # 最大循环次数
def _get_tools(self) -> List[Dict]:
"""获取可用工具定义(OpenAI Function Calling格式)"""
tools = [] # 初始化空列表
for skill_name in self.skills: # 遍历技能列表
skill = self.registry.get(skill_name) # 从注册表获取技能
if skill: # 如果技能存在
tools.append(skill.get_tool_definition()) # 添加工具定义
return tools # 返回工具列表
async def run(self, user_input: str) -> str:
"""
ReAct主循环
流程:
1. 调用LLM,看是否需要工具
2. 是 -> 执行工具,把结果加到消息,再调LLM
3. 否 -> 返回最终答案
"""
# 构造消息列表(系统提示 + 历史 + 用户输入)
messages = self._build_messages(user_input)
tools = self._get_tools() # 获取工具定义
# 循环最多max_iterations次
for iteration in range(self.max_iterations):
# ========== 步骤1:调用LLM ==========
response = await self.llm.chat(messages, tools=tools)
# 提取LLM返回的消息
message = response["choices"][0]["message"]
# ========== 步骤2:判断是否需要工具 ==========
# 检查message中是否有tool_calls字段
if "tool_calls" not in message or not message["tool_calls"]:
# 没有工具调用 -> 这是最终答案
# 保存到历史
self.history.append({"role": "user", "content": user_input})
self.history.append({"role": "assistant", "content": message["content"]})
return message["content"] # 返回答案
# ========== 步骤3:执行工具调用 ==========
messages.append(message) # 把LLM回复加入消息
# 遍历每个工具调用
for tool_call in message["tool_calls"]:
# 提取工具名和参数
tool_name = tool_call["function"]["name"]
# arguments是JSON字符串,需要解析
arguments = json.loads(tool_call["function"]["arguments"])
# 执行工具
result = await self.registry.execute(tool_name, arguments)
# 工具结果加入消息
messages.append({
"role": "tool", # 角色:工具
"tool_call_id": tool_call["id"], # 对应哪个调用
"content": json.dumps(result, ensure_ascii=False)
# ensure_ascii=False: 中文不转义
})
# 达到最大迭代仍未完成
return "达到最大迭代次数仍未完成"
逐行详解:
| 语法 | 作用 |
|---|---|
import json |
导入JSON库 |
class X(BaseClass): |
继承父类 |
def __init__(self, ...): |
构造函数 |
super().__init__(...) |
调用父类构造函数 |
self.skills = skills or [] |
兜底空列表(or短路) |
self.max_iterations = 10 |
保存为实例属性 |
def _method(self): |
内部方法(下划线开头约定) |
for x in list: |
遍历列表 |
dict["key"] |
字典取值 |
if x not in y: |
x不在y中 |
or |
短路或 |
for i in range(n): |
循环n次 |
await |
等待异步操作 |
list.append(x) |
列表末尾追加 |
json.loads(s) |
JSON字符串 → Python对象 |
json.dumps(obj, ensure_ascii=False) |
Python对象 → JSON字符串,保留中文 |
f"...{var}..." |
f-string |
5.5 消息结构详解
python
# OpenAI Chat API的消息格式
messages = [
{
"role": "system", # 系统消息:设定AI角色
"content": "你是助手"
},
{
"role": "user", # 用户消息
"content": "你好"
},
{
"role": "assistant", # 助手消息
"content": "你好!"
},
{
"role": "tool", # 工具消息
"tool_call_id": "call_abc", # 对应哪个工具调用
"content": '{"result": 42}' # 工具结果
}
]
role详解:
| role | 含义 | 谁发出 |
|---|---|---|
system |
系统提示词 | 开发者 |
user |
用户输入 | 真实用户 |
assistant |
模型回复 | LLM |
tool |
工具执行结果 | 程序 |
5.6 多Agent协作(逐行详解)
python
class MultiAgentSystem:
"""
多Agent协作系统
协调多个Agent按顺序完成任务
"""
def __init__(self):
"""初始化"""
self.agents = {} # 字典:agent名 -> agent实例
self.workflow = [] # 工作流步骤列表
def add_agent(self, name: str, agent):
"""
添加一个Agent
Args:
name: Agent唯一标识
agent: Agent实例
"""
if name in self.agents: # 检查是否已存在
raise ValueError(f"Agent {name} 已存在") # 抛异常
self.agents[name] = agent # 存入字典
def set_workflow(self, workflow: List[Dict]):
"""
设置协作流程
workflow示例:
[
{"from": "researcher", "to": "writer"},
{"from": "writer", "to": "reviewer"}
]
"""
self.workflow = workflow
async def run(self, task: str, start_agent: str) -> str:
"""
执行多Agent任务
Args:
task: 任务描述
start_agent: 起始Agent名
Returns:
最终输出
"""
context = {
"task": task, # 原始任务
"outputs": {} # 每个Agent的输出
}
current_agent = start_agent # 当前Agent
# 遍历工作流
for step in self.workflow:
if step["from"] != current_agent: # 不是当前Agent的步骤跳过
continue
agent = self.agents[step["from"]] # 获取Agent实例
next_agent = step["to"] # 下一个Agent
# 构造输入:包含原始任务 + 前序Agent的输出
input_text = f"原始任务: {task}\n\n"
for prev_agent, prev_output in context["outputs"].items():
# .items()返回键值对
input_text += f"--- {prev_agent} 的输出 ---\n{prev_output}\n\n"
input_text += "请基于以上信息完成你的工作。"
# 执行当前Agent
output = await agent.run(input_text)
# 保存输出
context["outputs"][current_agent] = output
# 移动到下一个Agent
current_agent = next_agent
return context["outputs"].get(current_agent, "")
# dict.get(key, default): key不存在返回default
逐行详解:
| 语法 | 作用 |
|---|---|
class X: |
定义类 |
self.agents = {} |
初始化为空字典 |
self.workflow = [] |
初始化为空列表 |
def add_agent(self, name, agent): |
方法定义 |
name: str |
参数类型注解 |
if name in self.agents: |
成员检查 |
raise ValueError(...) |
主动抛出异常 |
self.agents[name] = agent |
字典赋值 |
for step in self.workflow: |
遍历列表 |
step["from"] |
字典取值 |
for k, v in dict.items(): |
遍历字典键值对 |
dict.get(key, default) |
安全取值,key不存在返回default |
f"...{var}..." |
f-string |
await |
等待异步操作 |
六、进阶技术
6.1 模型压缩
python
# 知识蒸馏代码示例
for batch in dataloader:
# 教师模型输出(不计算梯度)
with torch.no_grad(): # 不计算梯度,节省显存
teacher_logits = teacher_model(batch.input_ids)
# 学生模型输出
student_logits = student_model(batch.input_ids)
# 蒸馏损失
loss = distillation_loss(
student_logits,
teacher_logits,
temperature=2.0 # 温度参数
)
loss.backward() # 反向传播
optimizer.step() # 更新参数
逐行详解:
| 语法 | 作用 |
|---|---|
for batch in dataloader: |
遍历数据加载器 |
with torch.no_grad(): |
上下文管理器:内部不计算梯度 |
teacher_model(...) |
调用模型 |
loss = distillation_loss(...) |
计算蒸馏损失 |
loss.backward() |
反向传播计算梯度 |
optimizer.step() |
更新模型参数 |
6.2 智能体评估
| 指标 | 说明 |
|---|---|
| 任务完成率 | 成功完成的任务比例 |
| 工具调用准确率 | 正确选择工具的比例 |
| 响应时间 | P50/P95/P99延迟 |
| Token消耗 | 平均每次任务消耗 |
| 用户满意度 | 人工评分 |
6.3 提示词工程
Few-shot提示(逐行详解):
python
FEW_SHOT_PROMPT = """将用户的疑问改写为独立的、完整的问题。
示例1:
用户:它的主要功能是什么?
改写:Python的主要功能是什么?
示例2:
用户:怎么安装?
改写:如何安装Anaconda?
用户:{question}
改写:"""
# 使用时用 f-string 替换 {question}
prompt = FEW_SHOT_PROMPT.format(question="Python怎么用?")
Chain-of-Thought(思维链):
python
COT_PROMPT = """让我们一步步思考。
问题:{question}
思考过程:
1. 首先,...
2. 然后,...
3. 最后,...
答案:"""
6.4 监控与可观测性
LangSmith追踪(逐行详解):
python
from langsmith import traceable # LangSmith追踪装饰器
@traceable # 自动追踪到LangSmith
async def agent_run(question: str) -> str:
"""
装饰器会自动记录:
- 函数名
- 输入参数
- 输出结果
- 执行时间
- token消耗
"""
response = await llm.chat([{"role": "user", "content": question}])
return response["choices"][0]["message"]["content"]
OpenTelemetry集成(逐行详解):
python
from opentelemetry import trace # OpenTelemetry追踪库
tracer = trace.get_tracer(__name__) # 获取tracer
# 创建一个span(追踪段)
with tracer.start_as_current_span("agent_run") as span:
# 设置span属性
span.set_attribute("question", question) # 记录输入
response = await agent.run(question) # 执行Agent
span.set_attribute("response_length", len(response)) # 记录输出长度
# span结束自动上报
逐行详解:
| 语法 | 作用 |
|---|---|
@traceable |
装饰器,自动追踪函数 |
from opentelemetry import trace |
导入OpenTelemetry |
trace.get_tracer(__name__) |
获取tracer(__name__是当前模块名) |
tracer.start_as_current_span("name") |
创建span,返回上下文管理器 |
span.set_attribute(key, value) |
设置span属性 |
with ... as span: |
上下文管理器 |
6.5 安全防护
Prompt注入防御(逐行详解):
python
# 常见的注入攻击关键词
INJECTION_PATTERNS = [
"ignore previous instructions", # "忽略之前的指令"
"忽略之前的指令",
"you are now", # "你现在是"
"你现在是"
]
def check_injection(user_input: str) -> bool:
"""
检测Prompt注入
Args:
user_input: 用户输入
Returns:
True=检测到注入,False=正常
"""
user_input_lower = user_input.lower() # 转小写
# any(): 任一条件满足则返回True
return any(pattern in user_input_lower for pattern in INJECTION_PATTERNS)
# 列表推导式:检查每个pattern是否在输入中
输出过滤(逐行详解):
python
SENSITIVE_KEYWORDS = ["密码", "身份证", "信用卡"]
def filter_output(text: str) -> str:
"""
过滤敏感信息
Args:
text: 模型输出
Returns:
过滤后的文本
"""
for keyword in SENSITIVE_KEYWORDS: # 遍历敏感词
if keyword in text: # 如果包含
text = text.replace(keyword, "***") # 替换为***
return text
逐行详解:
| 语法 | 作用 |
|---|---|
INJECTION_PATTERNS = [...] |
列表字面量 |
def check_injection(user_input): |
函数定义 |
user_input.lower() |
转小写(不区分大小写比较) |
any(...) |
任一满足则True |
for pattern in INJECTION_PATTERNS |
遍历列表 |
pattern in user_input_lower |
子串检查 |
text.replace(old, new) |
字符串替换 |
6.6 性能优化
响应缓存(逐行详解):
python
import hashlib # 哈希库
import json # JSON库
from typing import Optional # 类型提示
class LLMCache:
"""LLM响应缓存"""
def __init__(self, redis_client=None):
"""
Args:
redis_client: Redis客户端(生产环境)
None则使用内存字典(开发环境)
"""
self.redis = redis_client # Redis客户端
self._memory_cache = {} # 兜底内存缓存
self._max_size = 1000 # 内存缓存最大条数
def _get_key(self, messages, temperature):
"""
生成缓存键
相同messages和temperature -> 相同key
"""
# 把消息列表序列化为字符串
content = json.dumps(messages, sort_keys=True)
# sort_keys=True: 字典按键排序,保证序列化结果一致
# 加上temperature
content += f"|temp={temperature}"
# MD5哈希成固定长度字符串
return hashlib.md5(content.encode()).hexdigest()
# .encode(): 字符串转bytes(MD5需要bytes)
# .hexdigest(): 返回32位十六进制字符串
async def get(self, key: str) -> Optional[str]:
"""获取缓存"""
if self.redis: # 生产:从Redis读取
value = await self.redis.get(key)
return value.decode() if value else None
# 三元表达式:value非空则decode,否则None
else: # 开发:从内存读取
return self._memory_cache.get(key)
async def set(self, key: str, value: str, ttl=3600):
"""
设置缓存
Args:
key: 缓存键
value: 缓存值
ttl: 过期时间(秒),默认1小时
"""
if self.redis:
# Redis: setex = SET with EXpiration
await self.redis.setex(key, ttl, value)
else:
self._memory_cache[key] = value
async def get_or_compute(self, messages, temperature, compute_fn):
"""
获取缓存或计算
Args:
messages: 消息列表
temperature: 温度
compute_fn: 计算函数 async (messages, temperature) -> result
"""
key = self._get_key(messages, temperature) # 生成缓存键
# 1. 查缓存
cached = await self.get(key)
if cached: # 缓存命中
return {"cached": True, "result": json.loads(cached)}
# 2. 缓存未命中,执行计算
result = await compute_fn(messages, temperature)
# 3. 写入缓存
await self.set(key, json.dumps(result), ttl=3600)
return {"cached": False, "result": result}
逐行详解:
| 语法 | 作用 |
|---|---|
import hashlib |
导入哈希库 |
hashlib.md5(content) |
创建MD5哈希对象 |
.encode() |
str → bytes |
.hexdigest() |
返回十六进制字符串 |
json.dumps(obj, sort_keys=True) |
序列化,按键排序 |
value.decode() |
bytes → str |
await self.redis.setex(key, ttl, value) |
Redis带TTL的SET |
value if condition else None |
三元表达式 |
cached = await self.get(key) |
等待异步获取 |
七、实战建议
7.1 学习路线
第1阶段:基础(1-2月)
├─ Python + PyTorch
├─ Transformer原理
└─ 使用HuggingFace
第2阶段:进阶(2-3月)
├─ 预训练技术
├─ LoRA/QLoRA微调
└─ vLLM/TGI部署
第3阶段:Agent(2-3月)
├─ Prompt Engineering
├─ Function Calling
├─ RAG系统
└─ LangChain/LlamaIndex
第4阶段:生产(3-6月)
├─ 高并发架构
├─ 监控告警
├─ 性能优化
└─ 安全防护
7.2 推荐资源
论文:
- Attention Is All You Need (Transformer)
- GPT-3: Language Models are Few-Shot Learners
- LLaMA: Open and Efficient Foundation Language Models
- ReAct: Synergizing Reasoning and Acting in Language Models
开源项目:
| 项目 | 用途 |
|---|---|
| vLLM | 高性能推理 |
| LangChain | Agent框架 |
| LlamaIndex | RAG框架 |
| Dify | 可视化Agent平台 |
| FastGPT | 知识库问答 |
课程:
- Stanford CS324 - LLM基础
- DeepLearning.AI - Prompt Engineering
- HuggingFace Course
附录:Python语法详解
常用类型注解
python
from typing import List, Dict, Optional, Union, Tuple, Any, Callable
# 基础类型
name: str = "Alice" # str类型
age: int = 25 # int类型
height: float = 1.75 # float类型
is_student: bool = True # bool类型
# 容器类型
numbers: List[int] = [1, 2, 3] # 整数列表
scores: Dict[str, int] = {"math": 90} # 字符串→整数字典
optional_value: Optional[int] = None # int或None
maybe_string: Union[str, int] = "hi" # str或int
pair: Tuple[int, str] = (1, "one") # (int, str)元组
anything: Any = "could be anything" # 任意类型
callback: Callable[[int], str] # 接收int返回str的可调用对象
常用控制流
python
# 条件
if x > 0: # 条件判断
print("正数")
elif x < 0: # 否则如果
print("负数")
else: # 否则
print("零")
# 循环
for i in range(10): # 0到9
print(i)
for item in items: # 遍历列表
print(item)
while condition: # 条件循环
do_something()
# 推导式
squares = [x**2 for x in range(10)] # 列表推导式
evens = {x for x in range(10) if x % 2 == 0} # 集合推导式
squares_dict = {x: x**2 for x in range(10)} # 字典推导式
常用函数定义
python
def func(a, b=10, *args, **kwargs):
"""
文档字符串
Args:
a: 必填参数
b: 可选参数(默认10)
*args: 可变位置参数
**kwargs: 可变关键字参数
Returns:
返回值
"""
return a + b
异常处理
python
try: # 尝试执行
result = risky_operation()
except ValueError as e: # 捕获特定异常
print(f"值错误: {e}")
except Exception as e: # 捕获所有异常
print(f"出错了: {e}")
else: # 无异常时执行
print("成功")
finally: # 无论是否异常都执行
cleanup()
上下文管理器
python
# with语句:自动管理资源
with open("file.txt", "r") as f: # 自动打开和关闭文件
content = f.read()
# 自定义上下文管理器
from contextlib import contextmanager
@contextmanager
def my_context():
print("进入")
yield
print("退出")
with my_context():
print("中间")
装饰器
python
from functools import wraps
def my_decorator(func):
@wraps(func) # 保留原函数信息
def wrapper(*args, **kwargs):
print("调用前")
result = func(*args, **kwargs)
print("调用后")
return result
return wrapper
@my_decorator
def hello():
"""问候函数"""
print("Hello")
类与继承
python
class Parent:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, {self.name}"
class Child(Parent): # 继承Parent
def __init__(self, name, age):
super().__init__(name) # 调用父类__init__
self.age = age
def greet(self): # 方法重写
return f"Hi, {self.name}, {self.age}"
常用内置函数
| 函数 | 作用 | 示例 |
|---|---|---|
len() |
长度 | len([1,2,3]) = 3 |
range() |
范围 | range(5) = 0,1,2,3,4 |
enumerate() |
枚举 | for i, v in enumerate(list) |
zip() |
配对 | zip(a, b) |
map() |
映射 | map(func, list) |
filter() |
过滤 | filter(func, list) |
sorted() |
排序 | sorted(list, key=..., reverse=True) |
sum() |
求和 | sum([1,2,3]) = 6 |
min()/max() |
最小/最大 | min([1,2,3]) = 1 |
abs() |
绝对值 | abs(-5) = 5 |
all() |
全部为真 | all([True, True]) = True |
any() |
任一为真 | any([False, True]) = True |
常用模块
| 模块 | 用途 |
|---|---|
os |
操作系统接口 |
sys |
Python运行时 |
json |
JSON处理 |
re |
正则表达式 |
asyncio |
异步I/O |
typing |
类型提示 |
dataclasses |
数据类 |
functools |
函数工具 |
collections |
集合数据类型 |
pathlib |
路径处理 |
logging |
日志 |
argparse |
命令行参数 |
📋 总结
本教程涵盖了:
- ✅ Python 基础语法(类型提示、异步、装饰器、上下文管理器、数据类)
- ✅ Transformer 核心(自注意力、多头注意力、FFN)
- ✅ 训练框架(DeepSpeed、LoRA、QLoRA)
- ✅ 推理服务(vLLM、OpenAI兼容API)
- ✅ Agent 核心(基类、ReAct、消息结构)
- ✅ RAG 系统(Embedding、文档分片、向量检索)
- ✅ 多Agent协作(角色定义、编排器)
- ✅ 生产级优化(缓存、限流、批处理)
- ✅ 完整Python语法速查表(附录)
学习建议:
- 先读懂语法 → 跑通代码 → 改写实验 → 集成应用
- 每章的代码都要亲手敲一遍
- 遇到不懂的语法,查阅本附录或官方文档
- 关注每个"为什么"而非"是什么"