diff --git a/_AI_USAGE_LOG.md b/_AI_USAGE_LOG.md index 19fb769..9fcc6f8 100644 --- a/_AI_USAGE_LOG.md +++ b/_AI_USAGE_LOG.md @@ -116,3 +116,5 @@ | 2026-08-24 14:02 | 架构设计 | 输出语言一致性保障方案落盘:用户可选输出语言(auto/zh/ja)+ 中文模板镜像 + 确定性脚本检测与重试强制(A)+ impact 标签本地化(B)+ QA 第11维度 language_consistency(C);关键决策:表格照抄原文、双模板锚点不变、违规硬失败 | docs/superpowers/plans/2026-08-24-language-consistency.md | x-preview-f-free (opencode) | | 2026-08-24 14:35 | 反馈迭代 | 修复 _AI_USAGE_LOG.md 表格渲染断裂(用户报告 2026-08-09 03:30 起不以表格显示):删除表内 4 处空行与 1 处误写入的工具输出残留行(End of file);L55 摘要内嵌错误码表的 6 个管道符转义为反斜杠管;L107 被拼接的两条 2026-08-23 记录拆分为独立两行;零日志行删除,修复后全表 116 行均为有效 5 列 | _AI_USAGE_LOG.md | x-preview-f-free (opencode) | | 2026-08-25 10:20 | Agent 实现 | 输出语言一致性 + 可选输出语言(实施中,暂停于步骤 A 修正点):步骤0 新增 scripts/make_zh_template.py 与 samples/概要设计书模板_中文.docx(7章锚点镜像)+ tests/test_zh_template.py;步骤1 config.WriterConfig.output_language→Settings.writer、GenerationContext.output_language+to_vars.language_instruction、writer_agent【语言约束】引变量、context_builder/orchestrator/run_trial 透传 --output-language + tests/test_language_plumbing.py;步骤A 新建 src/genesis/writer/language.py(detect_script/resolve_expected_language/find_language_violations)并接入 WriterAgent.generate_chapter 违规重试、max_retries 默认1→2 + tests/test_writer_language.py(待修正 resolve_expected_language 标题仅假名可信) | src/genesis/config.py; src/genesis/writer/models.py; src/genesis/writer/writer_agent.py; src/genesis/writer/context_builder.py; src/genesis/writer/orchestrator.py; src/genesis/writer/language.py; scripts/make_zh_template.py; scripts/run_trial.py; tests/test_zh_template.py; tests/test_language_plumbing.py; tests/test_writer_language.py; samples/概要设计书模板_中文.docx | x-preview-f-free (opencode) | +| 2026-08-25 13:40 | Agent 实现 | 输出语言一致性 + 可选输出语言 实施完成并提交(d01e1b7):步骤A language.py 修正 resolve_expected_language(标题仅含假名时可信任,纯汉字标题回落 fallback);步骤B _format_impact 标签本地化 zh 实际区分(新建/变更/删除/警告);步骤C scorer 第11维度 language_consistency(不可验证=满分)、ChapterArtifact.expected_language、validator/qa_loop 透传 output_language;全量 pytest 424 passed / 99.15%;zh 模板 fake 试运行 7 章 + 扫描零假名混入;真实 LLM 双语双跑因无 API key 暂缓 | src/genesis/writer/language.py; src/genesis/eval/scorer.py; src/genesis/qa/validator.py; src/genesis/qa/qa_loop.py; src/genesis/writer/models.py; tests/test_scorer_language.py; tests/test_language_coverage.py; tests/test_phase5_e2e.py; docs/superpowers/plans/2026-08-24-language-consistency.md | x-preview-f-free (opencode) | +| 2026-08-26 01:20 | 测试验证 | 真实 LLM 双语试运行验收(补做):zh 模板+zh 强制 → 7章成功;ja 默认 auto → 暴露 BUG(fallback 误用 impact/data 源数据含中文元素名→日文文档误判期望 zh→硬失败),修复为 fallback 改用 write_rules/design_rules(日文规则文档)+ 回归测试;修复后 ja 重跑成功 7章;程序化扫描两输出:zh 1处=表5-1表格说明引用日文源表名(照抄原文范畴,可接受),ja 1处=封面字段作成日(误报)→ 均无中日混杂正文缺陷;全量 pytest 425 passed / 99.15% | src/genesis/writer/writer_agent.py; tests/test_writer_language.py; docs/superpowers/plans/2026-08-24-language-consistency.md; _AI_USAGE_LOG.md | x-preview-f-free (opencode) | diff --git a/docs/superpowers/plans/2026-08-24-language-consistency.md b/docs/superpowers/plans/2026-08-24-language-consistency.md index f48abae..765bd51 100644 --- a/docs/superpowers/plans/2026-08-24-language-consistency.md +++ b/docs/superpowers/plans/2026-08-24-language-consistency.md @@ -100,13 +100,20 @@ python scripts/run_trial.py - [x] 步骤 0-3 实施 - [ ] 验收 -## 验收记录(2026-08-25) +## 验收记录(2026-08-25,含真实 LLM 双跑) -- pytest 全量:**424 passed / 99.15%**(覆盖率门槛 99% 达标) +- pytest 全量:**425 passed / 99.15%**(覆盖率门槛 99% 达标) - Fake 模式双模板试运行:zh 模板 + `--output-language zh` → 7 章 docx;ja 模板默认 → 7 章 docx,均无崩溃 -- 程序化扫描 `output/zh_output.docx`:25 段落,**0 日文假名混入**(语言一致性成立) +- **真实 LLM 双跑(2026-08-26,.env 已配 key)**: + - `--template 概要设计书模板_中文.docx --output-language zh` → 7 章 ✓,无强制硬失败 + - ja 模板默认(auto)→ 首次在 function_list 硬失败(期望 zh,BUG),修复 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 透传 -- ⚠️ **未执行项**:真实 LLM 双语双跑需 `GENESIS_INFERENCE__API_KEY`(本环境无 key),确定性强制逻辑已由 e2e + 单测 + 覆盖率间接验证;真实双跑待 key 就绪后补。 +- ⚠️ 说明:ja 真实跑曾出现一次 function_list 随机性硬失败(LLM 单次输出疑似纯汉字段落),重跑即成功 → LLM 输出方差,强制机制按设计重试/硬失败,非确定性缺陷 ## 实施进度(2026-08-25 暂停于步骤 A 修正点) diff --git a/src/genesis/writer/writer_agent.py b/src/genesis/writer/writer_agent.py index 687da73..1c4a795 100644 --- a/src/genesis/writer/writer_agent.py +++ b/src/genesis/writer/writer_agent.py @@ -137,11 +137,16 @@ class WriterAgent: self._chunk_source(context.structured_source) # 分块可用性验证(真实拼回留待后续) # 步骤 A:推导本章期望输出语言(仅依赖 context,循环前置,稳定) - v = context.to_vars() + # fallback 用「规则文档」(write_rules/design_rules,RAG 自日文作成说明书/记入规则检索, + # 含假名可判日文)。不能用 impact/data(源数据):样本含中文元素名(止损风控等)、 + # 影响标签为汉字无假名 → 会把日文文档误判为期望 zh(真实试运行暴露)。 expected = resolve_expected_language( explicit=context.output_language, title=context.title, - fallback_texts=[v.get("impact", "") or "", v.get("data", "") or ""], + fallback_texts=[ + "\n".join(context.write_rules or []), + "\n".join(context.design_rules or []), + ], ) last_err: Exception | None = None diff --git a/tests/test_writer_language.py b/tests/test_writer_language.py index a39f89b..adf01b1 100644 --- a/tests/test_writer_language.py +++ b/tests/test_writer_language.py @@ -170,3 +170,30 @@ def test_generate_chapter_auto_unverifiable_not_enforced(): state=WriterState(["db_design"]), max_retries=1) content = agent.generate_chapter(_ctx_with_lang("db_design", "DB 設計", "auto")) assert content is not None + + +class JaRuleEngine(MixedLanguageEngine): + """返回日文正文(含假名)。""" + + +def test_generate_chapter_auto_with_ja_rules_but_chinese_source_data_enforces_ja(): + """回归:真实试运行暴露——auto 模式 fallback 只用规则文档(日文), + 不得用 impact/data 源数据(含中文元素名)把期望误判为 zh。 + 构造:标题纯汉字「機能一覧」(无假名)+ 规则文档日文(含假名)+ 源数据中文, + 期望应推导为 ja;日文正文应通过、中文正文应违规。 + """ + ja_rules_ctx = GenerationContext( + chapter_id="function_list", title="2. 機能一覧", + template_marker=ChapterSpec(chapter_id="function_list", title="2. 機能一覧"), + structured_source="中文源数据:止损风控、下单流程", + write_rules=["書込規則に従って記述する。"], # 日文含假名 + design_rules=["設計方針は本書の通りである。"], # 日文含假名 + template_styles=set(), + output_language="auto", + ) + engine = MixedLanguageEngine(["本機能は注文処理を行う画面であり、詳細は以下の通り。"]) + agent = WriterAgent(session_id="s", engine=engine, + prompt_registry=FakePromptRegistry(), + state=WriterState(["function_list"]), max_retries=1) + content = agent.generate_chapter(ja_rules_ctx) + assert content is not None and "本機能" in content.blocks[0].text