从“你好”到 1024 维坐标:大模型怎么识字

大模型看起来很聪明,你跟它聊什么都行。但它的底层只认得一个东西:数字。

这就引出了两个基础问题------怎么把文字变成数字(分词),以及怎么让这些数字带上语义(嵌入)。搞懂这两个概念,后面再遇到 token 计价、向量检索、RAG 这些东西,心里就有底了。

你输入的每个字,都会被切成 token

随便写一句话:"Hello, tiktoken! 你好,世界。"

在大模型眼里,这句话先变成一串整数:

yaml 复制代码
[9906, 11, 83, 292, 11410, 0, 3922, 33108, 233, 98220, 230]

这个过程叫分词(Tokenization) 。用的工具是 OpenAI 开源的 tiktoken 库,编码器叫 cl100k_base------GPT-4 和 GPT-3.5 都在用它。

用 JS 写就三行:

js 复制代码
import { getEncoding } from "js-tiktoken";

const enc = getEncoding('cl100k_base');
const tokens = enc.encode("Hello, tiktoken! 你好,世界");
// [9906, 11, 83, 292, ...]

反过来也简单:

perl 复制代码
enc.decode(tokens);
// "Hello, tiktoken! 你好,世界"

encode 进去,decode 出来,信息不丢。这套转换是 LLM 处理一切文本的入口。

有一个容易踩的坑:token 不等于单词。cl100k_base 的切割规则跟自然语言的"词"不是一回事。比如 "tiktoken" 这个单词可能会被切成两段,"你好"这种中文词也可能被切成好几块。切割逻辑完全由编码器的词表决定,不用纠结它为什么这么切------用就行了。

中英文的 token 消耗不一样

这是很多人在算成本时才注意到的事情:

  • 1 个英文字符大概消耗 0.3 个 token
  • 1 个中文大约 0.6~1 个 token

同样的意思,用中文写的 token 数大约是英文的两倍。如果你在调 prompt 控制成本,这个差异值得记住。

计费公式很简单:总 token = 输入 token + 输出 token。百万 token 现在大概几块钱人民币,不同模型价格有差异,但计价单位都是 token。

Embedding:让数字带上语义

分词只是第一步。token ID 本身只是个编号,123 和 456 之间没有"含义上的远近"。要让模型理解语义,还得做一次嵌入(Embedding) ------把每个 token 映射到一个高维空间里的点。

这个概念对应到代码上,就是调一个 embedding 接口:

php 复制代码
const res = await client.embeddings.create({
    model: 'text-embedding-v4',
    input: "Andrej Karpathy LLM tokenization 分词原理",
    dimensions: 1024
});
// 返回一个 1024 维的浮点数数组
// [0.023, -0.451, 0.189, ...]

返回的结果是一个 1024 维的向量,每个维度的值都在 -1 到 1 之间。这句话就变成了高维空间里的一个坐标点。

那怎么衡量两句话语义上近不近?用余弦相似度

js 复制代码
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));
}

这个函数的返回值在 -1 到 1 之间。越接近 1,语义越相似;接近 0,基本没关系。

跑一下试试

拿三句话做个实验:

js 复制代码
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(cosineSimilarity(vec1, vec2)); // 大概 0.9+
console.log(cosineSimilarity(vec1, vec3)); // 大概 0.1 左右

text1 和 text2 说的是同一件事------Karpathy 讲分词原理------只不过一个用英文写的,一个用中文写的。向量相似度接近 1。

text3 跟它们八竿子打不着,相似度直接掉到接近 0。

这就是 embedding 在整个 LLM 生态里被广泛使用的原因:它能把语义的远近量化成一个数字。RAG 检索靠它,语义搜索靠它,聚类、去重、推荐也靠它。

整条链路串起来

markdown 复制代码
你说的话 → Tokenizer 切成 token ID → Embedding 变成 1024 维向量
    → Transformer 一顿算 → 输出 token ID → 解码成文字返回给你

每一步都简单,连在一起就能让模型"理解"和生成语言。

如果你想自己跑一遍,依赖就三个包:

bash 复制代码
js-tiktoken   # 分词
openai        # 调 embedding 接口(兼容国内模型)
dotenv        # 管 API key

用阿里云的 DashScope 或者其他兼容 OpenAI 接口的国内服务都行------改一下 baseURLapiKey 就切过去了,代码不用变。


你平时写 prompt 的时候可能不会意识到 token 和 embedding 在背后干活,但理解这两个机制,能帮你更好地估算成本、设计检索策略、以及 debug 那些"模型怎么听不懂我说话"的奇怪时刻。

相关推荐
ShallWeL1 小时前
【机器学习】(2)—— 线性回归:损失函数
人工智能·机器学习
美团技术团队2 小时前
ICML 2026 | 美团技术团队学术论文精选
人工智能
moMo2 小时前
你的每一次对话,都是第一次
人工智能
不加辣椒2 小时前
第13章 检索增强提示工程
人工智能
小爷毛毛_卓寿杰2 小时前
我把 397B 的「Agentic 大脑」塞进了 Xinference,一键部署 Nex-N2
人工智能·架构·github
smallYoung2 小时前
Vibe Coding 笔记-中
人工智能
米小虾2 小时前
DSpark:让大模型"写得更快"的秘密武器
人工智能·deepseek
JavaGuide2 小时前
比 iTerm2 更适合 Claude Code/Codex 的终端,我换成 Ghostty 了
人工智能·后端
threerocks3 小时前
神级 Skill,作品个个儿爆,我开源了长期自用的手绘风格库
人工智能·aigc