课程笔记
说明 这里专门放我在修课时同步整理的笔记。每个学期会作为一个子目录,下面再放具体课程的 post。 学期目录 2026-2027 第一学期
说明 这里专门放我在修课时同步整理的笔记。每个学期会作为一个子目录,下面再放具体课程的 post。 学期目录 2026-2027 第一学期
什么是 Agent 你在 ChatGPT 的网页里打一句话,它回一段话。问天气,它给你天气。让它写首诗,它给你一首诗。到这里为止,你手里的是一个大语言模型(Large Language Model,LLM),一个很会接话的问答机器。 可如果它自己握着键盘鼠标,自己翻仓库里的文件,自己往数据库里写数据,把一个"把项目做完"的任务从头做到尾,情况就变了。人们把这种形态叫做 Agent(智能体)。 Claude Code 的 CLI 界面 2025年2月,一款Agent产品横空出世,它就是Claude Code。上图为它的CLI界面。这个就是一个Agent。 很多人在本地把 Agent 跑通了。模型能回答,能调用一两个工具,看起来挺像回事。可一旦放到真实环境里,让它稳定处理用户一个个请求,问题就全冒出来了。模型偶尔把格式写错,工具偶尔抛异常,流程偶尔卡在一个地方不动。每一样都得有人兜底。 这两个东西之间差了一层外壳。 LLM 只负责一件事,把输入变成输出。它没有手,没有脚,连执行一段代码都做不到,它只能生成文字。Agent 的玩法,是让 LLM 当大脑,外面套一个能真正动手的外围工程系统(Harness)。大模型提供推理能力,Harness 提供除模型权重之外的所有基础设施,把模型那些不可靠的自然语言输出,转成工程上可控的系统行为。分开说就是一句话,Agent 等于一个会想的大脑,加一个会干活的身体。 这篇文章会拆开这层壳,一路往下讲。先看 Harness 由什么组成,再看 Agent 接到任务后怎么运转,接着把工具调用和技能积累这两块讲透。 Harness 基座 Harness 通常分成三个核心层。 Runtime(运行时)。维持模型运转的核心循环,负责提示词的组装、结构化输出的解析,以及异常重试机制。可以把它想成发动机,让模型一圈一圈转下去。 Capabilities(能力层)。赋予 Agent 实际操作环境的能力,包括工具注册表、上下文管理、长期记忆读写。这一层决定 Agent 能摸到什么东西。 Assurance(保障层)。也叫 Eval Harness,它存在于离线开发路径里。批量遍历测试数据集(Goldens),调用 Agent 跑完整任务,收集执行轨迹(Traces),再用评估指标打分,比如准确率、幻觉率、LLM-as-a-judge。没有这一层,Agent 就没法稳定迭代。 flowchart TB M["Model 大模型大脑"] subgraph HARNESS["Harness 基座"] direction TB R["Runtime 运行时组装提示词 · 解析输出 · 异常重试"] C["Capabilities 能力层工具注册表 · 上下文管理 · 长期记忆"] A["Assurance 保障层评测数据集 · 收集轨迹 · 打分"] end M --> R R --> C C --> A 想真正学会这套东西,最实在的办法是落到你自己熟悉的工程栈里。用 Python 做测验或复习系统,就抛开高级封装库,手写一个最简的 Runtime Loop,自己处理模型的 JSON 输出和本地业务逻辑的对接。等你亲手撞过一次 JSON 解析报错和无限重试循环,Harness 的价值就彻底清楚了。 ...
前言 这是"线性代数基础"专栏的第一篇。这个专栏的目的很明确:补齐看懂本站进阶数学文章所需的基础。读完本文(以及后续两篇),你应该能顺畅读懂《矩阵微积分如何服务反向传播》和《Softmax 与缩放点积的数学》。 我们从一个最朴素的问题开始:什么是向量? 它为什么值得花一整篇来讨论? 向量:从几何到坐标 向量有两种看待方式,二者等价,互为补充: 几何视角:向量是空间中带方向和长度的箭头。它表示"从一点移动到另一点"。 代数视角:向量是 $\mathbb{R}^n$ 中的一个有序数组,如 $v = (v_1, v_2, \dots, v_n)$。其中 $n$ 是维度。 在深度学习中,我们几乎总是用数组(张量)表示向量:一个词嵌入是几百维的向量,一张图片展开后是几万维的向量。几何直觉在低维(2D/3D)依然成立,只是"看不见",但公式可以推广到任意维度。 向量的基本运算 对向量 $u, v$ 和标量 $c$: 加法:$(u + v)_i = u_i + v_i$。几何上就是"首尾相接"(平行四边形法则)。 数乘:$(cv)_i = c v_i$。几何上是把箭头拉伸($|c| > 1$)或压缩($|c| < 1$),$c < 0$ 时反向。 这两个运算非常重要,因为"对加法和数乘封闭"正是下一篇文章里"向量空间"定义的核心。 点积与范数 点积(内积) 两个 $n$ 维向量 $a$、$b$ 的点积定义为对应分量乘积之和: $$ a \cdot b = \sum_{i=1}^{n} a_i b_i $$它的几何形式揭示了本质: $$ a \cdot b = \|a\| \|b\| \cos\theta $$其中 $\theta$ 是两个向量之间的夹角,$\|a\|$ 是 $a$ 的模长(范数)。也就是说,点积同时度量了两个向量的长度和方向一致性:夹角越小,点积越大。 ...
前言 上一篇讲了向量。这一篇把向量"组织"起来——矩阵。矩阵是连接向量与线性变换的桥梁,也是神经网络里几乎所有计算(全连接层、注意力中的 $QK^\top$、反向传播的梯度回传)的载体。 读完本文,你会理解三件事:矩阵乘法到底在算什么、为什么神经网络一层是 $z = Wx + b$、以及 Jacobian 为什么能写成矩阵。 矩阵:数与表 矩阵是排成矩形的数表。一个 $m \times n$ 矩阵有 $m$ 行、$n$ 列: $$ A = \begin{bmatrix} a_{11} & a_{12} & \dots & a_{1n} \\ a_{21} & a_{22} & \dots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} & a_{m2} & \dots & a_{mn} \end{bmatrix} $$几个常用特例: 单位阵 $I$:对角线上全为 1,其余为 0。作用类似乘法里的"1"($IA = AI = A$)。 对角阵:非对角线全为 0。相当于对每个分量独立缩放。 零矩阵:全为 0。 转置 $A^\top$:把行列互换,$(A^\top)_{ij} = A_{ji}$。 对称矩阵:$A = A^\top$。它很重要,在特征值篇会看到它有多好用。 矩阵乘法 两个矩阵 $A$($m \times k$)和 $B$($k \times n$)可以相乘,结果 $C = AB$ 是 $m \times n$ 矩阵,其中: ...
前言 前两篇讲了向量和矩阵。这一篇回答一个更深刻的问题:矩阵这个变换,有没有"主轴"? 沿着某个方向,变换可能只是单纯地拉伸(方向不变、长度变);沿着另一个方向,可能完全不动。抓住这些"不改变方向"的方向,矩阵的行为就一目了然了。 这就是特征值与特征向量的思想。它在深度学习里极其重要——梯度消失/爆炸、LoRA、PCA、甚至注意力里的缩放,背后都有它的影子。 特征值与特征向量 定义 对 $n \times n$ 矩阵 $A$,如果存在非零向量 $v$ 和标量 $\lambda$ 使得: $$ Av = \lambda v $$则 $\lambda$ 称为 $A$ 的特征值,$v$ 是它对应的特征向量。 几何意义:$v$ 是变换 $A$ 的"主轴"方向——被 $A$ 作用后方向不变,只是长度缩放 $\lambda$ 倍。$\lambda > 1$ 拉伸,$0 < \lambda < 1$ 压缩,$\lambda < 0$ 反向。 如何求特征值 把定义移项:$(A - \lambda I)v = 0$。非零解存在的条件是矩阵不可逆,即: $$ \det(A - \lambda I) = 0 $$这就是特征多项式,是 $\lambda$ 的一个 $n$ 次多项式,有 $n$ 个根(计重数)。 例:求 $A = \begin{bmatrix} 2 & 1 \\ 1 & 2 \end{bmatrix}$ 的特征值与特征向量。 ...
前言 这篇文章是本站《Transformer 详解:从注意力机制到代码实战》的数学补充。它的定位非常具体:只讲"服务 Attention 的数学",不重复基础线性代数。 我们假设你已经读过本站的《矩阵微积分如何服务反向传播》,理解 Jacobian 与向量-Jacobian 乘积(VJP)这两个概念。在此基础上,本文回答三个问题: softmax 的梯度长什么样,为什么是这个形式? 为什么 softmax 与交叉熵组合在一起,梯度会变得极简且数值稳定? 缩放点积注意力中的 $\sqrt{d_k}$ 究竟从哪里来,为什么非除不可? Softmax 定义与直觉 给定一个实数向量 $z \in \mathbb{R}^n$(常称为 logits,即未归一化的分数),softmax 把它映射成一个概率分布: $$ \text{softmax}(z)_i = \frac{e^{z_i}}{\sum_j e^{z_j}} $$三个值得记住的性质: 输出非负且和为 1:天然是概率分布。 放大差异:指数运算放大了 logits 之间的差距。$z = [1, 2]$ 时,softmax 输出约 $[0.27, 0.73]$,而不是线性的 $[0.33, 0.67]$——赢家更突出。 平移不变:$\text{softmax}(z + c) = \text{softmax}(z)$(对任意常数 $c$)。分子分母同乘 $e^c$,抵消了。这个性质是后面 log-sum-exp 技巧的基础。 还有一个常被提及的变体:温度参数 $T$,写作 $\text{softmax}(z / T)$。$T < 1$ 时分布更"尖锐"(注意力更集中),$T > 1$ 时更"平滑"。在 Attention 里,softmax 的温度直接控制"注意力有多集中"。 Softmax 的梯度 softmax 的输入输出都是向量,所以它的"导数"是一个 Jacobian 矩阵。记 $s_i = \text{softmax}(z)_i$,并令分母 $Z = \sum_k e^{z_k}$。 ...
前言 Transformer 是目前深度学习中最重要的一类架构。从 GPT、BERT 这类大语言模型,到 ViT 这类视觉模型,近几年绝大多数突破背后都有它的身影。可以说,理解 Transformer 是读懂当代 AI 的必修课。 本文假设你已经读过本站的《正向传播与反向传播:神经网络到底如何学习》,理解"网络是一串函数复合、训练时误差沿链式法则反向流动"这两条主线。我们会沿用同样的思路拆解 Transformer:信息如何向前流动,梯度如何向后流动。 本文会从"为什么需要 Attention"讲起,逐步推导公式,最后用一个从零手写的迷你 Transformer(PyTorch)把代码落地。涉及 softmax 的数学细节——梯度、数值稳定性、为什么注意力要除以 $\sqrt{d_k}$——会链接到本站 ai-math 专栏的配套文章,避免在这里打断主线。 为什么要 Transformer RNN 的局限 在 Transformer 之前,处理序列(文本、语音等)的主流架构是 RNN(循环神经网络)。RNN 像一条传送带,按顺序逐个处理 token,把之前看到的信息压缩在一个隐藏状态里。这个设计有三个天然的瓶颈: 无法并行:第 $t$ 步的计算依赖第 $t-1$ 步的隐藏状态,只能从左到右依次计算,GPU 的大规模并行能力完全用不上。 长距离依赖困难:信息每传一步都要经过一次变换,距离越远衰减越明显。处理长文本时,开头的词往往"传不到"结尾。 信息瓶颈:所有历史都被压缩进一个固定大小的隐藏向量,容量有限。 Transformer 的思路 Transformer 的做法截然不同:一次看完整条序列。它不再按顺序传递状态,而是让序列中的任意两个位置直接交互。 先解释一个词:token(词元,我实在不喜欢它的官方中译) 是文本被切分后的基本单位,可以是一个词、一个字符或一个子词片段。比如"我吃了一个红苹果"可以切成 6 个 token:我 / 吃 / 了 / 一个 / 红 / 苹果。 flowchart LR subgraph RNN["RNN:信息一站一站传"] direction LR r1["第 1 个"] --> r2["第 2 个"] r2 --> r3["第 3 个"] r3 --> r4["第 4 个"] end subgraph ATTN["Transformer:任意两个直接对话"] direction LR a1["第 1 个"] --- a2["第 2 个"] a1 --- a3["第 3 个"] a1 --- a4["第 4 个"] a2 --- a3 a2 --- a4 a3 --- a4 end 上图为两种架构的token之间的交互示意: 从图论的角度来说,RNN 是一个 有向路径图,包含 $n$ 个节点(代表隐状态 $h_t$)和 $n-1$ 条有向边($h_{t-1} \to h_t$);而 Transformer 是一个 完全图,包含 $n$ 个节点和 $\frac{n(n-1)}{2}$ 条无向边(每两个 token 之间都有一条边)。 ...
前言 如果只看 PyTorch 代码,训练神经网络似乎很简单:写一个 forward,算出 loss,调用 loss.backward(),再让优化器更新参数。但这几行代码背后,其实压缩了深度学习最核心的一条数学主线: 正向传播负责把输入变成预测,反向传播负责把误差变成每个参数应该调整的方向。 理解这条主线之后,再看 CNN、ResNet、Transformer 或 LoRA,很多公式就不再像突然冒出来的符号。它们本质上都在回答同一个问题:信息如何向前流动,梯度又如何向后流动。 从一个神经元开始 一个最简单的神经元可以写成: $$ z = w^\top x + b $$其中 $x$ 是输入向量,$w$ 是权重向量,$b$ 是偏置。线性部分 $z$ 再经过一个非线性激活函数: $$ a = \sigma(z) $$如果没有激活函数,很多层线性变换叠在一起仍然只是一个线性变换,网络无法表示复杂的非线性关系。激活函数的作用,就是让每一层都能在“线性组合”之外引入弯曲和分段变化。 一层网络在做什么 把一个神经元扩展成一层全连接网络,可以写成矩阵形式: $$ \begin{aligned} z^{(l)} &= W^{(l)} a^{(l-1)} + b^{(l)} \\\\ a^{(l)} &= \sigma\left(z^{(l)}\right) \end{aligned} $$这里的上标 $(l)$ 表示第 $l$ 层。$a^{(l-1)}$ 是上一层输出,$W^{(l)}$ 和 $b^{(l)}$ 是这一层参数,$a^{(l)}$ 是这一层输出。 从这个角度看,神经网络并不是一个神秘黑盒,而是一串函数复合: $$ x \xrightarrow{f_1} a^{(1)} \xrightarrow{f_2} a^{(2)} \xrightarrow{f_3} \cdots \xrightarrow{f_L} \hat{y} $$正向传播就是沿着这条链从左到右计算。 ...
前言 这一篇不是基础线性代数笔记。矩阵乘法、转置、逆矩阵、特征值这些基础概念默认你已经见过。我们只关心一个更具体的问题:为什么深度学习里的反向传播经常要用矩阵微积分来描述? 在标量函数里,导数告诉我们“输入变化一点,输出会怎么变”。但神经网络里大量对象都不是标量:输入是向量,权重是矩阵,中间特征是高维张量,损失函数最后才压成一个标量。因此,普通的一元导数不够用,我们需要用 Jacobian、梯度向量和链式法则来描述这些对象之间的局部关系。 从标量导数到 Jacobian 设一个函数把向量 $x \in \mathbb{R}^n$ 映射到向量 $y \in \mathbb{R}^m$: $$ y = f(x) $$它的 Jacobian 矩阵定义为: $$ \begin{aligned} J_f(x) &= \frac{\partial y}{\partial x} \\\\ &= \begin{bmatrix} \frac{\partial y_1}{\partial x_1} & \cdots & \frac{\partial y_1}{\partial x_n} \\\\ \vdots & \ddots & \vdots \\\\ \frac{\partial y_m}{\partial x_1} & \cdots & \frac{\partial y_m}{\partial x_n} \end{bmatrix} \end{aligned} $$Jacobian 的含义不是“又多了一个复杂矩阵”,而是:它描述了函数 $f$ 在某一点附近的局部线性近似。 $$ f(x + \Delta x) \approx f(x) + J_f(x)\Delta x $$这就是 AI 中 Jacobian 最重要的直觉:非线性网络在局部可以近似看成线性变换。 ...
前言 直接从 Deep Learning 概览跳到 ResNet 会有一点跳跃,因为 ResNet 不只是一个 CNN 结构,它还依赖正向传播、反向传播和梯度流这些训练机制。如果你还不熟悉“网络是函数复合”“损失如何反传到参数”这些概念,可以先看正向传播与反向传播:神经网络到底如何学习。 ResNet(Residual Network,残差网络)是经典视觉网络中绕不开的模型,因为它解决的不是“怎么设计一个更复杂的卷积层”,而是一个更基础的问题:网络变深以后,为什么反而更难训练? 直觉上,深层网络至少不应该比浅层网络差。假设一个 20 层网络已经能学到不错的函数,那么 56 层网络完全可以让后面 36 层近似恒等映射,理论上应该复现 20 层网络的效果。但在 ResNet 论文之前,实验中经常观察到相反现象:网络加深后,训练误差也会上升。这不是单纯的过拟合,因为过拟合通常表现为训练误差低、测试误差高;这里的问题是训练集本身都拟合不好。 这个现象通常被称为退化问题(Degradation Problem)。ResNet 的核心贡献,就是用一种非常简单的结构改写了深层网络的优化目标。 先看普通网络在学什么 设某一组卷积层想学习的目标函数是: $$ H(x) $$这里的 $x$ 是输入特征图,$H(x)$ 是这几层网络最终应该输出的特征。普通卷积网络会直接让堆叠的层去拟合 $H(x)$。 ResNet 的想法是:不要直接学 $H(x)$,而是学习它和输入 $x$ 之间的差值: $$ F(x) = H(x) - x $$于是目标输出可以改写成: $$ H(x) = F(x) + x $$这个 $F(x)$ 就叫残差映射(Residual Mapping),而旁边那条把 $x$ 直接加回输出的路径,就是跳跃连接(Skip Connection) 或 Shortcut Connection。 flowchart LR x["输入 x"] --> block["普通卷积层堆叠"] block --> h["直接学习 H(x)"] 普通网络的压力在于:每一组层都必须直接学出目标映射 $H(x)$。而 ResNet 把这个任务拆成两部分:主分支只学习“相对输入还需要改什么”,shortcut 分支直接把输入送到输出端。 ...