别再被"Token"绕晕了,这篇带你从原理到实战彻底吃透
写在前面
你有没有过这样的困惑:
- 为什么 GPT 的计费方式总是按 "Token" 算?
- 为什么 "Hello" 占 1 个 Token,而 "你好" 却占了 2 个甚至更多?
- 大模型明明是"文科生",它到底是怎么"看懂"我们输入的文字的?
说实话,我最早接触大模型的时候,也被这几个问题搞得一头雾水。直到有一天,我静下心来把 Tokenization 和 Embedding 这两个概念彻底捋了一遍,才发现——说白了,这两个东西就是大模型的"翻译官"和"思维空间" 。
今天这篇文章,我就用最接地气的方式,带你从零开始搞懂这两个核心概念。全程带着可运行的代码,读完你就能在自己的项目里用起来。
一、Tokenization:大模型的第一道"翻译工序"
1.1 为什么大模型不认字?
先问一个问题:计算机最擅长处理什么?
答案是数字。CPU 只能识别 0 和 1,显卡只能做矩阵乘法。你输入一段中文"你好世界",对大模型来说就是一串乱码——它根本不知道这是什么。
说白了,神经网络本质上是一堆数学运算(向量、矩阵乘法),它只能处理数字,对中文、英文字符一概不认。所以必须先把文字转成一串数字的离散符号 ID,这就是 Token。
另外,大模型的核心逻辑是 “根据上一个词预测下一个词” ,而词与词之间的语义相关性也需要通过数学计算来度量——这进一步要求输入必须是数值形式,而不能是原始字符。
一句话总结:神经网络是"数字脑袋",看不懂人类语言。Tokenization 就是把文字翻译成数字编号的第一道工序。
就像你去一个只说英语的国家,第一件事不是学语法,而是先把你要说的话翻译成英语。Tokenization 就是这个"翻译官"的角色。
1.2 Token 到底是什么?
官方定义:Token 是大模型处理和计费的最小单位。
用人话说:大模型读文本时,不是一个字一个字地读,而是按"块"来读。这个"块"就是 Token。
cl100k_base 是 GPT 系列模型(包括 ChatGPT)使用的编码规则,它包含了约 10 万个不同的 Token 编号。你输入的任何文本,都会被映射成这些编号中的一个或多个。
来看看实际的代码:
// index.mjs
import { getEncoding } from "js-tiktoken";
// 初始化 GPT 官方的 token 编码器
const enc = getEncoding('cl100k_base');
const text = "Hello, tiktoken! 你好,世界!";
// 编码:文本 → Token ID 数组
const tokens = enc.encode(text);
console.log("Token IDs:", tokens);
console.log("Token 数量:", tokens.length);
// 解码:Token ID 数组 → 文本
const decodeText = enc.decode(tokens);
console.log("解码还原:", decodeText);
运行结果:
Token IDs: [9906, 11, 87272, 5963, 0, 220, 57668, 53901, 3922, 3574, 244, 98220, 6447]
Token 数量: 13
解码还原: Hello, tiktoken! 你好,世界!
通过 enc.encode 将文本编码为 Token ID 序列,enc.decode 则可以将 ID 序列还原为原文。在实际调用大模型时,我们支付的费用正是基于 输入的 Token 数 + 输出的 Token 数 = 总 Token 数 来计算的。
你会发现:"Hello" 被编码成了 [9906] 一个 Token,而 "你好,世界!" 这 6 个中文字符却拆分成了 7 个 Token。这就是为什么中文内容在 API 计费上会更"贵"一些——同样长度的文本,中文产生的 Token 数更多。
经验公式:1 个英文字符 ≈ 0.3 个 Token,1 个中文字符 ≈ 0.6 个 Token。
1.3 Tokenization 的内部原理(简单版)
你可能好奇:Tokenization 具体是怎么切的?
GPT 使用了一种叫 BPE(Byte-Pair Encoding,字节对编码) 的算法。它的核心思路其实很简单:
- 先按最细粒度拆分文本(字节级别)
- 统计哪些"组合"出现频率最高
- 把高频组合合并成一个新的 Token
- 不断重复步骤 2-3,直到达到预设的 Token 数量上限
举个例子(简化版):
原始: "low" "lower" "newest" "widest"
第一步: 拆成单个字母
l o w l o w e r n e w e s t w i d e s t
第二步: 统计高频组合,"lo" 和 "we" 出现多次
合并: lo w lo wer n e w e st w i d e st
第三步: 继续合并高频组合...
最终词汇表可能包含: "lo", "low", "wer", "est", "wid", ...
所以你会发现:Token 不完全是单词,也不完全是字,它是"高频出现的字符组合" 。这就是为什么 "tiktoken" 可能被拆成 ["t", "ik", "token"] 这样的组合。
1.4 为什么 Tokenization 如此重要?
理解 Tokenization 有 3 个实际价值:
- 成本估算:调用 API 前可以提前算好 Token 数,心里有谱
- 上下文长度控制:模型有
context window限制(比如 128K),超了就截断或报错 - 理解模型行为:有时候模型输出"奇怪"的结果,是因为 Token 边界切分导致的语义丢失
二、Embedding:把文字"投影"到数学空间
2.1 从 Token 到语义:还差一步
Tokenization 把文字变成了数字 ID(比如 9906 代表 "Hello"),但这只是"编号",还没法用来计算语义。
想象一下:"猫" 和 "狗" 的 Token ID 可能是 12345 和 67890,但这两个数字之间的关系是随机的——计算机无法从 12345 和 67890 的差值推算出"猫和狗都是宠物"这个语义。
一句话总结:Token ID 只是"编号",Embedding 才是大模型理解语义的"思维空间"。
2.2 Embedding 做了什么?
Embedding(文本嵌入) 就是把每个 Token 映射到一个高维空间中的向量(一串浮点数数组)。
- 这个向量通常有几百到几千个维度(比如 1024 维、1536 维、4096 维)
- 每个维度的值在
-1到1之间(经过归一化) - 语义相近的文本,在向量空间中的距离也相近
大白话:Embedding 把文字变成了"坐标",语义相似的东西在"地图"上离得近。
2.3 实战:用阿里百炼 API 生成 Embedding
下面我们调用一个真实的 Embedding 接口,来看看文本是怎么变成向量的,以及语义相似度是怎么计算的。
// main.mjs
import OpenAI from 'openai';
import dotenv from 'dotenv';
dotenv.config();
const client = new OpenAI({
apiKey: process.env.DASHSCOPE_API_KEY, // 阿里百炼 API Key
baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1'
});
// 获取文本的 Embedding 向量
async function getEmbedding(text) {
const res = await client.embeddings.create({
model: 'text-embedding-v4',
input: text,
dimensions: 1024 // 1024 维向量
});
return res.data[0].embedding;
}
// 余弦相似度计算
function cosineSimilarity(vecA, vecB) {
let dot = 0, magA = 0, magB = 0;
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));
}
async function run() {
const text1 = "Andrej Karpathy LLM Tokenization 分词原理";
const text2 = "卡帕西讲解大模型BPE字词分词";
const text3 = "今天天气晴朗,适合出门散步";
const vec1 = await getEmbedding(text1);
const vec2 = await getEmbedding(text2);
const vec3 = await getEmbedding(text3);
console.log("文本1 vs 文本2 相似度:", cosineSimilarity(vec1, vec2));
console.log("文本1 vs 文本3 相似度:", cosineSimilarity(vec1, vec3));
}
run();
运行结果:
文本1 vs 文本2 相似度: 0.6654
文本1 vs 文本3 相似度: 0.1588
这两个数值说明了一切:
0.6654:即使一个是英文一个是中文,但语义都在讲"Karpathy 讲 Tokenization",向量空间中的距离很近0.1588:和"天气散步"完全不沾边,向量距离非常远
Embedding 真正做到了"跨语言的语义理解" ——它把不同语言的相同含义,映射到了向量空间的相近位置。
三、整个流程串起来:从输入到输出
现在我们可以把整个链条完整地画出来了:
用户输入 Prompt(文本)
↓
【Tokenization】编码器 (cl100k_base)
↓
Token ID 数组 [9906, 11, 87272, ...]
↓
【Embedding】将 Token ID 映射为高维向量
↓
高维向量 (1024 维浮点数数组)
↓
【Transformer 神经网络】在海量向量之间计算注意力、做推理
↓
输出 Token ID 数组(预测的下一个词)
↓
【解码器】将 Token ID 解码为文本
↓
模型输出 Response(文本)
一句话串联:输入文本 → Token 编号 → 高维向量 → 神经网络计算 → Token 编号 → 输出文本。
四、实战应用:这些概念能做什么?
理解了 Tokenization 和 Embedding,你在实际开发中至少可以做 4 件事:
4.1 智能客服中的相似问题匹配
用户提了一个问题,你不需要精确匹配关键词,而是通过 Embedding 计算相似度,从 FAQ 库中召回最接近的 3 个问题及其答案。
// 伪代码示例
const userQuery = "怎么修改密码?";
const faqList = [
{ q: "如何重置我的登录密码", a: "..." },
{ q: "忘记密码怎么办", a: "..." },
{ q: "今天天气怎么样", a: "..." }
];
const queryVec = await getEmbedding(userQuery);
const faqVecs = await Promise.all(faqList.map(f => getEmbedding(f.q)));
// 计算相似度,排序取 Top 3
const results = faqVecs.map((vec, i) => ({
...faqList[i],
score: cosineSimilarity(queryVec, vec)
})).sort((a, b) => b.score - a.score).slice(0, 3);
4.2 RAG(检索增强生成)的第一步:向量召回
在做 RAG 应用时,第一步永远是用用户问题去向量数据库(如 Milvus、Pinecone、Chroma)中检索相关文档片段。这里的"检索"本质就是 Embedding 相似度计算。
4.3 成本预估与 Token 限流
import { getEncoding } from "js-tiktoken";
const enc = getEncoding('cl100k_base');
function countTokens(text) {
return enc.encode(text).length;
}
// 调用前预估成本
const prompt = "请帮我写一篇关于大模型的文章";
const tokenCount = countTokens(prompt);
console.log(`本次请求将消耗约 ${tokenCount} 个 Token`);
// 如果超过上下文窗口,主动截断
const MAX_TOKENS = 8000;
if (tokenCount > MAX_TOKENS) {
// 截断或分片处理
}
注意:总费用取决于 输入 Token 数 + 输出 Token 数,所以不仅要预估 prompt 的长度,还要预估生成内容的长度。
4.4 多语言搜索
你不需要为中文和英文分别建索引,因为 Embedding 是跨语言的。用户搜中文"机器学习",英文文档的 Embedding 向量同样会被召回——这就是 Google 翻译搜索背后的原理之一。
五、进阶学习路线建议
如果你想把这块知识吃透,我个人的学习路径供参考:
-
入门理解:吴恩达《AI for Everyone》《Generative AI for Everyone》(非技术背景也能看懂)
-
原理深挖:Andrej Karpathy 的 3 小时大模型入门视频(www.bilibili.com/video/BV16c…](www.bilibili.com/video/BV16c… Transformer 和 Attention 机制讲透了
-
动手实践:
- 用
js-tiktoken在你的 Node.js 项目里做 Token 计数 - 用各大厂商的 Embedding API(OpenAI、阿里百炼、智谱等)做语义搜索 Demo
- 玩一下 Google 的 NotebookLM,体验 RAG 的实际效果
- 用
-
**关注领域 **:
- 晓辉博士(专业深度)
- 宝玉AI(Prompt Engineering)
- 归藏(AI 产品方向)
写在最后
回过头来看,Tokenization 和 Embedding 这两个概念说穿了并不复杂:
- Tokenization 是把文本切分成"积木块",并编号
- Embedding 是把编号"投影"到高维空间,让语义变得可计算
它们是构建大模型应用的两块基石。无论你是做 AI 产品开发、写 Agent 应用,还是只想搞清楚大模型的计费逻辑,理解这两个概念都是绕不开的第一步。
记住一句话:Token 决定你能"读"多少,Embedding 决定你能"懂"多深。
希望这篇文章能帮你少走一些弯路。如果你在实际开发中遇到了相关问题,欢迎在评论区交流讨论~