大模型背后的"翻译官":一文搞懂 Tokenization 和 Embedding

0 阅读10分钟

别再被"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,字节对编码)  的算法。它的核心思路其实很简单:

  1. 先按最细粒度拆分文本(字节级别)
  2. 统计哪些"组合"出现频率最高
  3. 把高频组合合并成一个新的 Token
  4. 不断重复步骤 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 个实际价值:

  1. 成本估算:调用 API 前可以提前算好 Token 数,心里有谱
  2. 上下文长度控制:模型有 context window 限制(比如 128K),超了就截断或报错
  3. 理解模型行为:有时候模型输出"奇怪"的结果,是因为 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 翻译搜索背后的原理之一。

五、进阶学习路线建议

如果你想把这块知识吃透,我个人的学习路径供参考:

  1. 入门理解:吴恩达《AI for Everyone》《Generative AI for Everyone》(非技术背景也能看懂)

  2. 原理深挖:Andrej Karpathy 的 3 小时大模型入门视频(www.bilibili.com/video/BV16c…](www.bilibili.com/video/BV16c… Transformer 和 Attention 机制讲透了

  3. 动手实践

    • 用 js-tiktoken 在你的 Node.js 项目里做 Token 计数
    • 用各大厂商的 Embedding API(OpenAI、阿里百炼、智谱等)做语义搜索 Demo
    • 玩一下 Google 的 NotebookLM,体验 RAG 的实际效果
  4. **关注领域 **:

    • 晓辉博士(专业深度)
    • 宝玉AI(Prompt Engineering)
    • 归藏(AI 产品方向)

写在最后

回过头来看,Tokenization 和 Embedding 这两个概念说穿了并不复杂:

  • Tokenization 是把文本切分成"积木块",并编号
  • Embedding 是把编号"投影"到高维空间,让语义变得可计算

它们是构建大模型应用的两块基石。无论你是做 AI 产品开发、写 Agent 应用,还是只想搞清楚大模型的计费逻辑,理解这两个概念都是绕不开的第一步。

记住一句话:Token 决定你能"读"多少,Embedding 决定你能"懂"多深。

希望这篇文章能帮你少走一些弯路。如果你在实际开发中遇到了相关问题,欢迎在评论区交流讨论~