9.3 KiB
Phase 3「Word 解析优先」设计(Parser Agent - Word 解析 + 聚合)
状态: 已批准(brainstorming + 范围澄清吸收) 日期: 2026-08-09 里程碑: implementation-plan 阶段 3(Word 解析优先切片)
1. 背景与目标
implementation-plan.md 阶段 3 定义 Parser Agent 的 Word/PPT 解析与现系统探索。经范围澄清(用户确认),本次迭代只做 Word 解析优先 切片:实现为后续 Writer(阶段 7)、RAG 规则检索(阶段 4)、QA(阶段 8)服务的 Word 模板解析 / Word 规则文档 Markdown 化 / 全量输入聚合 基础设施。
现状:
data_models.py已定义ParsedTemplate/ChapterMarker/RuleDocument/StructuredSource/UnifiedDocument等数据类,可直接复用parsers/已有完整 Excel 解析链(ExcelParser → ExcelParseResult),且python-docx>=1.0已在pyproject.tomlsamples/已有 3 个 Word 样本:概要設計書テンプレート.docx(模板)、概要設計做成説明書.docx(做成说明书)、記入規則.docx(记入规则),以及 5 个 Excel 样本- 全量测试基线 132 passed / 100.00% 覆盖(fail_under=99 红线)
目标: 新增 WordTemplateParser(章构成/占位符/样式名提取)、RuleDocParser(docx → Markdown + 规则分类)、SourceParser 门面(按扩展名路由全量输入 → StructuredSource),并配套单元测试与真实样本集成测试,保持红线不回归。
2. 范围与不做的事
范围(implementation-plan 3.1 / 3.2 / 3.6 / 3.7):
- 3.1 WordTemplateParser:章构成(Heading 层级)提取、占位符(
{{section:xxx}})检测、样式名提取 - 3.2 RuleDocParser(Word):规则文档 Markdown 化、规则分类(按来源映射)
- 3.6 SourceAggregator:全量输入(Excel 要件定义 + Word 模板 + Word 规则)统一组装
StructuredSource - 3.7 Parser Agent 集成测试:真实样本(3 Word + 5 Excel)全链路
不做(YAGNI / 后续里程碑):
- ❌ 3.3 PPTXParser(无 .pptx 样本、python-pptx 未安装)→ 后续补样本后实施
- ❌ 3.4 现有系统代码探索(CodeParser 未实现、无 .java 样本)→ 后续实施
- ❌ 3.5 现有系统设计书探索(无现系统 Word/Excel 设计书样本)→ 后续实施
- ❌ FileReader 统一读取层(UnifiedDocument)(方案 B 否决;现有 Excel 链直接 openpyxl,本轮不重构)
- ❌ 完整样式定义提取(字号/颜色等)(YAGNI:阶段 3 无样式消费方,阶段 7/8 再按需深挖)
- ❌ LLM 参与的规则分类(按来源映射,零网络依赖、离线可测)
- ❌ data_models.py 数据模型改动(现有类型完全够用)
3. 设计
3.1 架构
在 src/genesis/parsers/ 下新增 3 个模块,与现有 excel_parser.py 同构(扁平模块、dataclass 结果、纯函数拆分):
parsers/
├── excel_parser.py # 现有,不动
├── word_template_parser.py # 新:WordTemplateParser
├── rule_doc_parser.py # 新:RuleDocParser
└── source_aggregator.py # 新:SourceParser 门面
3.2 WordTemplateParser
输入: docx 路径(str | Path)
输出: ParsedTemplate{file_name, sections, placeholders, styles}(复用 data_models 类型)
提取逻辑(python-docx):
| 产物 | 提取方式 | 说明 |
|---|---|---|
sections |
遍历文档段落,识别 Heading 样式的段落 → ChapterMarker(type="heading", name=段落文本, level=大纲级别);遍历书签(bookmarkStart)→ type="bookmark";遍历占位符 → type="placeholder" |
ChapterMarker.type 取值 `"heading" |
placeholders |
正则识别 {{section:xxx}} 与封面型 {{doc_title}} / {{version}} / {{created_at}} → {占位符名: 出现位置或上下文} |
占位符名去重 |
styles |
收集文档命名样式 + 各段落实际使用的样式名 → 去重集合 | 样式名级(不提取字号/颜色/字体明细) |
3.3 RuleDocParser
输入: docx 路径 + category(调用方按来源映射传入:"write" | "design" | "ref")
输出: RuleDocument{file_name, category, markdown_content, source_path, file_type="word", hash}
Markdown 化规则:
| docx 元素 | Markdown 输出 |
|---|---|
| Heading 1/2/3 | # / ## / ### 标题行 |
| 普通段落 | 文本行 |
| 表格 | GFM 表格(表头 + 分隔行 + 数据行) |
| 列表(List Bullet/Number) | - 项 / 编号项 |
| 空段 | 空行 |
hash= 文件内容 sha256 hex(供阶段 4 规则版本管理)file_type固定"word"
来源映射(分类策略,零 LLM):
| 输入文件 | category |
|---|---|
記入規則.docx |
write |
概要設計做成説明書.docx |
ref |
明确的策略: rule_paths 仅接受 .docx 规则文档;类别由门面按文件名映射(記入規則* → write,*説明書* → ref,其余文件名 → write 兜底)。Excel 图表规则(図表規則.xlsx)本轮不纳入 rule_docs(Excel 规则解析留给后续迭代)。
3.4 SourceParser 门面(3.6 SourceAggregator)
输入:
requirement_paths: list[str | Path]— 要件定义 Excel 列表template_path: str | Path | None— 概要设计模板 docxrule_paths: list[str | Path]— 规则文档列表(仅 docx)
类别映射(内置于门面,零 LLM): rule_paths 中文件名含 記入規則 → write;含 説明書 → ref;其它 → write 兜底。
路由:
| 扩展名/角色 | 解析器 | 产物 |
|---|---|---|
.xlsx |
现有 ExcelParser |
tables + comments |
| 模板 docx(template_path) | WordTemplateParser |
template: ParsedTemplate |
| 规则 docx(rule_paths) | RuleDocParser |
rule_docs: list[RuleDocument] |
输出: StructuredSource{tables, template, rule_docs, image_analyses=[], existing_system=None, comments}(image_analyses/existing_system 本轮恒为空/None,类型字段保留)。
3.5 数据流
samples/*.xlsx ─────────────► ExcelParser ─────► tables / comments
samples/テンプレート.docx ──► WordTemplateParser ─► template: ParsedTemplate ─┐
samples/記入規則.docx ──────► RuleDocParser ────► rule_docs: [RuleDocument] ──┼─► StructuredSource
┘
3.6 错误处理
| 场景 | 行为 |
|---|---|
| 文件不存在 | 抛出 FileNotFoundError(消息含路径,便于定位) |
| 模板无 Heading / 空文档 | 返回空 sections/placeholders,不崩溃(与 ExcelParser 的 skipped 哲学一致) |
非法占位符格式(非 {{section:xxx}} / {{doc_*}}) |
不识别为占位符,正文文本原样保留 |
未知扩展名(如 .txt/.md) |
SourceParser 路由阶段报错:ValueError("不支持的文件类型: ...") |
| docx 损坏 | 透出 python-docx 异常(PackageNotFoundError),测试不吞 |
3.7 与现有代码的关系
- 不改
excel_parser.py、data_models.py、pyproject.toml、任何现有测试 - 只新增
src3 个生产模块 + 3 个测试文件 + 扩展test_real_samples.py - 提交消息前缀:
feat:(生产实现)/test:(门禁测试)/docs:(本文档与 AI 日志)
4. 文件定位与测试先例
- 单元测试沿用
tests/test_real_samples.py:7的定位方式:Path(__file__).resolve().parents[1] / "samples",样本缺失pytest.skip - 临时 docx 构造(单元测试):用
python-docx在tmp_path生成内存文档(Heading/表格/占位符/书签),不依赖真实样本 - 全量回归命令:
python -m pytest -q(保持 ≥ 132 passed / 100.00%)
5. 验收标准
python -m pytest tests/test_word_template_parser.py tests/test_rule_doc_parser.py tests/test_source_aggregator.py tests/test_real_samples.py -v全绿- 全量回归
python -m pytest -q≥ 132 passed(新增用例后 ≥ 现有基线 + 新增数)/ 100.00% 覆盖 - 真实样本:模板 docx 解析出 7 个 H1 章(はじめに…バッチ一覧)+ 占位符;记入规则 docx 产出 category="write" 的 markdown
- 门面全量组装:
StructuredSource.tables非空、template非 None、rule_docs含 write/ref 两类 - 手工破坏验证(可选):删除模板占位符段落 → 占位符断言变红;恢复正常
6. 影响面
- 新增生产文件 3 个:
src/genesis/parsers/word_template_parser.py、rule_doc_parser.py、source_aggregator.py - 新增测试文件 3 个:
tests/test_word_template_parser.py、tests/test_rule_doc_parser.py、tests/test_source_aggregator.py - 修改文件:
tests/test_real_samples.py(追加 3 个 Word 样本用例)、_AI_USAGE_LOG.md(追加日志行) - 提交纪律:分任务提交(feat/test/docs/chore 各自独立 commit)
7. 不做的事(YAGNI 最终确认)
- ❌ PPTXParser(3.3)— 无样本、无依赖,后续里程碑
- ❌ 现有系统代码/设计书探索(3.4/3.5)— CodeParser 未实现
- ❌ FileReader 统一读取层 — 现有 Excel 链不重构
- ❌ 完整样式定义 / LLM 规则分类 / 模型改动