Files
2026Technology-Competition/docs/superpowers/plans/2026-08-24-language-consistency.md
T
lhl 1925ef7239 feat(writer): 章级管道重试兜底 + 表格 caption 语言检查 + 文档收尾
#1/#2 真实 LLM 随机方差兜底:orchestrator.generate 新增 chapter_attempts(默认 3),
单章 WriterGenerationError 不连坐整次 run,重试耗尽才抛错(不吞错)。新增
tests/test_orchestrator_retry.py(前 N 次失败后恢复 / 耗尽仍抛错)。

#3 表格 caption 语言检查:find_language_violations 现检 table.caption(生成正文需跟随
输出语言),rows/headers 仍照抄源不检;QA 维度经 ChapterArtifact.blocks=(type,text,caption)
同步生效。修复真实 zh 输出中表格说明引用日文源表名绕过强制的问题。

文档收尾:README 新增 --output-language/中文模板用法;design.md §6.2.1 输出语言控制、
§7.2 校验清单 10→11 项;计划验收勾选;.gitignore 加 .opencode/。
全量 pytest 431 passed / 99.15%
2026-08-26 00:49:36 +08:00

13 KiB
Raw Blame History

输出语言一致性保障 + 用户可选输出语言(2026-08-24)

背景

真实 LLM 试运行暴露:生成正文曾出现中日混杂(早期第 1-2 章中文、第 3-7 章日文;prompt 渲染缺陷 修复后全日文,但属概率性改善)。盘点确认:

  1. 唯一保障是 prompt 层【语言约束】,无任何程序化检测(grep 全代码库证实)
  2. 输入侧存在中文诱导源_format_impact() 固定标签(受影响:[警告])进入每章 prompt
  3. design.md §7.2 QA 十项清单没有语言一致性校验项
  4. 日文章标题多为纯汉字(「5. DB設計」无假名),仅凭标题无法判定期望语言

用户需求升级:让用户可选择输出中文还是日文(参数化),并配套中文模板。

关键用户决策(已确认)

# 决策点 结论
1 Excel 表格数据是否翻译 照抄原文——数据是源数据忠实呈现,翻译违反 §7.2 内容准确性/可追溯性
2 子节标题语言 双模板方案——提供中文/日文两套模板,按用户选择使用;锚点 id 语言中立不变
3 违规处理 重试耗尽后硬失败WriterGenerationError),与既有失败语义一致
4 实施范围 A(强制校验)+ B(impact 标签本地化)+ C(QA 第 11 维度)+ 参数贯通,全做

核心设计:模板 × 语言参数 双轨制

中文输出 → samples/概要设计书模板_中文.docx(新建镜像)+ --output-language zh
日文输出 → 既有日文模板 + --output-language ja(或不传,走 auto
日文模板(现状) 中文模板(新增镜像)
H1/H2 标题 1. はじめに / 2.1 機能一覧表 1. 前言 / 2.1 功能一览表
锚点 id section:function_list 完全相同(不变) → 映射/注入器零改动
封面 概要設計書 / バージョン 概要设计书 / 版本

实施清单(TDD,每项先 RED 后 GREEN

0. 中文样本模板

  • 新建 scripts/make_zh_template.pypython-docx 镜像日文模板结构 Title/H1×7/H2×6/锚点原样/封面字段),产出 samples/概要设计书模板_中文.docx 入库
  • 测试:解析 zh 模板断言 7 章 anchor id 与 ja 模板逐一对应

1. 语言参数贯通

  • config.py:新增 WriterConfig(output_language: "auto"|"zh"|"ja" = "auto")Settings.writer
  • models.pyGenerationContext.output_language 字段;to_vars() 输出动态 {{language_instruction}}(zh=必须使用中文撰写 / ja=必須日本語で記述 / auto=与标题一致)
  • writer_agent.py:【语言约束】段落改引该变量
  • context_builder.py / orchestrator.py / run_trial.py--output-language {auto,zh,ja} 逐层透传

A. 确定性脚本检测 + 失败重试【核心】

  • 新建 src/genesis/writer/language.py
    • detect_script(text):含假名(U+304030FF)→ "ja"CJK 汉字零假名 → "zh";否则 None
    • resolve_expected_language(explicit, title, fallback_texts):显式 > 标题假名 > 规则文档主导脚本; 单一事实来源(A 的重试校验与 C 的 QA 维度共用)
    • violations(...):仅检 paragraph/note/list 正文块;表格 rows 不检(照抄原文)、heading 不检(跟随模板); 违规判定 = 含 CJK 汉字零假名且长度 ≥12(防误杀短术语)
  • writer_agent.pygenerate_chapter 重试循环内后置校验,违规按生成失败重试; max_retries 默认 1→2(现默认无重试机会,已确认既有测试均显式传参)

B. _format_impact() 标签本地化

  • output_language 选标签集(zh=受影响 / ja=影響;auto 默认 ja);只影响 prompt 变量, 不影响 impact-report.json 独立产物

C. QA 第 11 维度 language_consistency

  • ChapterArtifact.expected_language: str = ""(上层解析后传入,scorer 不自行推导)
  • qa/validator.py 从 orchestrator 透传期望语言;歧义记 unverifiable 计入 detail
  • DEFAULT_THRESHOLDS["language_consistency"] = 1.0
  • ⚠️ 已识别风险:新维度改变 score() 总分均值,test_eval_scorer.py / test_phase5_scorer.py 具体分数断言需同步修正(诚实集成,不做旁路方法)

验收标准

# 中文概要设计书
python scripts/run_trial.py --template samples/概要设计书模板_中文.docx --output-language zh
# → 正文全中文、表格照抄日文原文、零中日混杂段落(程序化保证)

# 日文(现状默认,行为不变)
python scripts/run_trial.py
  1. 全量 pytest ≥99% 覆盖率(当前基线 389 passed / 99.04%
  2. 真实 LLM 双跑(zh/ja 各一次)+ 扫描脚本确认 output.docx 无违规件
  3. 提交 commit + 追加 _AI_USAGE_LOG.md

涉及文件

  • 新增:scripts/make_zh_template.pysamples/概要设计书模板_中文.docxsrc/genesis/writer/language.pytests/test_writer_language.py
  • 修改:config.pywriter/models.pywriter/writer_agent.pywriter/context_builder.pywriter/orchestrator.pyeval/scorer.pyqa/validator.pyscripts/run_trial.py
  • 测试更新:tests/test_phase5_writer_agent.pytests/test_phase5_models.pytests/test_eval_scorer.pytests/test_phase5_scorer.pytests/test_run_trial.py

状态

  • 计划已获用户批准(等待二次确认开工)
  • 计划评审(2026-08-24,对照真实代码逐条核验,见下节)
  • 步骤 0-3 实施
  • 验收

验收记录(2026-08-25,含真实 LLM 双跑)

  • pytest 全量:425 passed / 99.15%(覆盖率门槛 99% 达标)
  • Fake 模式双模板试运行:zh 模板 + --output-language zh → 7 章 docxja 模板默认 → 7 章 docx,均无崩溃
  • 真实 LLM 双跑(2026-08-26.env 已配 key
    • --template 概要设计书模板_中文.docx --output-language zh → 7 章 ✓,无强制硬失败
    • ja 模板默认(auto)→ 首次在 function_list 硬失败(期望 zhBUG),修复 fallback 后重跑成功 7 章 ✓
  • 程序化扫描真实输出
    • zh_real.docx48 非空段落,1 处含假名 = 表5-1 表格说明段落(中文句式 + 引用日文源表名 訂単テーブル/即時行情テーブル)→ 属"表格照抄原文"范畴,判定可接受
    • ja_real.docx:47 非空段落,1 处纯汉字 ≥12 = 封面字段「作成日: 2026-08-26」(模板元数据,非正文)→ 误报
    • 结论:两输出均无中日混杂正文缺陷;检测器按设计排除 table/heading 与封面元数据
  • 真实试运行暴露并修复的 BUGauto 模式 fallback 误用 impact/data 源数据(含中文元素名 止损风控 等 + 汉字标签无假名)→ 把日文文档误判期望 zh → 硬失败。修复:fallback 改用 write_rules/design_rules(规则文档,日文含假名),并加回归测试 test_generate_chapter_auto_with_ja_rules_but_chinese_source_data_enforces_ja
  • 约束链路单测覆盖:writer 重试/硬失败、QA 第 11 维度、validator 透传、qa_loop 透传
  • ⚠️ 说明:ja 真实跑曾出现一次 function_list 随机性硬失败(LLM 单次输出疑似纯汉字段落),重跑即成功 → LLM 输出方差,强制机制按设计重试/硬失败,非确定性缺陷

实施进度(2026-08-25 暂停于步骤 A 修正点)

已完成

  • 步骤 0(中文模板)scripts/make_zh_template.py + samples/概要设计书模板_中文.docx(已生成入库)+ tests/test_zh_template.py4 passed)。锚点 id 与 ja 模板逐一对应、译文正确。
  • 步骤 1(参数贯通)config.py 新增 WriterConfig.output_languageSettings.writerGenerationContext.output_language+to_vars().language_instructionzh/ja/auto 三档);writer_agent.py【语言约束】改引 {{language_instruction}}context_builder.build_contexts 透传;orchestrator.generateoutput_language 参数;run_trial.py--output-languagetests/test_language_plumbing.py5 passed)。
  • 步骤 A(检测+强制)部分src/genesis/writer/language.py 已建(detect_script/has_kana/has_cjk/resolve_expected_language/find_language_violations);writer_agent.generate_chapter 已接入期望语言推导 + 违规重试 + max_retries 默认 1→2。tests/test_writer_language.py 多数通过。

待修正(暂停点)

  • language.pyresolve_expected_language 逻辑需修正:当前实现在标题为纯汉字(如「DB 設計」,无假名)时 detect_script 返回 "zh",导致标题被误当作可靠信号、fallback 失效。 依据计划「显式 > 标题假名 > 规则文档主导脚本」,标题**仅当含假名(detect=="ja"**才可信;纯汉字标题对中/日均可能,应跳过、改看 fallback。 修正:将 resolve_expected_language 中标题分支改为 if detect_script(title) == "ja": return "ja"(不再用纯汉字标题推导 zh),随后才遍历 fallback_texts,最后返回 ""。
  • 修正后重跑 tests/test_writer_language.py 应全绿(已有 2 个用例因该逻辑失败:test_resolve_falls_back_to_fallback_texttest_resolve_unverifiable_when_no_hint)。

后续(未动)

  • 步骤 A 通过后→ 步骤 B_format_impact 标签本地化已预埋参数,待补 zh 标签集使其与 ja 实际不同 + 补测试)。
  • 步骤 CQA 第 11 维度 language_consistency + ChapterArtifact.expected_language + validator.validate_doc(expected_language=None) + DEFAULT_THRESHOLDS 加项 + 同步修正 test_eval_scorer.py/test_phase5_scorer.py 总分断言(按评审 R1:不可验证=满分 1.0)。
  • 验收:全量 pytest ≥99% + zh/ja 双真实试运行 + 提交 + _AI_USAGE_LOG.md 追加。

已落盘但未提交

  • 上述步骤 0/1/A 的源码与测试改动尚未 git commit(暂停前未提交)。

评审记录(2026-08-24

核验通过的关键假设

  1. config.py 为 pydantic-settings + extra="ignore",新增 Settings.writer 字段无 yaml 时取默认值,零风险
  2. 中文模板锚点 idsection:introduction/function_list/screen_list/report_list/db_design/if_definition/batch_list)已从真实日文模板解析确认,镜像后映射/注入器零改动
  3. _format_impact 无测试断言"受影响"字样,标签本地化安全;[新規]/[変更]/[削除]/[警告] 中日通用保留
  4. WriterAgent.max_retries 既有测试均显式传参(2 或 1),默认值 1→2 不破坏测试
  5. prompt 段落名【语言约束】保留、内容改引变量 → 既有模板断言兼容

评审修正(2 处)

# 原计划 修正后 依据
R1 C 维度"歧义记 unverifiable 跳过" 不可验证 = 满分通过(score 1.0),维度恒参与均值;detail 注明 "unverifiable" 实测 test_eval_scorer.py L154 / test_phase5_scorer.py L82 断言 total_score == 1.0——若跳过维度或给非满分,既有用例总分断言即破裂;恒定维度数 + 满分兜底可让多数既有断言不变
R2 ChapterArtifact.title: str = ""expected_language 两版表述并存 统一为 仅加 expected_language: str = ""scorer 完全不自行推导 单一事实来源原则,避免 scorer 内再出现一套标题猜测逻辑

评审补充(3 处说明)

# 说明
N1 validate_doc 增加可选 kwarg expected_language=Noneqa_loop.py L55/L69 与 test_phase5_report/test_phase5_validator 共 4 处调用方零破坏);None 时该章按 unverifiable=满分处理
N2 max_retries 默认 2 后,orchestrator.py L72 与 qa_loop.py L28 两处真实管线在失败时会多一次 LLM 调用——与 QALoopController 外层循环叠加的成本上界 = 章 × 2 × QA轮次,可接受;实施时在 WriterAgent docstring 标注
N3 运维注意事项写入 README/计划:zh 场景规则文档仍为日文 → auto 回落会判 ja,中文输出必须显式 --output-language zh

遗留风险(接受)

  • auto 模式对纯汉字日文正式文档(无假名标题+无假名规则)无法证明语言——保守跳过强制,由 C 维度报告层呈现 unverifiable

后续收尾(2026-08-26

  • #1/#2 章级管道重试orchestrator.generate 新增 chapter_attempts(默认 3),单章 WriterGenerationError 不连坐整次 run,重试耗尽才抛错(不吞错)。真实 LLM 随机方差兜底。
  • #3 表格 caption 语言检查find_language_violations 现检 table 的 caption(生成正文需跟随 输出语言);rows/headers 仍不检(照抄源)。QA 维度通过 ChapterArtifact.blocks=(type,text,caption) 同步生效。修复真实 zh 输出中"表5-1 表格说明引用日文源表名"绕过强制的问题。
  • 文档收尾:README 新增 --output-language 与中文模板用法;design.md §6.2.1/§7.2 同步(11 项校验); .gitignore 加入 .opencode/