惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
大猫的无限游戏
大猫的无限游戏
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 叶小钗
月光博客
月光博客
Last Week in AI
Last Week in AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
IT之家
IT之家
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
S
SegmentFault 最新的问题
宝玉的分享
宝玉的分享
博客园 - Franky
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Jina AI
Jina AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Cloudflare Blog
博客园 - 司徒正美
爱范儿
爱范儿

極客死亡計劃

Coffee Break Clojure, Vol.0 可怖的沉默 大脑充血 Vol.98 第一个人 大脑充血 Vol.97 少年承载了太多年长者的恶臭投射 现象学导论 Writing following the F-pattern is a horrible horrible idea Generated work should not be published. 大脑充血 Vol.96 给我发邮件吧,放轻松 计算机网络如何帮我理解「人们难以相互理解」? 大脑充血 Vol.95 骷髅编程 诺兰的《奥德赛》采取了什么样的改编策略? III 诺兰的《奥德赛》采取了什么样的改编策略? II 大脑充血 Vol.94 我的世界一直下雨 诺兰的《奥德赛》采取了什么样的改编策略? 大脑充血 Vol.93 新知识分子的新庸俗 艾尔特拉克在岣琅 大脑充血 Vol.92 川渝人在山东吃到没有辣味的麻辣香锅和红油水饺之后产生的哲学思考 Are We Interfacing Yet? 大脑充血 Vol.91 如何用宝可梦属性玩剪刀石头布? 什么是工程问题? 大脑充血 Vol.90 逃离合居生活
Token 应译作「符」
Eltrac · 2026-09-07 · via 極客死亡計劃

整场「要不要把 Token 翻译成词元?」的争论令我感到诡异,诡异的点在于所有参与者都只看到了 Token 作为大语言模型计价单位的意思,而 Token 一词存在于英语语言中已经有很久了(对中文的影响也很大)。若把 Token 先前的释义也译作「词元」,场面会非常可笑:

  • 这套桌游里的某个词元不见了!
  • 请求体里必须携带词元才能通过验证。
  • 在构造抽象语法树之前,要先把字符串词元化。(这倒还算接近的)
  • 把安全词元插入电脑的 USB-C 接口。
  • 为保证数据安全,可以把敏感信息词元化。
  • 用你的词元兑换优惠或者奖品。

正如人们滥用「人工智能」一词指代「大语言模型」,因为他们只知道热度最高的技术,便让 AI 这个上世纪就出现的概念被人工智能的一个小分支占据一样,人们滥用 Token 一词,以至于他们不关心其他的意思。更何况「词元」这个意思用在 LLM 里其实相当不准确。

不过,也需要批评前人,Token 一词的翻译本身就很混乱。

桌游里的 Token 是「指示物」的意思,还有人根据情况译作「代币」「标记」。大富翁里用来标记地产的房子,飞行棋里的飞机,龙与地下城里的角色小人,都叫作 Token。

用来表示人物、角色的指示物还被称作 Meeple(My People),音译作「米宝」。能用米宝来指代所有的指示物吗?当然不行!米宝的本意是人物,是 Token 里相当小的一类。同理,能用「词元」对应 Token 吗?不能!词元只指代相当小的范畴,你当然不能说桌游里的指示物是词元。

不仅桌游里的代币是 Token,游戏厅里的游戏机和赌场里的老虎机使用的代币,也叫作 Token coin,不过如今更多地被 ticket(票券)取代了。

密码学中的 Token 通常叫作「令牌」。常见的场景是客户端输入账号密码之后,服务端生成一个(多半有期限)的凭证,一般是字符串,之后客户端只需要在访问时提供这个凭证就好,期限时间内不需要再次输入密码。这个字符串一般保存在 Cookies 里,服务端自动读取,或者客户端携带在 HTTP 请求头里:

Authorization: Bearer eyJhbGci...<snip>...yu5CSpyHI

Bearer 之后的部分就是 Token。最常见的令牌之一是 JWT ,其他的应用场景也不少,不限于 HTTP 通信。任何能够在通信过程中,从密码学意义上验证用户身份的凭证字符串,都叫令牌。

顺带一提,令牌可以当作是时效性很强的密钥,如果泄露,攻击者就可以在令牌过期之前使用你的身份访问相关资源。令牌往往存放在 Cookies 里,这也是为什么 第三方 Cookies (或者说跨域 Cookies)常常受人诟病,现代浏览器也采取了很多限制。

还有一种密码学方法叫作令牌化( Tokenization ),指代把敏感信息替换为不敏感的等价物(即 Token)的过程。我对此了解不多,就不闹笑话了。

这类 Token 在解析代码的过程中产生,解析(parse)或者预处理(preprocess)还没有到编译(compile)或者解释(interpret)的地步,无论编译器还是解释器都有这个步骤。仔细想想,源代码只是储存在文件里的文本而已,可以当作字符串处理,解释器和编译器是怎么把字符串变成有意义、可执行的语句的?我们可以现场写个 Lisp 解析器来理解其过程。

程序员极有可能接触过简单的解释器,比方说,如何给下面这个算式字符串求值?

答案是构造抽象语法树(AST)。不难发现,上述算式可以表示为树形结构,(1 + 3) 是一个整体,4 * 7 因为乘法的优先级更高,也作为一个整体,那么就可以把 - 当作根,前面两个整体作为 - 的左右子树。继续递归,不难发现 (1 + 3)+ 为根,13 为叶子结点的子树,而 4 * 7* 为根,47 为叶子结点的子树。

(1 + 3) - 4 * 7 的树状表示

接下来只要深度优先遍历 AST 就好了,不难发现结点有两类,非叶子结点是操作符,叶子结点是数字。遍历时若是遇到数字,就直接返回值;若是遇到操作符,就根据操作符计算左右子树的值。在一系列奇妙的递归之后,程序就能求出这棵树的值为 -24

回顾一开始的算式,能不能把它写成这个样子?

也就是说,把中置操作符换成前置操作符,把所有的括号显式地写出来。如果把 () 看成列表,前置操作符的写法其实是嵌套的列表,而嵌套的列表就是树。这样一来,把字符串解析成 AST 的算法就好写多了。

假设我们现在不仅仅是要表示算式,而是要表示程式……

(format t "it's ~a~%" 
  (- (+ 1 3) (* 4 7)))

上面这段代码应该打印 it's -24

同样,手动解析为 AST,变成下图的这个样子:

上述 Lisp 代码的树形表示

现在,非叶子结点是函数,叶子结点是函数的参数。读者可能会觉得把不同类型的数据都放在一起有点奇怪,和刚才的算式差得有点远。不过,只要想到深度优先遍历和递归求值的思路,就不会觉得奇怪了。只不过函数不仅仅是计算得出了值,还可能带有副作用。比方说 format 的副作用就是在指定的输出流(此处是 stdout)中打印文本。

手动遍历这棵树:

  1. 求值根节点 format,发现是函数,于是求它的子树。
  2. 求值 format 的左子树,发现是值,返回 t
  3. 求值 format 的第二棵子树,发现是值,返回 "it's ~a~%"
  4. 求值 format 的右子树 -,发现是函数,求它的子树。
  5. 求值 - 的左子树 +,发现是函数,求它的子树
  6. 求值 + 的左子树,发现是值,返回 1
  7. 求值 + 的右子树,发现是值,返回 3
  8. 结点 + 的子树都求值完毕,对它本身求值得到 4
  9. 求值 - 的右子树 *,发现是函数,求它的子树
  10. 求值 * 的左子树,发现是值,返回 4
  11. 求值 * 的右子树,发现是值,返回 7
  12. 结点 * 的子树都求值完毕,对它本身求值得到 28
  13. 结点 - 的子树都求值完毕,对它本身求值得到 -24
  14. 结点 format 的子树都求值完毕,对它本身求值得到 nil,同时发生副作用:"it's -24" 被写入 stdout

或许用一门非 Lisp 语言表述上面这个程序会更直观:

// eval 对 AST 或子树求值
func eval(node Node) any {
    if node.IsLeaf() {
        // 如果是叶子结点,直接返回值
        return node.Value
    }         

    fn := node.Value
    var args []any
    for _, child := node.GetChildren() {
        args = append(args, eval(child))
    }
    // applyFn 根据函数名 fn,把某个操作作用在参数 args 上,最后返回值
    return applyFn(fn, args) 
}

你已经学会怎么写 Lisp 解释器了,快去造一门 Lisp 方言吧!

不过 eval() 函数的前提是 AST 已经被构造好了,而构造 AST 的前提是什么?回顾上面两棵树,你会发现每个结点中包含的都是有意义的语言单元。这个说法可能有点没头没脑的,难道还能包含没意义的语言单位吗?事实是,如果要创造完整的解释器,构造出 AST,就需要先划分出有意义的语言单元。

不能只根据空格划分,不然 "Hello World" 就会被分成 "HelloWorld" 两个单元。甚者,(format t "Hello World") 会变成:(formatt"HelloWorld")

假设有一个 tokenize() 函数,它的输入是未经处理的字符串,输出是字符串数组,数组里的每个元素都是独立的语言单元。执行 tokenize("(format t \"Hello World\")") 应该得到:

[]string{
    "(",
    "format",
    "t",
    "\"Hello World\"",
    ")"
}

之所以把括号留下,是因为它们需要作为标记传给 parse() 函数。一遇到 (,就认为下一个是根,之后的一直到 ) 都是子树。这个函数作为解析器,输入划分好的 Tokens,输出可以递归求值的 AST。parse() 具体怎么实现就不赘述了。

除了 Lisp,你还可以参照 C 语言编译器 gcc 的文档的 1.3 Tokenization 这一节。Tokenization 发生在预处理(preprocess)阶段。

至此,你应该明白我说的第二类 Token 指什么了。这类 Token 准确来说叫作 Lexical Token (词法记号,或者说…… 词元)。词法的(lexical)和句法的(syntactic,或名词 syntax)指代不同的抽象层次,词法分析就是把字符串划分为词法记号(lexical token)的过程,而句法分析(更常见的说法是语法分析)则是判断词法记号的组合有没有犯句法错误(syntax error)。Token 是词法层次的实体,分析句法时候我们就默认 Token 已经变成 AST 中不可分割的结点了。至于语法(grammar),则是词法和句法的组合,不过编程语言一般不说 grammar,都默认使用 syntax(句法或语法)一词。

真是为了一盘醋包了一场酣畅淋漓的饺子啊。

接下来是第三类 Token,即应用在 NLP 领域的 Token。前面我们在处理编程语言,而 NLP 是对自然语言的处理。那么 NLP 中的 Token 是指 jieba 这类分词工具吗?

的确,中文分词算法就是 NLP 分词的一种,叫作 Word tokenization。把英文句子打散成一个一个的单词,也属于这类分词。1

其他的分词方式还有:

  1. 字符分词(Character tokenization)
  2. 子词分词(Sub-word tokenization)
  3. 句分词(Sentence tokenization)
  4. N 元分词(N-gram tokenization)

第三个是不是看起来很不对劲?如果是以句子为单位,那为什么会叫作分词呢?这里的 Token 不是词法意义上的 Token,把 tokenization 译作「分词」显然不对,那么把 token 译作「词元」就更不对了。若是译作「词元」,难道不会和 word 混淆吗?

上述老派的 NLP 方法,一般用在非 LLM 聊天机器人、搜索引擎的 Query 分析和词频统计中,根据用例不同选用不同的 Tokenization 方法。那么在更新的 NLP 技术,大语言模型中,Token 又指代什么呢?

大语言模型使用的 Tokenization 方法与简单 NLP 类似,至少输入都是自然语言词句,但算法过程和输出完全不同。LLM 用到了字节对编码(Byte-pair encoding,BFE),最早在 1994 年提出的 BFE 算法如下。2

假设有形如 aaabdaaabac 的输入,其中 aa 这个字节对的出现频率很高,于是替换为整个字符串中没有出现过的其他字符,比如 Z,于是就变成了:

可见 ab 也出现了多次,替换为 Y

现在又有了多次出现的 ZY,替换为 X

通过递归的字节对编码,我们把 aaabdaaabac 压缩成了 XdXac

大模型修改了 BFE 算法,不再用来压缩字符串,而是用来把字符转换为自然数,因为只有数字才能在神经网络算法中处理。字符转换成自然数之后,就成了 Token。

比方说,aaabdaaabac 表示为:

0, 0, 0, 1, 2, 0, 0, 0, 1, 0, 3
a=0, b=1, d=2, c=3

再递归得到:

4, 5, 2, 4, 5, 0, 3
a=0, b=1, d=2, c=3, aa=4, ab=5

大语言模型的 Token 可以很大,GPT-3.5 和 GPT-4 的 Token 长度为 100258,其中有 258 个特殊 Token。这些自然数被 Unicode 编码之后可能会变成奇怪的字符,比如字节 32 会变成 Ġ(U+0120,对应的十进制数是 288,即 32+256),在某些大模型里表示空格。

通过字节对编码得到的 Token 显然不是词语,我们是在字节(byte)的层面对其进行编码的,没有任何意义的字符组合也可以被编码为 Token,我们根本没有在「分词」。

老派 NLP 中的 Token 可以是句子,如今的 LLM 中的 Token 则是基于字节的编码,无论怎么看,LLM 的 Token 都不应该译作「词元」。

桌游小人是 Token,游戏代币是 Token,通行凭证是 Token,编译器和解释器划分的词法单元是 Token,NLP 中的字符、词语、句子和 N 元是 Token,LLM 中的字节对编码也是 Token。

把上面这些句子里的 Token 换成「词元」这个中文词,说得通吗?哪怕仅仅是在 LLM 的语境下,「词元」也词不达意。字节对编码显然不是词。

Token 不该译作「词元」,我想这没什么争议了。唯一可以译作「词元」的,只有计算机在做词法分析时得到的词法单元,但那也只是小部分而已。

英文里的 Token 本意是什么?它的 词源 是原始印欧语词根 *deik-,意思是展示(to show),同源的古诺斯语 teikn 意味着星座和征兆(omen),古英语对应的单词 tacen 意思是指示、符号、证据和征兆。

星座和征兆都是符号或者说对某种符号的解读,符号就是指示含义或另一个物体的东西。Token 就是「指示另一个实体的东西」,至于这「另一个实体」是什么,要根据语境来看。

桌游里的 Token 指示游戏人物、生命值、财产等等,通行凭证或者说令牌指示访问某个资源的权限,编译器和解释器中的词法记号指示不能继续分割的词法要素,NLP 中的 Token 根据使用场景指示一层含义(词语表示的含义、句子表示的含义、N 个词语组成的短语或者说 N 元表示的含义),LLM 中的 Token 指示字节对,同时也对字节对的出现频率做统计学表示。

说到这里我想到一个有些偏门的例子,在《星露谷物语》的某些 Mod 里,由于缺乏标识「玩家是否完成某项任务」的机制,所以有的 Mod 会在玩家与某个 NPC 达成关键进度时,给予名为某某 Token 的物品,并提醒玩家要带着这个 Token 进入特定场景才会触发下一部分的剧情。这里的 Token 就指示「玩家已经达成了某项进度」。

说起通行凭证和令牌,不知道读者有没有看过早年间的古装剧。如果有的话,读者可能熟悉「兵符」这种东西:

「符」一般分為兩半,右半在帝王,左半在將軍,調兵之時,使者帶符上朝驗合,才可行動。「符」形狀多種,以虎符為主;質料有銅、木、玉等,以青銅為多。

—— 漢語多功能字庫

通行凭证和令牌不就是「符」吗?词法记号和 NLP 中的 token 就更不用说了,语言本身就是符号。编程语言中的关键字、括号、字面量也是词法符号。就算未来出现更多基于 token 本意衍生出的用法,它多半也是符号,是用来指示某个东西的,而汉语中同样表示「指示某个东西的东西」的词,就是「符」。


只有 Token 是「词元」吗?不,Lemma 也叫「词元」。

语言学的分支词法学(令人意外,英文名和 Lexical 以及 Lemma 没有关系,叫作 Morphology,morph- 是变化、变形的意思)中有个概念叫作 Lemma,一般译作词目或者词元

Lemma 也可以叫作 canonical form(规范形式)、dictionary form(词典形式)和 citation form(引用形式)。许多欧洲语言的词语都有多种词位变化,而在词典中往往写作一种形式,把变位作为衍生形式写在同一个条目中。词典中规范的形式就叫作词目或者词元。

比方说 go 也有 wentgoinggoesto gogone 等变位,但是在编写词典条目和查找词目的时候,我们只找 go 这个条目,而不找 went 或者 gone。有趣的是,gone 作为形容词,也可以是独立的词元。

可能这种区分看起来很没必要,但我给读者举个法语的例子就能看出词元这个概念的必要性了。法语词目 avoir 表示「有」,第一人称单数现在时直陈式为 ai,第二人称单数现在时直陈式为 as,第三人称单数现在时直陈式为 a,第一人称复数现在时直陈式为 avons,第二人称复数现在时直陈式为 avez,第三人称复数现在时直陈式为 ont,第一人称单数简单将来时直陈式为 aurai……