AI 智能体开发 · Day 2 详细学习手册

AI 智能体开发 · Day 2 详细学习手册

主题 :Transformer 架构直觉理解------从"为什么需要 Attention"到"GPT 怎么生成文本"

总时长 :2-2.5 小时(可分两次完成)

难度 :中等偏概念(抽象内容多,代码少但重要)

产出 :能用自己的话解释 Attention + 1 个注意力可视化脚本 + 结构化笔记

前置条件 :完成 Day 1(理解 LLM 基本概念、环境已搭建、API 可调用)

建议:今天内容偏抽象,建议先看 3Blue1Brown 的 GPT 视频(15 分钟)再开始


目录

  1. 学习目标与知识地图
  2. [Part A:为什么需要 Attention(30 分钟)](#Part A:为什么需要 Attention(30 分钟))
  3. [Part B:Self-Attention 机制详解(40 分钟)](#Part B:Self-Attention 机制详解(40 分钟))
  4. [Part C:多头注意力与位置编码(25 分钟)](#Part C:多头注意力与位置编码(25 分钟))
  5. [Part D:Transformer 整体架构(20 分钟)](#Part D:Transformer 整体架构(20 分钟))
  6. [Part E:Encoder vs Decoder(15 分钟)](#Part E:Encoder vs Decoder(15 分钟))
  7. [Part F:代码实验------注意力可视化(20 分钟)](#Part F:代码实验——注意力可视化(20 分钟))
  8. 今日笔记模板
  9. 验收清单
  10. [常见问题 FAQ](#常见问题 FAQ)
  11. 扩展资源
  12. 明日预告

1. 学习目标与知识地图

你今天要达成的目标

概念层面(能用自己话讲清楚):

  • RNN/LSTM 处理文本有什么问题,Attention 解决了什么
  • Q、K、V 三个概念分别是什么,怎么协同工作
  • 多头注意力为什么需要多个"头"
  • 位置编码为什么需要(Attention 本身没有顺序概念)
  • Transformer 的完整数据流(从文本到输出概率)
  • GPT 为什么是 Decoder-only,和 BERT 有什么区别

操作层面(亲手做过):

  • 用代码实现一个最简 Self-Attention
  • 可视化注意力权重(看模型"关注"了哪些词)
  • 验证 Attention 的无序性(打乱输入顺序看变化)

知识地图

复制代码
Part A: 问题背景
  ├── RNN/LSTM 怎么处理文本
  ├── RNN 的三大缺陷
  └── Attention 的核心思想

Part B: Self-Attention 机制
  ├── Q/K/V 的直觉理解
  ├── 逐步计算过程(手算级别)
  ├── 为什么用 Q·K 而不是直接比向量
  └── Softmax 归一化的作用

Part C: 多头注意力 + 位置编码
  ├── 为什么需要多个头
  ├── 多头怎么并行
  ├── 位置编码解决的问题
  └── 正弦/余弦位置编码

Part D: Transformer 架构
  ├── 完整数据流
  ├── Layer Normalization
  ├── Feed Forward Network
  └── 残差连接

Part E: 架构对比
  ├── Encoder-only (BERT)
  ├── Decoder-only (GPT)
  └── Encoder-Decoder (T5)

Part F: 代码实验
  ├── 最简 Self-Attention 实现
  ├── 注意力权重可视化
  └── 输入顺序实验

2. Part A:为什么需要 Attention(30 分钟)

这部分纯概念,不需要电脑。理解"为什么"比理解"怎么算"更重要。

2.1 Transformer 之前:RNN 怎么工作(10 分钟)

在 2017 年 Transformer 出现之前,处理文本(翻译、摘要、分类)主要用 RNN (循环神经网络)和它的升级版 LSTM(长短期记忆网络)。

RNN 的工作方式------逐词处理

复制代码
输入句子: "The cat sat on the mat because it was tired"

RNN 逐词处理:
  时刻 1: 读入 "The"     → 隐状态 h1(记住了一些信息)
  时刻 2: 读入 "cat"     → h1 + "cat" → 隐状态 h2
  时刻 3: 读入 "sat"     → h2 + "sat" → 隐状态 h3
  时刻 4: 读入 "on"      → h3 + "on"  → 隐状态 h4
  时刻 5: 读入 "the"     → h4 + "the" → 隐状态 h5
  时刻 6: 读入 "mat"     → h5 + "mat" → 隐状态 h6
  时刻 7: 读入 "because" → h6 + "because" → 隐状态 h7
  时刻 8: 读入 "it"      → h7 + "it" → 隐状态 h8
       ↑
       这时候 RNN 需要理解 "it" 指代谁
       但 "cat" 的信息经过了 6 次传递,已经很模糊了

通俗比喻

复制代码
RNN 就像"传话游戏":
  10 个人排成一排,第一个人看到一句话,
  然后悄悄告诉第二个人,第二个人告诉第三个人...
  
  传到最后一个人时:
  - 最近的词记得清楚
  - 最前面的词已经面目全非
  
  这就是"信息衰减"问题

2.2 RNN 的三大致命缺陷(10 分钟)

缺陷 1:长距离依赖丢失

复制代码
句子: "The animal that was walking through the forest and looking for food 
       near the river yesterday afternoon was a tiger"

问题: "was a tiger" 要和 "The animal" 建立联系
      但中间隔了 15+ 个词
      RNN 处理到 "tiger" 时,"animal" 的信息几乎丢失了

LSTM 用"门控机制"缓解了这个问题,但没根本解决
  → 长句子依然容易出错
  → 20 词以上的句子,LSTM 也开始力不从心

缺陷 2:无法并行计算

复制代码
RNN 的处理是串行的:
  必须先处理第 1 个词 → 才能处理第 2 个词 → 才能处理第 3 个词...

这意味着:
  - 训练时无法利用 GPU 的并行能力
  - 句子越长,训练越慢
  - 1000 词的文档要串行处理 1000 步

对比 Transformer:
  - 所有词同时处理(并行)
  - GPU 利用率极高
  - 这是 Transformer 能训练万亿参数的前提

缺陷 3:信息瓶颈

复制代码
RNN 把整个句子的信息压缩到最后一个隐状态 h_n

  "The cat sat on the mat" → h_6 = [0.3, -0.1, 0.8, ...]

  一个固定大小的向量要编码整个句子的所有信息
  句子越长,压缩损失越大
  
  类比: 把一本 300 页的书压缩成一张 A4 纸的摘要
        必然丢失大量细节

2.3 Attention 的核心思想(10 分钟)

Attention 不是某个人某天突然发明的,而是为了解决 RNN 的问题逐步演进而来。

核心思想一句话:处理每个词时,直接"看"句子中所有其他词,动态决定该关注哪些。

复制代码
传统 RNN 处理 "it":
  只能依赖前面传过来的、已经衰减的隐状态
  "it" 指代 "cat" 还是 "mat"?------信息不够,猜不准

Attention 处理 "it":
  "it" 直接看回句子中所有词:
    "The"    → 关注度 0.05(不太相关)
    "cat"    → 关注度 0.70(高度相关!"it" 可能指 cat)
    "sat"    → 关注度 0.05
    "on"     → 关注度 0.02
    "the"    → 关注度 0.03
    "mat"    → 关注度 0.10(也有可能指 mat)
    "because"→ 关注度 0.02
    "it"     → 关注度 0.03
  
  → "it" 的新表示 = 所有词的加权求和(cat 权重最大)
  → "it" 现在包含了 "cat" 的语义信息
  → 指代消歧成功!

通俗比喻升级版

复制代码
你在参加一个酒会:

RNN 模式:
  你只能听身边一个人说话
  他告诉你之前发生了什么
  但他的转述已经丢失了很多信息

Attention 模式:
  你能同时感知整个房间所有人的对话
  当别人提到"那个穿红衣服的人"时
  你的注意力自动聚焦到红衣服的人身上
  其他人变成背景噪音
  → 你直接获取了需要的信息,不需要别人转述

Attention 的三个关键特性

特性 说明 好处
全局视野 每个词都能看到所有其他词 解决长距离依赖
动态权重 关注度根据内容自动计算 不同语境下关注不同部分
并行计算 所有词同时处理 训练速度大幅提升

自测:能回答下面两个问题就过关------

  1. RNN 处理长文本的三个问题是什么?

    长距离依赖丢失、无法并行、信息瓶颈

  2. Attention 的核心思想是什么?用一句话说。

    处理每个词时,直接看所有其他词,动态决定关注哪些。


3. Part B:Self-Attention 机制详解(40 分钟)

这是今天最重要也最抽象的部分。慢慢来,反复读。

3.1 Q/K/V 的直觉理解(15 分钟)

Self-Attention 的核心是三个矩阵变换:Q(Query)、K(Key)、V(Value)

先不用管数学,用搜索引擎的类比理解:

复制代码
你在用搜索引擎搜索信息:

1. 你输入搜索词 "Python 教程"
   → 这就是 Query (Q):你在"找"什么

2. 搜索引擎有海量的网页,每个网页有标题和关键词
   → 这些标题/关键词就是 Key (K):每个网页"能提供"什么

3. 搜索引擎用你的 Query 和每个网页的 Key 做匹配
   → 算出相关度分数(Attention 权重)
   → "Python 入门教程" → 相关度 0.9
   → "Python 爬虫实战" → 相关度 0.7
   → "Java 编程指南"   → 相关度 0.05

4. 搜索引擎不是只返回最相关的那一个
   而是按相关度加权返回所有网页的内容
   → 这些网页的正文内容就是 Value (V)
   → 最终结果 = 0.9×(Python入门) + 0.7×(Python爬虫) + 0.05×(Java) + ...

Self-Attention 中的 Q/K/V

在 Self-Attention 中,Q、K、V 都来自同一个输入(所以叫"Self"):

复制代码
输入: "我 喜欢 编程"

每个词通过三个不同的权重矩阵,生成三个不同的向量:
  
  "我"   → Q_我, K_我, V_我
  "喜欢" → Q_喜欢, K_喜欢, V_喜欢
  "编程" → Q_编程, K_编程, V_编程

处理 "编程" 这个词时:
  1. 用 Q_编程("编程" 在找什么)去和每个 K 做匹配
     - Q_编程 · K_我   = 0.1  ("我" 和 "编程" 关系不大)
     - Q_编程 · K_喜欢 = 0.3  ("喜欢" 有点关系)
     - Q_编程 · K_编程 = 0.6  (自己和自己最相关)

  2. 用 Softmax 归一化(让权重加起来等于 1)
     - 0.1 → 0.08
     - 0.3 → 0.24
     - 0.6 → 0.68

  3. 用权重对 V 加权求和
     - "编程"的新表示 = 0.08×V_我 + 0.24×V_喜欢 + 0.68×V_编程
     - 这个新表示融合了整个句子的上下文信息

为什么需要三个不同的矩阵?

复制代码
同一个词在不同角色下需要不同的表示:

"编程" 作为 Query 时:表示"我在找什么"(找和编程相关的上下文)
"编程" 作为 Key 时:  表示"我能提供什么"(我是编程相关的信息)
"编程" 作为 Value 时:表示"我的实际内容"(编程的具体语义)

如果用同一个向量,模型就无法区分这三种角色。
所以用三个不同的权重矩阵 W_Q, W_K, W_V 来变换:

  Q = 输入 × W_Q
  K = 输入 × W_K  
  V = 输入 × W_V

这些 W_Q, W_K, W_V 是模型在训练过程中学出来的参数。

3.2 逐步计算过程(15 分钟)

用一个极简例子手动走一遍计算流程,帮你建立直觉。

设定:3 个词,每个词用 2 维向量表示(实际是 768 或 12288 维)

复制代码
输入(已经 Embedding 后的向量):
  x1 = [1, 0]   ("我")
  x2 = [0, 1]   ("喜欢")
  x3 = [1, 1]   ("编程")

假设训练好的权重矩阵(实际中这些是学出来的):
  W_Q = [[1, 0], [0, 0]]
  W_K = [[0, 1], [0, 0]]
  W_V = [[1, 0], [0, 1]]

Step 1:计算 Q、K、V

复制代码
Q = 输入 × W_Q
  Q1 = [1,0] × [[1,0],[0,0]] = [1, 0]   ← "我" 的 Query
  Q2 = [0,1] × [[1,0],[0,0]] = [0, 0]   ← "喜欢" 的 Query
  Q3 = [1,1] × [[1,0],[0,0]] = [1, 0]   ← "编程" 的 Query

K = 输入 × W_K
  K1 = [1,0] × [[0,1],[0,0]] = [0, 1]   ← "我" 的 Key
  K2 = [0,1] × [[0,1],[0,0]] = [1, 0]   ← "喜欢" 的 Key  ← 注意这里
  K3 = [1,1] × [[0,1],[0,0]] = [0, 1]   ← "编程" 的 Key

V = 输入 × W_V
  V1 = [1,0] × [[1,0],[0,1]] = [1, 0]   ← "我" 的 Value
  V2 = [0,1] × [[1,0],[0,1]] = [0, 1]   ← "喜欢" 的 Value
  V3 = [1,1] × [[1,0],[0,1]] = [1, 1]   ← "编程" 的 Value

Step 2:计算 Attention 分数(用 Q·K 的点积)

以 "编程"(第 3 个词)为例,看它对每个词的关注度:

复制代码
Score = Q3 · K_i

  Score(编程, 我)   = [1,0] · [0,1] = 1×0 + 0×1 = 0
  Score(编程, 喜欢) = [1,0] · [1,0] = 1×1 + 0×0 = 1   ← 最高!
  Score(编程, 编程) = [1,0] · [0,1] = 1×0 + 0×1 = 0

原始分数: [0, 1, 0]

Step 3:缩放 + Softmax 归一化

复制代码
缩放(除以 √d_k,d_k 是 Key 的维度,这里是 2):
  [0, 1, 0] / √2 = [0, 0.707, 0]

  为什么缩放?当维度很大时,点积值会很大,
  导致 Softmax 梯度消失。除以 √d_k 让数值稳定。

Softmax(把分数变成概率分布,加起来等于 1):
  e^0 / (e^0 + e^0.707 + e^0) = 1 / (1 + 2.028 + 1) = 0.249
  e^0.707 / (1 + 2.028 + 1) = 2.028 / 4.028 = 0.503
  e^0 / 4.028 = 0.249

  Attention 权重 = [0.249, 0.503, 0.249]
                    ↑          ↑          ↑
                   对"我"    对"喜欢"   对"编程"

Step 4:加权求和

复制代码
"编程"的新表示 = 0.249 × V1 + 0.503 × V2 + 0.249 × V3
               = 0.249 × [1,0] + 0.503 × [0,1] + 0.249 × [1,1]
               = [0.249, 0] + [0, 0.503] + [0.249, 0.249]
               = [0.498, 0.752]

原始 "编程" = [1, 1]
新的 "编程" = [0.498, 0.752]

新表示融合了上下文信息("喜欢" 的权重最大,所以新表示更偏向 "喜欢" 的方向)

这就是 Self-Attention 的完整计算流程。实际中维度是 768 或更大,但流程一模一样。

3.3 为什么用点积而不是其他相似度(5 分钟)

复制代码
为什么用 Q·K(点积)来算相似度?

  方案 A: 余弦相似度 → 需要额外归一化,计算多一步
  方案 B: 欧氏距离   → 值越小越相似,和 Attention 的"越大越关注"方向相反
  方案 C: 点积       → 简单高效,两个向量越"同向",点积越大

  点积的数学意义:
    A · B = |A| × |B| × cos(θ)
    
    当两个向量方向一致时(cos θ → 1),点积最大
    当两个向量正交时(cos θ = 0),点积为 0
    当两个向量相反时(cos θ = -1),点积最小

  语义上:方向一致的向量代表"语义相关"
  所以点积大 = 语义相关 = 应该多关注

3.4 Softmax 的作用(5 分钟)

复制代码
原始分数: [0, 1, 0]

为什么不直接用这些分数做权重?
  - 它们不一定是正数(可能是负数)
  - 它们的和不是 1(无法做概率解释)
  - 数值范围不可控

Softmax 做了两件事:
  1. 把所有分数变成正数(e^x 永远为正)
  2. 让它们加起来等于 1(变成概率分布)

  [0, 1, 0] → Softmax → [0.249, 0.503, 0.249]
                                ↑ 最大值被放大
                                其他值被压缩

Softmax 的"软"体现在:
  - 不是 hard max(不是选一个为 1 其他为 0)
  - 而是"软"地分配权重------大的更大,小的更小,但都保留
  
  这让模型可以同时关注多个相关词,而不是只盯一个

自测

  1. Q、K、V 分别是什么?用搜索引擎类比解释。
  2. 为什么 Attention 分数要除以 √d_k?
  3. Softmax 为什么叫"Soft"?

4. Part C:多头注意力与位置编码(25 分钟)

4.1 为什么需要多头注意力(10 分钟)

单个 Attention 头只能学一种"关注模式"。但语言中的关系是多维度的:

复制代码
句子: "The animal that was running quickly crossed the street because it was scared"

"it" 这个词需要同时处理多种关系:
  - 指代关系: "it" 指代 "animal"(一个头关注)
  - 因果关系: "scared" 因为 "running quickly"(另一个头关注)
  - 语法关系: "it" 是主语,"was scared" 是谓语(又一个头关注)
  - 语义关系: "scared" 和 "animal" 语义相关(又一个头关注)

一个头只能学到一种关系
→ 用多个头,每个头学不同的关系
→ 最后把所有头的结果拼接起来

多头注意力的计算

复制代码
输入: "我 喜欢 编程"  (每个词 6 维向量)

8 个头,每个头把 6 维切成 6/8... 不对,实际中维度更大

实际例子(GPT-3):
  - 输入维度: 12288
  - 头数: 96
  - 每个头维度: 12288 / 96 = 128

每个头独立做 Self-Attention:
  Head_1: 关注语法关系    → 输出 128 维
  Head_2: 关注指代关系    → 输出 128 维
  Head_3: 关注语义关系    → 输出 128 维
  ...
  Head_96: 关注某种模式   → 输出 128 维

拼接: [Head_1 | Head_2 | ... | Head_96] → 12288 维
再经过一个线性变换 → 最终输出 12288 维

类比

复制代码
一个头就像一个人只戴了一种颜色的眼镜看世界:
  - 红色眼镜:只看到温度(热/冷)
  - 蓝色眼镜:只看到湿度(干/湿)
  - 绿色眼镜:只看到距离(远/近)

多头就像同一个人同时戴了 96 副不同颜色的眼镜
  → 看到一个 96 维度的丰富世界
  → 对语言的理解更全面

4.2 位置编码------Attention 的"失忆症"(15 分钟)

问题发现

复制代码
Self-Attention 有一个"缺陷":它天生不知道词的顺序。

  输入 A: "狗 咬 人"
  输入 B: "人 咬 狗"

  对 Self-Attention 来说,A 和 B 的处理方式完全一样!
  因为 Attention 只看"哪些词之间相关",不看"谁在前谁在后"

  但显然 "狗咬人" 和 "人咬狗" 意思完全不同

为什么 Attention 没有顺序概念?

复制代码
Self-Attention 的计算:
  每个词的新表示 = 所有词的加权求和

  加权求和是"无序"的:
    a×V1 + b×V2 + c×V3 = c×V3 + a×V1 + b×V2

  改变输入顺序,只要权重也跟着变,结果可以一样
  → Attention 本身不编码位置信息

解决方案:位置编码(Positional Encoding)

复制代码
给每个位置加上一个"位置标记",让模型知道每个词在第几个位置。

原始 Embedding: 
  "狗" → [0.5, -0.3, 0.8, ...]
  "咬" → [0.2, 0.7, -0.1, ...]
  "人" → [0.9, -0.2, 0.4, ...]

加上位置编码后:
  位置 1: "狗" → [0.5, -0.3, 0.8, ...] + PE(1)
  位置 2: "咬" → [0.2, 0.7, -0.1, ...] + PE(2)  
  位置 3: "人" → [0.9, -0.2, 0.4, ...] + PE(3)

  PE(1), PE(2), PE(3) 是不同的向量
  → 即使同一个词出现在不同位置,加上 PE 后向量也不同
  → 模型能区分 "狗咬人" 和 "人咬狗"

位置编码怎么生成

复制代码
Transformer 原论文用正弦/余弦函数:

  PE(pos, 2i)   = sin(pos / 10000^(2i/d))
  PE(pos, 2i+1) = cos(pos / 10000^(2i/d))

  pos: 词的位置(第几个词)
  i:   向量的第几维
  d:   向量总维度

直觉理解:
  - 不同维度用不同频率的正弦波
  - 就像时钟:秒针转得快、分针中等、时针慢
  - 每个位置都有唯一的"波形指纹"
  - 模型通过这些波形就能推断出位置

后来还有:
  - 可学习位置编码(BERT 用的,位置编码是学出来的参数)
  - 相对位置编码(T5 用的,编码词之间的相对距离)
  - RoPE 旋转位置编码(Llama 用的,目前主流)

自测

  1. 为什么需要多头注意力?一个头不够吗?
  2. Self-Attention 为什么没有顺序概念?
  3. 位置编码解决什么问题?

5. Part D:Transformer 整体架构(20 分钟)

5.1 完整数据流(10 分钟)

把前面所有零件组装起来,看 Transformer 的完整数据流:

复制代码
输入文本: "Hello world"
    │
    ▼
┌─────────────────────────────────┐
│  1. Tokenization(分词)         │
│     "Hello world" → [15496, 995] │
│     文本 → Token ID 列表          │
└─────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────┐
│  2. Embedding(嵌入)            │
│     [15496, 995] → [[0.1,-0.3,..], [0.5,0.2,..]]
│     Token ID → 向量(每个向量 d_model 维)
│     这个向量是模型学出来的"词义"表示
└─────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────┐
│  3. 位置编码(Positional Encoding)│
│     向量 + 位置向量 → 带位置信息的向量
│     让模型知道每个词在第几个位置
└─────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────┐
│  4. Transformer Block × N (重复 N 层)  │
│                                         │
│  ┌───────────────────────────────────┐  │
│  │  4a. Multi-Head Self-Attention    │  │
│  │      每个词"看"所有词,生成新表示   │  │
│  └───────────────────────────────────┘  │
│    │  + 残差连接(把输入直接加到输出)    │
│    │  + Layer Normalization(归一化)    │
│    ▼                                    │
│  ┌───────────────────────────────────┐  │
│  │  4b. Feed Forward Network (FFN)   │  │
│  │      两层全连接,对每个词独立处理     │  │
│  │      先放大维度(4倍)→ 激活 → 缩回  │  │
│  └───────────────────────────────────┘  │
│    │  + 残差连接                         │
│    │  + Layer Normalization              │
│    ▼                                    │
│  输出 → 传给下一层 Transformer Block     │
└─────────────────────────────────────────┘
    │
    │  (GPT-2 有 48 层, GPT-3 有 96 层, GPT-4 估计上百层)
    │
    ▼
┌─────────────────────────────────┐
│  5. 输出层                       │
│     最终向量 → 线性变换 → logits  │
│     logits: 对词表中每个词的"分数" │
│     [0.1, -2.3, 5.7, 0.02, ...]  │
│     (词表大小可能是 5万-10万)      │
└─────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────┐
│  6. Softmax → 概率分布           │
│     [0.001, 0.0001, 0.95, ...]   │
│     分数最高的词就是预测的下一个词 │
└─────────────────────────────────┘
    │
    ▼
  预测输出: "!"  (比如补全 "Hello world!")

5.2 三个关键组件详解(10 分钟)

残差连接(Residual Connection)

复制代码
不残差连接:
  输入 → Attention → 输出

残差连接:
  输入 → Attention → 输出 + 输入(把输入直接加到输出上)

为什么需要?
  - Transformer 有几十上百层
  - 深层网络容易梯度消失(训练不动)
  - 残差连接让梯度可以"抄近路"直接传到前面
  - 训练深层网络变得可行

类比:
  你写了一篇文章,编辑改了一版
  残差连接 = 编辑的修改 + 你的原文
  如果编辑改得好,最终版 = 原文 + 改进
  如果编辑改得不好,最终版 ≈ 原文(不会比原来更差)

Layer Normalization(层归一化)

复制代码
做什么:
  对一个样本的所有特征做归一化(均值=0, 方差=1)

为什么需要:
  - 深层网络中,每层的输出数值范围可能越来越大或越来越小
  - 导致训练不稳定(梯度爆炸或消失)
  - LayerNorm 把数值拉回稳定范围

类比:
  就像调音量------每经过一层,信号可能变大或变小
  LayerNorm 确保每层的输出音量都在合适范围

Feed Forward Network(前馈网络)

复制代码
结构:
  输入 (d 维) → 升维 (4d 维) → ReLU 激活 → 降维 (d 维) → 输出

  比如 d=768:
    768 → 3072 → ReLU → 768

为什么需要:
  - Self-Attention 做的是"词与词之间的信息交换"
  - FFN 做的是"每个词内部的非线性变换"
  - 两者互补: Attention 负责横向(词间),FFN 负责纵向(词内)

  先放大维度再缩回: 让模型在更高维空间做非线性变换
  → 增强表达能力(就像在更大的画布上画画,再缩小回来)

ReLU 激活:
  负数变 0,正数不变
  → 引入非线性(没有激活函数,再多层也等价于一层线性变换)

6. Part E:Encoder vs Decoder(15 分钟)

6.1 三种架构对比

Transformer 有三种使用方式,对应三种模型类型:

复制代码
┌─────────────────────────────────────────────────────┐
│  Encoder-only(只用编码器)                          │
│                                                     │
│  输入 → [Attention: 能看所有词] → 输出              │
│                                                     │
│  特点: 每个词能同时看到前后所有词(双向)            │
│  适合: 理解类任务(分类、搜索、相似度)              │
│  代表: BERT, RoBERTa, DeBERTa                       │
│  类比: 阅读理解------你可以反复看全文                    │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│  Decoder-only(只用解码器)                          │
│                                                     │
│  输入 → [Attention: 只能看前面的词] → 预测下一个词   │
│                                                     │
│  特点: 每个词只能看到前面的词(单向/自回归)         │
│  适合: 生成类任务(对话、写作、代码)                │
│  代表: GPT 系列, Llama, DeepSeek, Qwen              │
│  类比: 即兴演讲------你只能基于已说过的内容继续说        │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│  Encoder-Decoder(编码器+解码器)                    │
│                                                     │
│  输入 → Encoder(双向) → 编码向量                     │
│  编码向量 → Decoder(单向+交叉注意力) → 输出          │
│                                                     │
│  特点: 编码器理解输入,解码器生成输出                │
│  适合: 转换类任务(翻译、摘要)                      │
│  代表: T5, BART, 早期 Transformer                   │
│  类比: 翻译------先理解原文,再逐词生成译文              │
└─────────────────────────────────────────────────────┘

6.2 为什么 GPT 是 Decoder-only

复制代码
Decoder-only 的核心特征: 自回归生成(Autoregressive)

  给定 "今天 天气 真" → 预测 "好"
  给定 "今天 天气 真 好" → 预测 ","
  给定 "今天 天气 真 好 ," → 预测 "适合"
  ...一个词一个词往后生成

为什么 Decoder 用"掩码注意力"(Masked Attention)?

  训练时:
    输入: "今天 天气 真 好"
    目标: 预测每个位置下一个词
    
    处理 "天气" 时,不能看到 "真" 和 "好"
    否则就是"作弊"------模型直接抄答案了
    
  掩码: 把当前词后面的 Attention 权重强制设为 0
    位置1 "今天": 只能看 "今天"
    位置2 "天气": 只能看 "今天" "天气"  
    位置3 "真":   只能看 "今天" "天气" "真"
    ...

  这就是为什么 ChatGPT 一个字一个字蹦出来:
    生成每个词时,它只能基于已经生成的词
    不能"偷看"未来

6.3 为什么现在是 Decoder-only 的天下

复制代码
2020 年之前: BERT (Encoder-only) 是 NLP 霸主
2022 年之后: GPT (Decoder-only) 统治一切

原因:
1. 生成能力: Decoder 天生适合生成,而 LLM 的核心能力就是生成
2. 扩展性:   Decoder-only 结构更简单,更容易扩展到超大参数量
3. 统一性:   生成是通用能力------翻译、摘要、问答、代码都可以用生成来做
              而理解类任务(分类)也可以通过 Prompt 转成生成任务
4. In-context Learning: 大规模 Decoder 模型涌现出了"上下文学习"能力
              给几个例子就能做新任务,不需要微调

自测

  1. Encoder-only 和 Decoder-only 的核心区别是什么?
  2. 为什么 Decoder 要用 Masked Attention?
  3. 为什么现在主流大模型都是 Decoder-only?

7. Part F:代码实验------注意力可视化(20 分钟)

用代码把抽象概念变直观。这是今天唯一的代码部分。

7.1 最简 Self-Attention 实现

创建 code/attention_basics.py

python 复制代码
"""
Day 2 代码实验:用最简代码实现 Self-Attention,并可视化注意力权重
"""
import numpy as np

# ============================================
# 实验 1: 最简 Self-Attention(手动实现)
# ============================================
print("=" * 60)
print("实验 1: 手动实现 Self-Attention")
print("=" * 60)

# 模拟 3 个词的 Embedding(4 维向量)
# 实际中维度是 768 或 12288
np.random.seed(42)
seq_len = 4       # 句子长度(4 个词)
d_model = 8       # 每个词的向量维度

# 随机生成输入(模拟 Embedding 后的向量)
X = np.random.randn(seq_len, d_model)
print(f"\n输入形状: {X.shape} (句子长度={seq_len}, 维度={d_model})")
print(f"输入(每个词的向量):")
for i in range(seq_len):
    print(f"  词{i}: {[f'{v:.3f}' for v in X[i]]}")

# 三个权重矩阵(实际中是训练学出来的)
W_Q = np.random.randn(d_model, d_model)
W_K = np.random.randn(d_model, d_model)
W_V = np.random.randn(d_model, d_model)

# Step 1: 计算 Q, K, V
Q = X @ W_Q   # (4, 8) @ (8, 8) = (4, 8)
K = X @ W_K
V = X @ W_V

print(f"\nQ 形状: {Q.shape} (每个词的 Query 向量)")
print(f"K 形状: {K.shape} (每个词的 Key 向量)")
print(f"V 形状: {V.shape} (每个词的 Value 向量)")

# Step 2: 计算 Attention 分数 (Q · K^T)
# K^T 是 K 的转置
scores = Q @ K.T   # (4, 8) @ (8, 4) = (4, 4)
print(f"\nAttention 分数矩阵形状: {scores.shape}")
print(f"  scores[i][j] = 词i 对 词j 的关注分数")

# Step 3: 缩放(除以 √d_k)
d_k = d_model
scaled_scores = scores / np.sqrt(d_k)

# Step 4: Softmax(按行归一化)
def softmax(x):
    """对每一行做 Softmax"""
    # 减去最大值防止数值溢出
    x_max = np.max(x, axis=-1, keepdims=True)
    exp_x = np.exp(x - x_max)
    return exp_x / np.sum(exp_x, axis=-1, keepdims=True)

attention_weights = softmax(scaled_scores)

print(f"\nAttention 权重矩阵(每行加起来=1):")
print(f"{'':>8}", end="")
for j in range(seq_len):
    print(f"  词{j}    ", end="")
print()
for i in range(seq_len):
    print(f"词{i}看 → ", end="")
    for j in range(seq_len):
        print(f"{attention_weights[i][j]:.3f}  ", end="")
    print(f"  (和={attention_weights[i].sum():.3f})")

# Step 5: 加权求和
output = attention_weights @ V   # (4, 4) @ (4, 8) = (4, 8)
print(f"\n输出形状: {output.shape}")
print(f"每个词的新表示融合了上下文信息")

# ============================================
# 实验 2: 可视化 Attention 权重
# ============================================
print("\n" + "=" * 60)
print("实验 2: Attention 权重可视化")
print("=" * 60)

# 用一个真实句子来演示
# 模拟 "The cat sat on the mat because it was tired"
words = ["The", "cat", "sat", "on", "the", "mat", "because", "it", "was", "tired"]
seq_len = len(words)
d_model = 16

np.random.seed(123)
X = np.random.randn(seq_len, d_model)
W_Q = np.random.randn(d_model, d_model)
W_K = np.random.randn(d_model, d_model)
W_V = np.random.randn(d_model, d_model)

Q = X @ W_Q
K = X @ W_K
V = X @ W_V

scores = Q @ K.T / np.sqrt(d_model)
weights = softmax(scores)

# 用方块字符做热力图
print(f"\n句子: {' '.join(words)}")
print(f"\nAttention 热力图(每行=一个词在看其他词,█越多=关注度越高):\n")

# 表头
print(f"{'':>10}", end="")
for w in words:
    print(f"{w:>6}", end="")
print()
print("-" * (10 + len(words) * 6))

for i, word_i in enumerate(words):
    print(f"{word_i:>10}", end="")
    for j in range(len(words)):
        w = weights[i][j]
        if w > 0.3:
            bar = "████"
        elif w > 0.2:
            bar = "███ "
        elif w > 0.15:
            bar = "██  "
        elif w > 0.1:
            bar = "█   "
        else:
            bar = "    "
        print(f" {bar}", end="")
    print()

print(f"\n解读: 看每一行,█越多表示当前词越关注那个位置的词")
print(f"(注意: 随机权重的热力图不会有明显模式,真实模型会有清晰模式)")

# ============================================
# 实验 3: Attention 的无序性验证
# ============================================
print("\n" + "=" * 60)
print("实验 3: 验证 Attention 的无序性")
print("=" * 60)

# 原始输入
X_original = np.random.randn(3, 8)
W_Q = np.random.randn(8, 8)
W_K = np.random.randn(8, 8)
W_V = np.random.randn(8, 8)

def compute_attention(X, W_Q, W_K, W_V):
    Q = X @ W_Q
    K = X @ W_K
    V = X @ W_V
    scores = Q @ K.T / np.sqrt(8)
    weights = softmax(scores)
    output = weights @ V
    return output, weights

# 原始顺序: [词0, 词1, 词2]
out_orig, w_orig = compute_attention(X_original, W_Q, W_K, W_V)

# 打乱顺序: [词1, 词0, 词2]
X_shuffled = X_original[[1, 0, 2]]
out_shuffled, w_shuffled = compute_attention(X_shuffled, W_Q, W_K, W_V)

print(f"\n原始输入顺序: 词0, 词1, 词2")
print(f"打乱输入顺序: 词1, 词0, 词2")

print(f"\n原始 Attention 权重:")
print(w_orig)

print(f"\n打乱后 Attention 权重:")
print(w_shuffled)

print(f"""
关键发现:
  打乱顺序后,Attention 权重矩阵的行也跟着换了位置
  但每个词对应的权重分布不变(只是换了行号)
  
  这证明了: Self-Attention 本身不感知位置
  → 这就是为什么需要位置编码(Positional Encoding)
  → 没有位置编码,"狗咬人" 和 "人咬狗" 对模型来说一样
""")

# ============================================
# 实验 4: 多头 Attention 模拟
# ============================================
print("=" * 60)
print("实验 4: 多头 Attention(模拟 4 个头)")
print("=" * 60)

seq_len = 4
d_model = 32
n_heads = 4
d_head = d_model // n_heads  # 每个头 8 维

np.random.seed(456)
X = np.random.randn(seq_len, d_model)

print(f"\n配置: {seq_len} 个词, {d_model} 维, {n_heads} 个头, 每头 {d_head} 维")

# 每个头有自己的 W_Q, W_K, W_V
heads_outputs = []
for h in range(n_heads):
    W_Q_h = np.random.randn(d_model, d_head)
    W_K_h = np.random.randn(d_model, d_head)
    W_V_h = np.random.randn(d_model, d_head)
    
    Q_h = X @ W_Q_h
    K_h = X @ W_K_h
    V_h = X @ W_V_h
    
    scores_h = Q_h @ K_h.T / np.sqrt(d_head)
    weights_h = softmax(scores_h)
    output_h = weights_h @ V_h
    
    heads_outputs.append(output_h)
    print(f"\n  Head {h+1} 权重矩阵:")
    for i in range(seq_len):
        print(f"    词{i}: {[f'{w:.2f}' for w in weights_h[i]]}")

# 拼接所有头的输出
concat = np.concatenate(heads_outputs, axis=-1)
print(f"\n拼接后形状: {concat.shape} (等于原始维度 {d_model})")
print(f"每个头学到了不同的关注模式,拼接后信息更丰富")

运行:

bash 复制代码
python code/attention_basics.py

预期输出(数值会不同,但格式一致):

复制代码
实验 1: 手动实现 Self-Attention
输入形状: (4, 8) (句子长度=4, 维度=8)

Attention 权重矩阵(每行加起来=1):
         词0     词1     词2     词3     
词0看 → 0.287  0.213  0.256  0.244  (和=1.000)
词1看 → 0.241  0.312  0.219  0.228  (和=1.000)
...

实验 2: Attention 权重可视化
句子: The cat sat on the mat because it was tired

Attention 热力图:
          The    cat    sat     on    the    mat  because     it    was  tired
----------------------------------------------------------------------
       The  █       ███     █       █       █     █       █       █       █       █
       cat  █       ███     █       █       █     █       █       █       █       █
       ...

实验 3: 验证 Attention 的无序性
关键发现: 打乱顺序后权重行跟着换,但分布不变 → 需要位置编码

实验 4: 多头 Attention(模拟 4 个头)
每个头有不同的权重分布 → 多维度理解文本

7.2 实验后思考题

notes/day2.md 中回答:

  1. 实验 1:Attention 权重矩阵的每一行为什么加起来等于 1?(答:Softmax 归一化)
  2. 实验 2:随机权重的热力图没有明显模式,你觉得真实模型训练后会出现什么模式?(提示:指代词会高权重指向指代对象)
  3. 实验 3:如果给输入加上位置编码,打乱顺序后结果还会一样吗?(答:不会,位置编码让每个位置的向量不同)
  4. 实验 4:4 个头的权重分布不同,这说明什么?(答:不同头学到了不同的关注模式)

8. 今日笔记模板

notes/day2.md 中写:

markdown 复制代码
# Day 2 笔记 --- Transformer 架构直觉理解

## 日期:2026-07-XX
## 学习时长:X 小时 X 分钟

## 一、今天学到的 5 件事

1. 
2. 
3. 
4. 
5. 

## 二、RNN 的三个问题(填表)

| 问题 | 说明 | Attention 怎么解决 |
|------|------|-------------------|
| | | |
| | | |
| | | |

## 三、Q/K/V 解释(用搜索引擎类比)

Q (Query):
K (Key):
V (Value):

## 四、Self-Attention 计算流程(按顺序写)

1. 
2. 
3. 
4. 
5. 

## 五、多头注意力(我的理解,200 字内)

(为什么要多个头?每个头做什么?)

## 六、位置编码解决什么问题

问题:
解决方案:

## 七、三种架构对比(填表)

| 架构 | 代表模型 | 能看哪些词 | 适合什么任务 |
|------|---------|-----------|-------------|
| Encoder-only | | | |
| Decoder-only | | | |
| Encoder-Decoder | | | |

## 八、GPT 为什么一个字一个字生成?

(用 Masked Attention 解释)

## 九、代码实验记录

| 实验 | 观察到的现象 |
|------|------------|
| 实验1 手动Attention | |
| 实验2 权重可视化 | |
| 实验3 无序性验证 | |
| 实验4 多头Attention | |

## 十、还不清楚的问题

- 
- 

## 十一、今日代码清单

- [ ] code/attention_basics.py 运行成功
- [ ] 4 个实验全部完成
- [ ] 4 道思考题回答完

9. 验收清单

概念验收

  • 能说出 RNN 的三个问题(长距离依赖、无法并行、信息瓶颈)
  • 能用搜索引擎类比解释 Q、K、V
  • 能按顺序说出 Self-Attention 的 5 步计算流程
  • 知道为什么 Attention 分数要除以 √d_k
  • 能解释 Softmax 的作用
  • 知道多头注意力为什么需要多个头
  • 能解释 Attention 为什么没有顺序概念
  • 知道位置编码解决什么问题
  • 能说出 Transformer Block 的组成部分(Attention + FFN + 残差 + LayerNorm)
  • 知道残差连接和 LayerNorm 的作用
  • 能区分 Encoder-only / Decoder-only / Encoder-Decoder
  • 能解释 GPT 为什么是 Decoder-only(自回归 + Masked Attention)

代码验收

  • attention_basics.py 运行成功
  • 实验 1:看到了 Attention 权重矩阵,每行和为 1
  • 实验 2:看到了热力图可视化
  • 实验 3:验证了 Attention 的无序性
  • 实验 4:看到了不同头的不同权重分布

笔记验收

  • notes/day2.md 按模板写完
  • 4 道思考题回答完
  • 至少记录了 5 件学到的事

10. 常见问题 FAQ

Q1:Q、K、V 的权重矩阵是固定的吗?

A:不是。W_Q、W_K、W_V 是模型在训练过程中学出来的参数。不同模型、不同层的权重矩阵都不同。这就是模型"智能"的来源------通过海量数据训练出合适的权重,让 Attention 关注该关注的地方。

Q2:为什么除以 √d_k 而不是 d_k?

A:当 Q 和 K 的分量是均值为 0、方差为 1 的独立分布时,点积 Q·K 的方差是 d_k(每项乘积的方差之和)。除以 √d_k 让方差变回 1,防止维度增大时点积值过大导致 Softmax 饱和(梯度消失)。这是数学上的最优缩放。

Q3:多头注意力的头数怎么选?

A:常见选择:8 头、16 头、32 头、96 头。头数和维度有关------总维度 ÷ 头数 = 每头维度,每头维度一般不低于 32(太小信息不够)。GPT-3 是 96 头 × 128 维/头 = 12288 维。头数不是越多越好,太多会导致每个头维度太小,信息不足。

Q4:位置编码为什么用正弦/余弦?

A:三个原因:

  1. 每个位置的编码是唯一的(不同频率的正弦波组合)
  2. 可以推广到训练时没见过的更长序列(正弦函数可以无限延伸)
  3. 相对位置可以通过线性变换表示(sin(a+b) 可以用 sin(a) 和 cos(a) 表示)

不过现代大模型(Llama 等)更多用 RoPE(旋转位置编码),效果更好。

Q5:Decoder 的 Masked Attention 具体怎么实现?

A:在计算 Attention 分数后、Softmax 之前,把当前词后面的所有位置设为负无穷(-∞)。Softmax 后这些位置的权重就变成 0(e^(-∞) = 0)。这样当前词就"看不到"后面的词了。

复制代码
原始分数矩阵:
  [0.5, 0.3, 0.8, 0.2]
  [0.1, 0.6, 0.7, 0.4]
  [0.3, 0.2, 0.5, 0.9]
  [0.4, 0.7, 0.1, 0.6]

加上 Mask(上三角设为 -∞):
  [0.5,  -∞,  -∞,  -∞]
  [0.1, 0.6,  -∞,  -∞]
  [0.3, 0.2, 0.5,  -∞]
  [0.4, 0.7, 0.1, 0.6]

Softmax 后:
  [1.0, 0.0, 0.0, 0.0]   ← 词0 只能看自己
  [0.4, 0.6, 0.0, 0.0]   ← 词1 只能看词0和词1
  [0.3, 0.2, 0.5, 0.0]   ← 词2 只能看词0、1、2
  [0.2, 0.3, 0.1, 0.4]   ← 词3 能看所有词

Q6:BERT 和 GPT 都用 Transformer,为什么能力差异这么大?

A:架构只是基础,更重要的差异是:

  1. 训练目标:BERT 用掩码语言模型(完形填空),GPT 用自回归生成(接龙)
  2. 规模:BERT 最大 3.4 亿参数,GPT-3 有 1750 亿参数,差 500 倍
  3. 训练数据:GPT 的数据量远大于 BERT
  4. 涌现能力:规模够大后,GPT 涌现出 in-context learning,BERT 没有

所以不是"Decoder 比 Encoder 好",而是大规模 + 自回归生成 + 海量数据 共同造就了 GPT 的成功。

Q7:Transformer 这么好,RNN 就完全没用了吗?

A:基本被淘汰了。但有些场景 RNN/LSTM 还有优势:

  • 资源极度受限的嵌入式设备(RNN 参数少)
  • 流式处理(RNN 天然逐词处理,不需要等全部输入)
  • 不过这些场景也在被轻量级 Transformer 替代

11. 扩展资源

必看(和今天内容直接相关)

资源 类型 时长 价值
3Blue1Brown「But what is a GPT?」 YouTube 视频 15 min GPT 直觉理解最佳,可视化 Attention
Jay Alammar「The Illustrated Transformer」 英文文章 30 min 图解 Transformer 最清晰,每一步都有图
李宏毅 Transformer 课程 YouTube 视频 40 min 中文讲解,直觉理解好

选看(有余力再看)

资源 类型 说明
Karpathy「Let's build GPT from scratch」 YouTube 2 小时,用代码从零实现 GPT,硬核
The Annotated Transformer 英文文章 逐行代码注释 Transformer 原论文
Attention Is All You Need 原论文 论文 2017 年 Transformer 原始论文,6 页
Jay Alammar「Illustrated Self-Attention」 英文文章 专门讲 Self-Attention 的图解

交互式工具

工具 说明
BertViz 可视化 Transformer 的注意力权重(Jupyter 插件)
Transformer Visualization 交互式 Transformer 可视化(网页版,推荐!)
LLM Visualization 3D 可视化 LLM 内部结构

12. 明日预告

Day 3 主题:Token、Embedding、Context Window

明天你会学到:

  • Token 到底是什么(不是词也不是字)
  • 用 tiktoken 库做 Token 计数实验
  • 中英文 Token 消耗差异
  • Embedding 怎么把文字变成向量
  • 用 Embedding 做语义相似度实验(RAG 的雏形)
  • Context Window 的限制和应对策略

明天代码量较大,有 2 个实验脚本,是后面 RAG 学习的基础。


附录:Day 2 时间分配建议

一次性学完(约 2-2.5 小时)

复制代码
00:00-00:30  Part A: 为什么需要 Attention(边读边画图)
00:30-01:10  Part B: Self-Attention 详解(最抽象,慢慢读)
01:10-01:15  休息 5 分钟
01:15-01:40  Part C: 多头注意力 + 位置编码
01:40-02:00  Part D: Transformer 整体架构
02:00-02:15  Part E: Encoder vs Decoder
02:15-02:35  Part F: 代码实验(attention_basics.py)
02:35-02:45  写笔记

分两次(推荐)

复制代码
第一次(1 小时):
  Part A: 为什么需要 Attention(30 min)
  Part B: Self-Attention 前半部分(30 min)

第二次(1-1.5 小时):
  Part B: Self-Attention 后半部分(15 min)
  Part C: 多头 + 位置编码(25 min)
  Part D: Transformer 架构(20 min)
  Part E: Encoder vs Decoder(15 min)
  Part F: 代码实验(20 min)
  写笔记(10 min)

纯概念模式(不看代码,1.5 小时)

如果你今天时间不够,可以只看 Part A-E 的概念部分(约 1.5 小时),代码实验放到周末和 Day 6 一起做。概念理解比代码更重要。


附录:Day 2 核心概念速查卡

复制代码
┌──────────────────────────────────────────────────────────┐
│  Transformer 核心公式                                     │
│                                                          │
│  Attention(Q, K, V) = softmax(Q·K^T / √d_k) · V        │
│                                                          │
│  多头: head_i = Attention(Q·W_i^Q, K·W_i^K, V·W_i^V)    │
│        MultiHead = Concat(head_1, ..., head_h) · W^O     │
│                                                          │
│  位置编码: PE(pos, 2i) = sin(pos / 10000^(2i/d))        │
│           PE(pos, 2i+1) = cos(pos / 10000^(2i/d))       │
│                                                          │
│  Transformer Block =                                     │
│    LayerNorm(x + MultiHeadAttention(x))                 │
│    LayerNorm(x + FeedForward(x))                        │
└──────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────┐
│  速记口诀                                                 │
│                                                          │
│  RNN 三病: 长距离丢、不能并行、信息瓶颈                    │
│  Attention 三好: 全局视野、动态权重、并行计算              │
│  QKV 三角色: Q找信息、K提供信息、V是信息本身              │
│  计算五步: 算QKV → 点积 → 缩放 → Softmax → 加权求和      │
│  多头: 一个头一种关系,多个头多维度理解                    │
│  位置编码: Attention没顺序感,加PE补上                    │
│  三架构: BERT双向理解、GPT单向生成、T5理解+生成           │
│  Masked Attention: 看前面不看后面,防止作弊              │
└──────────────────────────────────────────────────────────┘
相关推荐
网络安全零基础教程1 小时前
零基础转行网安,前两个月具体该学什么工具
网络·学习·安全·web安全·网络安全
1名持续学习的码农1 小时前
Codex 任务总中断:ChatGPT Plus 用户该升级 Pro,还是先把需求写清?
人工智能·gpt·ai·ai编程·codex
QN1幻化引擎1 小时前
把 意识评测做成了一场"非侵入实验":不碰生产代码,分数反而更真了
人工智能·算法·架构
恋猫de小郭1 小时前
KotlinLLM 开源 ,一个可以在运行时自己生成永久 Kotlin 代码的 Agent 库
android·前端·人工智能
EDA365电子论坛1 小时前
AI 智能管控差分线间距规范,消除内外间距统一导致耦合失效问题
人工智能
武子康1 小时前
OpenAI Tibo:同样的 Rate Card,为什么更强的 Sol 反而更快耗尽 Codex 限额
人工智能·chatgpt·openai
北冥you鱼1 小时前
深入解析 DEX 项目池流动性设计原理:从恒定乘积到集中流动性
人工智能·区块链
微学AI1 小时前
一款童年游戏对超级智能体应用开发的启示 — 从《武林群侠传》看 Agent 架构设计的“江湖智慧“
人工智能·游戏·agent
OBiO20131 小时前
AAV心脏靶向选型与HFpEF治疗新策略:Sub1靶点从发现到验证全解析
人工智能