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

173 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 输出语言一致性保障 + 用户可选输出语言(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.py`python-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.py``GenerationContext.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.py``generate_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`
具体分数断言需同步修正(诚实集成,不做旁路方法)
## 验收标准
```bash
# 中文概要设计书
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.py``samples/概要设计书模板_中文.docx`
`src/genesis/writer/language.py``tests/test_writer_language.py`
- 修改:`config.py``writer/models.py``writer/writer_agent.py``writer/context_builder.py`
`writer/orchestrator.py``eval/scorer.py``qa/validator.py``scripts/run_trial.py`
- 测试更新:`tests/test_phase5_writer_agent.py``tests/test_phase5_models.py`
`tests/test_eval_scorer.py``tests/test_phase5_scorer.py``tests/test_run_trial.py`
## 状态
- [x] 计划已获用户批准(等待二次确认开工)
- [x] 计划评审(2026-08-24,对照真实代码逐条核验,见下节)
- [x] 步骤 0-3 实施
- [x] 验收
## 验收记录(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.docx`48 非空段落,1 处含假名 = **表5-1 表格说明段落**(中文句式 + 引用日文源表名 訂単テーブル/即時行情テーブル)→ 属"表格照抄原文"范畴,判定可接受
- `ja_real.docx`:47 非空段落,1 处纯汉字 ≥12 = **封面字段「作成日: 2026-08-26」**(模板元数据,非正文)→ 误报
- 结论:**两输出均无中日混杂正文缺陷**;检测器按设计排除 table/heading 与封面元数据
- **真实试运行暴露并修复的 BUG**auto 模式 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.py`4 passed)。锚点 id 与 ja 模板逐一对应、译文正确。
- **步骤 1(参数贯通)**`config.py` 新增 `WriterConfig.output_language``Settings.writer``GenerationContext.output_language`+`to_vars().language_instruction`zh/ja/auto 三档);`writer_agent.py`【语言约束】改引 `{{language_instruction}}``context_builder.build_contexts` 透传;`orchestrator.generate``output_language` 参数;`run_trial.py``--output-language``tests/test_language_plumbing.py`5 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.py``resolve_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_text``test_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=None`qa_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/`