阅读文本 / 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