翻译验收

重复段落可以复用译文,缓存键却不能只有原文

“保存”在两个项目里看起来一样,但译法、大小写和上下文可能不同。把原文哈希作为唯一缓存键,很容易把一个项目的译文复用到另一个项目,甚至跨租户混用。缓存不是只有命中率,先要定义哪些条件相同才允许复用。

阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。 “保存”在两个项目里看起来一样,但译法、大小写和上下文可能不同。把原文哈希作为唯一缓存键,很容易把一个项目的译文复用到另一个项目,甚至跨租户混用。缓存不是只有命中率,先要定义哪些条件相同才允许复用。 缓存键应代表一次翻译决策 至少考虑源语言、目标语言、术语版本、模型或翻译策略版本,以及使用范围。上下文影响译文时,还要纳入上下文标识。模型名称相同并不保证服务端永远不变;若需要稳定重现,应保存你的策略版本与实际任务信息,而不是假装一个名称足以锁定所有行为。 下面是本地缓存键的合成示例。它不调用任何翻译接口,也不规定 OmniDoc(产品入口) 的内部缓存实现。 用结构化序列化避免拼接歧义 import hashlib import json def cache_key(tenant, text, source_lang, target_lang, glossary, policy): record = {"tenant": tenant, "text": text, "source": source_lang, "target": target_lang, "glossary": glossary, "policy": policy} raw = json.dumps(record, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8") return hashlib.sha256(raw).hexdigest() args = ("demo-a", "保存", "zh", "en", "terms-v1", "ui-v1") first = cache_key(*args) assert first == cache_key(*args) assert first != cache_key("demo-b", *args[1:]) assert first != cache_key("demo-a", "保存", "zh", "ja", "terms-v1", "ui-v1") assert first != cache_key("demo-a", "保存", "zh", "en", "terms-v2", "ui-v1") assert len(first) == 64 简单使用 text + language + version ,会遇到字段边界不清的问题。结构化序列化明确了字段名和取值边界;固定键顺序与分隔符,则使同一记录得到稳定字节。这里只演示这套固定协议,未来修改序列化规则时应同步升级缓存命名空间。 命中之后仍要检查可用状态 缓存条目可能来自一次失败、取消或未审校任务。命中键不意味着结果可以直接交付。条目还应记录状态、创建时间、来源任务,以及需要时的质量标记。术语改版后的旧缓存可以保留用于追溯,但不应继续被新策略当作当前结果。 变化 本例是否生成不同键 理由 租户不同 是 避免复用范围混淆 目标语言不同 是 翻译目标已改变 术语版本不同 是 术语决策已改变 输入和策略都相同 否 允许查询已有结果 哈希不等于加密或访问控制 不能因为缓存键是 SHA-256,就把正文当成已经脱敏。常见短句可能被枚举,缓存内容也仍然需要访问权限与保留策略。租户 ID 进入键只能隔离命名,不能替代查询时的权限检查。 为了追求命中率而统一删除空格、标点或数字,也可能把本不相同的文本合并。归一化规则应当明文定义,并用会改变语义的反例测试,不能只看节省了多少调用。 让复用服务于交付 如果把 OmniDoc 作为文档翻译入口,外层任务编排同样可以保留输入版本与验收记录。是否复用已有结果,应由你的任务协议决定;本文不推断平台是否使用了相同缓存策略,也不保证重复提交不会产生新任务或费用。 参考: Python hashlib 。 - 1 -
更新于 2026-10-08