DeepSeek Harness 中英文档怎么防漂:1078 组配对与 blob hash 校验
维护双语文档的人都知道那种漂移:英文侧改了一句,中文侧忘了跟,过三个月两边说的已经不是同一件事了,而且没人知道是哪一次改动开始分的岔。
deepseek-harness 这个仓库把这件事做成了机器能判的东西。截至我们采集的 2026-08-16、快照 47f9438,我们按 git ls-files 数出仓库里追踪了 1078 个 .i18n.yaml 和 1078 个 .zh.md;.md 文件总共 2355 个,去掉 .zh.md 之后是 1277 个。也就是说,这个仓库里绝大部分英文文档都挂着一个中文兄弟,以及一个专门用来记录”这两个当时确认过一致”的第三个文件。
先说清楚前提:这个仓库建立于 2026-08-13,我们采集时距建仓只有三天;根 package.json 里的版本是 0.1.0-rc.5,GitHub Releases 一个都没有,README 自述处于”开发者预览”阶段并明写”未来将出现破坏兼容性的变更”。下面提到的命令、文件路径与机制随时可能变。我们也没有安装、没有构建、没有运行过这个项目的任何一条命令,本文全部来自对快照文件的实读。
一对文档是三个文件
契约写在 docs/i18n/README.md,全文 61 行。其中 :10 的原话是”A pair is three sibling files.”——英文 foo.md、中文 foo.zh.md、一致性记录 foo.i18n.yaml,三个文件放同一个目录。这一句后面还跟了一串明确的否定:不要 locale 目录、不要独立的翻译仓库、不要中英交错写在一个文件里。
更前面一条是 :9:“Both languages carry equal authority.”两种语言地位对等,一份中文先写就的 Agent Note 和英文先写就的一样合法,谁也不是谁的附属品。
.i18n.yaml 长什么样?仓库根目录那份 README.i18n.yaml 是最短的例子,文件头四行注释加正文两行:
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write README.md
README.md: 8a4bd01332a23ce4144c661784bc549e0ba72d21
README.zh.md: b7bc214bfb1fd8a76a47de3f0aa242122aeb7603
正文就两行,各记一侧的 git blob hash。注释里那句 “as of the last confirmed-consistent state” 是这套机制的全部含义:它记的不是”这两份文件对不对”,而是”上一次人确认过它们说的是同一件事时,两边的内容分别是这个样子”。
为什么是 blob hash,不是 commit hash
这是我们觉得最值得抄的一个决定,理由写在 docs/i18n/README.md:11-18。
用 commit hash 的话,你没法给一次还没提交的改动记录状态——同一个 PR 里刚改完英文,中文还在工作区,commit 都还没有。而 blob hash 是对文件内容算的,git hash-object foo.md 随时能算,所以一致性变成了纯粹的内容比较,与提交历史无关。
同一段还写了 --write 的另一半动作:它会把这两份快照写进本地 Git 对象库,并把每个不同的 blob 钉在 refs/dsh/translation-pairing/snapshots/ 下面的 ref 上,理由原文是”避免垃圾回收让已记录的恢复指针失效”。这一步的意思是,.i18n.yaml 里那两串 hash 不只是校验用的指纹,还是能真正取回”上次确认一致时的原文”的指针——两边漂了之后,可以拿旧文本做最小 diff 去补另一侧,而不是整篇重译。
我们自己按这个口径算了一遍
blob hash 的算法是公开的:sha1("blob " + 字节长度 + "\0" + 文件内容)。我们写了个 Python 脚本,把这 1078 个 .i18n.yaml 里的每一条记录都取出来,找到对应文件,按上面这个公式现算一遍,再和记录里的值比。
结果是:2156 条 hash 记录(1078 组各两条),目标文件缺失 0 条,记录值与现算值不一致 0 条。
要说明的是,这是我们在快照上按 Git 的 blob hash 定义自己复算的结果,不是跑了这个项目的校验脚本——我们没有运行过 pnpm run verify-translation-pairing,也没有跑过仓库里任何一个 gate。所以”这 2156 条内容指纹全部对得上”是可以确认的,“这个 gate 会判绿”则是我们没有依据说的话。
hash 对上只是第一层
只比内容 hash 显然不够,因为 hash 只能告诉你”文件没被改过”,不能告诉你两边结构是不是还对得上。契约里另外两条补的就是这个。
docs/i18n/README.md:21 规定了语言切换器的固定格式:中文侧写 [English](foo.md) | 中文,英文侧写 English | [中文](foo.zh.md)。:22 规定结构镜像:标题深度与顺序、列表种类、有序列表的起始编号、列表项数量、表格的行数列数、链接目标、逐字代码块,都要一一对应。
执行体是 scripts/verify-translation-pairing.ts。我们读到的几段分别是::220-231 做 blob hash 比对、:248-252 比对生成区、:258-263 检查语言切换器、:264-269 比对结构签名。docs/i18n/README.md:29 给出的是 gate 的三条判据。
顺带一个量级参考:我们把根 package.json 的 scripts 解出来数了一下,一共 123 条,其中 verify- 开头的有 37 条。这套双语校验只是这 37 条里的一条。
底下还垫着一层:换行符
.gitattributes 只有 13 行,第 7 行是 * text=auto eol=lf。文件头 :1-3 的注释给出的理由值得抄下来:仓库的规范文本形态是 LF,且在 checkout 时也强制,这样工作区和仓库之间没有转换边界,“byte-level gates(verify-* 比较、blob hashing、coverage offsets)在每一台主机上看到的都是同一种形态”。
同一层意思在编辑器侧还有一份:.editorconfig 只有 8 行,里面写着 end_of_line = lf 与 insert_final_newline = true。两份配置分别管住 Git 的进出与编辑器的落盘,指向的是同一个结果——同一份文件在任何一台机器上都是同一串字节。
这条对 Windows 侧的读者尤其值得留意——不是我们的推断,是这个文件自己写下的理由:blob hash 是对字节算的,而字节形态要在所有主机上一致,这套校验才有意义。换行符要是在 checkout 时被改写,hash 就会跟着变,.i18n.yaml 里记的那两串值也就失去了参照。
.gitattributes 的最后一行(:13)是另一件事:*.i18n.yaml merge=dsh-translation-pairing。也就是说这类记录文件的合并交给了一个自定义 merge driver 而不是 Git 的默认文本合并。装这个 driver 的动作藏在 package.json:142 的 postinstall 里:node scripts/install-lefthook.mjs——docs/development.md:24 写明这个脚本会配置 worktree 本地的 Lefthook hooks 和 dsh-translation-pairing 这个 git merge driver。冲突善后另有一条脚本,在 package.json:86,叫 resolve-translation-pairing-conflicts。
这个 gate 自己承认管不到什么
docs/i18n/README.md:40 有一句写得非常直白,我们逐字抄过来:
a green gate means the pair was confirmed consistent at these exact contents, not that the confirmation was sound.
绿灯只意味着”这一对在这些确切内容上被确认过一致”,不意味着”那次确认本身是对的”。hash 和结构签名都是机械判据,一篇翻得很糟的中文,只要重新 --write 记录一次,照样能过 gate。项目把这一半明确划给了人工评审。
一处口径差异,只陈述位置
顺着这套机制往下翻,会碰到一处值得记下来的差异,写的时候我们只说两处位置各是什么,不推断原因。
英文 README.md:39-41 的社区渠道段落是三条:GitHub Discussions、dsh-plugin topic、Discord。中文 README.zh.md:39-41 前两条相同,第三条换成了企业微信群,并且在 :43-58 多出一个 HTML <table>,里面有三张二维码图片(assets/ 下确实存在这三个 png)。也就是英文侧不提企微、中文侧不提 Discord。相关背景记在 .agents/notes/implemented/process/2026-07-22-product-first-root-readme.md:19,写的是两侧社区段落各自指向该语言受众的主要渠道。
需要诚实标注的是:docs/i18n/README.md:22 与 :29 都声明结构签名会比对”表格行数与列数”,而这一对 README 的表格数量并不对等。我们没有运行过这个 gate,也没有查清 scripts/verify-translation-pairing.ts 的结构签名是怎么处理 HTML <table> 的——那不是 GFM 表格语法。我们能确认的只有一件事:README.i18n.yaml 里记的两个 blob hash 与这两份文件当前的内容完全吻合,这是我们实算过的。说到这里就停。
另一处相关的观察在 apps/cli/reference/README.md:72,英文侧原文里夹着一个中文词:Select 极简模式 when creating a Web session;。这个词是随包 agent preset 的显示名,定义在 apps/cli/config/agent-presets/minimal/preset.yml 的 name 字段(该目录下四个 preset 的名字分别是”标准模式""PTC 模式""极简模式""创造模式”);中文侧 apps/cli/reference/README.zh.md:72 写的是”请选择极简模式”。
这套做法能拿走什么
如果你也在维护双语文档,这个仓库里可复用的其实是三个很小的决定,跟它用什么框架、跑不跑得起来都没关系:
一是把”确认过一致”这件事变成一个可 review 的文件改动。.i18n.yaml 那两行 hash 的 diff 本身就是”我确认过”的签名动作,它会出现在 PR 里,而不是停留在某个人的记忆里。
二是用内容指纹而不是提交指纹。同一个 PR 内改的文件也能算,一致性判断和提交历史彻底解耦。
三是把 gate 的能力边界写在文档里。:40 那句话把”机器能判什么、人要判什么”划得很清楚,这比声称”我们有自动化保证翻译质量”要诚实得多。
这三条是我们从这个仓库的文件里读出来的做法,是否适合你的项目、要不要照搬,取决于你自己的场景,我们没有依据替你判断。
延伸阅读
- 从头读起:DeepSeek Harness 是什么:建仓三天、13 万 star 的 Agent 框架
- 本专题共 45 篇,完整分组目录见专题页
- DeepSeek Harness 的 —host 0.0.0.0:笔记说已实现,代码直接报错
- DeepSeek Harness 为什么要七份 vitest 配置:测试分层怎么切的
本文依据 DeepSeek Harness 官方仓库(github.com/deepseek-ai/deepseek-harness)的 README、docs/ 下的
架构与子系统文档、以及 packages/ 下的源码整理,核对日 2026-08-16,对应仓库快照 47f9438(版本 0.1.0-rc.5)。
本文内容为仓库源码与文档口径,我们没有安装、也没有运行过这个项目,
因此不涉及界面外观、操作手感与运行速度的任何描述。
该仓库建立于 2026-08-13,README 自述处于开发者预览阶段并明确说明未来会有破坏兼容性的变更,
文中出现的命令、配置与默认值随时可能变动,请以仓库最新内容为准。