说起多语言多领域机器翻译系统的搭建,我先讲一个让我印象深刻的场景:某电商平台把中文商品描述直接丢给通用翻译引擎,出来的是“医用一次性防护服”被翻成“医疗用一次性的保护性衣服”,而平台方坚持要术语表里的标准译法。这个场景基本概括了为什么我要专门搭一套系统——不是通用引擎不够好,而是在多语言、多领域的真实业务里,质量和可控性远比“能翻出来”重要。如果你也遇到领域术语乱翻、语种需要扩展、数据不能出内网、线上译文需要可干预,这篇文章就是为你准备的。
我会按实际搭建的顺序来写,尽量把每一步的取舍和坑都讲清楚。包括数据从哪来、模型怎么适配领域、服务怎么稳定上线、评测怎么不被指标骗,以及最后让我印象最深的几个踩坑记录。整套系统不是某个科研Demo,而是能接业务、能持续迭代的工程化项目。
1. 通用引擎解决不了的那部分需求,才是搭建系统的理由
1.1 一个让我决定自建系统的实际案例
先交代背景。我参与过一个内部项目,核心任务是给某制造企业的操作手册做多语言翻译,源语言是中文,目标语言包括英语、日语、德语、法语、西班牙语和阿拉伯语,还要覆盖设备维护、电气安全、零部件名称等垂直内容。起初团队直接调商用翻译API,试运行了两周,问题不是“能不能翻译”,而是“翻译出来没人敢用”。
主要矛盾有几个。第一是术语一致性,同一份手册里“紧急停机按钮”在第一章叫“emergency stop button”,在第五章变成“urgent stop button”,这种前后不一致在设备维护场景里不是小事。第二是数据合规,企业明确要求手册原文不能传到外部服务,只能在内部环境处理。第三是干预能力,业务方希望某个术语必须按他们维护的词汇表翻译,通用引擎不接受这种配置。第四是成本和稳定性,翻译量一旦上来,按字符计费并不便宜,而且深夜大促期间外部API的响应时长会明显波动。
这几个矛盾叠加在一起,结论很明确:与其继续给通用引擎“打补丁”,不如搭一套自己能控制的系统。注意,我没有打算做一个超越通用引擎的神器。通用引擎在泛领域文本上确实强,但在垂直领域、术语可控、数据不出内网这些需求面前,自建系统是更稳妥的方案。
1.2 自建系统的目标拆解
项目启动前,我先把目标量化。不能只说“提高翻译质量”,否则后面没法验收。我们当时的指标是:在内部领域的测试集上,术语准确率从通用引擎的82%提升到95%以上;译文BLEU比直接调用通用引擎高3个点以上;单条翻译(500字以内)P95延迟小于2秒;支持至少6个目标语种;所有数据留在内网。这套指标后来被证明很有用,因为它逼着团队把所有决策都围绕可测量的结果展开。
目标拆解之后,系统边界也就清晰了。我们不做浏览器划词翻译,不做语音翻译,不做全自动无人工审核的无人值守服务。我们只做“文本进、译文出”的批量和实时接口,并且允许业务方在中间环节配置术语表。这个边界很重要,砍掉不必要的功能,团队才能集中资源解决核心问题。很多项目失败不是因为模型差,而是因为需求边界模糊,什么都想塞进去。
2. 系统整体架构:先想清楚数据往哪流,再谈模型
2.1 训练、推理、评测三条链路的物理隔离
我见过不少团队拿到开源模型就急着部署,结果后面想更新模型时发现训练脚本、评测脚本和线上服务搅在一起,改一个参数要停整个服务。所以从第一天开始,我们把系统拆成三条物理隔离的链路:离线数据与训练链路、在线推理服务、评测沙箱。
离线链路负责语料清洗、数据增强、模型训练和导出。它跑在独立的计算集群上,不对外提供服务,训练完的模型统一写入模型仓库并附带版本号、训练数据范围、评测报告。没有这些元信息,后面做灰度发布就是盲人摸象。在线推理服务只加载模型仓库里已通过评测的模型,不直接接触原始训练脚本。评测沙箱则是独立的隔离环境,专门跑自动指标和人工评测任务,它的输入是固定版本的测试集,输出是一份可对比的报告。
这样做的好处是,线上服务可以随时回滚到上一个稳定模型,评测结果不会因为测试集被意外修改而失真,训练任务也不会因为线上流量高峰而抢走计算资源。我们在实际运行中遇到过模型更新后译文质量波动的情况,由于三套环境隔离,定位问题只花了半天,而不是整个团队停摆排查。
2.2 基座模型与领域适配层的关系
选基座模型是开局最重要的决定。我们的约束条件很明确:必须支持多语种,尤其是中文到低资源语种的能力不能太弱;必须能在内部服务器上跑推理,不能依赖外部服务;必须允许继续训练或微调,不能是纯黑盒。
我们当时选定一个开源的多语种翻译基座模型,内部代号叫BaseNMT-7B。它提供中文到十几个语种的预训练能力,缺点是通用领域表现尚可,垂直领域术语经常出错。但我不指望基座直接满足业务,而是把它当成“发动机”,真正决定业务表现的是领域适配层。
领域适配层由三部分组成:领域微调模型、术语注入模块、规则后处理。领域微调让模型熟悉目标领域的句式和词汇分布;术语注入模块在翻译前和翻译中把业务方定义的术语表强制生效;规则后处理则负责修复数字、单位、日期格式等模型容易忽略的硬规则。你可以把基座模型想象成一个见多识广的实习生,但必须给TA一本业务手册和一套检查清单,TA才能按规范交活。很多项目只做微调,不做术语注入,结果模型记住了领域风格,但关键名词还是飘忽不定,这类问题靠微调很难根治。
3. 多语种语料的获取、清洗与配比策略
3.1 语料从哪里来:公开数据集、逆向构建、人工挑错
训练多语种模型最缺的永远不是模型结构,而是干净、对业务有覆盖的平行语料。我们的语料来源主要是三条线。
第一条是公开的多语种平行语料。要注意,公开语料的质量参差不齐,很多句子来自网页爬虫,存在格式错乱、语言标注错误、内容重复。直接拿去训练,模型会学到很多坏习惯。第二条是内部积累的翻译记忆库。之前项目沉淀下来的历史翻译文档,包括产品手册、客服话术、法律条款,这些语料质量高、领域对口,是真正的主力。第三条是逆向构建。当目标语言材料不足时,我们会把已有中文文档交给人工翻译成目标语言,再和原文对齐。成本高,但效果立竿见影,尤其是阿拉伯语、德语这种语法差异大的语种,没有高质量平行句对,模型很难学好。
人工挑错是必须保留的环节。我们抽样检查了大概2000条对齐句对,发现公开语料里有不少“伪平行句对”,比如中文一句、英文两句,或者中英内容只是主题相关但并不是互译。这类数据对模型的伤害是隐性的,模型会慢慢学会“自由发挥”。我们当时的规则是,每个语种至少人工抽检500条,错误率超过5%就重新清洗。
3.2 清洗规则与语言识别
清洗规则我按优先级列一下,每一条都来自实际踩坑。
先做格式清洗。去掉不可见字符、控制字符、HTML标签残留。我们早期没有严格过滤,模型偶尔会在译文里输出“
”这种标签,就是因为训练语料里混入了网页片段。再做语言识别。中文句子可能混入英文品牌名、日文假名,如果不做语言识别,语种标签会混乱,后面多语种路由也会受影响。我们用语言识别模型先给每个句子打语种标签,置信度低于阈值的一律剔除。再做长度比过滤。源句和目标句的字符数比值超过1比3的,大概率是错位数据或漏译,直接删。最后做相似度去重。句子级去重不能只比完全相等,还要算n-gram重叠率。我们的经验是,重复的n-gram占比超过0.8就认为是重复句,保留最长的版本。
这些规则看似简单,执行顺序也很重要。如果把语言识别放在格式清洗之前,乱码文本会让识别器误判;如果把去重放在长度过滤之前,冗余数据会干扰长度分布判断。我们最终把流程固定为:格式清洗、语言识别、长度过滤、相似度去重、人工抽检。
3.3 语料配比:通用语料、领域语料、单语语料
语料不是越多越好,配比决定了模型的“性格”。我们的做法是把语料分成三类:通用平行语料、领域平行语料、单语语料。
通用平行语料保证模型的基础翻译能力,比如句式变换、常见词汇。领域平行语料决定模型在目标领域上的表现,比如设备操作、医疗说明、法律条款。单语语料主要用于数据增强和回译,它本身不是平行句对,但可以帮助模型熟悉目标语言的流畅表达。
具体配比上,我们用的基准是通用平行语料占60%,领域平行语料占30%,单语料增强占10%。对于某一个特定领域,比如医疗,我们会在领域部分中把医疗子集的权重再调高到50%。这里有一个容易犯的错:一味提高领域语料占比,模型会“过拟合”到领域模板句,一旦遇到领域外的表达就开始胡诌。所以通用语料的比例不能低于一半,这是我的个人经验,不是理论推导。
多语种之间的配比也要平衡。如果不做干预,中英语料的数量会远远碾压中日、中阿。我们按照目标语种的难度做了加权,对阿拉伯语、德语这种难点语种适当提高采样权重,避免模型被英语“带跑偏”。
4. 领域适配的落地方式:微调、提示词与术语表的组合
4.1 领域微调的具体做法
领域微调是整个系统里最直接见效的步骤,但操作不当也最容易产生副作用。我们用的方法是监督微调,即在基座模型基础上,用领域平行语料继续训练若干轮。训练数据的格式很简单,输入是源语言句子,输出是目标语言译文,中间用分隔符隔开。每一条训练样本都带有领域标签,比如“制造-设备操作”“医疗-药品说明”“法律-合同条款”。
微调时我建议分开做,而不是把所有领域混成一个训练集。我们一开始图省事,把所有领域数据混合微调,结果模型在“法律”测试集上术语准确率只有80%,在“制造”测试集上也只有85%。后来改成按领域各自微调出独立模型,再在推理层做路由分发,每个领域的测试集都提升了5个百分点以上。多领域微调不是不能做,但需要更精细的采样控制,如果团队人力有限,分开训练更可控。
训练轮数不宜过多。我们观察到一个反直觉的现象:在领域训练集上loss继续下降,但在领域测试集上BLEU开始下降,说明模型开始死记硬背训练集。我们最后把训练轮数控制在3到5个epoch,并每隔一个epoch保存一个检查点,用评测集选最好的一版,而不是直接选最后一个。
4.2 术语注入与上下文约束
光靠微调解决不了术语一致性问题,这是我们在项目里反复验证过的结论。微调只能让模型“更倾向于”使用某类词汇,但无法保证100%准确。比如客户要求“断路器”必须翻译成“circuit breaker”,模型可能随机输出“switch”或“disconnector”,这在设备维护场景里是不可接受的。
术语注入我们做了三层。第一层是翻译前替换,把源文本中出现的标准术语直接替换成目标语言术语,然后在句子前后加上标记,告诉模型这些片段已经指定。这个方式对简单名词最有效,但遇到术语被拆开、变形、搭配复杂短语时容易失效。第二层是提示词约束,在模型的输入前缀中附上当前任务相关的术语表,比如“翻译以下文本,注意device must be translated as equipment”。提示词对模型有引导作用,但不是硬约束,模型可能忽略。第三层是解码约束,在生成过程中把术语表的候选词强制限制在每一步生成概率最高的候选集合里。硬约束效果最稳,但实现成本高,需要能修改解码逻辑的推理框架。
我们的最终方案是三层组合:翻译前替换处理常规术语,提示词约束处理领域风格,解码约束锁死最关键的安全类术语。效果在后面评测表里能看到,术语准确率从微调后的93%提升到96%以上。
4.3 对比实测:通用模型 vs 领域适配模型
我们在内部测试集上做过一组对比,测试集包含制造、医疗、法律三个领域,每个领域1000条句子,人工标注了标准译文和关键术语。数字可以用来参考,不一定代表你的场景,但趋势是稳定的。
| 模型版本 | 领域测试集BLEU | 术语准确率 | 格式错误率 |
|---|---|---|---|
| BaseNMT-7B通用基座 | 27.1 | 81.3% | 6.8% |
| 领域微调版 | 31.5 | 93.2% | 3.5% |
| 领域微调 + 术语注入 | 32.6 | 96.4% | 2.1% |
| 领域微调 + 术语注入 + 规则后处理 | 32.4 | 96.8% | 0.7% |
注意一个细节,规则后处理介入后BLEU反而略微下降,但格式错误率大幅下降。这是因为BLEU对词汇重叠敏感,规则后处理把“2023年5月1日”统一成“May 1, 2023”可能会降低n-gram重叠得分,但它让日期格式在业务上是正确的。这也是为什么不能只看BLEU,术语准确率和格式正确率往往比BLEU更贴近业务。
5. 从模型到服务:推理部署中的工程细节
5.1 推理延迟与批处理取舍
模型训练好只是第一步,部署成服务还会遇到一堆工程问题。我们的在线服务目标是单条500字以内P95延迟小于2秒。一开始直接单条请求跑模型,显存占用不高,但GPU利用率很低,延迟波动很大。后来改成动态批处理。
所谓动态批处理,简单说就是请求进来后不立即推理,而是放进队列等一小段时间,攒够一批再一起跑。我们设定的参数是:最多等待50毫秒,批次大小达到16就立刻发送。这样在流量平稳时延迟增加不明显,但吞吐量提升明显,GPU利用率从35%提升到70%以上。如果流量非常稀疏,超过等待时间也只有一条请求,那就单独跑,不能为了批处理无限等下去。
延迟优化另一个关键是量化。我们把模型权重从16位浮点量化到8位整数,显存占用降低接近一半,单条推理速度提升约40%。代价是评测集上BLEU降低了0.3左右,但术语准确率没有变化。在业务更看重术语准确率的前提下,这个牺牲是可以接受的。不同显卡、不同模型对量化的敏感度不同,建议上线前跑一遍评测集确认损失可接受。
5.2 多语言路由与自动语种识别
多语言系统里,请求过来必须先判断“源语言是什么”“目标语言是什么”,再决定交给哪个模型。我们的做法是入口部署一个语种识别模块,它接收源文本后输出语种和置信度。置信度大于0.9时走对应语言方向的领域模型;置信度在0.7到0.9之间时,走通用模型但提示词里附上领域标签;置信度低于0.7时,直接进入人工翻译队列,不做自动翻译。
这个回退策略很关键。我们遇到过用户传了一段中英文混合的SKU描述,语种识别器置信度只有0.65,如果硬走中文到英文模型,结果会出现大量英文被当成中文重新翻译。回退到人工队列看起来“不够智能”,但至少不会输出不可用的译文。
目标语种的识别相对简单,因为业务方通常会在接口参数里显式指定。但为了鲁棒性,我们仍然会校验目标语言参数是否在支持列表内,不在列表内直接返回400。不要试图用一个模型处理所有语种,虽然技术上可行,但领域适配时你会被各个语种的术语问题折腾到怀疑人生。
5.3 服务稳定性:超时、重试、熔断
服务上线后,稳定性问题很快浮出水面。我们的下游调用方很多,高峰期并发能有每秒几百个请求。推理服务偶尔会因为显存不足或GPU过热变慢,如果不做防护,一个慢请求就可能拖垮整条链路。
我做了三层保护。第一层是接口超时,单次推理超过3秒就中断并返回错误,调用方可以自行重试。第二层是重试策略,调用方对于超时请求最多重试两次,但重试之间需要增加随机延时,避免所有请求同时打过来造成雪崩。第三层是熔断,连续错误率达到10%时,服务自动切换到只读模式,不再接收新的翻译请求,只返回“服务暂不可用”,直到错误率恢复正常。
缓存也是被低估的优化手段。我们发现业务方有大量重复的商品描述和FAQ,不同请求只是个别字不同。我们在服务端加了一层Redis缓存,key是“源语言+目标语言+文本哈希”,缓存的命中率在10%左右。别小看这10%,高峰期它能显著降低GPU压力。
6. 评测体系与线上质量监控
6.1 评测集怎么建才不会被指标骗
评测集是整个系统最重要的资产,但我见过很多团队随便找几千条句子,算一个BLEU就宣布模型可以上线。这是典型的自欺欺人。BLEU对领域术语、数字格式、性别一致性都不敏感,两个模型的BLEU只差0.5,可能其中一个在关键术语上错得离谱。
我们当初建评测集做了四层设计。第一层是通用质量集,覆盖日常表达,用于观察模型有没有整体退化。第二层是领域术语集,每个领域挑出200个高频关键术语,人工构造包含这些术语的句子,统计“标准术语命中率”。第三层是格式与实体集,专门测试日期、时间、数字、单位、产品型号的翻译是否准确。第四层是语用与风格集,包括敬语、正式/非正式语气、性别一致性,这对日语、德语、法语尤其重要。
每个测试集我们都会维护一个“标准答案版本”,任何评测结果必须注明测试集版本。否则你会发现,某次预处理脚本改动后,测试集也被悄悄改了,两个模型的分数根本没有可比性。这个坑我们踩过,后来所有评测报告必须带上测试集git提交号。
6.2 线上反馈闭环:用户纠错如何回到训练集
模型上线不是终点,而是数据循环的起点。我们会记录线上翻译请求的日志,包括源文本、目标文本、模型版本、延迟和用户后续操作。如果用户复制了译文回去用,大概率说明质量可接受;如果用户手动修改了译文,修改后的内容就是珍贵的纠错数据。
我们把用户纠错数据分成三个等级。第一等级是术语类纠错,用户把“circuit breaker”改成“breaker”,说明术语表需要更新。第二等级是格式类纠错,用户把日期格式改了,说明规则后处理需要补充。第三等级是通顺度纠错,用户只是调整了语序,这类数据暂时不进训练集,因为噪音太大。
每隔两周,我们会把积累的纠错数据整理成增量训练集,对模型做一轮轻量微调。这里要注意,增量训练不能只放新数据,必须混合一部分旧语料,否则模型会出现灾难性遗忘,学会了新术语却忘了旧领域的表达。
7. 复盘:真正拖慢进度的不是模型,而是数据与评测
7.1 三个印象深刻的坑
第一个坑是清洗规则太激进。我们曾经过滤掉所有包含括号的句子,理由是公开语料里括号内容经常是HTML残留。但运行一个月后,评测人员发现术语集里大量术语是不带括号的,但真实业务文本里“断路器(CB)”这种写法全被删了。后来我们改成只过滤“括号内包含url或标签”的句子,保留正常括号,这才救回来。
第二个坑是术语表没有做词形归一。英文术语表里写的是“circuit breakers”,但源文本里经常出现“circuit breaker”,精确匹配失败,术语注入没生效。我们后来对英文术语做了小写、单复数归一,并且用词形还原生成多个变体,再送进匹配器。这个坑不深但很容易踩。
第三个坑是评测只看BLEU,导致选错模型。我们有一个中间版本模型,BLEU比当前版本高1.2,但线上反馈说译文经常“自己加内容”。后来用忠实度检查一查,发现它在长句上会脑补不存在的信息。BLEU完全不惩罚这类“加戏”,从那以后我们的评测必须同时跑忠实度检查,即对比源文本和目标文本在关键词上的覆盖度,覆盖度过低直接判负。
7.2 给后来者的一句话建议
如果你也想搭一套多语言多领域机器翻译系统,我的建议很简单:先建评测集和术语资产,再选模型和训练方案。没有可靠的评测集,你的一切优化都是盲目的;没有术语资产,领域适配就是纸上谈兵。我见过太多项目把精力花在换更大模型上,结果上线后被术语一致性打回原形。
个人体会是,机器翻译系统的成功七成在数据工程,两成在评测工程,只有一成在模型结构。别急着追新架构,先把业务语料的结构、质量、配比琢磨明白,你的系统就已经超过了大多数通用方案。搭建过程确实琐碎,但当你看到业务方拿着标准术语表对照译文逐条勾选通过的时候,你会发现前面所有的坑都值得。