feat: add interactive demos for AI history, Auth design, and Git intro
This commit is contained in:
@@ -1,24 +1,34 @@
|
||||
# 人工智能进化史:从 "逻辑" 到 "直觉" (Interactive Intro)
|
||||
# 人工智能进化史:从"逻辑"到"直觉"(交互式教程)
|
||||
|
||||
> 💡 **学习指南**:本章节通过交互式演示,带你梳理人工智能 70 年的发展脉络。从最早的下棋程序,到今天能写诗作画的 ChatGPT。
|
||||
> 💡 **学习指南**:本章节无需编程基础,通过交互式演示带你梳理人工智能 70 年的发展脉络。从最早的下棋程序,到今天能写诗作画的 ChatGPT。我们将深入理解 AI 从"人工规则"到"机器学习"的进化历程。
|
||||
|
||||
<AiEvolutionDemo />
|
||||
|
||||
## 0. 引言:机器能思考吗?
|
||||
|
||||
图灵在 1950 年提出了这个问题。
|
||||
为了回答它,人类进行了长达半个多世纪的探索。
|
||||
1950 年,艾伦·图灵在论文《计算机器与智能》中提出了这个问题:
|
||||
**"机器能思考吗?"**
|
||||
|
||||
我们走过弯路(试图穷举规则),也经历过寒冬(算力不足),最终在模仿人脑(神经网络)的道路上取得了突破。
|
||||
为了回答它,人类进行了长达半个多世纪的探索。我们走过弯路(试图穷举规则),也经历过寒冬(算力不足),最终在模仿人脑(神经网络)的道路上取得了突破。
|
||||
|
||||
AI 的进化史,就是人类探索"如何让机器拥有智能"的历史。这条探索之路经历了三个主要阶段:
|
||||
|
||||
1. **符号主义**:教机器"守规矩"——人工写规则
|
||||
2. **连接主义**:教机器"像人脑一样思考"——神经网络学习
|
||||
3. **生成式人工智能**:机器有了"创造力"——大语言模型
|
||||
|
||||
本教程将带你从零开始,一步步理解这些范式的演变。
|
||||
|
||||
<AIEvolutionTimelineDemo />
|
||||
|
||||
---
|
||||
|
||||
## 1. 符号主义:教机器"守规矩" (1950s - 1980s)
|
||||
## 1. 符号主义:教机器"守规矩"(20世纪50年代 - 80年代)
|
||||
|
||||
早期的 AI 科学家认为:智慧就是**逻辑推理**。
|
||||
只要我们把世界上的所有知识都写成 `If...Then...` 的规则,机器就能像人一样聪明。
|
||||
|
||||
这被称为**专家系统 (Expert Systems)**。
|
||||
这被称为**专家系统**或**符号主义人工智能**。
|
||||
|
||||
### 1.1 什么是"基于规则"?
|
||||
|
||||
@@ -27,7 +37,60 @@
|
||||
- 如果看到红灯,就停下。
|
||||
- 如果下雨,就带伞。
|
||||
|
||||
### 1.2 交互演示:规则 vs 学习
|
||||
在代码中,这表现为:
|
||||
|
||||
```javascript
|
||||
// 基于规则的 AI 示例
|
||||
function decideTrafficLight(color) {
|
||||
if (color === 'red') {
|
||||
return 'stop'
|
||||
} else if (color === 'yellow') {
|
||||
return 'caution'
|
||||
} else if (color === 'green') {
|
||||
return 'go'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 专家系统的巅峰:MYCIN
|
||||
|
||||
1970 年代,斯坦福大学开发的 MYCIN 系统能诊断血液感染,准确率达到专家水平。
|
||||
|
||||
它的工作原理是:
|
||||
|
||||
```lisp
|
||||
;; MYCIN 系统的规则示例 (伪代码)
|
||||
(IF
|
||||
(organism IS gram-positive)
|
||||
(morphology IS coccus)
|
||||
(growth-chains IS chains)
|
||||
THEN
|
||||
(identity IS 0.7 streptococcus))
|
||||
```
|
||||
|
||||
_数据示例 (知识库格式)_:
|
||||
```json
|
||||
// 专家系统知识库示例
|
||||
{
|
||||
"rules": [
|
||||
{
|
||||
"id": "RULE-001",
|
||||
"conditions": ["traffic_light == red", "speed > 0"],
|
||||
"action": "brake",
|
||||
"priority": 1
|
||||
},
|
||||
{
|
||||
"id": "RULE-002",
|
||||
"conditions": ["weather == rainy", "visibility < 100m"],
|
||||
"action": "turn_on_lights",
|
||||
"priority": 2
|
||||
}
|
||||
]
|
||||
// 系统按优先级依次匹配规则,遇到匹配就执行
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 交互演示:规则 vs 学习
|
||||
|
||||
下方的演示展示了两种方式的区别。
|
||||
|
||||
@@ -36,55 +99,230 @@
|
||||
|
||||
<RuleBasedVsLearningDemo />
|
||||
|
||||
**局限性**:你能写出"识别猫"的规则吗?
|
||||
"有胡须"?老鼠也有。"有尖耳朵"?狗也有。
|
||||
现实世界太复杂,规则写不完。这就是符号主义 AI 衰落的原因。
|
||||
### 1.4 符号主义的局限性
|
||||
|
||||
规则看起来很完美,但现实世界太复杂了。
|
||||
|
||||
<CombinatorialExplosionDemo />
|
||||
|
||||
**问题 1:组合爆炸**
|
||||
- 试图写下"识别猫"的所有规则?不可能!
|
||||
- "有胡须"?老鼠也有。
|
||||
- "有尖耳朵"?狗也有。
|
||||
- "毛茸茸的"?兔子也是。
|
||||
- 现实世界有无限边界情况,规则永远写不完。
|
||||
|
||||
**问题 2:无法处理不确定性**
|
||||
- 如果规则冲突怎么办?
|
||||
- 如果遇到没见过的情况怎么办?
|
||||
- 规则系统很"脆弱",缺少人类常识。
|
||||
|
||||
> ⚠️ **教训**:试图用有限规则描述无限现实,注定失败。这导致了 1980 年代的**AI 寒冬**。
|
||||
|
||||
---
|
||||
|
||||
## 2. 连接主义:教机器"像人脑一样思考" (2010s+)
|
||||
## 2. 连接主义:教机器"像人脑一样思考"(21世纪10年代至今)
|
||||
|
||||
既然规则写不完,不如让机器自己学?
|
||||
既然规则写不完,不如换个思路:**让机器自己学**?
|
||||
科学家开始模仿人脑的结构——**神经元**。
|
||||
|
||||
### 2.1 感知机 (Perceptron)
|
||||
这就是**连接主义**的核心思想。
|
||||
|
||||
这是最简单的神经元模型。它接收多个输入,根据**权重 (Weight)** 加权求和,如果超过某个**阈值 (Bias)**,就激活。
|
||||
### 2.1 人脑的启示
|
||||
|
||||
人脑有约 860 亿个神经元,每个神经元通过突触连接成千上万个其他神经元。
|
||||
|
||||
**关键发现**:
|
||||
- 单个神经元很"笨"(只是兴奋或不兴奋)
|
||||
- 但几百亿个神经元连在一起,就产生了智能
|
||||
|
||||
### 2.2 感知机
|
||||
|
||||
1957 年,康奈尔大学的 Frank Rosenblatt 发明了感知机——这是最简单的人工神经元。
|
||||
|
||||
它的工作原理:
|
||||
|
||||
1. **接收输入**:从多个"突触"接收信号($x_1, x_2, ...$)
|
||||
2. **加权求和**:每个输入有对应的**权重**,代表重要性
|
||||
3. **激活判断**:如果总和超过某个**阈值(偏置)**,就激活(输出 1)
|
||||
|
||||
$$ Output = \begin{cases} 1 & \text{if } \sum (w_i \cdot x_i) + b > 0 \\ 0 & \text{otherwise} \end{cases} $$
|
||||
|
||||
听起来很复杂?动手试一下!
|
||||
### 2.3 交互演示:玩转神经元
|
||||
|
||||
### 2.2 交互演示:玩转神经元
|
||||
调整下方的**权重**和**偏置**,看看能否控制神经元的输出。
|
||||
|
||||
调整下方的 **Weights (权重)** 和 **Bias (偏置)**,看看能否控制神经元的输出。
|
||||
|
||||
- **Weights ($w$)**:代表输入的"重要性"。$w$ 越大,这个输入对结果影响越大。
|
||||
- **Bias ($b$)**:代表神经元的"门槛"。$b$ 越小,神经元越容易兴奋(输出 1)。
|
||||
- **权重($w$)**:代表输入的"重要性"。$w$ 越大,这个输入对结果影响越大。
|
||||
- **偏置($b$)**:代表神经元的"门槛"。$b$ 越小,神经元越容易兴奋(输出 1)。
|
||||
|
||||
<PerceptronDemo />
|
||||
|
||||
当几十亿个这样的神经元连接在一起,奇迹就发生了——这就是**深度学习 (Deep Learning)**。
|
||||
### 2.4 从单神经元到深度学习
|
||||
|
||||
单个神经元能做什么?只能做简单分类(比如判断"苹果还是樱桃")。
|
||||
|
||||
但如果把神经元分层连接:
|
||||
|
||||
```
|
||||
输入层 (图片像素)
|
||||
↓
|
||||
隐藏层 1 (识别边缘)
|
||||
↓
|
||||
隐藏层 2 (识别形状)
|
||||
↓
|
||||
隐藏层 3 (识别物体部件)
|
||||
↓
|
||||
输出层 (识别物体)
|
||||
```
|
||||
|
||||
这就是**神经网络**。当网络有很多层时,我们称之为**深度学习**。
|
||||
|
||||
<NeuralNetworkVisualizationDemo />
|
||||
|
||||
### 2.5 神经网络是如何学习的?
|
||||
|
||||
不像专家系统需要人写规则,神经网络通过**看数据**自己学。
|
||||
|
||||
**学习过程(反向传播)**:
|
||||
1. **前向传播**:输入数据,得到预测结果
|
||||
2. **计算误差**:对比预测和真实答案
|
||||
3. **反向传播**:根据误差调整每个神经元的权重
|
||||
4. **重复**:重复几百万次,直到误差足够小
|
||||
|
||||
<BackpropagationDemo />
|
||||
|
||||
_数据示例 (训练数据格式)_:
|
||||
```json
|
||||
// 图像分类训练数据示例
|
||||
{
|
||||
"dataset": "cats_vs_dogs",
|
||||
"samples": [
|
||||
{
|
||||
"image": "cat_001.jpg",
|
||||
"label": 1, // 1 = 猫
|
||||
"features": [0.2, 0.8, 0.5, ...] // 提取的特征向量
|
||||
},
|
||||
{
|
||||
"image": "dog_001.jpg",
|
||||
"label": 0, // 0 = 狗
|
||||
"features": [0.7, 0.3, 0.9, ...]
|
||||
}
|
||||
]
|
||||
// 神经网络会自动学习:什么样的 feature 组合更可能是猫
|
||||
}
|
||||
```
|
||||
|
||||
### 2.6 连接主义的突破:2012 年 AlexNet
|
||||
|
||||
2012 年,AlexNet 在 ImageNet 竞赛中以压倒性优势夺冠,标志着深度学习时代的到来。
|
||||
|
||||
**关键因素**:
|
||||
- **大数据**:ImageNet 提供了 1400 万张标注图片
|
||||
- **大算力**:GPU 的并行计算能力让训练深度网络成为可能
|
||||
- **新算法**:ReLU 激活函数、Dropout 正则化等技术突破
|
||||
|
||||
### 2.7 连接主义的局限
|
||||
|
||||
深度学习很强大,但也不是完美的:
|
||||
|
||||
- **黑盒问题**:虽然能识别猫,但我们说不清"它是怎么识别的"
|
||||
- **数据饥渴**:需要海量标注数据,获取成本高
|
||||
- **缺乏常识**:能认猫,但不知道"猫会怕狗"
|
||||
|
||||
---
|
||||
|
||||
## 3. 生成式 AI:机器有了"创造力" (2020s+)
|
||||
## 3. 生成式人工智能:机器有了"创造力"(21世纪20年代至今)
|
||||
|
||||
以前的 AI 主要是**判别式**(这是猫还是狗?)。
|
||||
现在的 AI 是**生成式**(画一只猫!)。
|
||||
|
||||
这一切的背后,是 **Transformer** 架构的诞生。它让 AI 学会了理解上下文,学会了"举一反三"。
|
||||
|
||||
> 关于大语言模型 (LLM) 的详细原理,请移步下一章:[大语言模型入门](./llm-intro.md)
|
||||
### 3.1 从"识别"到"创造"
|
||||
|
||||
传统深度学习(判别式模型):
|
||||
- 输入:一张图
|
||||
- 输出:这是猫(概率 98%)
|
||||
|
||||
生成式 AI:
|
||||
- 输入:一句话"一只戴着墨镜的猫"
|
||||
- 输出:生成一张对应的图片
|
||||
|
||||
<DiscriminativeVsGenerativeDemo />
|
||||
|
||||
### 3.2 Transformer:AI 的"瑞士军刀"
|
||||
|
||||
2017 年,Google 发表论文《Attention Is All You Need》(注意力机制就是你所需的全部),提出 Transformer 架构。
|
||||
|
||||
它的核心创新:**注意力机制**
|
||||
|
||||
**原理**:让模型在处理一个词时,能"关注"到句子中其他相关的词。
|
||||
|
||||
例如:"小明把苹果给了**他**的母亲"
|
||||
|
||||
当模型处理"他"时,注意力机制会让它关注到"小明",从而理解"他"指代的是小明。
|
||||
|
||||
<AttentionMechanismDemo />
|
||||
|
||||
### 3.3 GPT:从文本生成到通用智能
|
||||
|
||||
2018 年,OpenAI 发布 GPT-1(生成式预训练变换器)。
|
||||
|
||||
**核心思想**:
|
||||
1. **预训练**:在海量文本上学习"预测下一个词"
|
||||
2. **微调**:在特定任务上调整(比如问答、翻译)
|
||||
|
||||
从 GPT-1 (2018) → GPT-2 (2019) → GPT-3 (2020) → GPT-4 (2023)
|
||||
- 参数量从 1.17 亿 → 1750 亿 → 1.8 万亿(估计)
|
||||
- 能力从文本生成 → 多模态(图片、音频、视频)
|
||||
|
||||
<GPTEvolutionDemo />
|
||||
|
||||
### 3.4 生成式人工智能的局限
|
||||
|
||||
虽然强大,但也存在问题:
|
||||
|
||||
- **幻觉**:一本正经地胡说八道
|
||||
- **偏见放大**:从训练数据中学到人类偏见
|
||||
- **不可解释**:仍然是个黑盒,不知道内部怎么运作
|
||||
|
||||
---
|
||||
|
||||
## 4. 总结
|
||||
## 4. AI 范式对比总结
|
||||
|
||||
| 时代 | 核心理念 | 代表产物 | 局限 |
|
||||
| :------------ | :-------------- | :------------------------ | :--------------------------- |
|
||||
| **符号主义** | 智慧 = 规则 | 深蓝 (下棋), 医疗诊断系统 | 无法处理模糊、复杂的现实世界 |
|
||||
| **连接主义** | 智慧 = 神经网络 | AlphaGo, 人脸识别 | 需要海量数据,是个"黑盒" |
|
||||
| **生成式 AI** | 智慧 = 通用理解 | ChatGPT, Midjourney | 幻觉 (一本正经胡说八道) |
|
||||
| 时代 | 核心理念 | 代表产物 | 优势 | 局限 |
|
||||
| :------------------ | :-------------- | :------------------------ | :------------------------ | :--------------------------- |
|
||||
| **符号主义** | 智慧 = 规则 | 深蓝(下棋)、MYCIN(诊断) | 可解释性强,逻辑清晰 | 无法处理模糊、复杂的现实世界 |
|
||||
| **连接主义** | 智慧 = 神经网络 | AlphaGo、人脸识别 | 能处理复杂模式,性能强大 | 需要海量数据,是个"黑盒" |
|
||||
| **生成式人工智能** | 智慧 = 通用理解 | ChatGPT、Midjourney | 能创造新内容,理解上下文 | 幻觉、偏见、不可解释 |
|
||||
|
||||
AI 的进化,就是从"人工设定规则"到"机器自动学习数据"的过程。
|
||||
**AI 的进化趋势**:
|
||||
|
||||
1. **从人工到自动**:从人写规则 → 机器自动学习
|
||||
2. **从单一到通用**:从下棋专用 → 通用人工智能
|
||||
3. **从判别到生成**:从分类识别 → 创造新内容
|
||||
|
||||
> 关于大语言模型的详细原理,请移步下一章:[大语言模型入门](./llm-intro.md)
|
||||
|
||||
---
|
||||
|
||||
## 5. 名词速查表
|
||||
|
||||
| 名词 | 英文原文 | 解释 |
|
||||
| :----------------- | :------------------------- | :----------------------------------------------------------------------------------------- |
|
||||
| **符号主义** | Symbolic AI | 基于规则的人工智能。认为智能可以用逻辑规则表示。代表:专家系统、深蓝。 |
|
||||
| **专家系统** | Expert Systems | 符号主义的代表产物。通过人工编写大量规则来模拟专家决策。代表:MYCIN(医疗诊断)。 |
|
||||
| **连接主义** | Connectionism | 基于神经网络的人工智能。模仿人脑神经元连接结构,通过数据自动学习。 |
|
||||
| **感知机** | Perceptron | 最简单的神经网络单元。接收多个输入,加权求和后通过激活函数输出。 |
|
||||
| **神经网络** | Neural Network | 由多个感知机分层连接组成的模型。通过调整权重来学习数据中的模式。 |
|
||||
| **深度学习** | Deep Learning | 使用**多层**神经网络的学习方法。能自动提取层次化特征(边缘 → 形状 → 物体)。 |
|
||||
| **反向传播** | Backpropagation | 神经网络的学习算法。通过计算预测误差,反向调整每层的权重,逐步优化模型。 |
|
||||
| **生成式人工智能** | Generative AI | 能**创造新内容**的人工智能(文本、图片、音频等),而非仅仅是分类或识别。代表:ChatGPT、Midjourney。 |
|
||||
| **判别式人工智能** | Discriminative AI | 用于**分类**的人工智能(如:这是猫还是狗?)。传统深度学习大多是判别式的。 |
|
||||
| **Transformer** | Transformer | 2017 年由 Google 提出的架构,基于注意力机制。是现代大语言模型(GPT、BERT)的基础。 |
|
||||
| **注意力机制** | Attention Mechanism | 让模型在处理一个元素时,能动态"关注"其他相关元素的技术。是 Transformer 的核心。 |
|
||||
| **GPT** | Generative Pre-trained Transformer | OpenAI 的系列模型。通过"预训练 + 微调"范式,在大量文本上学习生成能力。 |
|
||||
| **预训练** | Pre-training | 在大规模无标注数据上进行初步训练,学习通用知识(如语言规律)。 |
|
||||
| **微调** | Fine-tuning | 在预训练模型基础上,使用特定任务的小规模数据进行调整,使模型适应具体应用。 |
|
||||
| **幻觉** | Hallucination | 生成式人工智能模型"自信地编造错误内容"的现象。如 ChatGPT 编造不存在的论文或事实。 |
|
||||
| **通用人工智能** | Artificial General Intelligence | 像人类一样具备多领域智能、能自主学习推理的人工智能(尚未实现)。 |
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
# API 入门:软件世界的"服务员"
|
||||
|
||||
> 💡 **学习指南**:本章节无需编程基础,通过交互式演示带你深入了解 API(应用程序接口)。我们将从最基础的"什么是 API"讲起,到如何阅读 API 文档,再到实际调用 API。
|
||||
|
||||
<ApiQuickStartDemo />
|
||||
|
||||
## 0. 引言:无处不在的"桥梁"
|
||||
|
||||
你用微信登录第三方 APP 时,是谁在幕后传递信息?
|
||||
你在淘宝查询物流时,是谁帮你连接快递公司的数据?
|
||||
你用 AI 写代码时,是谁把你的需求传给大模型?
|
||||
|
||||
这背后都有一个功臣:**API (Application Programming Interface)**。
|
||||
|
||||
如果软件是"餐厅",那 API 就是"服务员"。
|
||||
你需要什么(数据、功能),告诉服务员(调用 API),服务员会去厨房(服务器)取来,端到你面前(返回结果)。
|
||||
|
||||
### 0.1 为什么需要 API?
|
||||
|
||||
想象一下,如果没有服务员(API):
|
||||
|
||||
- ❌ 每个顾客都要自己冲进厨房找菜
|
||||
- ❌ 厨房会被搞乱,效率极低
|
||||
- ❌ 顾客需要知道厨房怎么运作
|
||||
|
||||
有了服务员(API):
|
||||
|
||||
- ✅ 顾客只需看菜单(API 文档)点餐
|
||||
- ✅ 服务员传递订单,厨房专注做菜
|
||||
- ✅ 顾客不需要知道厨房怎么运作
|
||||
|
||||
**关键点**:API 让不同软件之间能够"对话",而不需要了解对方的内部实现。
|
||||
|
||||
---
|
||||
|
||||
## 1. 第一步:理解 API 的本质
|
||||
|
||||
### 1.1 什么是 API?
|
||||
|
||||
**API (Application Programming Interface)** = 应用程序编程接口。
|
||||
|
||||
翻译成人话:**软件之间的"约定"和"服务员"**。
|
||||
|
||||
- **Application(应用)**:两个不同的软件系统(如你的 APP 和微信服务器)
|
||||
- **Programming(编程)**:通过代码来交互
|
||||
- **Interface(接口)**:双方约定的"沟通方式"
|
||||
|
||||
<ApiConceptDemo />
|
||||
|
||||
**关键点**:API 定义了:
|
||||
- 你可以请求什么(有哪些功能)
|
||||
- 怎么请求(格式、参数)
|
||||
- 会返回什么(数据结构)
|
||||
|
||||
### 1.2 API 的类型
|
||||
|
||||
API 有很多种形式,最常见的有:
|
||||
|
||||
| 类型 | 例子 | 说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| **Web API** | REST API、GraphQL | 通过 HTTP 协议调用,最常见 |
|
||||
| **库 API** | React、Vue | 代码库提供的函数接口 |
|
||||
| **系统 API** | 文件系统 API | 操作系统提供的功能接口 |
|
||||
|
||||
本教程重点讲解 **Web API**,因为它最常用,也最容易理解。
|
||||
|
||||
---
|
||||
|
||||
## 2. API 是怎么工作的?
|
||||
|
||||
### 2.1 请求-响应模型
|
||||
|
||||
API 的工作原理就像"点餐-上菜":
|
||||
|
||||
1. **发起请求**:你告诉服务员要什么(调用 API)
|
||||
2. **处理请求**:服务员去厨房传达(服务器处理)
|
||||
3. **返回结果**:服务员把菜端上来(返回数据)
|
||||
|
||||
<RequestResponseFlow />
|
||||
|
||||
### 2.2 HTTP 方法:四种基本操作
|
||||
|
||||
在 Web API 中,我们使用 HTTP 方法来表达不同的操作:
|
||||
|
||||
| 方法 | 作用 | 类比 |
|
||||
| :--- | :--- | :--- |
|
||||
| **GET** | 获取数据 | "给我看看菜单" |
|
||||
| **POST** | 创建数据 | "我要点这道菜" |
|
||||
| **PUT** | 更新数据 | "把这道菜换成辣的" |
|
||||
| **DELETE** | 删除数据 | "取消这道菜" |
|
||||
|
||||
<ApiMethodDemo />
|
||||
|
||||
**关键点**:REST API 遵循"统一接口"原则,用这四种方法就能完成所有操作。
|
||||
|
||||
---
|
||||
|
||||
## 3. 认识 API 文档
|
||||
|
||||
### 3.1 什么是 API 文档?
|
||||
|
||||
API 文档就像**餐厅的菜单**,它告诉你:
|
||||
|
||||
- 📋 **有哪些菜可以点**(API 提供哪些功能)
|
||||
- 💰 **每个菜的名字和价格**(接口地址、参数)
|
||||
- 📝 **菜的详细说明**(返回数据格式)
|
||||
- ⚠️ **注意事项**(限制条件、错误码)
|
||||
|
||||
<ApiDocumentDemo />
|
||||
|
||||
### 3.2 API 文档的组成
|
||||
|
||||
一个完整的 API 文档通常包含:
|
||||
|
||||
#### 1️⃣ 基本信息
|
||||
```
|
||||
接口地址:https://api.example.com/users
|
||||
请求方法:GET
|
||||
功能说明:获取用户列表
|
||||
```
|
||||
|
||||
#### 2️⃣ 请求参数
|
||||
```
|
||||
参数名 类型 必填 说明
|
||||
page number 否 页码,默认 1
|
||||
limit number 否 每页数量,默认 20
|
||||
```
|
||||
|
||||
#### 3️⃣ 返回示例
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "张三",
|
||||
"email": "zhangsan@example.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 4️⃣ 错误码说明
|
||||
```
|
||||
400 - 参数错误
|
||||
401 - 未授权
|
||||
404 - 资源不存在
|
||||
500 - 服务器错误
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 实战:如何使用 API?
|
||||
|
||||
### 4.1 阅读文档的步骤
|
||||
|
||||
拿到一个新的 API,按以下步骤操作:
|
||||
|
||||
**第 1 步:找到文档入口**
|
||||
- 通常在官网的 "Developers" 或 "API" 板块
|
||||
- 常见的文档平台:Swagger、Apiary、Readme.io
|
||||
|
||||
**第 2 步:理解接口功能**
|
||||
- 看接口名称和说明,判断是否是你需要的功能
|
||||
- 注意请求方法(GET/POST/PUT/DELETE)
|
||||
|
||||
**第 3 步:查看请求参数**
|
||||
- 必填参数:一定要提供
|
||||
- 可选参数:根据需要提供
|
||||
- 参数类型:字符串、数字、布尔值
|
||||
|
||||
**第 4 步:看返回示例**
|
||||
- 了解成功时的返回格式
|
||||
- 查看错误时的返回格式
|
||||
|
||||
**第 5 步:尝试调用**
|
||||
- 可以用在线工具(如 Postman、curl)
|
||||
- 或者在代码中调用
|
||||
|
||||
<ApiPlayground />
|
||||
|
||||
### 4.2 真实案例:调用天气 API
|
||||
|
||||
让我们调用一个真实的天气 API 来查询北京的天气。
|
||||
|
||||
<RealWorldApiDemo />
|
||||
|
||||
**代码示例**:
|
||||
|
||||
```javascript
|
||||
// 使用 JavaScript 调用 API
|
||||
fetch('https://api.weatherapi.com/v1/current.json?key=YOUR_KEY&q=Beijing')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('北京天气:', data.current.temp_c, '°C');
|
||||
console.log('天气状况:', data.current.condition.text);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('出错了:', error);
|
||||
});
|
||||
```
|
||||
|
||||
```python
|
||||
# 使用 Python 调用 API
|
||||
import requests
|
||||
|
||||
response = requests.get('https://api.weatherapi.com/v1/current.json', params={
|
||||
'key': 'YOUR_KEY',
|
||||
'q': 'Beijing'
|
||||
})
|
||||
|
||||
data = response.json()
|
||||
print(f"北京天气:{data['current']['temp_c']}°C")
|
||||
print(f"天气状况:{data['current']['condition']['text']}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 常见问题与最佳实践
|
||||
|
||||
### 5.1 为什么我的 API 调用失败了?
|
||||
|
||||
常见错误:
|
||||
|
||||
| 错误码 | 原因 | 解决方案 |
|
||||
| :--- | :--- | :--- |
|
||||
| **400** | 参数错误 | 检查参数名、类型、格式 |
|
||||
| **401** | 未授权 | 检查 API Key 是否正确 |
|
||||
| **404** | 接口不存在 | 确认 URL 是否正确 |
|
||||
| **429** | 请求过于频繁 | 降低请求频率或联系提供方 |
|
||||
| **500** | 服务器错误 | 稍后重试或联系技术支持 |
|
||||
|
||||
### 5.2 最佳实践
|
||||
|
||||
✅ **使用 API 时要注意**:
|
||||
|
||||
1. **阅读文档**:不要猜测,仔细看文档
|
||||
2. **处理错误**:不要假设调用总是成功
|
||||
3. **控制频率**:避免被限流(Rate Limit)
|
||||
4. **保护密钥**:不要把 API Key 写在公开代码里
|
||||
5. **缓存数据**:相同数据不要重复请求
|
||||
|
||||
❌ **常见错误**:
|
||||
|
||||
- 不看文档就盲目调用
|
||||
- 不处理错误响应
|
||||
- 密钥泄露到 GitHub
|
||||
- 无限重试导致被封禁
|
||||
|
||||
---
|
||||
|
||||
## 6. 总结与进阶
|
||||
|
||||
恭喜你!现在你已经掌握了 API 的基础知识。
|
||||
|
||||
### 6.1 核心知识点回顾
|
||||
|
||||
- ✅ API 是软件之间的"服务员"和"桥梁"
|
||||
- ✅ API 工作原理:请求 → 处理 → 响应
|
||||
- ✅ HTTP 方法:GET(查)、POST(增)、PUT(改)、DELETE(删)
|
||||
- ✅ API 文档包含:接口地址、参数、返回格式、错误码
|
||||
- ✅ 调用 API 的五步法:找文档 → 理解功能 → 查参数 → 看示例 → 尝试调用
|
||||
|
||||
### 6.2 学习路线
|
||||
|
||||
1. **入门**(今天)
|
||||
- 理解 API 的概念
|
||||
- 会阅读简单的 API 文档
|
||||
- 能用工具(Postman)调用 API
|
||||
|
||||
2. **进阶**(1 周)
|
||||
- 在代码中调用 API
|
||||
- 处理认证(API Key、OAuth)
|
||||
- 处理分页、过滤等高级功能
|
||||
|
||||
3. **深入**(持续)
|
||||
- 学习 GraphQL(REST 的替代方案)
|
||||
- 设计自己的 API
|
||||
- API 性能优化和安全
|
||||
|
||||
### 6.3 推荐资源
|
||||
|
||||
- **练习平台**:
|
||||
- [JSONPlaceholder](https://jsonplaceholder.typicode.com/) - 假数据 API,用于练习
|
||||
- [Public APIs](https://publicapis.dev/) - 收录了大量免费 API
|
||||
|
||||
- **文档工具**:
|
||||
- [Postman](https://www.postman.com/) - API 调试工具
|
||||
- [Swagger Editor](https://editor.swagger.io/) - API 文档编辑器
|
||||
|
||||
- **学习资料**:
|
||||
- [REST API Tutorial](https://restfulapi.net/)
|
||||
- [MDN Web API 文档](https://developer.mozilla.org/zh-CN/docs/Web/API)
|
||||
|
||||
---
|
||||
|
||||
## 7. 名词速查表
|
||||
|
||||
| 名词 | 英文 | 解释 |
|
||||
| :--- | :--- | :--- |
|
||||
| **API** | Application Programming Interface | 应用程序编程接口,软件之间的"服务员" |
|
||||
| **HTTP** | HyperText Transfer Protocol | 超文本传输协议,Web API 的基础 |
|
||||
| **REST** | Representational State Transfer | 一种 API 设计风格,最常见 |
|
||||
| **GET** | - | HTTP 方法,用于获取数据 |
|
||||
| **POST** | - | HTTP 方法,用于创建数据 |
|
||||
| **PUT** | - | HTTP 方法,用于更新数据 |
|
||||
| **DELETE** | - | HTTP 方法,用于删除数据 |
|
||||
| **Endpoint** | - | 接口地址,如 /users |
|
||||
| **Request** | - | 请求,客户端发给服务器 |
|
||||
| **Response** | - | 响应,服务器返回给客户端 |
|
||||
| **JSON** | JavaScript Object Notation | 一种数据格式,API 常用 |
|
||||
| **Authentication** | - | 认证,验证你是谁 |
|
||||
| **Rate Limit** | - | 限流,控制请求频率 |
|
||||
@@ -27,6 +27,12 @@
|
||||
|
||||
<AuthBasicsDemo />
|
||||
|
||||
### 0.2 交互式演示:登录流程
|
||||
|
||||
让我们通过一个真实的登录演示,来理解认证和授权是如何工作的。
|
||||
|
||||
<AuthInteractiveLoginDemo />
|
||||
|
||||
**关键点**:鉴权是第一道防线,所有敏感操作都必须先验证身份。
|
||||
|
||||
---
|
||||
|
||||
@@ -6,26 +6,181 @@
|
||||
|
||||
## 0. 引言:看不见的"加速器"
|
||||
|
||||
你刷朋友圈时,为什么几秒钟就能加载出几百张图片?
|
||||
你查询订单时,为什么瞬间就能看到几个月前的数据?
|
||||
你有没有想过这些问题:
|
||||
|
||||
- 刷朋友圈时,为什么几秒钟就能加载出几百张图片?
|
||||
- 查询订单时,为什么瞬间就能看到几个月前的数据?
|
||||
- 刷新短视频时,为什么视频几乎瞬间就能播放?
|
||||
|
||||
这背后都有一个功臣:**缓存 (Cache)**。
|
||||
|
||||
如果数据库是"仓库",那缓存就是"柜台"。
|
||||
常用的商品(热数据)放在柜台上,随拿随用;不常用的商品才需要去仓库里找。
|
||||
### 0.1 什么是缓存?用生活化的例子理解
|
||||
|
||||
### 0.1 为什么要缓存?
|
||||
想象一下你在家里的场景:
|
||||
|
||||
**场景 1:没有缓存的日子**
|
||||
|
||||
每次想喝水,你都要:
|
||||
1. 走到厨房(相当于访问数据库)
|
||||
2. 打开柜子
|
||||
3. 拿出水壶
|
||||
4. 倒水
|
||||
5. 回到客厅
|
||||
|
||||
即使你一小时内要喝 10 次水,每次都要重复这个过程。很累对吧?
|
||||
|
||||
**场景 2:有了缓存**
|
||||
|
||||
你在客厅的茶几上放了一个水杯(这就是缓存!):
|
||||
- 第一次喝水:你还是要去厨房倒水,但把水杯留在茶几上
|
||||
- 之后每次喝水:直接拿起茶几上的水杯喝就行
|
||||
|
||||
**这就是缓存的核心思想**:把常用的东西放在触手可及的地方,避免每次都"跑远路"。
|
||||
|
||||
回到计算机世界:
|
||||
|
||||
| 生活中的例子 | 计算机中的对应 |
|
||||
| :--- | :--- |
|
||||
| **茶几上的水杯** | **内存缓存**(速度快,但容量小) |
|
||||
| **厨房的水壶** | **数据库**(速度慢,但容量大) |
|
||||
| **"我刚才用过这个水杯"** | **时间局部性**(刚用过的数据,很可能还会用) |
|
||||
| **"把这些常用的都放在茶几上"** | **空间局部性**(用过的数据附近的数据,也可能用到) |
|
||||
|
||||
### 0.2 为什么要缓存?
|
||||
|
||||
只有一个理由:**快**。
|
||||
|
||||
| 存储介质 | 访问延迟 | 吞吐量 | 典型用途 |
|
||||
| :--------------- | :------- | :----- | :------------- |
|
||||
| **L1 CPU 缓存** | ~1 ns | 极高 | 寄存器、变量 |
|
||||
| **内存 (Redis)** | ~100 ns | 高 | 热点数据、会话 |
|
||||
| **SSD 数据库** | ~1 ms | 中 | 持久化存储 |
|
||||
| **HDD 数据库** | ~10 ms | 低 | 归档存储 |
|
||||
但有多快呢?我们用个形象的比喻:
|
||||
|
||||
**关键点**:缓存的本质是**用空间换时间**,通过在更快的存储介质中保留数据副本,减少访问慢速存储的次数。
|
||||
| 存储介质 | 访问时间 | 生活类比 | 能做什么 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **L1 CPU 缓存** | ~1 纳秒 | 眨一下眼睛(1/10秒)的 **十亿分之一** | CPU 执行一条指令 |
|
||||
| **内存 (Redis)** | ~100 纳秒 | 眨一下眼睛的 **千万分之一** | 存储热点数据 |
|
||||
| **SSD 数据库** | ~1 毫秒 | 眨一下眼睛 | 读写文件 |
|
||||
| **HDD 数据库** | ~10 毫秒 | 眨 10 下眼睛 | 传统硬盘操作 |
|
||||
|
||||
**换个角度理解**:
|
||||
- 从内存读数据 = 从茶几拿水杯
|
||||
- 从 SSD 读数据 = 从厨房拿水壶
|
||||
- 从 HDD 读数据 = 从楼下便利店买水
|
||||
|
||||
**关键点**:缓存的本质是**用空间换时间**——多准备几份"副本"放在快速的地方,节省每次都去"慢速地方"取数据的时间。
|
||||
|
||||
### 0.3 缓存的真实案例
|
||||
|
||||
**案例 1:淘宝商品详情页**
|
||||
|
||||
当你打开一个商品页面时:
|
||||
- **商品基本信息**(价格、标题):从 Redis 缓存读取(~5 毫秒)
|
||||
- **商品大图**:从 CDN 缓存读取(~20 毫秒)
|
||||
- **用户浏览历史**:从本地缓存读取(~1 毫秒)
|
||||
|
||||
如果这些都不用缓存,全部查数据库:
|
||||
- 查询时间可能从 **5 毫秒** 变成 **200 毫秒**
|
||||
- 数据库要同时处理几百万人的请求,直接"累垮"
|
||||
|
||||
**案例 2:微信朋友圈**
|
||||
|
||||
你刷朋友圈时:
|
||||
- **图片**:之前看过的图片,都在手机本地缓存里
|
||||
- **好友列表**:第一次加载后缓存在内存里
|
||||
- **点赞数据**:热点数据在 Redis 缓存中
|
||||
|
||||
没有缓存的话:每次刷新都要重新下载所有内容,流量和速度都受不了。
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ 全局观:缓存知识地图
|
||||
|
||||
在深入细节之前,让我们先看看缓存设计的"全貌"。就像旅游前先看地图一样,这样你不会迷路。
|
||||
|
||||
### 核心目标(一句话概括)
|
||||
|
||||
**让数据访问更快、系统更强,同时保证数据不出错。**
|
||||
|
||||
### 知识体系地图
|
||||
|
||||
```
|
||||
缓存设计
|
||||
│
|
||||
├─ 📦 基础概念(为什么需要缓存?)
|
||||
│ ├─ 局部性原理(时间局部性、空间局部性)
|
||||
│ ├─ 缓存生命周期(写入 → 命中 → 过期 → 淘汰)
|
||||
│ └─ 性能对比(内存 vs 数据库:快 100 倍)
|
||||
│
|
||||
├─ 🏗️ 架构选型(用什么缓存?)
|
||||
│ ├─ 本地缓存(单机快,但容量小)
|
||||
│ ├─ 分布式缓存(容量大,但稍慢)
|
||||
│ └─ 多级缓存(组合使用,最佳方案)
|
||||
│ ├─ 浏览器缓存(用户本地)
|
||||
│ ├─ CDN 缓存(离用户近)
|
||||
│ ├─ 应用本地缓存(极速)
|
||||
│ ├─ Redis 缓存(高容量)
|
||||
│ └─ 数据库(兜底)
|
||||
│
|
||||
├─ 🎯 设计模式(怎么用缓存?)
|
||||
│ ├─ Cache-Aside(最常用,手动控制)
|
||||
│ ├─ Read-Through(缓存自己加载)
|
||||
│ ├─ Write-Through(同步写缓存和数据库)
|
||||
│ └─ Write-Behind(异步写,最快但可能丢数据)
|
||||
│
|
||||
├─ ⚠️ 常见问题(缓存会出什么错?)
|
||||
│ ├─ 缓存穿透(查不存在数据,数据库压力大)
|
||||
│ ├─ 缓存击穿(热点数据过期,瞬间高并发)
|
||||
│ └─ 缓存雪崩(大量数据同时过期)
|
||||
│
|
||||
├─ 🔒 一致性保证(缓存和数据库不一致怎么办?)
|
||||
│ ├─ 更新策略(先更数据库,再删缓存)
|
||||
│ ├─ 延迟双删(极致一致性)
|
||||
│ └─ Binlog 订阅(异步解耦)
|
||||
│
|
||||
└─ 🛠️ 实战技巧(工程中怎么做?)
|
||||
├─ 布隆过滤器(快速判断数据是否存在)
|
||||
├─ 分布式锁(防止缓存击穿)
|
||||
├─ 随机 TTL(防止雪崩)
|
||||
├─ 缓存预热(启动时加载热点数据)
|
||||
└─ 监控调优(命中率要 > 90%)
|
||||
```
|
||||
|
||||
### 学习路径建议(0基础小白版)
|
||||
|
||||
**第一步:理解核心概念**(1-2 天)
|
||||
- 理解"为什么需要缓存"(茶几 vs 厨房的例子)
|
||||
- 记住性能数据:内存比数据库快 100 倍
|
||||
- 了解缓存的生命周期(写入 → 命中 → 过期 → 淘汰)
|
||||
|
||||
**第二步:掌握最常用的模式**(2-3 天)
|
||||
- 重点学习 **Cache-Aside 模式**(90% 的场景都用这个)
|
||||
- 动手写代码:用 Redis 做简单的键值缓存
|
||||
- 理解"为什么删缓存而不是更新缓存"
|
||||
|
||||
**第三步:学习多级缓存**(3-5 天)
|
||||
- 理解为什么需要"多层防御"(浏览器 → CDN → 本地 → Redis → 数据库)
|
||||
- 掌握每一层的用途和特点
|
||||
- 动手实践:给自己的项目加一层缓存
|
||||
|
||||
**第四步:解决常见问题**(1 周)
|
||||
- 理解缓存三大问题(穿透、击穿、雪崩)
|
||||
- 学习解决方案(布隆过滤器、分布式锁、随机 TTL)
|
||||
- 实战演练:模拟高并发场景,看缓存如何保护数据库
|
||||
|
||||
**第五步:深入一致性**(1-2 周)
|
||||
- 理解缓存和数据库可能不一致的场景
|
||||
- 掌握"先更数据库,再删缓存"的最佳实践
|
||||
- 进阶:学习 Binlog 订阅方案
|
||||
|
||||
**第六步:实战项目**(2-4 周)
|
||||
- 设计一个完整的缓存系统(如商品详情页缓存)
|
||||
- 搭建监控系统,实时查看缓存命中率
|
||||
- 压测验证:看看性能提升了多少倍
|
||||
|
||||
### 关键指标(学完后你要能回答)
|
||||
|
||||
- 缓存的**命中率**是多少?(优秀:> 90%)
|
||||
- 缓存能**提升多少性能**?(10-100 倍)
|
||||
- 如何解决缓存**三大问题**?(穿透、击穿、雪崩)
|
||||
- 缓存和数据库**不一致**怎么办?(先更库,再删缓存)
|
||||
- **多级缓存**的顺序是什么?(浏览器 → CDN → 本地 → Redis → 数据库)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Canvas 2D 入门:从像素到动画 (Interactive Guide to Canvas)
|
||||
# Canvas 2D 入门:从像素到动画(交互式教程)
|
||||
|
||||
> **学习指南**:本章节无需深厚的前端基础,通过交互式演示带你掌握 Canvas 2D 的核心原理和实践技巧。我们将从最基础的绘制开始,一直到构建复杂的交互式图形应用。
|
||||
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
> 💡 **学习指南**:如果说 Prompt Engineering 是教 AI "怎么说话",那么 Context Engineering 就是教 AI "怎么记事"。本章节将通过一系列交互式实验,带你深入理解 AI 的记忆机制,从基础的滑动窗口到高级的 RAG 系统,掌握让 AI "过目不忘"的核心技术。
|
||||
|
||||
在开始之前,建议你先了解两个概念:
|
||||
|
||||
- **Token 是什么**:可以先阅读 [大语言模型入门](./llm-intro.md) 的「分词 & Token」部分。
|
||||
- **Prompt 是什么**:如果你还不熟悉 System / User / Assistant 的基本结构,可以先看 [提示词工程](./prompt-engineering.md)。
|
||||
|
||||
<AgentContextFlow />
|
||||
|
||||
## 0. 引言:金鱼与大象
|
||||
|
||||
想象一下,你正在和两个人聊天:
|
||||
@@ -11,6 +18,13 @@
|
||||
|
||||
**上下文工程 (Context Engineering)** 的目标,就是通过技术手段,让 AI 从 "金鱼" 进化成 "大象"。
|
||||
|
||||
更具体地说:你每次调用模型时,都会把一份「输入包」发给它,这份输入包通常由这些部分拼起来:
|
||||
|
||||
- **系统设定**(System Prompt):角色、规则、边界。
|
||||
- **对话历史**(Messages):你们之前聊过什么。
|
||||
- **工具结果**(Tool / Observation):Agent 调用外部工具拿到的新信息。
|
||||
- **检索片段**(RAG Context):从知识库临时取回的相关内容。
|
||||
|
||||
但这里有一个核心挑战:**AI 的"脑容量"(上下文窗口)是有限的**。我们不能把全世界的信息都塞进去。
|
||||
|
||||
我们需要解决五个核心问题:
|
||||
@@ -31,7 +45,8 @@
|
||||
|
||||
### 1.2 实验:Token 与容量
|
||||
|
||||
在 AI 的世界里,计量的单位不是"字",而是 **Token**。一个 Token 大约相当于 0.75 个英文单词,或者 0.5-1 个汉字。
|
||||
在 AI 的世界里,计量的单位不是"字",而是 **Token**。(Token 的更完整解释可以回看 [大语言模型入门](./llm-intro.md)。)
|
||||
粗略地说,一个 Token 大约相当于 0.75 个英文单词,或 0.5-1 个汉字(会因内容而变化)。
|
||||
|
||||
试着在下面的模拟器中输入文字,看看它是如何填满上下文窗口的:
|
||||
|
||||
@@ -39,9 +54,14 @@
|
||||
|
||||
**关键点**:
|
||||
|
||||
- **溢出即丢失**:一旦超过红色警戒线,模型不仅会报错,或者会直接截断后面的内容。
|
||||
- **溢出即丢失**:一旦超过红色警戒线,模型可能会报错,或者直接截断后面的内容。
|
||||
- **昂贵的记忆**:上下文越长,推理速度越慢,费用也越高。
|
||||
|
||||
### 1.3 额外收益:前缀稳定与缓存命中
|
||||
|
||||
在 Agent 场景里,上下文通常是「系统设定 + 工具定义 + 历史消息 + 本轮新信息」的拼接。
|
||||
如果你能让这份输入包的**前半段尽量稳定**(比如系统提示、工具列表不要频繁变动),很多模型/服务会更容易复用缓存,从而降低延迟与成本。
|
||||
|
||||
---
|
||||
|
||||
## 2. 第二步:即时记忆 (Sliding Window)
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
> 💡 **一句话解释**:Git 就是代码世界的**游戏存档管理器**。它能让你随时“读档”重来,也能让你和队友在各自的“平行宇宙”里互不干扰地开发。
|
||||
|
||||
> ✅ **安全说明**:本页所有交互组件都是“模拟器”,不会对你电脑上的真实 Git 仓库执行任何操作;但真实项目里建议严格按步骤来,不要依赖“自动下一步”。
|
||||
|
||||
## 0. 最常用的 5 个场景(直接照抄)
|
||||
|
||||
如果你只想“立刻能用”,先把这块过一遍:每个场景都是现实工作中最常见的 Git 流程。
|
||||
|
||||
<GitScenariosDemo />
|
||||
|
||||
## 1. 为什么我们需要它?
|
||||
|
||||
你是否经历过这种绝望?
|
||||
|
||||
@@ -107,24 +107,95 @@
|
||||
|
||||
---
|
||||
|
||||
## 3.5 插播:到底什么是“模型”?
|
||||
|
||||
在讲具体的架构之前,我们先通俗地理解一下“模型”这个词。
|
||||
|
||||
在 AI 领域,**模型(Model)** 其实就是一个超级复杂的**函数**或者**黑盒子**。
|
||||
|
||||
- **输入**:一堆数字(比如上面的 Token ID)。
|
||||
- **处理**:黑盒子里有亿万个参数(可以理解为亿万个调节旋钮),它们会对输入数据进行疯狂的加减乘除运算。
|
||||
- **输出**:另一堆数字(代表预测结果,比如下一个词的概率)。
|
||||
|
||||
**打个比方:**
|
||||
|
||||
你可以把模型想象成一位**经验丰富的老厨师**:
|
||||
1. **输入(食材)**:你给他牛肉、土豆、番茄。
|
||||
2. **模型(厨师的脑子)**:他根据自己学过的成千上万道菜谱(训练数据),在脑子里快速计算:牛肉切块、土豆去皮、火候控制...
|
||||
3. **输出(菜肴)**:最后端出一盘土豆炖牛腩。
|
||||
|
||||
所谓的**训练(Training)**,就是让这位厨师从学徒做起,让他试错亿万次。做咸了就调一下“盐旋钮”,做淡了就调一下“火候旋钮”,直到他能稳定做出美味的菜肴。
|
||||
|
||||
现在的 LLM,就是一位“读过全人类书本”的超级厨师,只不过他炒的不是菜,而是文字。
|
||||
|
||||
## 4. 进化之路:从 RNN 到 Transformer
|
||||
|
||||
现在我们有了**高效的数据表达**(矩阵),接下来需要一个**高效的机器**(模型)来处理它。
|
||||
有了数据(Token),有了厨师(模型),接下来要看这位厨师是怎么思考的。
|
||||
|
||||
### 4.1 为什么要淘汰 RNN?
|
||||
在 AI 进化史上,主要有两种“思考方式”(架构):**RNN** 和 **Transformer**。
|
||||
|
||||
以前的模型(RNN)像人读书一样,**从左到右**一个字一个字读。
|
||||
### 4.1 以前的笨办法:RNN(传话游戏)
|
||||
|
||||
- **缺点1:慢**。必须读完第1个字才能读第2个,没法并行(浪费了矩阵并行的优势)。
|
||||
- **缺点2:忘**。读到文章最后,可能已经忘了开头讲什么了(长距离遗忘)。
|
||||
早期的模型(RNN,循环神经网络)处理一句话时,就像我们在玩**传话游戏**。
|
||||
|
||||
### 4.2 Transformer 强在哪?
|
||||
**工作方式:**
|
||||
1. 读第 1 个词“我”,记在脑子里,传给第 2 步。
|
||||
2. 读第 2 个词“喜欢”,结合刚才的记忆,更新一下脑子里的信息,再传给第 3 步。
|
||||
3. 读第 3 个词“吃”,再更新记忆...
|
||||
4. ...直到读完最后一个词。
|
||||
|
||||
现在的 LLM 都基于 Transformer 架构,它完美契合了矩阵并行的特性:
|
||||
**这就带来了两个致命缺点:**
|
||||
|
||||
1. **并行阅读**:它可以**一眼看完**整句话,不用一个字一个字读。
|
||||
2. **注意力机制 (Attention)**:它可以让句子里的每一个词,都**直接关注**到其他所有词。
|
||||
- 比如读到“它”这个字时,模型能瞬间注意到前面的“小猫”,从而知道“它”指代的是猫。
|
||||
1. **慢(无法并行)**:必须等上一个人传完话,下一个人才能开始。没法让 100 个人同时干活。
|
||||
2. **忘(长距离遗忘)**:传话传到第 100 个人时,他可能早就忘了第 1 个人说的是“我”还是“你”。这就导致模型写长文章时,容易前言不搭后语。
|
||||
|
||||
### 4.2 现在的天才设计:Transformer(圆桌会议)
|
||||
|
||||
2017 年,Google 提出了一种全新的架构——**Transformer**。它彻底改变了规则,把“传话游戏”变成了**圆桌会议**。
|
||||
|
||||
**工作方式:**
|
||||
Transformer 不再一个接一个地传话,而是让**所有词一次性全部坐上桌**。
|
||||
|
||||
1. **上帝视角(并行计算)**:所有词同时进场,不用排队。大家把自己的信息写在纸上,摊在桌子中间。
|
||||
2. **注意力机制(Attention)**:这是它的杀手锏。每个词都可以**直接**去看桌上其他任何一个词的信息。
|
||||
- 比如读到“它”这个字时,模型不需要回忆前面的传话,而是直接一眼看到前面的“小猫”,瞬间明白“它 = 小猫”。
|
||||
|
||||
**这就完美解决了 RNN 的痛点:**
|
||||
|
||||
* **快**:大家同时看资料,GPU 可以火力全开,效率极高。
|
||||
* **不忘**:不管句子多长,第 1 个词和第 10000 个词的距离都是“一步之遥”,想看谁就看谁。
|
||||
|
||||
> **总结一下**:
|
||||
> * **RNN**:像走迷宫,一步一步摸索,容易迷路。
|
||||
> * **Transformer**:像开上帝视角看地图,终点起点尽收眼底。
|
||||
|
||||
#### 为什么还需要“位置”信息?
|
||||
|
||||
因为 Transformer 是“一锅端”,如果不做特殊处理,它分不清“我爱你”和“你爱我”的区别(词都一样,只是顺序不同)。
|
||||
所以我们会给每个词贴个**号码牌(位置编码)**,告诉模型谁在第 1 位,谁在第 2 位。
|
||||
|
||||
> 小提醒:很多 LLM 是自回归(预测下一个词)的,所以在生成时仍然是一 token 一 token 往外吐;但在**每一步生成**的内部计算里,Transformer 依旧更能利用矩阵并行与缓存优化。
|
||||
|
||||
### 4.3 效率黑科技:KV 缓存 (KV Cache)
|
||||
|
||||
你可能听说过,生成长文本时,越到后面越慢,或者显存占用越大。这通常是因为模型需要“记住”之前生成的所有内容。
|
||||
|
||||
**Transformer 怎么“记笔记”?**
|
||||
|
||||
在 Transformer 的注意力机制中,每个词都会生成 `Key (K)` 和 `Value (V)` 两个向量,用来供后面的词“查询”。
|
||||
|
||||
- 当模型生成第 100 个词时,它需要回头看前 99 个词的 K 和 V。
|
||||
- 如果每次都重新计算前 99 个词的 K 和 V,那就太浪费了!
|
||||
|
||||
**KV Cache 的作用:**
|
||||
|
||||
KV Cache 就像是一个**“增量笔记本”**。
|
||||
|
||||
1. **不重算**:算完第 1 个词的 K 和 V,存起来。
|
||||
2. **只算新**:生成第 2 个词时,只计算第 2 个词的 K 和 V,然后和第 1 个词的 K、V 拼在一起。
|
||||
3. **越存越多**:随着对话进行,这个“笔记本”(显存占用)会越来越厚。
|
||||
|
||||
这就是为什么长文本对话(Long Context)会消耗大量显存的原因——**不是模型变大了,而是笔记(KV Cache)太厚了。**
|
||||
|
||||
<RNNvsTransformer />
|
||||
|
||||
|
||||
@@ -6,26 +6,245 @@
|
||||
|
||||
## 0. 引言:系统的"缓冲器"
|
||||
|
||||
你在淘宝买完东西,为什么点击"支付"后,不会立刻收到短信通知?
|
||||
你在抖音发了一条评论,为什么点赞数不是瞬间就增加?
|
||||
### 0.1 从生活中的例子说起
|
||||
|
||||
这背后都有一个功臣:**消息队列 (Message Queue)**。
|
||||
想象一下这个场景:
|
||||
|
||||
如果同步调用是"打电话",那消息队列就是"发微信"。
|
||||
打电话要求对方**立即响应**(同步),发微信可以等对方**稍后处理**(异步)。
|
||||
**🏪 餐厅点餐的智慧**
|
||||
|
||||
### 0.1 为什么要用消息队列?
|
||||
你走进一家繁忙的餐厅,前台服务员(A)迅速给你点单、收钱,然后告诉你"请稍等,餐好了会叫号"。你不需要站在厨房门口等着厨师(B)直接把菜端给你,而是可以安心坐下刷手机。
|
||||
|
||||
只有一个理由:**解耦和削峰**。
|
||||
**为什么这么做?**
|
||||
- 如果每个顾客都站在厨房门口等(同步调用),厨房会乱成一团
|
||||
- 用"叫号系统"(消息队列),服务员快速完成点餐,厨房按自己的节奏做菜
|
||||
- 即使厨师临时休息了,点餐也不会受影响,订单会排队等他回来
|
||||
|
||||
- **解耦**:A 不需要直接调用 B,把消息扔给队列就完事了。
|
||||
- _例子_:用户下单后,订单服务不需要直接调用库存、积分、通知服务,而是发一条"下单成功"消息。
|
||||
- **削峰**:把瞬间的高峰流量"摊平",避免系统被打爆。
|
||||
- _例子_:秒杀活动,1 秒内有 10 万个请求,但数据库只能处理 1000 个。队列把这 10 万个请求暂存起来,慢慢处理。
|
||||
**🛒 淘宝支付的秘密**
|
||||
|
||||
你在淘宝买完东西,点击"支付"后,系统显示"支付成功",但你可能要等几秒甚至几分钟才收到短信通知。
|
||||
|
||||
**为什么不是立即收到?**
|
||||
因为支付系统要做的事情太多了:
|
||||
- ✅ 扣款(必须立即完成)
|
||||
- ⏳ 发送短信通知(可以稍后)
|
||||
- ⏳ 更新积分(可以稍后)
|
||||
- ⏳ 给推荐系统发送数据(可以稍后)
|
||||
|
||||
如果把所有事情都卡在"支付"这个按钮上,你可能要等 5 秒才能看到"支付成功"。聪明的系统会:
|
||||
1. 先完成扣款
|
||||
2. 把其他任务扔进一个"待办事项池"(消息队列)
|
||||
3. 立即告诉你"支付成功"
|
||||
4. 后台慢慢处理那些待办事项
|
||||
|
||||
**这就是消息队列的核心价值:把"必须现在做"和"可以稍后做"的事情分开。**
|
||||
|
||||
### 0.2 什么是消息队列?
|
||||
|
||||
**消息队列**就像一个智能的"中转站"或"缓冲区":
|
||||
|
||||
```
|
||||
如果同步调用是"打电话"(要求对方立即响应)
|
||||
那消息队列就是"发微信"(可以等对方稍后处理)
|
||||
```
|
||||
|
||||
**用一个比喻理解**:
|
||||
|
||||
> **没有消息队列**:你直接把文件交给同事,他正在开会,你只能干等。
|
||||
>
|
||||
> **有消息队列**:你把文件放到他的办公桌(队列),继续做自己的事。他开完会自己来拿。
|
||||
|
||||
### 0.3 为什么要用消息队列?
|
||||
|
||||
核心原因就两个:**解耦**和**削峰**。
|
||||
|
||||
#### 📌 解耦:让系统更灵活
|
||||
|
||||
**问题**:A 直接调用 B,一旦 B 出问题,A 也跟着完蛋。
|
||||
|
||||
```python
|
||||
# 紧耦合的例子(不好)
|
||||
def create_order(user_id, product_id):
|
||||
order = db.save_order(user_id, product_id)
|
||||
|
||||
# 如果通知服务挂了,整个订单创建就失败
|
||||
notification.send_sms(user_id, "订单创建成功")
|
||||
notification.send_email(user_id, "订单创建成功")
|
||||
|
||||
return order
|
||||
```
|
||||
|
||||
**解决**:用消息队列做"中介",A 只管发消息,不关心 B 是否在线。
|
||||
|
||||
```python
|
||||
# 松耦合的例子(好)
|
||||
def create_order(user_id, product_id):
|
||||
order = db.save_order(user_id, product_id)
|
||||
|
||||
# 扔到队列里就完事了,不管通知服务是否在线
|
||||
queue.publish("order.created", {
|
||||
"user_id": user_id,
|
||||
"order_id": order.id
|
||||
})
|
||||
|
||||
return order
|
||||
```
|
||||
|
||||
**好处**:
|
||||
- ✅ 订单系统不依赖通知系统
|
||||
- ✅ 可以随时增加新的消费者(比如加一个"积分系统")
|
||||
- ✅ 通知系统升级不影响订单系统
|
||||
|
||||
#### 📌 削峰:把洪峰变成平缓的水流
|
||||
|
||||
**问题**:瞬间流量太高,系统扛不住。
|
||||
|
||||
**场景**:双11秒杀
|
||||
- 1 秒内有 10 万个请求涌进来
|
||||
- 数据库每秒只能处理 1000 个
|
||||
- 如果直接打到数据库,数据库会直接"爆掉"
|
||||
|
||||
**解决**:用消息队列当"蓄水池"
|
||||
|
||||
```
|
||||
洪水来了(10 万请求/秒)
|
||||
↓
|
||||
[大坝] 消息队列暂存
|
||||
↓
|
||||
平缓流出(1000 请求/秒)
|
||||
↓
|
||||
[农田] 数据库慢慢处理
|
||||
```
|
||||
|
||||
<PeakShavingDemo />
|
||||
|
||||
**关键点**:消息队列的本质是**异步通信**,通过把"立即执行"变成"稍后处理",提升系统的吞吐量和可用性。
|
||||
### 0.4 消息队列的本质
|
||||
|
||||
**一句话总结**:消息队列的本质是**异步通信**,通过把"立即执行"变成"稍后处理",提升系统的吞吐量和可用性。
|
||||
|
||||
**关键特点**:
|
||||
- ✅ **异步**:不需要等任务完成,立即返回
|
||||
- ✅ **解耦**:服务之间不直接依赖
|
||||
- ✅ **缓冲**:暂存消息,平滑流量
|
||||
- ✅ **可靠**:消息持久化,不怕丢失
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ 全局观:消息队列知识地图
|
||||
|
||||
### 消息队列的核心价值
|
||||
|
||||
> **用"空间换时间,用异步换性能"** —— 让系统可以"快速响应请求,慢慢处理任务"
|
||||
|
||||
### 知识体系地图
|
||||
|
||||
```
|
||||
消息队列知识体系
|
||||
│
|
||||
├── 📦 基础概念(必学)
|
||||
│ ├── 生产者(Producer):发送消息的一方
|
||||
│ ├── 消费者(Consumer):接收并处理消息的一方
|
||||
│ ├── 消息代理(Broker):存储和转发消息的中介
|
||||
│ └── 消息模式
|
||||
│ ├── 点对点(P2P):一条消息被一个消费者消费
|
||||
│ └── 发布订阅(Pub/Sub):一条消息被多个消费者消费
|
||||
│
|
||||
├── 🎯 核心应用场景(必学)
|
||||
│ ├── 异步处理:把同步改成异步,提升响应速度
|
||||
│ ├── 削峰填谷:缓冲高峰流量,保护系统
|
||||
│ ├── 系统解耦:消除服务之间的直接依赖
|
||||
│ └── 数据分发:一条消息分发给多个消费者
|
||||
│
|
||||
├── 🔒 可靠性保证(重要)
|
||||
│ ├── 消息不丢失:持久化 + ACK 机制 + 多副本
|
||||
│ ├── 消息不重复:幂等性设计
|
||||
│ └── 消息顺序:单分区或内存排序
|
||||
│
|
||||
├── 🚀 高级特性(进阶)
|
||||
│ ├── 死信队列(DLQ):处理无法消费的消息
|
||||
│ ├── 延迟消息:指定时间后才消费
|
||||
│ └── 事务消息:保证本地事务和消息发送的一致性
|
||||
│
|
||||
├── 🛠️ 主流消息队列(了解)
|
||||
│ ├── RabbitMQ:传统消息队列,功能丰富
|
||||
│ ├── Kafka:分布式日志系统,吞吐量极大
|
||||
│ ├── RocketMQ:电商级消息队列,功能全面
|
||||
│ └── Redis Stream:轻量级队列,适合小规模应用
|
||||
│
|
||||
└── 📊 实战设计(综合应用)
|
||||
└── 秒杀系统、订单系统、异步任务处理
|
||||
```
|
||||
|
||||
### 学习路径建议(0 基础小白)
|
||||
|
||||
#### 🎒 第一阶段:建立直觉(1-2 小时)
|
||||
**目标**:理解消息队列是什么,为什么需要它
|
||||
|
||||
1. **阅读本章节的 0. 引言部分**
|
||||
- 理解"餐厅点餐"和"淘宝支付"的例子
|
||||
- 掌握"解耦"和"削峰"两个核心价值
|
||||
|
||||
2. **动手体验**(可选)
|
||||
- 找一个生活中的"队列"例子(如餐厅叫号、客服排队)
|
||||
- 画出它的流程图
|
||||
|
||||
#### 📚 第二阶段:掌握基础(1-2 天)
|
||||
**目标**:理解核心概念和基本用法
|
||||
|
||||
1. **学习基础概念**
|
||||
- 生产者、消费者、Broker
|
||||
- 点对点 vs 发布订阅
|
||||
- 阅读本章节第 1 部分
|
||||
|
||||
2. **选择一个消息队列上手**
|
||||
- 推荐从 **Redis Stream** 或 **RabbitMQ** 开始(学习曲线低)
|
||||
- 跟着官方文档写一个"生产者-消费者"的 Hello World
|
||||
|
||||
3. **实现第一个异步任务**
|
||||
- 场景:用户注册后,异步发送欢迎邮件
|
||||
- 用代码实现:注册接口 → 发消息到队列 → 消费者发送邮件
|
||||
|
||||
#### 🔥 第三阶段:深入核心(1 周)
|
||||
**目标**:掌握消息队列的核心用法
|
||||
|
||||
1. **学习核心设计模式**
|
||||
- 异步处理:提升响应速度
|
||||
- 削峰填谷:保护系统
|
||||
- 系统解耦:降低依赖
|
||||
- 阅读本章节第 3 部分
|
||||
|
||||
2. **保证可靠性**
|
||||
- 消息不丢失:持久化 + ACK
|
||||
- 消息不重复:幂等性设计
|
||||
- 阅读本章节第 4 部分
|
||||
|
||||
3. **实战练习**
|
||||
- 设计一个"秒杀系统":用消息队列削峰
|
||||
- 设计一个"订单系统":用消息队列解耦
|
||||
|
||||
#### 🚀 第四阶段:精通高级特性(2-4 周)
|
||||
**目标**:处理复杂场景
|
||||
|
||||
1. **高级特性**
|
||||
- 死信队列:处理异常消息
|
||||
- 延迟消息:定时任务
|
||||
- 事务消息:保证一致性
|
||||
- 阅读本章节第 5 部分
|
||||
|
||||
2. **完整系统设计**
|
||||
- 设计一个带监控的异步处理系统
|
||||
- 处理各种异常场景(消息丢失、重复、顺序错乱)
|
||||
|
||||
3. **深入学习特定 MQ**
|
||||
- Kafka:学习高可用架构(多副本、分区)
|
||||
- RocketMQ:学习事务消息
|
||||
|
||||
### 学习建议
|
||||
|
||||
- ✅ **先理解,再动手**:不要一开始就陷入代码细节,先理解为什么需要消息队列
|
||||
- ✅ **从简单开始**:不要一上来就学 Kafka,从 Redis Stream 或 RabbitMQ 开始
|
||||
- ✅ **边学边练**:每学一个概念,就写代码实践一下
|
||||
- ✅ **关注应用场景**:不仅要知其然,还要知其所以然
|
||||
- ✅ **阅读真实案例**:看看淘宝、抖音等大厂如何使用消息队列
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user