LLM 分词与向量化:大模型是如何"读懂"文字的?------Tokenization × Embedding 原理与实战
本文深入解析 LLM 的两大底层机制:Tokenization(分词)与 Embedding(向量化)。从为什么必须分词,到 js-tiktoken 的编码解码实战,再到阿里百炼 Embedding API 调用与余弦相似度计算------彻底搞懂大模型"读懂"文本的背后原理。
前言
我们每天都在和 LLM 对话,但有没有想过这样一个问题:
神经网络只能处理数字(向量、矩阵),看不懂中文、英文等字符------那大模型是怎么"读懂"你输入的 Prompt 的?
答案藏在两个关键步骤中:
- 分词(Tokenization):将文本切割为 Token ID(一串数字)
- 嵌入(Embedding):将 Token ID 映射为高维向量(数字语义)
本文将带你深入理解这两大底层机制,并用代码动手实践。
一、LLM 处理文本的完整流水线
1.1 从输入到输出的四个步骤
scss
Prompt(文本输入)
│
▼
① Tokenizer(分词器)
└── 文本 → Token IDs(一串数字)
│
▼
② Embedding(嵌入层)
└── Token IDs → 高维向量(语义数字表达)
│
▼
③ Transformer(核心计算)
└── Attention → MLP → 推理
│
▼
④ Decoder(解码器)
└── 输出 Token IDs → 文本
│
▼
回答(文本输出)
1.2 为什么必须分词?
arduino
计算机底层只能处理 0 和 1
字符 'A' → ASCII 编码 → 65(一个数字)
字符 '吃' → Unicode 编码 → 21505(一个数字)
问题:
- 把一整段文本"映射"为一个数字?→ 信息量太大,无法表达语义关系
- 把每个字符"映射"为一个数字?→ 太过细碎,单字符无语义
解决方案:
→ 切成 token(比字符大、比句子小、语义相关的最小单位)
💡 核心洞察:Token 不能切成字符(太细碎,无意义),也不能不切(一段文本无法整体编码)。Token 是"语义相关的最小单位"------它介于字符和单词之间。
二、Tokenization(分词):文本到数字的第一次转换
2.1 Token 是什么?
Token 是大模型计价和处理的最小单位。
| 文本类型 | 1 个字符 ≈ | 示例 | Token 数 |
|---|---|---|---|
| 英文 | 0.3 个 token | "Hello" |
~1 token |
| 中文 | 0.6 个 token | "你好" |
~1.2 tokens |
| 特殊符号 | 视编码而定 | "👋" |
1~2 tokens |
定价参考:百万 Token 约几元人民币(不同模型价格不同)。
2.2 分词过程图解
csharp
输入文本: "Hello, 世界!"
分词器编码(encode):
→ Token IDs: [15496, 11, 91387, 235, 120]
↑ ↑ ↑ ↑ ↑
Hello , 世 界 !
解码(decode):
[15496, 11, 91387, 235, 120] → "Hello, 世界!"
⚠️ 注意事项 :Token 不等于单词。中文一个字可能占 0.6 个 token,英文一个完整单词一般 1 个 token。实际分词结果取决于分词器使用的编码规则(如
cl100k_base)。
2.3 实战:js-tiktoken 编码解码
javascript
// index.mjs
import { getEncoding } from 'js-tiktoken';
// GPT-4 官方分词器:cl100k_base
const enc = getEncoding('cl100k_base');
// 原始文本
const text = "Hello, tiktoken! 你好,世界!";
// 编码:文本 → Token IDs
const tokens = enc.encode(text);
console.log("Token IDs:", tokens);
// 输出示例:[15496, 11, 125262, 0, ...]
console.log("Token 数量:", tokens.length);
// 解码:Token IDs → 文本(无损还原)
const decodedText = enc.decode(tokens);
console.log("解码文本:", decodedText);
// 输出:"Hello, tiktoken! 你好,世界!"
执行流程:
文本 → cl100k_base 映射规则 → Token ID
↑ ↑
不一定是单词,而一定是 Token 每个 ID 对应 100k+ 词汇表中的一个
2.4 为什么 Token 数量影响费用?
markdown
输入:用户的 Prompt → 编码为 Token IDs → 计算消耗
输出:模型生成的回答 → 编码为 Token IDs → 计算消耗
↓
总 Token 数 = 输入 Token + 输出 Token
费用 = 总 Token 数 × 单价
三、Embedding(嵌入):从数字 ID 到语义向量
3.1 Token ID 的局限
arduino
Token ID: 15496 → "Hello"
问题:
15496 和 15497 之间没有语义关系
"Hello" 和 "Hi" 的 Token ID 可能相差很远
数字大小不代表语义远近
Token ID 只是字典中的序号,不包含任何语义信息。
3.2 Embedding 的作用
Embedding 将 Token ID 映射为高维空间中的向量,让语义相近的词在空间中距离更近。
arduino
Token ID 空间: Embedding 向量空间:
┌──────────┐ ┌──────────────────────┐
│ 15496 → │ │ [0.12, -0.35, ...] │
│ "Hello" │ │ ↑ 语义相近的词 │
│ │ │ │ 向量"距离"近 │
│ 16492 → │ Embedding │ [0.11, -0.33, ...] │
│ "Hi" │ ──────────────→ │ "Hi" │
│ │ │ │
│ 91387 → │ │ [0.87, 0.22, ...] │
│ "世界" │ │ 语义不同 → 向量远 │
└──────────┘ └──────────────────────┘
3.3 Embedding 的核心特性
| 特性 | 说明 | 意义 |
|---|---|---|
| 语义相似 | 相似词 → 相近向量 | 找到"意思相近"的内容 |
| 维度高 | 1024~4096 维 | 容纳足够的语义信息 |
| 数值范围 | -1, 1 | 方便计算相似度 |
| 连续空间 | 非离散值 | 可进行算术运算 |
💡 经典案例 :
vector("国王") - vector("男人") + vector("女人") ≈ vector("女王")--- 向量空间允许语义算术。
3.4 实战:阿里百炼 Embedding API
javascript
// main.mjs
import OpenAI from 'openai';
import dotenv from 'dotenv';
dotenv.config();
const client = new OpenAI({
apiKey: process.env.DASHSCOPE_API_KEY,
baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1'
});
/**
* 获取文本的 Embedding 向量
* @param {string} text - 输入文本
* @returns {number[]} - 1024 维向量
*/
async function getEmbedding(text) {
const res = await client.embeddings.create({
model: 'text-embedding-v4', // 阿里百炼嵌入模型
input: text,
dimensions: 1024 // 指定向量维度
});
return res.data[0].embedding;
}
向量是什么?
javascript
// 一个 1024 维的向量示例(截取前 5 维)
const embedding = [0.015, -0.023, 0.087, -0.001, 0.054, ...];
// 每一个数值代表文本在某个"语义维度"上的强度
// 1024 个维度共同构成文本的语义指纹
四、余弦相似度:计算语义距离
4.1 数学原理
两个文本的相似度 = 它们的 Embedding 向量之间的余弦值。
css
cos(θ) = (A · B) / (|A| × |B|)
A · B = 点积(对应位置相乘再相加)
|A| = 向量 A 的模长
|B| = 向量 B 的模长
4.2 JavaScript 实现
javascript
function cosineSimilarity(vecA, vecB) {
let dot = 0; // 点积
let magA = 0; // 向量 A 模长平方
let magB = 0; // 向量 B 模长平方
for (let i = 0; i < vecA.length; i++) {
dot += vecA[i] * vecB[i]; // 对应位置相乘累加
magA += vecA[i] ** 2; // 平方累加
magB += vecB[i] ** 2;
}
return dot / (Math.sqrt(magA) * Math.sqrt(magB));
}
4.3 完整语义相似度对比
javascript
async function run() {
// 准备三段文本
const text1 = "Andrej Karpathy LLM Tokenization 分词原理";
const text2 = "卡帕西讲解大模型BPE字词分词";
const text3 = "今天天气晴朗,适合出门散步";
// 获取 Embedding 向量(1024 维)
const vec1 = await getEmbedding(text1);
const vec2 = await getEmbedding(text2);
const vec3 = await getEmbedding(text3);
// 计算余弦相似度
console.log("text1 vs text2:", cosineSimilarity(vec1, vec2));
// ↑ 语义相关(都是 LLM 分词),输出 ≈ 0.7~0.8
console.log("text1 vs text3:", cosineSimilarity(vec1, vec3));
// ↑ 语义无关(分词 vs 天气),输出 ≈ 0.1~0.2
}
结果解读:
vbnet
text1: "Andrej Karpathy LLM Tokenization 分词原理"
text2: "卡帕西讲解大模型BPE字词分词"
余弦相似度 ≈ 0.75
→ 语义相近!都讲 LLM 分词
text1: "Andrej Karpathy LLM Tokenization 分词原理"
text3: "今天天气晴朗,适合出门散步"
余弦相似度 ≈ 0.15
→ 语义无关,话题完全不同
五、Embedding 的典型应用
5.1 语义搜索
arduino
用户搜索:"大模型是怎么分词的?"
传统搜索:匹配关键词
❌ 没有"分词"二字 → 搜不到
语义搜索(基于 Embedding):
✅ "Tokenization"的向量与"分词"的向量相近 → 能搜到
5.2 知识库 RAG
css
用户提问 → Embedding 向量化
│
▼
向量数据库检索(余弦相似度)
│
▼
找到最相关的 Top N 知识片段
│
▼
注入 LLM 上下文 → 生成回答
5.3 文本聚类
markdown
10000 条用户评论 → 每条 Embedding 向量化
│
▼
K-Means 聚类
│
▼
发现 5 大类主题:
├── 产品质量
├── 配送速度
├── 客服态度
├── 价格优惠
└── 使用体验
六、LLM 学习建议
6.1 学习路径
less
第一步:搞懂 AI 是什么
├── 吴恩达 AI for Everyone(入门)
├── Karpathy 3小时大模型入门视频(原理)
└── https://www.bilibili.com/video/BV16cNEeXEer/
第二步:动手用起来
├── Claude Code / Codex:日常编码
├── NotebookLM:RAG 实践
└── Obsidian:第二大脑
第三步:做个人作品
├── Vibe Coding:从想法到应用
└── Agent 开发:真正的自动化
第四步:持续关注
├── 晓辉博士(专业深度)
├── 42章经(行业洞察)
├── 宝玉AI(Prompt Engineering)
└── 归藏(AI 产品)
6.2 需要了解的底层概念
| 概念 | 说明 | 难度 |
|---|---|---|
| Tokenization | 分词,本文已讲 | ★☆☆ |
| Embedding | 向量化,本文已讲 | ★☆☆ |
| Attention | 注意力机制 | ★★☆ |
| Transformer | 整体架构(Google 提出) | ★★★ |
| Fine-tuning | 微调 | ★★☆ |
七、知识图谱
arduino
LLM 分词与向量化
├── LLM 处理流水线
│ ├── Tokenizer(分词)
│ ├── Embedding(嵌入)
│ ├── Transformer(计算)
│ └── Decoder(解码输出)
├── Tokenization 分词
│ ├── 为什么必须分词?
│ ├── Token 的概念
│ ├── Token 定价(中英文差异)
│ └── js-tiktoken 实战
│ ├── encode:文本 → Token IDs
│ └── decode:Token IDs → 文本
├── Embedding 嵌入
│ ├── Token ID 的局限
│ ├── Embedding 的作用(语义向量化)
│ ├── 核心特性(高维/连续/语义相似)
│ └── 阿里百炼 Embedding API
│ ├── text-embedding-v4 模型
│ └── 1024 维向量
├── 余弦相似度
│ ├── 数学原理(cos θ)
│ ├── JavaScript 实现
│ └── 语义相似度对比
└── 应用场景
├── 语义搜索
├── RAG 知识库
└── 文本聚类
八、总结
本文深入解析了 LLM 的两大底层机制:
- Tokenization 是将文本切割为 Token ID 的过程。计算机看不懂文字,只能处理数字。Token 是介于字符和单词之间的语义最小单位。
- Embedding 是将 Token ID 映射为高维向量的过程。Token ID 只是字典序号,不包含语义;Embedding 向量让语义相近的词在空间中距离更近。
- js-tiktoken 是 OpenAI 官方的分词库,支持
cl100k_base(GPT-4 编码器),可完成 encode/decode 操作。 - 阿里百炼 Embedding API 提供了
text-embedding-v4模型,支持指定维度(如 1024),将文本向量化。 - 余弦相似度 是衡量两个向量方向的指标,在语义搜索、RAG、文本聚类等场景中广泛应用。
- LLM 学习路径应遵循"先理解原理,再动手使用,最后做个人作品"的渐进式路线。
🚀 学习建议:一定要亲手跑一遍 js-tiktoken 的 encode/decode,以及 Embedding API 的余弦相似度计算。理解"文本 → Token ID → 向量 → 语义"这条完整链路,才能真正理解大模型的工作原理。
参考资源
- Karpathy 深入ChatGPT模型 视频
- OpenAI Tokenizer 在线工具
- js-tiktoken npm 包
- 阿里百炼 Embedding API
- 吴恩达 AI for Everyone
📌 标签:#LLM #Tokenization #Embedding #分词 #向量化 #余弦相似度 #大模型 #js-tiktoken
💬 互动:你在使用 LLM 时考虑过 Token 消耗吗?有没有试过用 Embedding 做语义搜索?欢迎在评论区分享!