上一篇文章中,我记录了 A Tour of Go 简体中文 103 个正式课程页面的 ChatGPT 全量重译过程。
整个过程最终形成:
8 个首次全量翻译 Batch
+
3 个 revision Batch
=
11 个 ChatGPT BatchBatch 001~008 首次完整覆盖 103 页,Batch 009~011 则继续处理后续发现的术语和语言质量问题。
上一篇记录:
https://www.shuijingwanwq.com/2026/08/19/26947/
到这里,一个很容易产生的想法是:
103 页既然已经全部翻译完成,而且都通过了现有 validator,是不是就可以直接覆盖正式 zh-CN?
我最后没有这样做。
因为这一轮让我进一步确认了一件事:
结构正确和语言质量足够好,是两个不同的问题。
自动 validator 能够很好地回答:
present.Section 有没有被破坏?
链接 target 是否保持正确?
代码和 directive 是否保持正确?
保护 token 是否完整?
restore 后结构是否与原文对应?但它不能完全回答:
技术含义有没有细微偏差?
中文是不是足够自然?
同一个术语是否在不同页面保持一致?
有没有明显的翻译腔?
作为正式 Go 初学者教程是否足够顺畅?因此,103 页完成 ChatGPT 重译以后,我没有立即进入生产发布。
中间又增加了一道独立的:
完整语义质量审核。
一、自动校验通过,并不代表语义审核结束
A Tour of Go 的 .article 并不是普通 Markdown。
课程页面中可能同时存在:
present.Section
链接
行内代码
预格式化代码
.play
.image
强调结构
其他 present directive翻译模型只要错误改变其中某些内容,即使生成出来的中文看起来完全正常,最终页面也可能无法正确解析或者渲染。
所以自动 validator 一直都是正式 candidate 的必要条件。
但这一次 103 页 ChatGPT 重译完成以后,我越来越明确:
validator 是必要条件,却不是语言质量证明。
例如下面两种译文:
结构完全正确
技术含义基本正确
中文可以理解和:
结构完全正确
技术含义准确
术语一致
中文自然
符合正式教程表达都可能通过相同的结构 validator。
但如果目标是正式替换已经上线的 zh-CN,显然应该尽量达到后一种状态。
因此,这一次没有把:
validator 全部通过直接等价为:
可以正式发布二、103 页重新做完整语义质量分级
为了避免只检查少量代表页,我最终把审核范围扩大到了全部:
103 / 103正式课程页面。
这一轮使用 A/B/C/D 四级来记录每个页面当前的语义和语言质量。
这里的 A/B/C/D 不是 present parser、结构 validator 或自动测试产生的结果,而是一套专门用于本轮完整语义审核的内部质量分级。
四个等级大致表示:
A
可以直接发布。
技术含义准确、忠实原文、中文自然,
术语和教学表达均达到正式发布要求。
B
已经达到发布质量,可以不修改。
只存在比较轻微、可选的表达优化空间。
即使保持当前译文,也不会因此阻塞正式发布。
C
建议发布前修改。
存在比较明显的翻译腔、术语问题、
表达不够清楚或其他能够带来明确质量收益的问题。
D
必须修复。
存在误译、遗漏、技术错误,
或者可能影响读者正确理解原文的明显歧义。从发布角度,可以进一步理解成:
A → 直接满足正式发布质量
B → 已达到发布质量,修改属于可选优化
C → 建议发布前 revision
D → 必须阻塞发布并修复这里还有一个很重要的审核原则:
“还能换一种写法”本身,不构成降级理由。
自然语言几乎永远可以继续改写。
如果只要模型还能提出另外一种表达,就不断把页面判为 B 或 C,那么审核永远无法真正收敛。
所以需要判断的是:
当前译文是否存在能够明确指出的问题,以及修改以后是否真的有明确质量收益。
最终审核结果是:

最终统计:
Formal course pages : 103
A : 103
B : 0
C : 0
D : 0
Missing pages : 0
Duplicate pages : 0
Extra pages : 0也就是说,到最终冻结这一轮语义审核时:
全部 103 个页面都进入了 A 档。
但这里还有一个过程值得特别说明。
三、B 本来可以不改,但最后还是把 2 页改到了 A
语义审核过程中,并不是一开始就得到:
A=103
B=0
C=0
D=0当时曾经有:
2 个页面被评为 B。
按照前面的分级标准,B 本身已经达到正式发布质量,因此理论上完全可以不修改。
也就是说,即使最后停在:
A=101
B=2
C=0
D=0也不会因为这两页而阻塞正式发布。
但最后我仍然决定继续把这两页调整掉。
原因并不是 B “不合格”。
恰恰相反,是因为:
只剩 2 页,而且修改成本已经很低。
到了整个项目接近收尾的时候,需要处理的已经不是几十页,而只是两个非常明确的小范围 revision。
这时候继续修订的边际成本不高,但能够让最终状态从:
101 个 A
+
2 个 B收敛到:
103 个 A所以最终还是完成了这两个页面的 revision。
这个决定也体现了我这次使用 A/B/C/D 分级的目的:
等级首先用于判断是否值得阻塞发布,而不是强迫所有页面无限追求同一种措辞。
如果当时还有几十页 B,我未必会为了把数字变成 A=103 而全部重写。
但只剩 2 页,而且修改成本已经很低,那么顺手完成最后的语言优化就比较合理。
因此最终:
A=103
B/C/D=0并不是因为:
B 也必须修复。
而是因为:
B 本来可以发布,只是最后仅剩 2 页,继续优化的成本很低,因此顺便完成了最终收敛。
四、为什么我把整体评价从约 94 分提高到约 98 分
在前一轮正式 zh-CN 质量评估中,我给出的内部工程判断大约是:
94 / 100更准确一些,可以理解为:
93~95它本身已经属于质量比较好的正式译文。
问题主要不是存在大量明显错误,而是仍然可以感觉到:
少量翻译腔
部分表达不够自然
个别术语还有继续统一的空间
部分页面还可以更接近正式中文技术教程这也是后来继续研究 minimal-protect、Static Context 和 Translation Engine 的原因。
整个实验最后证明,真正明显改善语言质量的关键并不是继续减少结构保护,而是:
更换 Translation Engine。
ChatGPT 完成全部 103 页整页重译以后,再经过后续 revision 和完整语义审核,我现在更愿意把这一版 zh-CN 的整体质量评价放在:
约 98 / 100这里需要强调:
98 分不是程序计算出来的自动分数,也不是 Go 官方评价。
它仍然是结合整轮翻译、审核和工程验证后得到的内部综合判断。
支持这一判断的主要依据包括:
103/103 完整重新翻译
全部页面统一语义审核
最终 A=103
B/C/D=0
术语继续统一
已知不良术语完成扫描
正常英文自然语言遗漏清理
多轮 revision
相同结构 validator 再次通过与原来的约 94 分相比,差异已经不再只是几个代表页面上的主观感受,而是最终覆盖到了全部 103 个正式课程页面。
五、A=103 为什么仍然不是 100 分
这里需要区分两个概念:
A 档
≠
100 分完美译文A 表示:
当前页面已经达到本轮设定的正式发布质量,不存在值得继续阻塞发布的明确语义、术语或表达问题。
而 100 分意味着的是一个明显更高的标准:
几乎不存在任何合理的编辑改进空间这一轮虽然完成了 103 页页面级语义审核,但并没有进行一种成本更高的流程:
由独立 Go 技术专家和专业中文技术编辑,对 103 页逐句完成出版级最终校对。
而且自然语言本身也不存在唯一正确译法。
同一句英文完全可能存在两个都准确、自然的中文表达。
一个可能更简洁,另一个可能更符合某种编辑风格。
所以剩下的约 2 分,更准确地说是:
对未来编辑级微调和极小概率遗漏保留的不确定性。
它并不意味着已经知道“还有 2% 的句子存在错误”。
因此,我认为:
约 98比:
100更适合作为当前这一版 zh-CN 的工程质量评价。
六、A=103 并不是第一次审核就得到的
最终看到:
A=103
B/C/D=0很容易让人觉得 103 页第一次检查以后就已经是这个结果。
实际上并不是。
Batch 001~008 完成第一次全量覆盖以后,后续审核仍然发现了一些值得继续调整的地方。
于是又产生了:
Batch 009
Batch 010
Batch 011这些 Batch 不再是为了补齐缺失页面。
它们专门承担:
术语统一
明确的语言质量 revision
少量 B 级页面最终优化
个别页面最终表达修订所以历史 Batch 一旦形成以后,我没有回去直接修改原来的 evidence。
而是遵循:
旧 Batch
→ 保持不变
发现质量问题
→ 新建 revision Batch这让最终页面不仅能知道:
现在使用的译文是什么。
还能够继续追溯:
它为什么从早期版本变成了现在这个版本。
七、最终 canonical 并不都来自第一次全量 Batch
这一点从最终 status.tsv 的 provenance 中可以直接看到。

welcome/1 仍来自 Batch 001,而 concurrency/1、methods/17、methods/19 分别采用后续 Batch 009 和 Batch 011 的 revision,最终均处于 ready 并通过 canonical validator。例如:
welcome/1
→ chatgpt-zh-CN-001说明这个页面的早期版本已经达到要求。
没有必要为了让所有页面都来自最新 Batch,而重新改写本来已经很好的译文。
而:
concurrency/1
→ chatgpt-zh-CN-009说明它最终采用了后续 revision。
再例如:
methods/17
methods/19
→ chatgpt-zh-CN-011一直到最后一个 revision Batch,它们才被冻结为最终版本。
所以 canonical promotion 的原则并不是:
找到第一次完整覆盖的 103 页
↓
全部覆盖正式译文而是:
检查每一个 page
↓
确定该页最终有效 revision
↓
验证完整 provenance
↓
再进入正式 canonical八、历史 evidence 不能为了正式文件“变漂亮”而修改
真正准备 canonical promotion 时,又遇到了一个看起来很小、实际上很重要的问题。
历史 Batch 中保存的 candidate,文件结尾并不完全统一。
统计以后发现:
23 个 candidate
→ 结尾一个换行
80 个 candidate
→ 结尾存在两个或更多换行如果直接把这些 historical candidate 按字节复制到正式 canonical:
git diff --check会出现文件结尾空白相关警告。
最简单的处理方法似乎是:
直接把历史 candidate 的多余换行删掉。
但最后没有这么做。
因为这些历史文件已经承担 evidence 的角色。
如果为了最终提交更整洁,而反过来修改历史 candidate,就会破坏此前已经建立起来的:
raw response
↓
restore
↓
historical candidate精确对应关系。
最终冻结下来的规则变成:
Historical evidence
raw
↓
restore
↓
batch candidate
保持历史字节不变然后到了正式 promotion 边界:
Promotion boundary
batch candidate
↓
deterministic EOF canonicalization
↓
validator
↓
canonical candidate只有跨入正式 canonical 时,才执行确定性的 EOF normalization。
规则非常简单:
只删除文件结尾多余的 \n
最终保证恰好一个 \n
正文和其他字节不改变这样既保护 historical evidence,又保证正式仓库中的 candidate 文件保持规范。
九、canonical promotion 还要证明译文真的来自对应 ChatGPT evidence
真正准备 promotion 时,我还专门加强了一轮 evidence chain。
因为只知道:
某个 Batch 里存在 candidate仍然不够。
理论上,如果有人后来手工修改过 candidate,而 promotion 只检查最终结构,那么依然有可能把一个无法证明来源的文件正式提升进去。
所以最终的 promotion 不只是“找到文件并复制”。
还需要重新证明整条来源关系。
大致包括:
manifest 中记录的 input
↓
保存时的 input SHA
↓
当前 Default protector 重新生成 input
↓
字节级比较
↓
ChatGPT raw response
↓
restore
↓
historical candidate
↓
精确字节比较
↓
validator
↓
promotion这样最终正式 candidate 的 provenance 就不再只是:
这个文件位于 ChatGPT Batch 目录中。
而是:
能够证明它确实来自已经保存的 ChatGPT raw response,并经过确定性的 restore 和相同 validator。
十、存在 retry history 时,还要正确识别最终有效 attempt
上一篇文章记录过两个正式 retry 页面:
moretypes/1
concurrency/1到了 promotion 阶段,还需要继续解决一个问题:
如果一个页面存在 retry history,promotion 能不能正确识别并选择最终有效的 attempt?
例如:
attempt-001
→ 校验失败
attempt-002
→ 校验成功那么 promotion 需要证明:
最终被提升的是 attempt-002 对应的有效结果。
不能因为历史目录中仍然保留着 attempt-001,就在后续处理时错误回退到更早的失败结果。
因此后面又加强了 retry provenance 规则。
最终要求类似:
存在 retry history
↓
必须识别最终有效 attempt
attempt 编号必须连续
前序 validation history 必须完整存在
不能凭空出现 attempt-999
不能跳过历史 attempt
不能把 provenance 倒退到已经失败的旧 attempt这部分看起来很严格,但目的很简单:
正式 promotion 不仅要证明“这个文件能用”,还要证明“它确实来自这条 retry history 中最终确认有效的那一次尝试”。
十一、正式 apply:103 页中 102 页发生变化
全部语义审核和 promotion 机制都冻结以后,才真正执行正式 apply。
结果如下:

第一次正式 apply:
pages : 103
changed : 102
unchanged : 1
EOF normalized : 80这里的:
unchanged : 1并不意味着有一个页面没有使用 ChatGPT 新译文。
而是这个页面当前 canonical candidate 本来就已经与最终目标完全相同,所以不需要产生新的文件差异。
真正值得关注的是:
changed : 102103 页中有 102 个正式 candidate 实际发生变化。
同时:
EOF normalized : 80正好对应前面发现的 80 个历史 candidate 文件结尾需要规范化。
十二、为什么 apply 完以后还要再跑一次 dry-run
正式 apply 完成以后,我没有马上提交。
而是重新执行了一次 promotion dry-run。
结果:
changed : 0
unchanged : 103这一步验证的是:
promotion 是否已经达到确定、稳定的最终状态。
如果第二次 dry-run 仍然出现:
changed > 0那就意味着 promotion 本身可能还有:
非确定性处理
状态没有完全落盘
文件生成结果不稳定之类的问题。
最终:
0 changed
103 unchanged说明在相同输入和相同 historical evidence 下再次计算,不会继续修改 canonical。
也就是具备了很重要的:
幂等性。
十三、最终正式提交只有 103 个数据文件
promotion 完成以后,又对 Git change set 做了一次最终检查。

bfa9f92。本次提交只包含 102 个发生变化的正式 candidate 和 1 个 status.tsv,共 103 个文件,没有任何意外路径;提交完成后工作区保持 clean。最终提交:
bfa9f92
data: 提升 ChatGPT 重译候选为 zh-CN 正式候选统计:
103 files changed
628 insertions(+)
533 deletions(-)再按路径分类:
canonical candidates : 102
status.tsv : 1
unexpected paths : 0也就是:
102 个正式 candidate
+
1 个状态文件
=
103 个文件这次提交中没有顺手混入:
promotion 实现代码
测试代码
historical Batch
raw response
其他项目文件这也是我希望长期保留的一条边界:
正式数据提升和实现 promotion 的代码修改,不应该混在同一个 Git commit 中。
十四、promotion 完成以后,又遇到了一个“测试失败”
正式 candidate 替换完成以后,完整测试并不是第一次就全部通过。
当时有几个测试失败。
继续排查以后发现,并不是 ChatGPT 新译文破坏了程序。
真正原因是:
旧测试把上一版正式中文句子本身当成了固定测试基线。
例如测试曾经直接依赖某一句旧译文。
当 ChatGPT 把它改成技术含义相同、中文更自然的新表达以后:
程序正确
结构正确
页面正确测试却因为:
中文句子不再逐字相同而失败。
这其实暴露了另外一个问题:
测试到底应该保护什么?
如果测试目标是确保某个页面仍然保持正确的 publication semantics,那么更适合检查:
稳定语义锚点
页面结构
发布顺序
状态字段
provenance而不是永久冻结整句中文。
所以后面只更新了与新 canonical 有关的测试基线。
最终:
go test -mod=readonly -count=1 ./...完整通过。
到这里,新的 ChatGPT canonical 才真正完成仓库级正式验收。
十五、从约 94 到约 98,增加的不只是模型能力
如果只从表面看,这轮变化可以简单总结成:
GLM-5.2
↓
ChatGPTTranslation Engine 的变化当然是语言质量明显提升的关键原因。
但真正把原来的约 94 分推进到我愿意评价为约 98 分的,并不只是模型本身。
还包括后面的:
103 页全量覆盖
↓
完整语义审核
↓
A/B/C/D 分级
↓
术语统一
↓
revision Batch
↓
最终 A=103
↓
provenance 验证
↓
retry provenance
↓
canonical promotion
↓
EOF canonicalization
↓
再次 dry-run
↓
完整测试换句话说:
更强的 Translation Engine 提供更好的原始译文,而完整工程流程负责证明这些译文最终值得进入正式项目。
缺少前者,语言质量很难明显提高。
缺少后者,即使模型翻得很好,也很难放心地一次替换 103 个正式页面。
十六、103 页翻完和 103 页正式可发布,是两个里程碑
回头来看,这次最值得保留下来的经验之一,就是不要把:
translation completed和:
release ready当成同一个状态。
上一篇文章结束时,我们已经做到:
103/103 ChatGPT 重译完成但真正到这一篇结束,才完成:
103/103 语义审核完成
↓
曾有 2 页 B,但已经达到发布质量
↓
因修改成本很低,继续优化
↓
最终 A=103、B/C/D=0
↓
最终 revision 确认
↓
canonical promotion
↓
102 candidate changes
↓
103/103 promotion 收敛
↓
完整测试通过到这里,我才愿意说:
新的 ChatGPT zh-CN 已经不再只是实验 candidate,而是正式 canonical。
结合旧版本和这轮 103 页完整审核结果,我对当前 A Tour of Go 简体中文整体质量的内部工程评价,也从此前大约:
94 / 100提高到了:
约 98 / 100但即便做到这里,还有最后一个问题没有回答:
仓库中的正式 canonical 已经替换成 ChatGPT 译文,是否就等于用户打开网站时看到的一定也是这套新译文?
答案仍然是否定的。
正式 release、生产部署、公网页面、CDN 缓存和真实 Run / Format,都属于下一层。
所以第三篇不再继续讨论 Translation Engine,也不会重复之前已经写过的 deployment script 设计过程。
只回答最后一个问题:
怎样证明生产环境中的 103 个正式课程页面,真的已经全部变成这一轮经过完整语义审核和 canonical promotion 的 ChatGPT 新译文。
A Tour of Go 多语言翻译项目
本系列完整记录 A Tour of Go 多语言翻译项目从架构设计、整页翻译、结构保护、自动校验,到生产发布与后续维护的实际开发过程。
项目入口:
✅ 在线学习:A Tour of Go 简体中文版
✅ 项目源码:GitHub:shuijingwan/go-tour-i18n
当前第一阶段已完成简体中文版本。项目属于非官方社区多语言翻译项目,与 Go 官方无隶属或授权关系。

发表回复