docs(design): add Phase 5 Writer/QA subsystem section

This commit is contained in:
lhl
2026-08-13 11:36:08 +08:00
parent 64c271a22c
commit 7368626de6
+71
View File
@@ -17,6 +17,7 @@
9. [数据模型与 Provenance 层](#9-数据模型与-provenance-层)
10. [异常处理策略](#10-异常处理策略)
11. [通信语言与文档规范](#11-通信语言与文档规范)
12. [Phase 5Writer / QA 子系统](#12-phase-5writer--qa-子系统)
---
@@ -1710,3 +1711,73 @@ Step 3(关联推理)中部分功能推理失败:
- 不得将客户数据、公司信息上传至外部公开仓库
- API Key 配置在环境变量或配置文件中,不得硬编码在源码
- 确认所有依赖的许可证类型,禁止使用盗版软件
---
## 12. Phase 5Writer / QA 子系统
> 本章记录在 phase5/writer-qa 分支上落地的「Writer / QA 子系统」实现,作为设计 §6(Writer Agent 详细设计)与 §7(QA Agent 详细设计)的工程落地补充。实现严格遵循设计基线,并诚实标注了范围边界与推后项。
### 12.1 目标与范围
**目标**:打通「结构化源 → 单章内容生成 → 渲染 → 注入 Word 模板 → QA 校验 → 闭环仅重失败章」的最小可用链路。
**范围内**
- 单章内容生成(WriterAgent 调用 InferenceEngine 产出 `ChapterContent`)。
- 内容块渲染(`render_chapter_blocks``ChapterContent``Block` 序列)。
- Word 注入(`DocxInjector.inject` 将章节内容写入模板对应 `{{section:id}}` 占位符)。
- QA 校验(确定性维度:`traceability` / `placeholder_residue` / `chapter_completeness`)。
- QA 闭环(`QALoop` 仅对失败章重新生成,受 `QALoopController(DEFAULT_MAX_QA_ROUNDS=3)` 约束)。
**范围外(诚实标注)**
- **语义 QA 为探针**:内容准确性 / 幻觉检测 / 规则遵守等 LLM 语义维度,经 `ChapterScorer.llm_evaluators` 钩子注入,默认中性分,尚未接入真实推理(设计 §7.5 已声明待 Phase5)。
- **图表生成**:本实现不生成图形/图表,仅支持表格/列表/段落/提示框等文本型 Block(设计 §6.4 的 table/list/paragraph/note)。
- **跨章引用一致性**:设计 §7.2 第 4 项「关联一致性」由 `WriterState.cross_refs` 记录,但端到端语义校验(与 ImpactReport 逐条比对)超出本实现范围,留待人工质量门禁与后续里程碑。
### 12.2 组件与数据流
```
StructuredSource
│ build_contexts(structured_source, samples_dir)
list[ChapterContext] (每章:chapter_id / 数据选择器 / 模板标记)
│ WriterAgent.generate_chapter(ctx) 逐章串行
ChapterContentblocks: list[ContentBlock] + source_uris
│ render_chapter_blocks(content)
list[Block]DocxInjector.Blockparagraph/heading/table/list/note
│ DocxInjector(template_path).inject(sections, meta)
Document(注入后 Word 文档)
│ QALoopDEFAULT_MAX_QA_ROUNDS=3
│ ├─ QAValidator 校验各章(仅确定性维度)
│ └─ 仅对失败章:WriterAgent.generate_chapter → render → 重新注入
最终 Document + QAReport
```
关键约定:
- 逐章**串行**生成(设计 §6.8.1 基线约束),`WriterState` 跨章共享摘要与关键表结构供后章引用。
- QA 闭环**仅重失败章**,不重新生成全部,受最大轮次护栏约束,禁止无限重试(设计 §7.4 护栏)。
### 12.3 实现期发现的真实 API 适配(避坑记录)
实现过程中,以下真实接口与设计/规范文档存在偏差,已按真实接口落地,此处统一记录供后人避坑:
1. **`DocxInjector` 真实接口**:为 `DocxInjector(template_path).inject(sections: dict[section_id, list[Block]], meta) -> Document`。**不存在** `inject_blocks` 方法;`sections` 字典的键是 `{{section:id}}` 中的 `id`(不含 `section:` 前缀)。
2. **`InferenceEngine.chat_structured`** 签名为 `chat_structured(*, session_id, prompt, variables, schema, retry_count=2) -> StructuredResult`,返回对象含 `.data`(解析后的 dict)与 `.status`ok / parse_error / failed)。调用时必须关键字传参。
3. **`RagService.retrieve_*`** 为**同步**方法(非 async)。调用方在同步编排链路中直接调用即可,无需 `await`
4. **`map_template`** 消费真实的 `ParsedTemplate.sections`(元素类型为 `ChapterMarker`,含 `type` / `name` / `level`)。映射按文档顺序:遇到 `heading` 起一章;其后的 `section:<id>` 占位符归属该章 → `chapter_id = id``section_placeholder = "section:<id>"`
5. **`ChapterScorer.score(chapters: list[ChapterArtifact], source: StructuredSource)`**QA 层需要 `ChapterContent → ChapterArtifact` 适配器(由 `ChapterContent.blocks` 拼接得到 `text`,并从各 block 收集 `source_uris`);设计 §7.5 的 `ChapterArtifact` 并非直接由 Writer 产出,需经适配。
6. **真实 `DocxInjector.Block`** 已支持 `table` / `list` / `note` 类型;表格注入会渲染 `caption` 段落(caption 非空时在其上方/下方生成说明段落),非空 caption 不应被丢弃。
### 12.4 垂直切片状态
**FakeLLM 模式已打通(可回归)**
- 运行 `python scripts/run_phase5_slice.py --fake`,使用 `FakeLLMClient` 驱动整条链路,产出 `samples/phase5-slice/output.docx`
- 该切片覆盖:build_contexts → 逐章生成 → 渲染 → 注入 → QA 闭环(仅重失败章),并附带 `QAReport`
**真实 LLM 生成 + 人工质量门禁(待人工执行项,P5-T10 推后)**
- 真实推理接入(DeepSeek / Qwen 等)与端到端人工质量门禁(内容准确性 / 格式精度 / 规则遵守的人工判读)不在本自动实现范围内,标记为推后项。
- 真实 LLM 接入点已预留(`InferenceEngine` 默认实例 + `PromptRegistry` 注入),人工执行时仅需提供可用模型配置与 `scripts/run_phase5_slice.py` 的非 `--fake` 路径。