翻译质量不稳,问题到底出在模型还是流程?同一个模型对同一段文本,隔一天再跑,术语、句式甚至标点都能变。我最初以为换个更强的模型就能解决,实测发现换了模型,漂移反而更难追。最后我放弃了”一次调好”的幻想,把质量拆成术语表、分段、提示词版本化、模型分级、人工反馈五件套,再配上回归测试和可观测性,把质量稳定在了可商用水平。下面按落地顺序讲清楚每件套的具体做法和踩过的坑。
一、不稳定的来源
动手解决之前,我先花了一周把”不稳定”现象归类,避免瞎调参。总结下来,漂移的来源有五类:
- 模型温度参数 > 0;
- 上下文长度变化,注意力分布不同;
- 提示词差异:标点、空行、Markdown 风格;
- 模型版本升级;
- 训练集偏见。
第一类直观:温度大于 0 时,模型每次采样都有随机性,同样的输入可能给出不同的输出。我一开始把温度压到 0,效果立竿见影,但很快发现长文档还是会漂,因为上下文长度变化这一因素,光靠调温度压不住。到这里我才意识到,质量问题不是一个参数能解决的,得从流程上治。
二、术语表与一致性
排查日志时我发现一个高频现象:同一篇文档里,”repository”第一次译成”仓库”,第二次译成”代码库”;库名、命令名被音译或者意译,五花八门。根因是模型每次翻译都在”自由发挥”,没有一个强制约束。术语表就是给模型划定的硬边界,也是这套体系里投入产出比很突出的一环:
- 项目专有名词(如库名、命令名、API 名)固定译法;
- 同一术语在所有任务中保持一致;
- 术语表由用户或管理员维护,存到数据库;
- 模型 prompt 注入术语表,强制使用。
术语表注入是典型的”提示词拼接”操作,实现起来很简单,把术语对按行拼进 prompt 末尾即可。下面这段代码解决的就是”把术语表塞进提示词”的问题:
function withGlossary(prompt: string, glossary: GlossaryEntry[]) {
const lines = glossary.map((g) => `${g.source} → ${g.target}`);
return `${prompt}\n\n术语表:\n${lines.join("\n")}`;
}
这段代码跑通之后,术语命中率立刻从六成出头提到九成五以上,效果非常直接。要提醒的是:术语表不是越多越好,术语太多会把 prompt 撑长、还会互相冲突,我后面按文档域拆分了术语表,冲突率才降下来。
三、分段策略
术语表解决了”翻得对不对”,还有一个问题是”长文档翻得好不好”。整篇塞给模型,超过一定长度后质量明显下滑,而且中途某段失败,整篇都得重来。我按长度做了一版分段策略,实测效果如下:
| 长度 | 推荐做法 |
|---|---|
| < 500 字 | 一次性翻译,温度 0.1 |
| 500–2000 字 | 分段翻译,按 H2 切分 |
| > 2000 字 | 切分 + 主模型 + review 模型复核 |
分段边界必须稳定,这是我踩过的坑:一开始按字符数硬切,结果把代码块和列表从中间劈开,翻译出来格式全乱。改成按 H2 标题切分后,每段语义完整,格式也保住了。2000 字以上的文档还会加一道 review 模型复核,专门挑”看起来流畅但其实错了”的译文。
四、提示词版本化
把提示词当代码管理,是我花了不少学费才学到的。早期我习惯”顺手改一下提示词”,结果线上译文悄悄变了,用户反馈”翻译风格怎么突然不对了”,我还查不到是哪次改动引起的。后来我把提示词全部版本化:
- 提示词存到数据库表
Prompt; - 任务记录用的 prompt 版本号;
- 修改提示词走 A/B,新旧并行一周;
- 评估指标对比:术语命中率、复读率、用户评分。
现在每次改提示词,我会先建一个新版本,让新旧版本各跑一部分真实流量,一周后对比指标再决定全量切换。改完还会顺手写一条变更记录,出了问题能精确回滚到上一个版本。
五、模型分级
成本和质量本来是个单选题,我用模型分级把它解开了。不是所有段落都值得用大模型,有些高频低价值的段落用快模型就够了,把预算留给关键内容:
- 普通段落:快模型(gpt-4o-mini 等);
- 关键段落(README、API 概念):主模型;
- 校对:强模型(Claude 3.5 Sonnet);
- 自定义:用户可指定模型。
分级跑了一个月后统计,单任务总成本下降 30–50%,质量指标没有明显回落。分级的关键是”判级”要准,我把判级规则写成白名单加启发式:README、API 段落必然走主模型,正文段落默认走快模型,用户可以在设置里手动升级。
六、复读与不一致检测
模型分级之后,新的问题浮出来:段落之间术语不一致。快模型翻译的段落可能用了不同的译法,或者整段重复了前一段的内容。这个我靠检测加二次修正来处理:
- 提取前后段落中所有命名实体;
- 与术语表对比,差异项标红;
- 让二级模型统一替换;
- 仍然不一致时进入人工 review。
检测规则不复杂,但很有效。二级模型替换时我会带上术语表做约束,避免二次漂移;连续两次都救不回来的段落,直接标红丢给人工,不硬撑。
七、人工反馈
模型再强也不可能 100% 准确,所以这套系统从设计第一天就给人留了入口。翻译结果以 PR 的形式交给用户,用户可以直接在评论区反馈”翻译不准”,这些反馈是我们特别宝贵的语料:
- 用户可在 PR 中评论”翻译不准”;
- 系统收集反馈进
TranslationFeedback表; - 定期 review 反馈,更新术语表与提示词;
- 关键文档强制人工 review。
我每个月会集中过一遍反馈表,把高频错误归类:是术语表缺条目,还是提示词写得含糊,或者是分段边界没对齐。一次归类整理,顶得上闷头调十次参数。
八、回滚与重译
翻译错了不能只靠人工改,系统得支持重译。重译最容易踩的坑是”版本漂移”:同一个段落,重译时用的术语表和提示词跟第一次不一样,出来的结果自然对不上。我把重译设计成单片段任务,强制复用原任务参数:
- 用户点击”重译此段”,任务进入单片段队列;
- 用相同的术语表与提示词版本,避免”版本漂移”;
- 历史译文存
TranslationSegment表,可对比。
历史译文表帮了大忙,用户重译后能看到新旧两个版本对照,觉得新版不如旧版时,一键切回,不丢历史。
九、质量评估
有了这么多机制,怎么证明它有效?我建了一套质量评估指标,每个指标都有明确的采集方式,避免拍脑袋:
| 指标 | 含义 | 采集方式 |
|---|---|---|
| 术语命中率 | 译文术语与术语表一致 | 自动 diff |
| 复读率 | 段落重复句子占比 | 自动统计 |
| 用户评分 | 人工打分 | 反馈表 |
| 编辑距离 | 译文与人工参考的差异 | 抽样评估 |
这套指标里的术语命中率和复读率可以全自动采集,每天跑一次;编辑距离是抽样评估,我每周抽 20 篇对人工参考做一次对比。四类指标合在一起,既覆盖了机器可判的硬指标,也留了人工感知的软指标。
十、回归测试
质量系统怕的是”悄悄退化”:某次改完提示词,指标没崩,但几个月后整体质量慢慢下滑,等发现已经晚了。我加了一层回归测试兜底:
- 准备 50 篇参考译文;
- 跑翻译,输出术语命中、复读率;
- CI 失败时阻断发布。
这 50 篇参考译文覆盖了不同长度、不同文档类型,每次改提示词、换模型、改分段策略,都会触发一次回归。指标跌破阈值就阻断发布,把退化挡在线上之前。
十一、可观测性
最后是兜底的兜底:可观测性。质量问题怕”无法定位”,所以我从三个粒度把运行数据埋全:
- 任务级别:模型、token、耗时、术语命中率;
- 段落级别:状态、重试次数、用户反馈;
- 全局:模型版本、提示词版本、术语表版本。
三个粒度对应三种排查场景:任务级别的数据用来回答”这次翻译为什么慢了、贵了”;段落级别的数据用来定位”哪一段出了问题”;全局版本信息用来回答”这次行为变化是哪个改动引起的”。埋完这层,绝大多数质量投诉都能在十分钟内定位根因。
十二、给同类项目的建议
到这里,整套方案的落地链路就完整了。把沉淀下来的经验浓缩成几条建议,给做类似翻译工具或 LLM 生成管线的项目参考:
- 提示词版本化,永远不要”边写边改”;
- 术语表是质量地基;
- 模型分级,控制成本;
- 必须有人工反馈入口;
- 用回归测试防止”悄悄退化”。
这几条每一条都是我用线上事故换来的。按优先级排的话,术语表和回归测试放前两位,它们是低成本高收益的两件事,值得先做。
常见问题(FAQ)
Q1:温度设 0 就稳定吗?
部分稳定。但段落长度、提示词差异仍会带来变化。
Q2:术语表越多越好吗?
不是。术语太多会增加 prompt 长度与冲突,按域维护。
Q3:人工反馈如何驱动改进?
把高频错误归类,更新术语表或提示词模板。