README.md
Translation Module
translation/ 是当前项目翻译能力的主目录。
如果要开发、部署、联调、压测翻译服务,优先看这份文档。
对应服务:
- translator service:
http://127.0.0.1:6006 - 业务侧统一通过 <code>translation/client.py</code> 调用
- 服务内统一通过 <code>translation/service.py</code> 路由到具体翻译实现
相关脚本与报告:
- 启动脚本:<code>scripts/start_translator.sh</code>
- 虚拟环境:<code>scripts/setup_translator_venv.sh</code>
- 模型下载:<code>scripts/download_translation_models.py</code>
- 本地模型压测:<code>scripts/benchmark_translation_local_models.py</code>
- 性能报告:<code>perf_reports/20260317/translation_local_models/README.md</code>
1. 设计目标
翻译模块采用:
- 一个 translator service
- 多个 capability backend
- 一个统一外部接口:
model + scene
这套设计的目标是:
- 翻译能力可以独立扩展、独立启停
- scene、语言码、prompt 模板、模型方向约束等翻译域知识集中在
translation/ - 配置尽量集中在 <code>config/config.yaml</code> 的
services.translation - 配置错误应尽早报错,不做静默兼容和隐式回退
2. 目录结构
核心文件:
- <code>translation/client.py</code> 业务侧 HTTP client,供 query/indexer 等模块调用
- <code>translation/service.py</code> translator service 内部的统一编排层
- <code>translation/settings.py</code> 翻译配置的规范化与校验辅助函数
- <code>translation/scenes.py</code> scene 规范和值校验
- <code>translation/languages.py</code> 语言码映射、Marian 方向映射等静态知识
- <code>translation/prompts.py</code> LLM 翻译 prompt 模板
- <code>translation/protocols.py</code> 输入输出协议类型
后端实现:
- <code>translation/backends/qwen_mt.py</code> Qwen-MT 云端翻译
- <code>translation/backends/llm.py</code> 通用 LLM 翻译
- <code>translation/backends/deepl.py</code> DeepL 翻译
- <code>translation/backends/local_seq2seq.py</code> 本地 Hugging Face Seq2Seq 模型,包括 NLLB 和 Marian/OPUS MT
3. 配置约定
翻译的部署配置统一放在:
- <code>config/config.yaml</code> ->
services.translation
示例:
services:
translation:
service_url: "http://127.0.0.1:6006"
default_model: "llm"
default_scene: "general"
timeout_sec: 10.0
cache:
enabled: true
key_prefix: "trans:v2"
ttl_seconds: 62208000
sliding_expiration: true
key_include_scene: true
key_include_source_lang: true
capabilities:
qwen-mt:
enabled: true
backend: "qwen_mt"
model: "qwen-mt-flash"
base_url: "https://dashscope-us.aliyuncs.com/compatible-mode/v1"
timeout_sec: 10.0
use_cache: true
llm:
enabled: true
backend: "llm"
model: "qwen-flash"
base_url: "https://dashscope-us.aliyuncs.com/compatible-mode/v1"
timeout_sec: 30.0
deepl:
enabled: false
backend: "deepl"
api_url: "https://api.deepl.com/v2/translate"
timeout_sec: 10.0
nllb-200-distilled-600m:
enabled: true
backend: "local_nllb"
model_id: "facebook/nllb-200-distilled-600M"
model_dir: "./models/translation/facebook/nllb-200-distilled-600M"
device: "cuda"
torch_dtype: "float16"
batch_size: 16
max_input_length: 256
max_new_tokens: 64
num_beams: 1
attn_implementation: "sdpa"
opus-mt-zh-en:
enabled: true
backend: "local_marian"
model_id: "Helsinki-NLP/opus-mt-zh-en"
model_dir: "./models/translation/Helsinki-NLP/opus-mt-zh-en"
device: "cuda"
torch_dtype: "float16"
batch_size: 16
max_input_length: 256
max_new_tokens: 256
num_beams: 1
opus-mt-en-zh:
enabled: true
backend: "local_marian"
model_id: "Helsinki-NLP/opus-mt-en-zh"
model_dir: "./models/translation/Helsinki-NLP/opus-mt-en-zh"
device: "cuda"
torch_dtype: "float16"
batch_size: 16
max_input_length: 256
max_new_tokens: 256
num_beams: 1
配置边界:
config.yaml只放部署和运行参数 例如service_url、default_model、default_scene、enabled、base_url、api_url、model_dir、device- translation 目录内部放翻译静态知识 例如 scene 规则、语言码映射、prompt 模板、Marian 方向约束
说明:
service_url、default_model、default_scene只从 YAML 读取- 不再通过环境变量静默覆盖翻译行为配置
- 密钥仍通过环境变量提供
4. 环境变量
当前翻译模块主要依赖:
# Qwen / LLM
DASHSCOPE_API_KEY=sk-xxx
# DeepL
DEEPL_AUTH_KEY=xxx
服务启动端口仍可以由启动脚本环境控制:
TRANSLATION_HOST=0.0.0.0
TRANSLATION_PORT=6006
5. Scene 规则
当前只支持 3 个标准 scene:
generalsku_nameecommerce_search_query
定义位置:
约定:
scene是公共接口字段- 不再接受旧的
context - 不再对外暴露
prompt - LLM prompt 在服务内根据
scene自动生成
6. 对外 HTTP 接口
服务入口在:
默认地址:
http://localhost:6006
提供接口:
POST /translateGET /health
6.1 POST /translate
请求体:
{
"text": "商品名称",
"target_lang": "en",
"source_lang": "zh",
"model": "opus-mt-zh-en",
"scene": "sku_name"
}
字段说明:
text支持string或string[]target_lang目标语言source_lang源语言model已配置的 capability 名称scene翻译场景
响应体:
{
"text": "商品名称",
"target_lang": "en",
"source_lang": "zh",
"translated_text": "Product name",
"status": "success",
"model": "opus-mt-zh-en",
"scene": "sku_name"
}
批量时:
- 返回列表和输入等长
- 单条失败返回
null
6.2 GET /health
返回示例:
{
"status": "healthy",
"service": "translation",
"default_model": "llm",
"default_scene": "general",
"available_models": ["qwen-mt", "llm", "nllb-200-distilled-600m", "opus-mt-zh-en", "opus-mt-en-zh"],
"enabled_capabilities": ["qwen-mt", "llm", "nllb-200-distilled-600m", "opus-mt-zh-en", "opus-mt-en-zh"],
"loaded_models": ["llm"]
}
7. 代码调用方式
业务侧统一这样调用:
from translation.client import create_translation_client
translator = create_translation_client()
result = translator.translate(
text="商品名称",
source_lang="zh",
target_lang="en",
model="opus-mt-zh-en",
scene="sku_name",
)
批量调用:
results = translator.translate(
text=["商品1", "商品2"],
source_lang="zh",
target_lang="en",
model="opus-mt-zh-en",
scene="sku_name",
)
接口 shape 约定:
translate(text="...")返回Optional[str]translate(text=[...])返回List[Optional[str]]- 批量模式始终保持“等长、同序返回”;某条失败时对应位置为
None - backend/client 可通过
supports_batch暴露是否支持原生批量;服务端会在必要时自动逐条拆分并保持返回 shape 不变
8. 具体实现说明
8.1 Qwen-MT
实现文件:
特点:
- 云端机翻
- 支持 Redis 翻译缓存
- 适合质量优先、非超高并发场景
注意:
- 当前默认
qwen-mt-flash限速较低 - 大量重复请求应依赖缓存
8.2 LLM Translation
实现文件:
特点:
- 通用大模型翻译
- 根据
scene生成内部 prompt - 更灵活,但成本和稳定性取决于上游模型
8.3 DeepL
实现文件:
特点:
- 商业翻译 API
- scene 会映射到内部上下文
- 当前默认关闭
8.4 facebook/nllb-200-distilled-600M
实现文件:
模型信息:
- Hugging Face 名称:
facebook/nllb-200-distilled-600M - 简介:多语种翻译:覆盖约 200 种语言。作为NLLB-200系列的蒸馏版本,该模型通过知识蒸馏技术将原130亿参数模型压缩至600M,同时保持了80%以上的翻译质量。
- 本地目录:
models/translation/facebook/nllb-200-distilled-600M - 当前磁盘占用:约
2.4G - 模型类型:多语种 Seq2Seq 机器翻译模型
- 来源:Meta NLLB(No Language Left Behind)系列的 600M 蒸馏版
- 结构特点:
- Transformer encoder-decoder 架构
- 12 层 encoder + 12 层 decoder
d_model=1024- 通过
source_lang + forced_bos_token_id控制翻译方向 - 语言标识采用
language_script形式,例如eng_Latn、zho_Hans - 改良 encoder-decoder(含嵌入层缩放
scale_embedding、相对位置等)
核心配置如下:
| 配置项 | 参数值 | 备注 |
|---|---|---|
隐藏层维度(d_model) |
1024 | |
| 编码器 / 解码器层数 | 12 / 12 | |
| 注意力头数 | 16 | |
| FFN 维度 | 4096 | |
| 词表大小 | 256,206 | 多语统一词表 |
| 最大序列长度 | 1024 tokens | 满足长文本翻译 |
config.json 片段(示意):
{
"d_model": 1024,
"encoder_layers": 12,
"decoder_layers": 12,
"attention_dropout": 0.1,
"use_cache": true,
"torch_dtype": "float32",
"max_length": 200
}
模型定位:
- 优势是多语覆盖面广,一个模型可以支撑很多语言方向
- 劣势是相较于 Marian 这种双语专用模型,推理更重、延迟更高
- 更适合做索引翻译(离线 / 批量),不建议作为在线 query 翻译的默认方案
显存占用情况:
- 600M 模型半精度(float16)权重约
~1.25G;推理还会叠加 CUDA context、allocator reserve、激活张量、batch、输入/生成长度等开销 - 当前这台
Tesla T4上,优化后的实际运行峰值大约在2.8-3.0 GiB
当前实现特点:
- backend 类型:
local_nllb - 支持多语
- 调用时必须显式传
source_lang - 语言码映射定义在 <code>translation/languages.py</code>
- 当前 T4 推荐配置:
device=cuda、torch_dtype=float16、batch_size=16、max_new_tokens=64、attn_implementation=sdpa
当前实现已经利用的优化:
- 已做批量分块:
translate()会按 capability 的batch_size分批进入模型 - 已做动态 padding:tokenizer 使用
padding=True、truncation=True - 已传入
attention_mask:由 tokenizer 生成并随generate()一起送入模型 - 已设置方向控制:NLLB 通过
tokenizer.src_lang和forced_bos_token_id指定语言对 - 已启用推理态:
torch.inference_mode()+model.eval() - 已启用半精度和更优注意力实现:当前配置为
float16 + sdpa - 已关闭高开销搜索:默认
num_beams=1,更接近线上低延迟设置
和你给出的批处理示例对照:
- 核心思路已经覆盖,现有实现与
tokenizer(batch) -> model.generate(...) -> batch_decode(...)一致 - 差异在于服务端额外做了语言校验、统一 chunking、输入长度约束和单条/批量 shape 保持
- “预计算 attention mask” 目前没有单独缓存层;现状是每个 batch 在 tokenizer 阶段实时生成
attention_mask,这也是 HF 常规推理路径
优化空间(按场景):
- 线上 query:优先补测
batch_size=1的真实延迟与 tail latency,而不是继续拉大 batch。 - 离线批量:可再尝试更激进的 batching / 长度分桶 / 独立批处理队列(吞吐更高,但会增加在线尾延迟风险)。
- 进一步降显存 / 提速:可评估
ctranslate2/ int8;当前仓库尚未引入该运行栈。
8.5 opus-mt-zh-en
实现文件:
模型信息:
- Hugging Face 名称:
Helsinki-NLP/opus-mt-zh-en - 本地目录:
models/translation/Helsinki-NLP/opus-mt-zh-en - 当前磁盘占用:约
1.2G - 模型类型:Marian / OPUS MT 专用双语翻译模型
- 方向约束:只支持
zh -> en
结构特点:
- encoder-decoder Seq2Seq
- 聚焦特定语言对
- 模型更小、加载更轻、吞吐更高
8.6 opus-mt-en-zh
实现文件:
模型信息:
- Hugging Face 名称:
Helsinki-NLP/opus-mt-en-zh - 本地目录:
models/translation/Helsinki-NLP/opus-mt-en-zh - 当前磁盘占用:约
1.5G - 模型类型:Marian / OPUS MT 专用双语翻译模型
- 方向约束:只支持
en -> zh
结构特点:
- encoder-decoder Seq2Seq
- 双语定向模型
- 更适合中英双向拆分部署
9. 本地模型安装与部署
9.1 准备环境
cd /data/saas-search
./scripts/setup_translator_venv.sh
9.2 下载模型
下载全部本地模型:
./.venv-translator/bin/python scripts/download_translation_models.py --all-local
下载完成后,默认目录应存在:
models/translation/facebook/nllb-200-distilled-600M
models/translation/Helsinki-NLP/opus-mt-zh-en
models/translation/Helsinki-NLP/opus-mt-en-zh
9.3 打开能力
编辑 <code>config/config.yaml</code>,把对应模型的 enabled 改成 true。
9.4 启动服务
./scripts/start_translator.sh
建议:
- 本地模型服务使用单 worker
- 避免多 worker 重复加载模型
- GPU 机器上优先使用
cuda + float16 - CPU 只建议用于功能验证或离线低频任务
- 对 NLLB,T4 上优先采用
batch_size=16 + max_new_tokens=64 + attn_implementation=sdpa
9.5 验证
健康检查:
curl http://127.0.0.1:6006/health
翻译测试:
curl -X POST http://127.0.0.1:6006/translate \
-H 'Content-Type: application/json' \
-d '{
"text": "男士偏光飞行员太阳镜",
"source_lang": "zh",
"target_lang": "en",
"model": "opus-mt-zh-en",
"scene": "sku_name"
}'
10. 性能测试与复现
性能脚本:
数据集:
复现命令:
cd /data/saas-search
./.venv-translator/bin/python scripts/benchmark_translation_local_models.py
单模型复现示例:
./.venv-translator/bin/python scripts/benchmark_translation_local_models.py \
--single \
--model opus-mt-zh-en \
--source-lang zh \
--target-lang en \
--column title_cn \
--scene sku_name
单条请求延迟复现:
./.venv-translator/bin/python scripts/benchmark_translation_local_models.py \
--single \
--model nllb-200-distilled-600m \
--source-lang zh \
--target-lang en \
--column title_cn \
--scene sku_name \
--batch-size 1 \
--limit 100
说明:
- 对当前脚本和本地 backend 来说,“单条请求”可以直接等价理解为
batch_size=1 - 此时脚本里的
batch_latency_*,就可以直接视为“单次请求延迟”指标 - 线上搜索 query 翻译更应该关注这组数据,而不是大 batch 吞吐
当前单条请求实测(Tesla T4,limit=100):
nllb-200-distilled-600m zh->en:p50 约292.54 ms,p95 约624.12 ms,平均约321.91 msnllb-200-distilled-600m en->zh:p50 约481.61 ms,p95 约1171.71 ms,平均约542.47 ms
当前压测环境:
- GPU:
Tesla T4 16GB - Python env:
.venv-translator - 数据量:
18,576条商品标题
最终性能结果:
| Model | Direction | Device | Rows | Load s | Translate s | Items/s | Avg item ms | Batch p50 ms | Batch p95 ms |
|---|---|---|---|---|---|---|---|---|---|
opus-mt-zh-en |
zh -> en |
cuda |
18,576 | 3.1435 | 497.7513 | 37.32 | 26.795 | 301.99 | 1835.81 |
opus-mt-en-zh |
en -> zh |
cuda |
18,576 | 3.1867 | 987.3994 | 18.81 | 53.155 | 449.14 | 2012.12 |
nllb-200-distilled-600m |
zh -> en |
cuda |
500 | 7.3397 | 25.9577 | 19.26 | 51.915 | 832.64 | 1263.01 |
nllb-200-distilled-600m |
en -> zh |
cuda |
500 | 7.4152 | 42.0405 | 11.89 | 84.081 | 1093.87 | 2107.44 |
NLLB 性能优化经验:
- 起作用的优化点 1:
float16 + cuda- 模型确认以
torch.float16实际加载到cuda:0 - 优化后在 T4 上的峰值显存约
2.8-3.0 GiB
- 模型确认以
- 起作用的优化点 2:
batch_size=16- 相比
batch_size=8,吞吐提升明显 - 继续提升到
32虽然还能增吞吐,但 batch p95 和 batch max 会恶化很多
- 相比
- 起作用的优化点 3:
max_new_tokens=64- 商品标题翻译通常不需要
256的生成上限 - 收紧生成长度后,
zh->en与en->zh都有明显收益
- 商品标题翻译通常不需要
- 起作用的优化点 4:
attn_implementation=sdpa- 对当前 PyTorch + T4 环境有效
- 配合半精度和较合理 batch size 后,整体延迟进一步下降
- 已有但不需要单独开关的点:
attention_mask- 当前实现会在 tokenizer 阶段自动生成并传入
generate() - 它属于标准推理路径,不是一个额外的“高级优化开关”
- 当前实现会在 tokenizer 阶段自动生成并传入
为什么最终没有采用其它方案:
- 当前 HF 原生方案已经能在 T4 上稳定跑通
- 在
10G+可用显存下,原生float16已足够支撑 NLLB-600M - 因此暂时不需要为这个模型额外引入 GGUF 或 CT2 的新运行栈
- 如果未来目标变成“继续压缩显存”或“进一步追求更低延迟”,再评估
ct2-int8会更合适
关键结论:
- 当前机器上,
opus-mt-zh-en是三个新增本地模型里最快的 opus-mt-en-zh大约是opus-mt-zh-en吞吐的一半nllb-200-distilled-600M在显存充足时可以用cuda + float16 + batch_size=16 + max_new_tokens=64 + sdpa正常运行nllb最终可用,但吞吐仍明显低于两个 Marian 模型,更适合多语覆盖或独立资源环境
最终推荐部署方案:
- 模型:
facebook/nllb-200-distilled-600M - 设备:
cuda - 精度:
float16 - 推荐卡型:至少
Tesla T4 16GB这一级别 - 推荐 batch:
16 - 推荐
max_input_length:256 - 推荐
max_new_tokens:64 - 推荐
num_beams:1 - 推荐注意力实现:
sdpa - 运行方式:单 worker,避免重复加载
更详细的性能说明见:
11. 开发说明
如果要新增翻译 backend,最少需要做这些事:
- 在 <code>translation/backends/</code> 下新增实现
- 在 <code>translation/service.py</code> 注册 backend 创建逻辑
- 在 <code>config/config.yaml</code> 的
services.translation.capabilities中新增 capability 配置 - 如果有新的静态规则:
- scene 规则放到 <code>translation/scenes.py</code>
- 语言映射放到 <code>translation/languages.py</code>
- prompt 模板放到 <code>translation/prompts.py</code>
原则:
- 不要再引入 translation provider 兼容层
- 不要把 scene / prompt / 语言方向规则重新散落到别的目录
- 不要在代码里写隐式默认和静默兼容
12. 常见建议
- 中英商品标题双向场景,优先考虑
opus-mt-zh-en和opus-mt-en-zh - 多语种统一方案,可以考虑
nllb-200-distilled-600M - 但
nllb更适合独占资源环境 - 如果追求更高质量或更复杂语义处理,可使用
qwen-mt或llm - 如果追求稳定商业 API,可考虑
deepl