机器翻译是怎么工作的:从规则、统计到神经网络的三次演进
作为开发者,你大概率每天都在享受机器翻译的便利------读英文技术文档时开着网页翻译,排查报错时顺手搜一段日文博客,看 commit 记录里的俄文注释也不再是障碍。但如果追问一句:这些译文到底是怎么生成的?很多人只知道"AI 翻译"四个字,至于 AI 在里面具体做了什么,基本是个黑盒。这篇文章把机器翻译七十年的三次技术演进讲清楚,看完你会明白译文为什么长这样,也知道它为什么会错。
把语法写成代码的规则时代
最早的机器翻译出现在上世纪五十年代,思路非常直白:编一部双语词典,再写一堆语法规则,源语言的句子逐词查词典换成目标语言,然后按目标语言的语法调整语序。听起来可行,真做下去到处是坑。
语言里的歧义是第一道坎。"bank"是银行还是河岸,要看上下文才能定;一个词同时可能是名词和动词,查词典根本兜不住。第二道坎是语序:日语把动词放在句尾,德语会把动词拆到句子的两个位置,调整语序的规则互相纠缠,越写越多,也越写越容易打架。再加上中文这种连词与词的边界都不用空格标记的语言,分词本身就是个独立难题。
1966 年美国 ALPAC 报告给这条路泼了冷水。报告认为当时的机器翻译距离实用化仍然很远,质量和成本都不乐观,此后美国政府对相关研究的资助大幅收缩。机器翻译研究并没有完全停止,但在美国一度明显降温,直到 1980 年代后期统计方法兴起才重新迎来高潮。
让平行语料说话的统计时代
到了 1980 年代末、1990 年代初,思路开始彻底换方向:与其让人手写规则,不如让机器从数据里统计规律。统计机器翻译(SMT)的核心原料是平行语料------同一批句子的人工双语文本,典型代表是积累了几十年的联合国会议记录和欧洲议会文件。
IBM 提出的经典模型把翻译看成一个噪声信道问题:假设目标语言句子经过某种"信道"后变成了我们观察到的源语言句子,翻译时再反向推算最可能的目标语言句子。落到实现上,主要依赖翻译模型和语言模型的配合------前者判断某种源语表达对应哪种目标语表达的概率更高,后者判断生成的目标语句子是否自然。后来的短语统计模型把操作单位从单词升级成短语,"look forward to"整体对应"期待",译文立刻自然了不少。在切换到神经机器翻译之前,Google Translate 的核心技术路线长期就是短语统计机器翻译。
统计方法的短板同样明显:它把句子切成短语片段独立处理,片段内部的翻译质量尚可,整句的连贯性和长距离依赖管不住------代词指代前文、主语跨越半个句子,这些都会翻车。
注意力机制改变一切
2014 年序列到序列(seq2seq)模型出现,神经机器翻译(NMT)登场:编码器把整个源句压缩成一个固定维度的向量,解码器拿这个向量逐词生成译文。但向量是个瓶颈------句子一长,一个向量装不下全部信息,长句质量骤降。
转机出现在 2014---2015 年。Bahdanau 等人提出的注意力机制,让解码器生成每个词时都能动态关注源句中不同的位置。译到"猫"的时候注意力集中在"cat"上,译到句尾动词时注意力落在源句末尾,长句问题随之大幅缓解。
2017 年的 Transformer 把这条路推到极致:干脆抛弃循环结构,主要靠自注意力机制,让句子里的不同位置可以直接建立联系,再配合位置编码保留词序信息,模型由此能够学习复杂的依赖和修饰关系。这篇论文后来成为深度学习领域影响力最大的论文之一,而它最初要解决的任务恰恰就是机器翻译。今天的大语言模型同样建立在 Transformer 架构之上。对于 GPT 这类自回归模型,训练的核心任务是预测下一个 token;随着模型规模和训练数据扩大,翻译成为它可以通过语言建模能力完成的众多任务之一。
对做工程的人来说,这个演进有个值得记住的细节:神经翻译是端到端训练的,中间不再有人工设计的特征和规则,效果提升的同时,出错时的原因也变得更难解释------这是能力提升换来的透明度代价。
译文质量怎么衡量:BLEU 和它的局限
机器翻译绕不开自动评价指标 BLEU。它的原理不复杂:拿机器译文和人工参考译文对比,统计连续 n 个词的重合比例,再用截断计数防止重复词刷分,最后对 1 到 4 元组取几何平均,乘上长度惩罚。BLEU 里最核心的 modified n-gram precision,用 Python 十几行就能看明白:
python
from collections import Counter
def ngrams(tokens, n):
return [tuple(tokens[i:i + n]) for i in range(len(tokens) - n + 1)]
def modified_precision(candidate, reference, n):
cand_counts = Counter(ngrams(candidate, n))
ref_counts = Counter(ngrams(reference, n))
overlap = sum(min(c, ref_counts[g]) for g, c in cand_counts.items())
return overlap / max(1, sum(cand_counts.values()))
reference = "the cat is on the mat".split()
candidate = "the cat the cat on the mat".split()
print([round(modified_precision(candidate, reference, n), 4)
for n in range(1, 5)])
# 输出: [0.7143, 0.5, 0.2, 0.0]
一元组得分 0.7143,说明候选译文里的词大多能在参考译文中找到;但四元组得分归零,说明候选译文已经找不到与参考译文完全一致的连续四词片段。BLEU 正是通过不同长度的 n-gram 重合度,粗略衡量候选译文和参考译文在局部表达上的接近程度。
BLEU 的局限也很清楚:它只看字符串表面重合,合理的同义改写会被低估;一句参考译文覆盖不了多种合法译法;对中文这类没有空格分隔的语言还得先分词再算。近年来,COMET 这类基于神经网络的语义评价指标越来越常见,通常会和 BLEU、chrF 等指标搭配使用;BLEU 因为计算简单、历史基准丰富,至今仍被广泛报告。
开发者接入翻译能力的几种方式
原理讲完,回到工程视角。想在项目里加上翻译能力,目前主要三条路可选。
第一种是自部署开源翻译模型,Hugging Face 上的 NLLB、OPUS-MT 系列都可以直接拿来推理,数据无需发送到第三方翻译服务,在合规和安全配置完善的前提下,隐私与部署可控性更强,代价是要自己扛 GPU 资源和推理延迟。第二种是调用云服务商的翻译 API,集成最快,按量计费,适合不想碰模型运维的团队。第三种需求其实不涉及开发:如果只是自己读外文文档,直接用浏览器翻译功能就是成本最低的方案。
三种方式没有绝对的高下,按场景选就好------对数据边界和模型控制要求很高,可以考虑自部署;追求快速上线和低运维成本,优先考虑 API;个人阅读则直接使用成熟的浏览器翻译工具即可。领域术语要求高时,再根据术语库、上下文控制、微调能力和成本决定具体方案。真正值得花时间的是前面那些原理:知道译文为什么错(训练数据没覆盖你的领域、句子太长、歧义词选错义项),才知道往哪个方向补救。
写在最后
从手写语法规则,到从百万句平行语料里统计规律,再到让神经网络自己学出词与词之间的关系,机器翻译三次换引擎,每一次都不是小修小补,而是整个建模范式的更换。语言学家的规则输给了统计,统计又输给了注意力------回头看,每次范式更替都保留了一部分旧问题:如何表示语言、如何利用上下文、如何在多个候选译文中选择更合理的结果,只是解决这些问题的方法彻底变了。
对开发者来说,理解这段演进史的实际价值不在于应付面试,而在于建立一个正确的预期:机器翻译本质上不是逐词对应的精确转换,而是在给定源文本和上下文后,从许多可能的表达中生成一个概率上合理的目标语言序列。带着这个预期去用它、集成它、为它的错误兜底,才是一个工程视角下健康的姿势。