20 Mar, 2026

1 commit

  • 问题描述
    ----------
    使用 facebook/nllb-200-distilled-600M(CTranslate2 后端)时,若 API 传入 ISO 639-1
    或 FLORES 短标签(如 ca、da、nl、sv、no、tr 等),会触发
    「Unsupported NLLB source/target language」。模型与 tokenizer 实际支持这些语言;
    根因是 resolve_nllb_language_code 仅依赖 translation/languages.py 里十余条
    NLLB_LANGUAGE_CODES 映射,大量合法短码未注册,校验误报为不支持。
    
    修改内容
    ----------
    1. 新增 translation/nllb_flores_short_map.py
       - NLLB_FLORES_SHORT_TO_CODE:与 HF 模型卡 language 列表对齐的短标签 ->
         NLLB 强制 BOS/src_lang 形式(<ISO639-3>_<ISO15924>,如 cat_Latn)。
       - NLLB_TOKENIZER_LANGUAGE_CODES:从 tokenizer.json 提取的 202 个语言 token
         全集,供直接传入 deu_Latn 等形式时做规范化解析。
       - 额外约定:ISO 639-1「no」映射 nob_Latn(书面挪威语 Bokmål);nb/nn 分别
         对应 nob_Latn / nno_Latn;「ar」显式指向 arb_Arab(与 NLLB 一致)。
    
    2. 调整 translation/languages.py
       - build_nllb_language_catalog:合并顺序为 FLORES 全表 -> NLLB_LANGUAGE_CODES
        (保留少量显式覆盖,如 zh->zho_Hans)-> 调用方 overrides。
       - resolve_nllb_language_code:在目录与别名之后,增加基于
         NLLB_TOKENIZER_LANGUAGE_CODES 的大小写不敏感匹配(如 eng_latn -> eng_Latn),
         覆盖「已传完整 NLLB 码」的场景。
    
    3. tests/test_translation_local_backends.py
       - 新增 test_nllb_resolves_flores_short_tags_and_iso_no,覆盖用户关心的短码及
         deu_Latn 直通解析。
    
    方案说明
    ----------
    NLLB 接口语义以 Hugging Face NllbTokenizer 为准:语言标识为 FLORES-200 风格
    三字母语种码 + 下划线 + 四字母脚本子标签(ISO 15924)。业务侧常用 ISO 639-1
    (de、sv)或模型卡短列表(ca、nl),需在服务内统一映射到 tokenizer 特殊 token。
    本实现以模型卡 language 字段 + tokenizer 词表为单一事实来源生成静态表,
    避免运行时依赖额外库;同时保留原有 NLLB_LANGUAGE_CODES 作为薄覆盖层以兼容
    既有配置与测试。
    
    Refs: https://huggingface.co/facebook/nllb-200-distilled-600M
    Made-with: Cursor
    tangwang
     

19 Mar, 2026

2 commits

  • 推理”,不再是先按原始输入条数切块。也就是说,如果 100 条请求分句后变成
    150 个 segments,batch_size=64 时会按 64 + 64 + 22
    三批推理,推理完再按原始分句计划合并并还原成 100 条返回。这个改动在
    local_seq2seq.py (line 241) 和 local_ctranslate2.py (line 391)。
    
    日志这边也补上了两层你要的关键信息:
    
    分句摘要日志:Translation segmentation
    summary,会打印输入条数、非空条数、发生分句的输入数、总 segments
    数、当前 batch_size、每条输入分成多少段的统计,见 local_seq2seq.py (line
    216) 和 local_ctranslate2.py (line 366)。
    每个预测批次日志:Translation inference
    batch,会打印第几批、总批数、该批 segment
    数、长度统计、首条预览。CTranslate2 另外还会打印 Translation model batch
    detail,补充 token 长度和 max_decoding_length,见 local_ctranslate2.py
    (line 294)。
    我也补了测试,覆盖了“分句后再
    batching”和“日志中有分句摘要与每批推理日志”,在
    test_translation_local_backends.py (line 358)。
    tangwang
     
  • 改动:
    
    新增分句与预算工具:translation/text_splitter.py
    接入 HF 本地后端:translation/backends/local_seq2seq.py (line 157)
    接入 CT2 本地后端:translation/backends/local_ctranslate2.py (line 301)
    补了测试:tests/test_translation_local_backends.py
    我先把代码里实际限制梳理了一遍,关键配置在 config/config.yaml (line
    133):
    
    nllb-200-distilled-600m: max_input_length=256,max_new_tokens=64,并且是
    ct2_decoding_length_mode=source +
    extra=8。现在按这个配置计算出的保守输入预算是 56 token。
    opus-mt-zh-en:
    max_input_length=256,max_new_tokens=256。现在保守输入预算是 248 token。
    opus-mt-en-zh: 同上,也是 248 token。
    这版分句策略是:
    
    先按强边界切:。!?!?;;…、换行、英文句号
    不够再按弱边界切:,,、::()()[]【】/|
    再不够才按空白切
    最后才做 token 预算下的硬切
    超长时会“分句翻译后再回拼”,中文目标语言默认无空格回拼,英文等默认按空格回拼,尽量别切太碎
    验证:
    
    python3 -m compileall translation
    tests/test_translation_local_backends.py 已通过
    tangwang
     

18 Mar, 2026

1 commit


17 Mar, 2026

1 commit