关系图例 · 线色=关系
演进谱系代际 / 谱系
实现构建用 X 写 · 编译为
运行依赖跑在 / 依赖
规范表达ISA↔汇编/CPU
算力·能力使用GPU⇢DL · →Agent
盒子颜色=哪棵树(蓝=计算机 / 绿=AI);线的颜色只表示关系类型。

计算机与人工智能知识树

同一粒种子——图灵 1936 年的一纸证明——长成两棵树。按年份生长,点枝收展。

全
悬停 = 把节点连到底层的那条棕线提到最前 · 点击 = 钉住棕线并弹出讲解卡(部分节点卡里可「展开扩展内容」,左右滑动看)· ▶ 生长 / ⏭ 单步时自动弹出「这一年长出了什么」· 图灵也可点
AI 树领域线(和架构正交):NLP自然语言CV视觉ASR语音跨多模态
横切技术 · 训练与规模化(跨架构,不是单独模型):Scaling Law 规模律 · MoE 专家混合 · RLHF/DPO 偏好对齐 · LoRA 低秩微调 · Reasoning 推理范式(长 CoT / 测试时计算 / o1 式)
位置编码 · RoPE欧拉公式 / 极坐标旋转★
FFN 前馈两层全连接 · 升维降维★
残差连接 + 层归一化Add & Norm · 稳住训练★
输出头→ 下一个 token★
⚙ 编译器传统 ⇄ AI · 点开
Agent · 智能体 — Harness · Loop:把 LLM 与组件编排成「感知-规划-执行-反馈」闭环
LLM认知与推理引擎 · 大脑
Planning规划 · 任务分解
Memory短期 + 长期记忆
Tools工具调用(含 MCP)
Runtime运行环境 · 沙箱
State状态管理
Feedback执行结果反馈
Security权限 / 安全边界
Workflow多步编排 · 流程
后端基础设施 · 云原生
云计算虚拟化(VM/容器) + 分布式 → 弹性平台 · K8s
分布式系统单机→集群:共识(Raft/Paxos) · 复制 · 分区 · CAP
后端中间件数据库 · 消息队列 · 缓存 · Web 服务器(用语言写,依赖 OS)
编译原生 · AOTGo · Rust(编到原生机器码、不进 VM;C 同属 AOT)
字节码 · 纯解释CPython(无 JIT · 解释器 dispatch 执行)
字节码 · 解释 + JITJava · JS/Node · Kotlin · Scala(热点 JIT)
前端 · WebJS 在浏览器里做 UI
HTML/CSS · Vue/React
高级语言生态跑在操作系统上
操作系统Linux = Unix 思想 + Minix 启发 + C 实现 · Windows / macOS
网络 · TCP/IPSocket · TCP/UDP/IP · DNS
OS 提供 · 分布式/云/Agent 的底座
C系统编程语言 · GCC/Clang 工具链
C++1983 · C + 面向对象
汇编语言直接对着 ISA 写 · 助记符
x86CISC · Intel/AMD
ARMRISC
RISC-VRISC · 开源
ISA 指令集早期指令集思想(1940s 存储程序机)· 1964 S/360 定名架构
Jev判断服务 · Choice/Score/Noul · 不生成
跨多模态跨架构能力
NLPBERT2018 · 理解
CVViT2020 · 图像当词
NLPT52019 · 文本到文本
ASRWhisper2022 · 弱监督多语言
开源Llama/Qwen
闭源GPT/Claude
仅编码器Encoder-only · 理解
编码器-解码器Enc-Dec · seq2seq
仅解码器Decoder-only · 现代 LLM
模型部署与推理KV Cache · 量化
批处理 · vLLM
Transformer2017 · 编码器 + 解码器(粗干)
NLP注意力机制2014 · 为 Seq2Seq 瓶颈而生★
NLP向量数据库存 Embedding 做相似检索
传统库+插件 / 纯向量库
NLP词嵌入 Embedding稠密向量·语义相邻
Transformer 输入层
★
CVCNN卷积 · 2012 AlexNet 引爆
NLPRNN1980s · 早期循环网络
LSTM1997 · 门控记忆解长依赖
NLPWord2Vec2013 · skip-gram · 稠密词向量
生成式模型GAN 2014 → Diffusion 2020
深度学习机器学习的一支 · 模型训练与推理
强化学习ML 三范式之一 · 试错+奖励
深度 RL(虚线) · AlphaGo 2016
NLPNLP 文本表示统计 → 神经
ngram→词袋→Word2Vec→嵌入
前向传播输入→输出 · 逐层计算
反向传播1986 推广 · 多层网络可训
机器学习监督 / 无监督 / 强化
感知机 / 神经网络1958 Rosenblatt · 多层感知机
人工神经元1943 McCulloch-Pitts
思想源头 · 来自神经科学
专家系统知识库 + 推理机
连接主义神经元/网络学智能
源自神经科学
符号主义逻辑·搜索·规划
知识表示
冯诺依曼模型 · 存储程序
内存 · 存储器
DRAM主存·动态
DDRDDR4/5 接口
显存HBM/GDDR
◀──▶总线
MMU虚拟→物理
◀──▶地址
CPU · 运算器+控制器
寄存器最快最小
CacheL1/L2/L3
▲▼
外设输入 / 输出设备
并行 · Flynn 分类(怎么同时处理更多数据)
SISD单指令单数据
传统标量
SIMD单指令多数据 · 向量
MISD多指令单数据
罕见/容错
MIMD多指令多数据
多核/多机
GPU1999 · 大规模并行
▼
SIMTGPU 执行模型
单指令多线程
FPGA可编程 · 半定制
ASIC · 专用集成电路1980s · 固化电路 · 专芯专用
TPU2016 · 张量专用
NPU2017 · 端侧推理
算力谱系 CPU → GPU → FPGA → ASIC(TPU/NPU) 灵活性↓ 效率↑
图灵 Alan Turing计算机科学之父 · 人工智能之父 (1936)
共同的土壤 基础理论(1936 及更早)
可计算性理论图灵机、可判定性
形式语言与自动机正则、上下文无关文法
数学基础集合、逻辑、证明
信息理论香农:信息熵 · 交叉熵损失
计算复杂度P、NP 等
数值计算算法与数值分析
线性代数矩阵 · 19 世纪(高斯、凯莱)
微积分导数/积分 · 17 世纪(牛顿、莱布尼茨)
概率统计分布与推断 · 17–19 世纪
高等数学分析 · 19 世纪严格化
延伸 · 一段代码怎么跑起来:编译与执行流水线
HOW CODE RUNS

一段代码怎么跑起来:编译与执行流水线

树讲的是「谁架在谁之上」;这条流水线讲的是「源码一步步变成能跑的东西」。真正的区别不是「解释 vs 编译」,而是 分发物(源码 / 字节码 / 机器码)× 运行时是否 JIT——三条路由此分叉。

源码.py · .java
.go · .rs …
编译原生 · AOT 编译器前端词法 / 语法 / 类型 → IR→ 后端 codegen优化 → 机器码→ 链接器合并库 · 重定位→ 可执行文件
C · Go · Rust;编译期直接生成机器码(Rust 走 LLVM、Go 自研后端,都不经过 C)。进程就是程序本身。
字节码 · 纯解释 编成字节码.pyc→ 解释器 dispatch原生程序 · switch 逐条执行
CPython(无 JIT);字节码是数据,解释器逐条解释,永不为程序代码生成机器码。
字节码 · 解释 + JIT 编成字节码.class / V8 字节码→ 解释器 + JITJVM(C1/C2) · V8
Java · JS · Kotlin;解释器执行、热点 JIT 成机器码缓存,下次直接跑。
进程的虚拟地址空间
高地址
栈 Stack↓ 向下增长
函数调用帧 · 局部变量 · 返回地址
⋮ 空闲的虚拟空间
堆 Heap↑ 向上增长
动态分配(malloc / new)· 字节码/对象当数据住这类区
code cacheJVM / V8
JIT 把热点字节码编成的机器码(不是 .text)
数据段 .data / .bss
全局变量 · 静态变量
代码段 .text
CPU 执行的机器指令(只读)— AOT 是程序本身;纯解释 / JIT 这里是解释器·VM 本体
低地址
OS:分页→虚拟地址 → 物理地址
CPU取指 → 译码 → 执行 → 访存 → 写回
物理内存 RAM按页帧存放代码与数据
对应树里最底层的「CPU · 内存」。

交互详解 · 一段代码怎么跑起来(可切换语言)

一段代码怎么跑起来

宏观上所有语言同一条路;差别在「各自怎么处理」。关键一问:这个进程到底是谁——是程序本身,还是一台虚拟机(JVM / CPython / V8)把程序代码当数据加载进来跑?点标签切语言。

宏观:最终都是 CPU 跑机器码,但那机器码是谁的不一样
源代码
→
路 A · 编译原生 (AOT)
编译→程序的机器码→进程 = 程序本身
C/C++ · Go · Rust:程序代码就是要跑的机器码
路 B · 字节码 + 虚拟机
编成字节码数据→VM 解释 (±JIT)→进程 = VM
Python · Java · JS:跑的是 VM / JIT 的机器码,程序代码是它加载的数据
→
基础库glibc / libstdc++ · 可选→ 系统调用用户态↔内核态→ 内核 OS文件 / 网络 / 进程→ CPU / ISA取指执行
唯一对所有语言都成立的:CPU 永远只执行机器码。区别是这段机器码是程序本身(AOT),还是解释器 / VM + JIT 的产物(字节码语言)——源码本身可能从不变成机器码(纯解释)。
尾链里 基础库(glibc / libstdc++)是可选的一层封装:静态链接、或 Go 这类运行时可绕过 libc 直发系统调用;但系统调用这道用户态↔内核态的门谁都绕不过,再往下才是内核与 CPU/ISA。

原理详解

上面讲每种语言各自怎么跑;下面四块是它们共用的底层机器——点标签切换。

核心机制 · 解释器怎么跑一段字节码(Python / Java / JS 通用)

解释器本身是个原生程序,核心是一个 switch 分派循环

字节码语言的「VM」说白了就是一个普通的原生程序(它的机器码在进程的 .text)。它的心脏是一个循环:取一条字节码 → switch 跳到这条 opcode 的处理逻辑——源码里是一段 C 函数,但构建解释器时就已经 AOT 编成机器码、躺在 .text 里 → CPU 执行这段现成机器码 → 取下一条。字节码只是被它读取的数据。

// 解释器的心脏(简化)
for (;;) {
  op = *pc++;            // 取下一条字节码
  switch (op) {
    case LOAD:  push(local); break;
    case ADD:   push(pop()+pop()); break;
    case CALL:  call_func(); break;
    // …每条 opcode 对应一段处理代码(构建解释器时已编成机器码)
  }
}
  • 字节码 = 数据:每条 opcode 查 switch 跳到它的处理代码。这些代码用 C 写,但构建 CPython 时就已 AOT 编成机器码——运行期 CPU 跑的是这份现成机器码,解释器不为程序代码生成任何新机器码。
  • 纯解释(CPython):到此为止,每次都走这个循环。慢,但简单、可移植。
  • 解释 + JIT(Java/JS):解释器顺便数每段代码跑了多少次;热点被 JIT 编成真机器码缓存起来,下次绕过 dispatch 循环直接执行。
  • Java 的分层:解释器(L0) → C1(轻量 JIT,快编、顺便采集热度) → C2(重度优化 JIT)。C1/C2 都是 JIT,解释的是解释器。
字节码 解释器 dispatch switch 逐条执行(纯解释到此) 机器码缓存 (code cache) 仅 Java/JS · 下次直接跑 CPU 执行机器码 两条都在这跑 逐条解释 数到热点 · 触发 JIT JIT 以字节码为输入编译 解释器本身也是机器码

实线=冷 / 解释路径(字节码被解释器逐条解释、解释器本身也在 CPU 上跑);虚线=热代码路径(数到热点 → 触发 JIT → 以字节码为输入编成机器码 → 这段热机器码直接在 CPU 上跑)。

⚠ 两条路最终都由 CPU 执行机器码——CPU 只会跑机器码;区别是它跑的是「解释器」还是「程序自身的专用机器码」

① 解释执行时,CPU 在跑什么

CPU 跑的是解释器自己的机器码。对每一条字节码,都重复一遍:
取码 → switch 查跳转 → 执行该 opcode 的处理机器码(C 写的、构建时编好)→ 回循环顶 ↺
一条字节码 ≈ 几十条 CPU 指令的间接开销,还没法跨字节码优化。

② JIT 后,CPU 在跑什么

热点字节码被一次性编成程序自身逻辑的机器码。之后 CPU:
连续直跑这段机器码:无取码 / 无 switch / 无回环
还能跨指令优化(值留寄存器、内联、删冗余检查)——就是普通原生机器码。
⚡ 所以 JIT 快:解释=「CPU 跑一个通用解释器去逐条翻译字节码」,每条都付分派开销;JIT=「CPU 直接跑这段逻辑的专用机器码」,编一次、之后零分派——同样的活常快 10~100×。代价是编译要花时间,所以只对热点才值得。
Java 细节 · HotSpot 内部:字节码解释器 + C1 / C2 分层编译

一个方法怎么从「解释」逐步升到「重度优化的机器码」

HotSpot 里有三套执行引擎:一个字节码解释器负责解释,两个 JIT(C1、C2)负责编译。方法越热,待遇越高;所有编译产物都进 Code Cache。

L0 解释字节码解释器
逐条 switch 解释执行,同时统计调用次数 / 循环回边次数(数热度)。刚启动的代码都在这跑。
↓ 热度过阈值(温)
C1 · L1–3Client 编译器(轻量 JIT)
编译快、优化保守,并插桩采集 profile。先让程序快起来,同时摸清谁是真热点。→ 机器码进 Code Cache。
↓ profile 显示是真热点(烫)
C2 · L4Server 编译器(重度优化 JIT)
基于 profile 做内联 / 逃逸分析 / 循环优化,生成最快的机器码。→ 机器码进 Code Cache。
Code Cache独立的本地内存区(不是 Java 堆)。C1/C2 编出的机器码都放这里;下次调用直接跑机器码,绕过解释循环。
deopt(去优化)= 赌错了就退回:JIT 的激进优化都基于乐观假设(赌某情况永远成立,于是省掉检查、生成极快的机器码)。假设被打破时,这份机器码就是错的,HotSpot/V8 便丢弃它、退回解释器重新正确执行,之后可再编译——这是「乐观优化」能成立的安全网。
// V8 的例子
add(1,2); add(3,4); → 赌「a,b 一直是整数」,编出跳过类型检查的快机器码
add("x","y");   → 假设破!guard 发现是字符串 → deopt 退回解释器,按拼接重算 "xy"
常被赌的假设:类型/对象形状稳定、调用点单态(→内联)、某分支从不走;Java 还有「没有子类覆盖此方法」(CHA),后来加载了覆盖的子类 → deopt。
V8(JS/Node)同理,只是分更多档:Ignition(解释器)→ Sparkplug(基线 JIT)→ Maglev → TurboFan(重度优化)。思路一致:先解释、数热度、热点逐级 JIT、假设破了就 deopt 退回解释器。
共用机器 ① · 编译器 = 前端 → IR → 后端

所有编译器都是这三段,换的只是实现

前端只管读懂源语言,后端只管生成某个 CPU 的指令,中间靠 IR(中间表示) 解耦。字节码语言的 javac 也是编译器——只是它的"后端"停在字节码,真正的 codegen 推迟到运行期的 JIT。

源码
→
前端词法 · 语法 · 语义 → AST
→
IR 中间表示与语言/芯片都无关
→
后端优化 · 寄存器分配 · codegen
→
目标机器码某个 ISA
GCC前端多语言 → GIMPLE/RTL(自家 IR)→ 多后端。老牌、全自带。
Clang + LLVMClang 当前端 → LLVM IR → LLVM 后端。IR 可复用是它出圈的关键。
rustcRust 前端 → LLVM IR → LLVM 后端(蹭 LLVM 的成熟后端)。
Go (gc)自研前端 → 自研 SSA IR → 自研后端,不用 LLVM,图快。
javac / V8前端 → 字节码(停在中间的 IR),后端=运行期 JIT。
共用机器 ② · 链接器 = 把碎片拼成能跑的整体

编译只产出一堆目标文件,链接器才拼成可执行

每个源文件单独编成目标文件 .o(含「我用了 printf 但不知道它在哪」的未决符号)。链接器把这些符号和库里的实现对上、合并成一个整体。

静态链接(编译期拼死)

  • 库代码(.a)直接拷进可执行文件
  • 自包含、换机器能跑;但大,每个程序各带一份
  • 默认:Go、Rust(rlib)、musl 静态构建

动态链接(运行期再拼)

  • 只记「我要 libc.so」,代码留在共享库(.so/.dll)
  • 多进程共享、可单独升级;但要环境里有那个库
  • 默认:C/C++ 链 libc、系统共享库
VM 语言里,运行时自己(java/python/node)就是被这样链接出来的原生可执行文件——字节码/源码是它启动后再加载的数据,是另一回事。
机器码跑起来 · 经典 x86 地址翻译(两进程案例)

两个进程、相同的虚拟地址,怎么落到不同的物理内存

机器码里写的是虚拟地址。经典 x86 保护模式走完整三段:逻辑地址 →(分段)→ 线性地址 →(分页)→ 物理地址。让两个进程用相同的虚拟地址,看它们各自落到不同物理页帧。

进程 A(浏览器)
mov eax, [0x08048000]
读虚拟地址 0x08048000
进程 B(编辑器)
mov eax, [0x08048000]
读虚拟地址 0x08048000
↑ 两个进程用的是同一个虚拟地址,彼此却互不干扰——秘密全在下面的翻译链
① 逻辑地址段选择子 : 偏移
CPU 拿到的是 段选择子:偏移(如 CS:0x08048000),段选择子指向描述符表某一项。
↓
② 分段GDT / LDT
段选择子查 GDT(全局,全系统共享)或 LDT(每进程一份)→ 取段基址。线性地址=段基址+偏移。现代 64 位平坦模型段基址=0,这步近乎透明。
↓
③ 线性地址= 段基址 + 偏移
分段的产物。平坦模式下≈那个虚拟地址本身,交给分页硬件(MMU)。
↓
④ 分页CR3 → 页目录 → 页表
这步才是两进程分道扬镳的地方。每个进程有自己一套页表,根在 CR3。切进程时 OS 换 CR3,同一线性地址查到不同物理页帧:
进程 A 的 CR3 → A 的页表 → 物理页帧 0x200000
进程 B 的 CR3 → B 的页表 → 物理页帧 0x5A0000
↓
⑤ 真实物理内存(RAM)
内核0x0–
进程A 代码物理 0x200000
空闲
进程B 代码物理 0x5A0000
空闲
同一虚拟地址 0x08048000,进程 A 落物理 0x200000、进程 B 落 0x5A0000——地址空间隔离就这么来的。
为什么一个进程读不到另一个进程的数据? 每个进程都有一整套属于自己的虚拟地址空间(0 → 最高地址),它「以为整台机器的内存都归它」,根本不知道别的进程存在。它手里只有虚拟地址,而翻译用的页表(CR3 指向的那套)只登记了它自己的页——进程 A 想碰进程 B 的数据,它的地址空间里压根没有通往那些物理页的映射,连个有效地址都写不出来。
所以进程隔离不是「禁止读」,而是压根够不着:访问没映射的地址 → 触发缺页 → 段错误(SIGSEGV)。内核和共享库是例外——它们被映射进每个进程(同一份物理页),所以人人可用。进程间要通信得走专门渠道(管道 / 共享内存 / socket),由内核牵线。
关键寄存器:CR0(开关保护/分页)、CR2(缺页时存出错的线性地址)、CR3(当前进程页表根=PDBR,切进程就换它);CR1 保留。
现代简化:64 位长模式用平坦模型,段基址≈0、分段近乎关掉,实际只剩「虚拟≈线性 →(分页)→ 物理」。ARM 没有分段,只有分页(根在 TTBR0/1)。翻译结果由 TLB 缓存。
AI 系统分层 · 从应用到芯片
AI SYSTEM STACK

AI 系统分层:从应用到芯片

AI 系统的完整分层(对应《AI 系统:原理与架构》表 1.3.1)——从「用 AI 解决什么」一路落到硅片。自上而下五层:领域应用 → 开发体系 → 框架 → 编译器 → 芯片。

① 领域算法应用用 AI 解决什么
CV 视觉CNN · ViT · 检测/分割
NLP 语言Transformer · LLM
音频 / 多模态ASR · 语音 · 图文
生成 / 决策GAN · Diffusion · 强化学习
代表模型 CNN / RNN·LSTM / Transformer / GAN·Diffusion / RL——即右树「人工智能之树」的模型谱系,这里换个视角、只列它们落地的领域。
▼ 用什么写
② 开发体系编程语言 + 工具
PythonAI 主语言 · 粘合层
Jupyter交互式实验
VS CodeIDE
PyCharmIDE
框架都以 Python 为主接口(PyTorch/TF 与 Python 集成);性能内核仍是 C/C++/CUDA。Python 本身属左树「高级语言生态」。
▼ 用什么算
③ 框架 / 引擎自动微分 · 训练框架 + 推理引擎
PyTorchMeta · 动态图 · 主流
TensorFlowGoogle · 早期静态图
JAXGoogle · 函数式 · 靠 XLA
MindSpore华为 · 配昇腾 NPU
训练框架核心=自动微分:写好前向、框架自动反向求梯度(损失自己写、框架求其梯度);分前向模式(输入维度少时划算)与反向模式(输出少、参数多时划算,深度学习用它)。省显存靠缓存分配器 + 梯度检查点(重算换显存)。
分布式并行(单卡放不下就切开,大模型训练的命根子):数据并行(切 batch)· 张量并行(切单层权重)· 流水并行(按层切到多卡)· 混合并行(三者组合)。
推理引擎(部署端,不走训练框架):vLLM · TensorRT-LLM · SGLang · llama.cpp——PagedAttention / KV Cache / 连续批处理;配模型轻量化:量化(低比特) · 剪枝(去冗余权重) · 蒸馏(大模型教小模型)。对应主树节点「模型部署与推理」。
▼ 编译 · 下沉算子图
④ 编译器算子图 → 硬件指令
CUDAnvcc → PTX → GPU 机器码
XLATF/JAX 算子融合 → GPU/TPU
TVM开源 · 自动调优 · 多后端
CANN华为昇腾 · 对标 CUDA
AI 编译器的优化:算子融合(多算子合一、少读写显存)· 图优化(常量折叠 / 消冗余)· Auto-Tuning(自动搜最快实现)——这是 AI 编译器比"直接调库"更快的原因。
后端大量复用 LLVM(CUDA/XLA 底层、MLIR 即 LLVM 项目)——这正是「AI 时代仍离不开传统编译基础设施」、编译器成为连接两棵树第三座桥的原因。另有 Triton / TensorRT / ROCm。
底层通信(多卡/多机训练的通信底座):NCCL(英伟达) / HCCL(昇腾) · 集合通信 AllReduce 等——分布式并行靠它在卡间同步梯度/权重。
▼ 生成机器码 · 执行
⑤ 加速芯片大规模并行算力
GPU通用并行 · 生态最全
NPU昇腾/端侧 · 神经网络专用
TPUGoogle · 张量 ASIC
对应主树地基的算力谱系:CPU → GPU → FPGA → ASIC(TPU/NPU),灵活性↓、效率↑。
领域应用 → 开发体系 → 框架 → 编译器 → 芯片:AI 系统从「用什么解决问题」一路落到「跑在硅片上」的完整分层。