Blame view

translation/README.md 30.8 KB
00471f80   tangwang   trans
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  # Translation Module
  
  `translation/` 是当前项目翻译能力的主目录。  
  如果要开发、部署、联调、压测翻译服务,优先看这份文档。
  
  对应服务:
  - translator service:`http://127.0.0.1:6006`
  - 业务侧统一通过 [`translation/client.py`](/data/saas-search/translation/client.py) 调用
  - 服务内统一通过 [`translation/service.py`](/data/saas-search/translation/service.py) 路由到具体翻译实现
  
  相关脚本与报告:
  - 启动脚本:[`scripts/start_translator.sh`](/data/saas-search/scripts/start_translator.sh)
  - 虚拟环境:[`scripts/setup_translator_venv.sh`](/data/saas-search/scripts/setup_translator_venv.sh)
  - 模型下载:[`scripts/download_translation_models.py`](/data/saas-search/scripts/download_translation_models.py)
  - 本地模型压测:[`scripts/benchmark_translation_local_models.py`](/data/saas-search/scripts/benchmark_translation_local_models.py)
46ce858d   tangwang   在NLLB模型的 /data/sa...
16
17
18
19
20
  - 聚焦压测脚本:[`scripts/benchmark_translation_local_models_focus.py`](/data/saas-search/scripts/benchmark_translation_local_models_focus.py)
  - 基线性能报告:[`perf_reports/20260318/translation_local_models/README.md`](/data/saas-search/perf_reports/20260318/translation_local_models/README.md)
  - CT2 扩展报告:[`perf_reports/20260318/translation_local_models_ct2/README.md`](/data/saas-search/perf_reports/20260318/translation_local_models_ct2/README.md)
  - CT2 聚焦调优报告:[`perf_reports/20260318/translation_local_models_ct2_focus/README.md`](/data/saas-search/perf_reports/20260318/translation_local_models_ct2_focus/README.md)
  - NLLB T4 商品标题专项报告:[`perf_reports/20260318/nllb_t4_product_names_ct2/README.md`](/data/saas-search/perf_reports/20260318/nllb_t4_product_names_ct2/README.md)
00471f80   tangwang   trans
21
22
23
  
  ## 1. 设计目标
  
3eff49b7   tangwang   trans nllb-200-di...
24
  翻译模块采用:
00471f80   tangwang   trans
25
26
27
28
29
30
  
  - 一个 translator service
  - 多个 capability backend
  - 一个统一外部接口:`model + scene`
  
  这套设计的目标是:
00471f80   tangwang   trans
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  - 翻译能力可以独立扩展、独立启停
  - scene、语言码、prompt 模板、模型方向约束等翻译域知识集中在 `translation/`
  - 配置尽量集中在 [`config/config.yaml`](/data/saas-search/config/config.yaml)`services.translation`
  - 配置错误应尽早报错,不做静默兼容和隐式回退
  
  ## 2. 目录结构
  
  核心文件:
  
  - [`translation/client.py`](/data/saas-search/translation/client.py)
    业务侧 HTTP client,供 query/indexer 等模块调用
  - [`translation/service.py`](/data/saas-search/translation/service.py)
    translator service 内部的统一编排层
  - [`translation/settings.py`](/data/saas-search/translation/settings.py)
    翻译配置的规范化与校验辅助函数
  - [`translation/scenes.py`](/data/saas-search/translation/scenes.py)
    scene 规范和值校验
  - [`translation/languages.py`](/data/saas-search/translation/languages.py)
    语言码映射、Marian 方向映射等静态知识
  - [`translation/prompts.py`](/data/saas-search/translation/prompts.py)
    LLM 翻译 prompt 模板
  - [`translation/protocols.py`](/data/saas-search/translation/protocols.py)
    输入输出协议类型
  
  后端实现:
  
  - [`translation/backends/qwen_mt.py`](/data/saas-search/translation/backends/qwen_mt.py)
    Qwen-MT 云端翻译
  - [`translation/backends/llm.py`](/data/saas-search/translation/backends/llm.py)
    通用 LLM 翻译
  - [`translation/backends/deepl.py`](/data/saas-search/translation/backends/deepl.py)
    DeepL 翻译
ea293660   tangwang   CTranslate2
63
64
  - [`translation/backends/local_ctranslate2.py`](/data/saas-search/translation/backends/local_ctranslate2.py)
    本地 CTranslate2 翻译模型,包括 NLLB 和 Marian/OPUS MT
00471f80   tangwang   trans
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  
  ## 3. 配置约定
  
  翻译的部署配置统一放在:
  
  - [`config/config.yaml`](/data/saas-search/config/config.yaml) -> `services.translation`
  
  示例:
  
  ```yaml
  services:
    translation:
      service_url: "http://127.0.0.1:6006"
      default_model: "llm"
      default_scene: "general"
      timeout_sec: 10.0
      cache:
00471f80   tangwang   trans
82
83
        ttl_seconds: 62208000
        sliding_expiration: true
00471f80   tangwang   trans
84
85
86
87
88
89
90
91
92
93
94
95
96
97
      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
cd4ce66d   tangwang   trans logs
98
          use_cache: true
00471f80   tangwang   trans
99
100
101
102
103
        deepl:
          enabled: false
          backend: "deepl"
          api_url: "https://api.deepl.com/v2/translate"
          timeout_sec: 10.0
cd4ce66d   tangwang   trans logs
104
          use_cache: true
00471f80   tangwang   trans
105
106
107
108
109
        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"
ea293660   tangwang   CTranslate2
110
111
112
113
          ct2_model_dir: "./models/translation/facebook/nllb-200-distilled-600M/ctranslate2-float16"
          ct2_compute_type: "float16"
          ct2_conversion_quantization: "float16"
          ct2_auto_convert: true
46ce858d   tangwang   在NLLB模型的 /data/sa...
114
115
116
117
118
119
          ct2_inter_threads: 4
          ct2_max_queued_batches: 32
          ct2_batch_type: "examples"
          ct2_decoding_length_mode: "source"
          ct2_decoding_length_extra: 8
          ct2_decoding_length_min: 32
00471f80   tangwang   trans
120
121
          device: "cuda"
          torch_dtype: "float16"
3eff49b7   tangwang   trans nllb-200-di...
122
          batch_size: 16
00471f80   tangwang   trans
123
          max_input_length: 256
3eff49b7   tangwang   trans nllb-200-di...
124
          max_new_tokens: 64
00471f80   tangwang   trans
125
          num_beams: 1
cd4ce66d   tangwang   trans logs
126
          use_cache: true
00471f80   tangwang   trans
127
128
129
130
131
        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"
ea293660   tangwang   CTranslate2
132
133
134
135
          ct2_model_dir: "./models/translation/Helsinki-NLP/opus-mt-zh-en/ctranslate2-float16"
          ct2_compute_type: "float16"
          ct2_conversion_quantization: "float16"
          ct2_auto_convert: true
00471f80   tangwang   trans
136
137
138
139
140
141
          device: "cuda"
          torch_dtype: "float16"
          batch_size: 16
          max_input_length: 256
          max_new_tokens: 256
          num_beams: 1
cd4ce66d   tangwang   trans logs
142
          use_cache: true
00471f80   tangwang   trans
143
144
145
146
147
        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"
ea293660   tangwang   CTranslate2
148
149
150
151
          ct2_model_dir: "./models/translation/Helsinki-NLP/opus-mt-en-zh/ctranslate2-float16"
          ct2_compute_type: "float16"
          ct2_conversion_quantization: "float16"
          ct2_auto_convert: true
00471f80   tangwang   trans
152
153
154
155
156
157
          device: "cuda"
          torch_dtype: "float16"
          batch_size: 16
          max_input_length: 256
          max_new_tokens: 256
          num_beams: 1
cd4ce66d   tangwang   trans logs
158
          use_cache: true
00471f80   tangwang   trans
159
160
161
162
163
164
165
166
167
168
169
170
171
  ```
  
  配置边界:
  
  - `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 读取
  - 不再通过环境变量静默覆盖翻译行为配置
  - 密钥仍通过环境变量提供
ea293660   tangwang   CTranslate2
172
  - `local_nllb` / `local_marian` 当前由 CTranslate2 运行;首次启动时若 `ct2_model_dir` 不存在,会从 `model_dir` 自动转换
00471f80   tangwang   trans
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  
  ## 4. 环境变量
  
  当前翻译模块主要依赖:
  
  ```bash
  # Qwen / LLM
  DASHSCOPE_API_KEY=sk-xxx
  
  # DeepL
  DEEPL_AUTH_KEY=xxx
  ```
  
  服务启动端口仍可以由启动脚本环境控制:
  
  ```bash
  TRANSLATION_HOST=0.0.0.0
  TRANSLATION_PORT=6006
  ```
  
  ## 5. Scene 规则
  
  当前只支持 3 个标准 scene:
  
  - `general`
  - `sku_name`
  - `ecommerce_search_query`
  
  定义位置:
  - [`translation/scenes.py`](/data/saas-search/translation/scenes.py)
  
  约定:
  - `scene` 是公共接口字段
  - 不再接受旧的 `context`
  - 不再对外暴露 `prompt`
  - LLM prompt 在服务内根据 `scene` 自动生成
  
  ## 6. 对外 HTTP 接口
  
  服务入口在:
  - [`api/translator_app.py`](/data/saas-search/api/translator_app.py)
  
  默认地址:
  - `http://localhost:6006`
  
  提供接口:
  - `POST /translate`
  - `GET /health`
  
  ### 6.1 POST /translate
  
  请求体:
  
  ```json
  {
    "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`
    翻译场景
  
  响应体:
  
  ```json
  {
    "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
  
  返回示例:
  
  ```json
  {
cd4ce66d   tangwang   trans logs
273
   "status": "healthy",
00471f80   tangwang   trans
274
275
276
277
278
    "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"],
cd4ce66d   tangwang   trans logs
279
    "loaded_models": ["qwen-mt", "llm", "nllb-200-distilled-600m", "opus-mt-zh-en", "opus-mt-en-zh"]
00471f80   tangwang   trans
280
281
282
  }
  ```
  
cd4ce66d   tangwang   trans logs
283
284
285
286
  说明:
  - translator service 进程启动时会一次性初始化全部已启用 capability
  - 因此本地模型加载失败、依赖缺失、配置错误会在启动阶段直接暴露,而不是拖到首个在线请求
  
00471f80   tangwang   trans
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
  ## 7. 代码调用方式
  
  业务侧统一这样调用:
  
  ```python
  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",
  )
  ```
  
  批量调用:
  
  ```python
  results = translator.translate(
      text=["商品1", "商品2"],
      source_lang="zh",
      target_lang="en",
      model="opus-mt-zh-en",
      scene="sku_name",
  )
  ```
  
1d6727ac   tangwang   trans
316
317
318
319
320
321
  接口 shape 约定:
  - `translate(text="...")` 返回 `Optional[str]`
  - `translate(text=[...])` 返回 `List[Optional[str]]`
  - 批量模式始终保持“等长、同序返回”;某条失败时对应位置为 `None`
  - backend/client 可通过 `supports_batch` 暴露是否支持原生批量;服务端会在必要时自动逐条拆分并保持返回 shape 不变
  
00471f80   tangwang   trans
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  ## 8. 具体实现说明
  
  ### 8.1 Qwen-MT
  
  实现文件:
  - [`translation/backends/qwen_mt.py`](/data/saas-search/translation/backends/qwen_mt.py)
  
  特点:
  - 云端机翻
  - 支持 Redis 翻译缓存
  - 适合质量优先、非超高并发场景
  
  注意:
  - 当前默认 `qwen-mt-flash` 限速较低
  - 大量重复请求应依赖缓存
  
  ### 8.2 LLM Translation
  
  实现文件:
  - [`translation/backends/llm.py`](/data/saas-search/translation/backends/llm.py)
  
  特点:
  - 通用大模型翻译
  - 根据 `scene` 生成内部 prompt
  - 更灵活,但成本和稳定性取决于上游模型
cd4ce66d   tangwang   trans logs
347
  - 支持 Redis 翻译缓存
00471f80   tangwang   trans
348
349
350
351
352
353
354
355
356
357
  
  ### 8.3 DeepL
  
  实现文件:
  - [`translation/backends/deepl.py`](/data/saas-search/translation/backends/deepl.py)
  
  特点:
  - 商业翻译 API
  - scene 会映射到内部上下文
  - 当前默认关闭
cd4ce66d   tangwang   trans logs
358
  - 支持 Redis 翻译缓存
00471f80   tangwang   trans
359
360
361
362
  
  ### 8.4 `facebook/nllb-200-distilled-600M`
  
  实现文件:
ea293660   tangwang   CTranslate2
363
  - [`translation/backends/local_ctranslate2.py`](/data/saas-search/translation/backends/local_ctranslate2.py)
00471f80   tangwang   trans
364
365
366
  
  模型信息:
  - Hugging Face 名称:`facebook/nllb-200-distilled-600M`
1d6727ac   tangwang   trans
367
  - 简介:多语种翻译:覆盖约 200 种语言。作为NLLB-200系列的蒸馏版本,该模型通过知识蒸馏技术将原130亿参数模型压缩至600M,同时保持了80%以上的翻译质量。
00471f80   tangwang   trans
368
369
  - 本地目录:`models/translation/facebook/nllb-200-distilled-600M`
  - 当前磁盘占用:约 `2.4G`
cd4ce66d   tangwang   trans logs
370
  - 支持 Redis 翻译缓存
00471f80   tangwang   trans
371
  - 模型类型:多语种 Seq2Seq 机器翻译模型
3eff49b7   tangwang   trans nllb-200-di...
372
  - 来源:Meta NLLB(No Language Left Behind)系列的 600M 蒸馏版
00471f80   tangwang   trans
373
  - 结构特点:
3eff49b7   tangwang   trans nllb-200-di...
374
375
376
    - Transformer encoder-decoder 架构
    - 12 层 encoder + 12 层 decoder
    - `d_model=1024`
3eff49b7   tangwang   trans nllb-200-di...
377
378
    - 通过 `source_lang + forced_bos_token_id` 控制翻译方向
    - 语言标识采用 `language_script` 形式,例如 `eng_Latn`、`zho_Hans`
1d6727ac   tangwang   trans
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
    - 改良 encoder-decoder(含嵌入层缩放 `scale_embedding`、相对位置等)
  
  核心配置如下:
  
  | 配置项 | 参数值 | 备注 |
  | --- | --- | --- |
  | 隐藏层维度(`d_model`) | 1024 |  |
  | 编码器 / 解码器层数 | 12 / 12 |  |
  | 注意力头数 | 16 |  |
  | FFN 维度 | 4096 |  |
  | 词表大小 | 256,206 | 多语统一词表 |
  | 最大序列长度 | 1024 tokens | 满足长文本翻译 |
  
  `config.json` 片段(示意):
  
  ```json
  {
    "d_model": 1024,
    "encoder_layers": 12,
    "decoder_layers": 12,
    "attention_dropout": 0.1,
    "use_cache": true,
    "torch_dtype": "float32",
    "max_length": 200
  }
  ```
3eff49b7   tangwang   trans nllb-200-di...
405
406
407
408
  
  模型定位:
  - 优势是多语覆盖面广,一个模型可以支撑很多语言方向
  - 劣势是相较于 Marian 这种双语专用模型,推理更重、延迟更高
1d6727ac   tangwang   trans
409
  - 更适合做**索引翻译**(离线 / 批量),不建议作为在线 query 翻译的默认方案
3eff49b7   tangwang   trans nllb-200-di...
410
411
  
  显存占用情况:
1d6727ac   tangwang   trans
412
  - 600M 模型半精度(float16)权重约 `~1.25G`;推理还会叠加 CUDA context、allocator reserve、激活张量、batch、输入/生成长度等开销
3eff49b7   tangwang   trans nllb-200-di...
413
  - 当前这台 `Tesla T4` 上,优化后的实际运行峰值大约在 `2.8-3.0 GiB`
00471f80   tangwang   trans
414
415
416
  
  当前实现特点:
  - backend 类型:`local_nllb`
ea293660   tangwang   CTranslate2
417
  - 运行时:`CTranslate2 Translator`
00471f80   tangwang   trans
418
419
420
  - 支持多语
  - 调用时必须显式传 `source_lang`
  - 语言码映射定义在 [`translation/languages.py`](/data/saas-search/translation/languages.py)
46ce858d   tangwang   在NLLB模型的 /data/sa...
421
  - 当前 T4 推荐配置:`device=cuda`、`ct2_compute_type=float16`、`ct2_inter_threads=4`、`ct2_max_queued_batches=32`、`ct2_batch_type=examples`、`ct2_decoding_length_mode=source(+8,min=32)`、`batch_size=16`、`max_new_tokens=64`
00471f80   tangwang   trans
422
  
1d6727ac   tangwang   trans
423
424
  当前实现已经利用的优化:
  - 已做批量分块:`translate()` 会按 capability 的 `batch_size` 分批进入模型
ea293660   tangwang   CTranslate2
425
426
427
  - 已切换到 CTranslate2 推理引擎:不再依赖 PyTorch `generate()`
  - 已设置方向控制:NLLB 通过 target prefix 指定目标语言
  - 已启用半精度:当前配置为 `float16`
1d6727ac   tangwang   trans
428
429
430
431
432
433
434
435
436
437
  - 已关闭高开销搜索:默认 `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 / 长度分桶 / 独立批处理队列(吞吐更高,但会增加在线尾延迟风险)。
ea293660   tangwang   CTranslate2
438
  - **进一步降显存 / 提速**:可在当前 CT2 方案上继续评估 `int8_float16`
1d6727ac   tangwang   trans
439
  
00471f80   tangwang   trans
440
441
442
  ### 8.5 `opus-mt-zh-en`
  
  实现文件:
ea293660   tangwang   CTranslate2
443
  - [`translation/backends/local_ctranslate2.py`](/data/saas-search/translation/backends/local_ctranslate2.py)
00471f80   tangwang   trans
444
445
446
447
448
449
450
451
452
453
454
455
  
  模型信息:
  - 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
  - 聚焦特定语言对
  - 模型更小、加载更轻、吞吐更高
cd4ce66d   tangwang   trans logs
456
  - 支持 Redis 翻译缓存
00471f80   tangwang   trans
457
458
459
460
  
  ### 8.6 `opus-mt-en-zh`
  
  实现文件:
ea293660   tangwang   CTranslate2
461
  - [`translation/backends/local_ctranslate2.py`](/data/saas-search/translation/backends/local_ctranslate2.py)
00471f80   tangwang   trans
462
463
464
465
466
467
468
469
470
471
472
473
  
  模型信息:
  - 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
  - 双语定向模型
  - 更适合中英双向拆分部署
cd4ce66d   tangwang   trans logs
474
475
476
477
478
479
480
  - 支持 Redis 翻译缓存
  
  ### 8.7 翻译缓存
  
  - 所有 translation capability 都使用统一的 Redis 缓存层
  - 每个 capability 通过各自的 `use_cache` 控制是否启用缓存
  - 缓存 key 格式固定为 `trans:{model}:{target_lang}:{source_text[:4]}{sha256}`
00471f80   tangwang   trans
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
  
  ## 9. 本地模型安装与部署
  
  ### 9.1 准备环境
  
  ```bash
  cd /data/saas-search
  ./scripts/setup_translator_venv.sh
  ```
  
  ### 9.2 下载模型
  
  下载全部本地模型:
  
  ```bash
  ./.venv-translator/bin/python scripts/download_translation_models.py --all-local
  ```
  
  下载完成后,默认目录应存在:
  
  ```bash
  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 打开能力
  
  编辑 [`config/config.yaml`](/data/saas-search/config/config.yaml),把对应模型的 `enabled` 改成 `true`
  
  ### 9.4 启动服务
  
  ```bash
  ./scripts/start_translator.sh
  ```
  
  建议:
  - 本地模型服务使用单 worker
  - 避免多 worker 重复加载模型
  - GPU 机器上优先使用 `cuda + float16`
  - CPU 只建议用于功能验证或离线低频任务
46ce858d   tangwang   在NLLB模型的 /data/sa...
522
  - 对 NLLB,T4 上优先采用 `batch_size=16 + max_new_tokens=64 + ct2_compute_type=float16 + ct2_inter_threads=4 + ct2_max_queued_batches=32 + ct2_batch_type=examples + ct2_decoding_length_mode=source(+8,min=32)`
00471f80   tangwang   trans
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
  
  ### 9.5 验证
  
  健康检查:
  
  ```bash
  curl http://127.0.0.1:6006/health
  ```
  
  翻译测试:
  
  ```bash
  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. 性能测试与复现
  
ea293660   tangwang   CTranslate2
548
549
550
551
  说明:
  - 本节现有数值是 `2026-03-18` 的 Hugging Face / PyTorch 基线结果。
  - 切换到 CTranslate2 后需要重新跑一轮基准,尤其关注 `nllb-200-distilled-600m` 的单条延迟、并发 tail latency 和 `opus-mt-*` 的 batch throughput。
  
00471f80   tangwang   trans
552
553
  性能脚本:
  - [`scripts/benchmark_translation_local_models.py`](/data/saas-search/scripts/benchmark_translation_local_models.py)
46ce858d   tangwang   在NLLB模型的 /data/sa...
554
  - [`scripts/benchmark_translation_local_models_focus.py`](/data/saas-search/scripts/benchmark_translation_local_models_focus.py)
00471f80   tangwang   trans
555
556
557
558
  
  数据集:
  - [`products_analyzed.csv`](/data/saas-search/products_analyzed.csv)
  
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
559
560
561
562
  最新报告:
  - 摘要:[`perf_reports/20260318/translation_local_models/README.md`](/data/saas-search/perf_reports/20260318/translation_local_models/README.md)
  - 完整 Markdown:[`perf_reports/20260318/translation_local_models/translation_local_models_extended_221846.md`](/data/saas-search/perf_reports/20260318/translation_local_models/translation_local_models_extended_221846.md)
  - 完整 JSON:[`perf_reports/20260318/translation_local_models/translation_local_models_extended_221846.json`](/data/saas-search/perf_reports/20260318/translation_local_models/translation_local_models_extended_221846.json)
46ce858d   tangwang   在NLLB模型的 /data/sa...
563
564
565
  - CT2 扩展总结:[`perf_reports/20260318/translation_local_models_ct2/README.md`](/data/saas-search/perf_reports/20260318/translation_local_models_ct2/README.md)
  - CT2 聚焦调优总结:[`perf_reports/20260318/translation_local_models_ct2_focus/README.md`](/data/saas-search/perf_reports/20260318/translation_local_models_ct2_focus/README.md)
  - NLLB T4 商品标题专项调优:[`perf_reports/20260318/nllb_t4_product_names_ct2/README.md`](/data/saas-search/perf_reports/20260318/nllb_t4_product_names_ct2/README.md)
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
  
  ### 10.1 先看哪组数据
  
  这里把 3 类结果分开看,不再混在一张表里:
  
  - `batch_sweep`
    固定 `concurrency=1`,只比较不同 `batch_size` 的单流批处理性能
  - `concurrency_sweep`
    固定 `batch_size=1`,看“单条请求”在不同并发下的延迟和吞吐
  - `batch x concurrency matrix`
    同时看 `batch_size` 和 `concurrency` 的交互效应;本轮限制为 `batch_size * concurrency <= 128`
  
  建议:
  
  - 看线上 query 翻译延迟:优先看 `concurrency_sweep`
  - 看离线批量翻译吞吐:优先看 `batch_sweep`
  - 看单 worker 服务容量边界:再看 `batch x concurrency matrix`
  
  ### 10.2 本轮补测参数
  
  测试时间:`2026-03-18`
  
  环境:
  - GPU:`Tesla T4 16GB`
  - Python env:`.venv-translator`
  - Torch / Transformers:`2.10.0+cu128 / 5.3.0`
  
  统一参数:
  - cache:关闭(`--disable-cache`),避免缓存命中干扰性能结果
  - `batch_sweep`:每档 `256` items
  - `concurrency_sweep`:固定 `batch_size=1`,每档 `32` requests
  - `batch x concurrency matrix`:每档 `32` requests,且只保留 `batch_size * concurrency <= 128`
  - 预热:`1` batch
  
00471f80   tangwang   trans
600
601
602
603
604
605
606
  复现命令:
  
  ```bash
  cd /data/saas-search
  ./.venv-translator/bin/python scripts/benchmark_translation_local_models.py
  ```
  
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  本轮扩展压测复现命令:
  
  ```bash
  cd /data/saas-search
  ./.venv-translator/bin/python scripts/benchmark_translation_local_models.py \
    --suite extended \
    --disable-cache \
    --serial-items-per-case 256 \
    --concurrency-requests-per-case 32 \
    --concurrency-batch-size 1 \
    --output-dir perf_reports/20260318/translation_local_models
  ```
  
  单模型扩展压测示例:
00471f80   tangwang   trans
621
622
623
624
  
  ```bash
  ./.venv-translator/bin/python scripts/benchmark_translation_local_models.py \
    --single \
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
625
    --suite extended \
00471f80   tangwang   trans
626
627
628
629
    --model opus-mt-zh-en \
    --source-lang zh \
    --target-lang en \
    --column title_cn \
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
630
631
632
633
634
635
636
    --scene sku_name \
    --disable-cache \
    --batch-size-list 1,4,8,16,32,64 \
    --concurrency-list 1,2,4,8,16,64 \
    --serial-items-per-case 256 \
    --concurrency-requests-per-case 32 \
    --concurrency-batch-size 1
00471f80   tangwang   trans
637
638
  ```
  
1d6727ac   tangwang   trans
639
640
641
642
643
  单条请求延迟复现:
  
  ```bash
  ./.venv-translator/bin/python scripts/benchmark_translation_local_models.py \
    --single \
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
644
    --suite extended \
1d6727ac   tangwang   trans
645
646
647
648
649
    --model nllb-200-distilled-600m \
    --source-lang zh \
    --target-lang en \
    --column title_cn \
    --scene sku_name \
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
650
651
652
653
654
655
    --disable-cache \
    --batch-size-list 1 \
    --concurrency-list 1,2,4,8,16,64 \
    --serial-items-per-case 256 \
    --concurrency-requests-per-case 32 \
    --concurrency-batch-size 1
1d6727ac   tangwang   trans
656
657
  ```
  
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
  ### 10.3 单流 batch 结果
  
  这组只看 `concurrency=1`,不要把这里的 `request p95` 当作线上并发请求的 p95。
  
  `nllb-200-distilled-600m zh -> en`
  
  | Batch | Items/s | Avg item ms | Req p95 ms |
  |---:|---:|---:|---:|
  | 1 | 2.91 | 343.488 | 616.27 |
  | 4 | 8.44 | 118.545 | 722.95 |
  | 8 | 14.85 | 67.335 | 728.47 |
  | 16 | 27.28 | 36.662 | 769.18 |
  | 32 | 38.6 | 25.908 | 1369.88 |
  | 64 | 58.3 | 17.152 | 1659.9 |
  
  `nllb-200-distilled-600m en -> zh`
  
  | Batch | Items/s | Avg item ms | Req p95 ms |
  |---:|---:|---:|---:|
  | 1 | 1.91 | 524.917 | 866.33 |
  | 4 | 4.94 | 202.473 | 1599.74 |
  | 8 | 8.25 | 121.188 | 1632.29 |
  | 16 | 13.52 | 73.956 | 1649.65 |
  | 32 | 21.27 | 47.017 | 1827.16 |
  | 64 | 32.64 | 30.641 | 2031.25 |
1d6727ac   tangwang   trans
683
  
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
684
  `opus-mt-zh-en zh -> en`
1d6727ac   tangwang   trans
685
  
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
  | Batch | Items/s | Avg item ms | Req p95 ms |
  |---:|---:|---:|---:|
  | 1 | 6.15 | 162.536 | 274.74 |
  | 4 | 15.34 | 65.192 | 356.0 |
  | 8 | 25.51 | 39.202 | 379.84 |
  | 16 | 41.44 | 24.129 | 797.93 |
  | 32 | 54.36 | 18.397 | 1693.31 |
  | 64 | 70.15 | 14.255 | 2161.59 |
  
  `opus-mt-en-zh en -> zh`
  
  | Batch | Items/s | Avg item ms | Req p95 ms |
  |---:|---:|---:|---:|
  | 1 | 4.53 | 220.598 | 411.57 |
  | 4 | 10.12 | 98.844 | 761.49 |
  | 8 | 14.63 | 68.361 | 1930.85 |
  | 16 | 24.33 | 41.1 | 2098.54 |
  | 32 | 33.91 | 29.487 | 2152.28 |
  | 64 | 42.47 | 23.547 | 2371.85 |
  
  批处理结论:
  
  - 纯吞吐看,4 个方向的最佳 raw throughput 都出现在 `batch_size=64`
  - 如果还要兼顾单个 batch 的尾延迟,`batch_size=16` 往往更均衡
  - `opus-mt-zh-en` 是本轮 bulk 场景最快模型,`nllb en->zh` 最慢
  
  ### 10.4 单条请求并发结果
  
  这组固定 `batch_size=1`,可以直接理解成“单条请求在不同并发下的表现”。
  
  `nllb-200-distilled-600m zh -> en`
  
  | Concurrency | Items/s | Avg req ms | Req p50 ms | Req p95 ms |
  |---:|---:|---:|---:|---:|
  | 1 | 4.17 | 239.99 | 226.34 | 373.27 |
  | 2 | 4.1 | 477.99 | 459.36 | 703.96 |
  | 4 | 4.1 | 910.74 | 884.71 | 1227.01 |
  | 8 | 4.04 | 1697.73 | 1818.48 | 2383.8 |
  | 16 | 4.07 | 2801.91 | 3473.63 | 4145.92 |
  | 64 | 4.04 | 3714.49 | 3610.08 | 7337.3 |
  
  `nllb-200-distilled-600m en -> zh`
  
  | Concurrency | Items/s | Avg req ms | Req p50 ms | Req p95 ms |
  |---:|---:|---:|---:|---:|
  | 1 | 2.16 | 463.18 | 439.54 | 670.78 |
  | 2 | 2.15 | 920.48 | 908.27 | 1213.3 |
  | 4 | 2.16 | 1759.87 | 1771.58 | 2158.04 |
  | 8 | 2.15 | 3284.44 | 3658.45 | 3971.01 |
  | 16 | 2.14 | 5669.15 | 7117.7 | 7522.48 |
  | 64 | 2.14 | 7631.14 | 7510.97 | 14139.03 |
  
  `opus-mt-zh-en zh -> en`
  
  | Concurrency | Items/s | Avg req ms | Req p50 ms | Req p95 ms |
  |---:|---:|---:|---:|---:|
  | 1 | 9.21 | 108.53 | 91.7 | 179.12 |
  | 2 | 8.92 | 219.19 | 212.29 | 305.34 |
  | 4 | 9.09 | 411.76 | 420.08 | 583.97 |
  | 8 | 8.85 | 784.14 | 835.73 | 1043.06 |
  | 16 | 9.01 | 1278.4 | 1483.34 | 1994.56 |
  | 64 | 8.82 | 1687.08 | 1563.48 | 3381.58 |
  
  `opus-mt-en-zh en -> zh`
  
  | Concurrency | Items/s | Avg req ms | Req p50 ms | Req p95 ms |
  |---:|---:|---:|---:|---:|
  | 1 | 3.6 | 277.73 | 145.85 | 1180.37 |
  | 2 | 3.55 | 559.38 | 346.71 | 1916.96 |
  | 4 | 3.53 | 997.71 | 721.04 | 2944.17 |
  | 8 | 3.51 | 1644.28 | 1590.93 | 3632.99 |
  | 16 | 3.5 | 2600.18 | 2586.34 | 5554.04 |
  | 64 | 3.52 | 3366.52 | 2780.0 | 7950.41 |
00471f80   tangwang   trans
759
  
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
760
761
762
763
764
765
766
767
768
769
770
771
  并发结论:
  
  - 当前本地 seq2seq backend 内部是单模型锁,单 worker 下提高客户端并发基本不会提升吞吐,主要会把等待时间堆到请求延迟上
  - 线上 query 翻译如果追求稳定延迟,应优先控制在低并发;`8+` 并发后,4 个方向的 p95 都明显恶化
  - 在线场景里,`opus-mt-zh-en` 延迟最稳;`nllb en->zh` 最慢,且并发放大后尾延迟最明显
  
  ### 10.5 batch x concurrency 怎么看
  
  完整矩阵见:
  - [`perf_reports/20260318/translation_local_models/translation_local_models_extended_221846.md`](/data/saas-search/perf_reports/20260318/translation_local_models/translation_local_models_extended_221846.md)
  
  这张表主要回答两个问题:
00471f80   tangwang   trans
772
  
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
773
774
775
776
777
778
779
780
  - 如果已经知道自己要跑离线批处理,`batch_size` 拉大后,在不同并发下吞吐会不会继续涨
  - 如果要拿单 worker 服务扛请求,在哪个 `batch_size x concurrency` 组合下开始明显排队
  
  本轮矩阵的共同特征:
  
  - 吞吐主要由 `batch_size` 决定,`concurrency` 不是主要增益来源
  -`batch_size` 固定时,`concurrency` 从 `1` 升到 `2/4/8/...`,`items/s` 变化很小,但 `avg req ms / p95` 会持续抬升
  - 因此当前实现更像“单 worker + 内部串行 GPU 推理服务”,不是一个靠客户端并发放大吞吐的服务
3eff49b7   tangwang   trans nllb-200-di...
781
782
783
784
  
  NLLB 性能优化经验:
  
  - 起作用的优化点 1:`float16 + cuda`
46ce858d   tangwang   在NLLB模型的 /data/sa...
785
    - 当前本地 NLLB 由 `CTranslate2` 在 `cuda:0` 以 `float16` 运行
3eff49b7   tangwang   trans nllb-200-di...
786
787
788
789
    - 优化后在 T4 上的峰值显存约 `2.8-3.0 GiB`
  - 起作用的优化点 2:`batch_size=16`
    - 相比 `batch_size=8`,吞吐提升明显
    - 继续提升到 `32` 虽然还能增吞吐,但 batch p95 和 batch max 会恶化很多
46ce858d   tangwang   在NLLB模型的 /data/sa...
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
  - 起作用的优化点 3:`ct2_inter_threads=4 + ct2_max_queued_batches=32`
    -`batch=1` 高并发商品标题场景收益最直接
    - 相比默认 CT2 配置,`zh->en` 和 `en->zh` 的在线吞吐都能稳定提升
  - 起作用的优化点 4:动态解码上限
    - 推荐 `ct2_decoding_length_mode=source`
    - 推荐 `ct2_decoding_length_extra=8`
    - 推荐 `ct2_decoding_length_min=32`
    - 这样可以保留 `max_new_tokens=64` 的安全上限,同时让短标题不再为长标题上限付费
  - 起作用的优化点 5:`ct2_batch_type=examples`
    - 在当前数据和 T4 上,比 `tokens` 更稳
    - 更适合作为线上默认
  - 不建议直接作为默认的实验:
    - `max_new_tokens=48`
    - 大 batch 和在线吞吐都会继续变好
    - 但商品标题 spot-check 已看到明显截断,尤其 `en->zh`
  - 收益有限或不稳定的实验:
    - `ct2_batch_type=tokens`
    - `ct2_max_queued_batches` 从 `16` 再继续拉高,收益很小
    - `ct2_decoding_length_mode=source(+4,min=24)` 更快,但仍有少量长标题截断风险
3eff49b7   tangwang   trans nllb-200-di...
809
810
811
  
  为什么最终没有采用其它方案:
  
46ce858d   tangwang   在NLLB模型的 /data/sa...
812
813
814
815
  - 当前本地最优路径已经切到 `CTranslate2 + float16`
  - 对这个 600M 级 encoder-decoder 模型,T4 上最有效的是把 CT2 的并行和解码策略调对
  - 因此这轮没有继续引入更重的服务化栈
  - 如果未来目标变成“继续压缩显存”或“进一步追求更低延迟”,再评估 `int8_float16` 或服务级微批处理队列会更合适
00471f80   tangwang   trans
816
817
818
819
820
  
  关键结论:
  
  - 当前机器上,`opus-mt-zh-en` 是三个新增本地模型里最快的
  - `opus-mt-en-zh` 大约是 `opus-mt-zh-en` 吞吐的一半
46ce858d   tangwang   在NLLB模型的 /data/sa...
821
  - `nllb-200-distilled-600M` 在 T4 上推荐 `cuda + CTranslate2 float16 + batch_size=16 + ct2_inter_threads=4 + ct2_max_queued_batches=32 + dynamic decoding`
3eff49b7   tangwang   trans nllb-200-di...
822
823
824
825
826
827
828
829
830
831
832
833
  - `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`
46ce858d   tangwang   在NLLB模型的 /data/sa...
834
835
836
837
  - 推荐 CT2 并行:`ct2_inter_threads=4`
  - 推荐 CT2 队列:`ct2_max_queued_batches=32`
  - 推荐 CT2 batch 类型:`examples`
  - 推荐动态解码:`ct2_decoding_length_mode=source`、`ct2_decoding_length_extra=8`、`ct2_decoding_length_min=32`
3eff49b7   tangwang   trans nllb-200-di...
838
  - 运行方式:单 worker,避免重复加载
00471f80   tangwang   trans
839
840
  
  更详细的性能说明见:
2a6d9d76   tangwang   更新了压测脚本和文档,让“单条请求...
841
  - [`perf_reports/20260318/translation_local_models/README.md`](/data/saas-search/perf_reports/20260318/translation_local_models/README.md)
46ce858d   tangwang   在NLLB模型的 /data/sa...
842
  - [`perf_reports/20260318/nllb_t4_product_names_ct2/README.md`](/data/saas-search/perf_reports/20260318/nllb_t4_product_names_ct2/README.md)
00471f80   tangwang   trans
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
  
  ## 11. 开发说明
  
  如果要新增翻译 backend,最少需要做这些事:
  
  1.[`translation/backends/`](/data/saas-search/translation/backends) 下新增实现
  2.[`translation/service.py`](/data/saas-search/translation/service.py) 注册 backend 创建逻辑
  3.[`config/config.yaml`](/data/saas-search/config/config.yaml)`services.translation.capabilities` 中新增 capability 配置
  4. 如果有新的静态规则:
     - scene 规则放到 [`translation/scenes.py`](/data/saas-search/translation/scenes.py)
     - 语言映射放到 [`translation/languages.py`](/data/saas-search/translation/languages.py)
     - prompt 模板放到 [`translation/prompts.py`](/data/saas-search/translation/prompts.py)
  
  原则:
  - 不要再引入 translation provider 兼容层
  - 不要把 scene / prompt / 语言方向规则重新散落到别的目录
  - 不要在代码里写隐式默认和静默兼容
  
  ## 12. 常见建议
  
  - 中英商品标题双向场景,优先考虑 `opus-mt-zh-en` 和 `opus-mt-en-zh`
  - 多语种统一方案,可以考虑 `nllb-200-distilled-600M`
  -`nllb` 更适合独占资源环境
  - 如果追求更高质量或更复杂语义处理,可使用 `qwen-mt` 或 `llm`
  - 如果追求稳定商业 API,可考虑 `deepl`
  
  ## 13. 相关文档
  
1d6727ac   tangwang   trans
871
  - [`docs/翻译模块说明.md`](/data/saas-search/docs/翻译模块说明.md)(已收口到本 README,保留为跳转页)
00471f80   tangwang   trans
872
873
  - [`docs/QUICKSTART.md`](/data/saas-search/docs/QUICKSTART.md)
  - [`docs/DEVELOPER_GUIDE.md`](/data/saas-search/docs/DEVELOPER_GUIDE.md)
41345271   tangwang   文档更新
874
  - [`docs/搜索API对接指南-00-总览与快速开始.md`](/data/saas-search/docs/搜索API对接指南-00-总览与快速开始.md)(分册导航;微服务见 `-07`