中文技术写作的受控判准 —— 照做只有一种做法。
技术中文的失败不是「写得不好看」,是两个人照同一句话动手,做出的动作不同。技术中文常见四种毛病:省掉主语、堆叠「的」字、程度词没有基准、条件范围含糊。在散文里它们只是不好读。在照着执行的文档里,它们是事故。模型更糟:它不会停下来问「这句里的『它』指谁」,它会猜,而且每次猜的可能不一样。
这套判准治的是这个。它配一个判定器、一个确定性改写层、一个 pi 强制层,全部只用 Node,无第三方依赖。
| 问题 | 答不出来的样子 |
|---|---|
| 谁动手? | 「确认后通知相关负责人」——谁确认,通知谁 |
| 做几个动作? | 「检查配置并且重启服务」——两步合成一句,失败在哪一步停 |
| 什么时候停? | 「尽快处理」——快了算完,慢了呢 |
一句答不出其中一问,就改。其余规则都由这三问展开。
不是翻译,是原创的中文判准。 这套东西起于航太业的简化技术英语标准 ASD-STE100。它管词的那一层在中文里没有对应物:时态、语态、冠词、875 词受控词典。英文的歧义靠词法形态制造。中文的歧义靠省略主语、「的」字链、无基准的程度词。借用的是设计精神:一个概念一个名字、短句、主动语态。
本项目不含 ASD-STE100 的任何内容,不使用其名称,与 ASD 无关联。
一条命令接线技能与强制层(pi 与 Codex 都装):
bash install.sh只装一个:bash install.sh --pi / bash install.sh --codex。卸载:bash install.sh --uninstall。
任何支持 skills CLI 的 agent:
bunx skills add multing-olo/controlled-chinese| 宿主 | 技能目录 | 强制层 |
|---|---|---|
| pi | ~/.pi/agent/skills/ |
~/.pi/agent/extensions/controlled-chinese.ts |
| Codex | ~/.codex/skills/ |
~/.codex/hooks.json(装完要在 Codex 里跑 /hooks 信任一次,步骤与自查见 docs/codex-trust.md) |
| 其他 | 把 skills/controlled-chinese/ 拷到该 agent 的技能目录 |
无。只有判准与判定器 |
Codex 的钩子声明在 hooks/hooks.json(插件默认路径,Codex 自动发现)。install.sh 另外写一份 ~/.codex/hooks.json,内容相同,改用绝对路径。
在技能目录里执行。改完跑一次,把分数写进交付:
node scripts/zh-lint.ts 草稿.md分数是每百字违规数,越低越干净。每条违规后面跟一条正向处方,不是只说犯了什么。目标:一般模式每百字 2.5 以下,严格模式 1.5 以下,干净的中文技术文本接近 0。
判定器只覆盖机械可判定的那一部分,也就是 AI 味所在的那一部分。名词链改从句、拆超长句这类需要判断的,留给改写者。
5 个中文写作任务 × 2 条件,唯一变量是判准。两个条件都关掉扩展与技能发现,只有系统提示不同。跑法:bash evals/experiment.sh。
| 任务 | 裸基线 | 受控判准 | 变化 |
|---|---|---|---|
| README 引言(限定字数的散文) | 0.58 | 0.54 | −7% |
| 429 错误信息 | 1.81 | 1.14 | −37% |
| PR 描述 | 0.00 | 0.58 | 变差 |
| 解释型回答 | 1.09 | 0.00 | −100% |
| 产品介绍 | 1.61 | 0.84 | −48% |
违规总条数 24 → 11。分类别看,long_sentence 7→1、marketing 5→2、passive 4→0。
没站住的部分(三条,都在 evals/experiment-results.md):
- 本来就干净的任务上它没用还倒扣。PR 描述基线 0.00,受控 0.58。
- 它自己引入了两类新违规。判准强调条件范围和强度词,模型就多写了这两类结构,然后在别处撞上探测器。
- 第一次实验是彻底的空结果。 用「150-250 字、纯散文」这种强约束任务时两个条件没有差异。判断一个写作判准有没有用,任务得先能诱发它要治的毛病。
局限:基线在 0.00 到 1.81 之间,天花板效应明显;5 个任务、1 个模型、每格 1 次运行,方向性的,不是证明。分数只测形式上的 AI 味,它改不了没有事实的段落。
这几条优先于所有风格规则:
- 不删事实
- 不补造原文没有的人名、时限、数值
- 不指向不存在的文件
- 规范强度逐句与原文一致
- 技术串原样保留
- 用户可见文案不带标记
同一个判定器,四个触发点在两个宿主上的落地方式:
| 层 | 干什么 | pi | Codex |
|---|---|---|---|
| 规则卡 | 把三问塞进上下文 | before_agent_start 改 systemPrompt |
UserPromptSubmit 注入 additionalContext |
| 硬门 | 落地的散文先过判定器 | tool_call 拦 write/edit |
PreToolUse 拦 apply_patch/Bash |
| 报分 | 落地即给分 | tool_result 追加一行 |
PostToolUse 注入 additionalContext |
| 上屏前 | 删开场套话与结尾客套 | message_end 替换消息 |
做不了 |
前三层两个宿主等价。第四层只有 pi 有:message_end 能在消息上屏前替换它,Codex 没有对应事件。
Codex 的 Stop 钩子跟 Claude Code 同形:返回 decision: "block" 加 reason,Codex 会自动生成一条新的续写提示。读者会把答案看两遍——这正是原版 skill 花整个 v2 打补丁修的那个问题。所以 Codex 上不做重发,只保留前三层。
Some specialized tool paths can opt out of the default hook path. Treat tool hooks as a useful guardrail, not a complete enforcement boundary.
Multiple matching command hooks for the same event are launched concurrently, so one hook can't prevent another matching hook from starting.
Non-managed hooks must be reviewed and trusted before they run.
换成实操含义:硬门是护栏不是铁门,绕过路径(cp、mv、绕过 apply_patch 的间接写入)不拦;钩子要你手动信任;多个钩子并发,你的钩子拦不住别人的。
skills/controlled-chinese/ 技能本体(Codex 插件与各 agent 共用这个目录)
SKILL.md references/ scripts/ agents/openai.yaml
hooks/ Codex 强制层(hooks.json + 三个钩子)
pi/ pi 强制层
.codex-plugin/plugin.json Codex 插件清单
.claude-plugin/ 通用插件清单
install.sh pi 与 Codex 的接线脚本
scripts/ 是词库与判据的唯一来源,两个宿主的强制层都从这里加载,没有第二份。
node evals/run.ts # 15 条回归用例:干净样本必须 0 分
node evals/gate.test.ts # 21 条落门断言
node evals/fix.test.ts # 11 条改写断言
node evals/codex.test.ts # 25 条 Codex 断言:patch 解析 + 三个钩子的真实 stdin/stdout合计 72 条断言,CI 在 Node 22 / 24 / 26 上跑全部四套。
MIT。词库存在 scripts/zh-lint.ts 里,那是唯一来源。要增删词,改那里。