本章目标:理解流水线第一站。学完你能回答:为什么不直接把 docx z 喂给 LLM?转换主链怎么走?
图片和表格这两类"特殊内容"怎么进 Markdown?什么是约定区、为什么要落标?
理论上你可以把 docx 的纯文本抽出来直接丢给 LLM。本工程不这么做,有三条硬理由:
所以 convert2md 的产出 *_SRC_*.md 是下游全链的唯一真相源(SRC 后缀的由来)——
后续所有环节(提取/检索/评估对照)都只认这份 md,不再回看 docx。
主链一句话:docx →(图片先抽走换成理解块)→ 格式映射成 md 行流 → 清洗 → 落盘。
data/workspace/01_raw/*.docx
│ 按后缀分流:.xlsx 走 ExcelParser 单跳直转(3.5 节)
▼ .docx
DocumentProcessor 四个 pass:段落图 → 表格图 → 页眉页脚图 → 公式
▼ 产出 processed_*.docx(图片 run 已原位替换为文字描述块)
UnifiedConverter.convert —— 三档策略 dispatch:
CODE 纯 python-docx 确定性映射(默认档,零 LLM)
MODEL 全文喂 LLM 重排(几乎不用)
HYBRID 先 CODE,启发式检测到层级问题才请 LLM 修复
▼ 三步后处理:SOURCE 溯源标签 → 约定区落标(3.6 节)→ 转换统计
data/workspace/02_markdown/{stem}_SRC_{时间戳}.md
+ assets/{md主名}/img-NNN.*(原图)+ .meta.json(血缘)+ .report.json(统计)
三档策略是个值得记住的成本分级设计:默认走最便宜的确定性路径(CODE),LLM 只做"修复器"
不做"主转换器"(HYBRID 里启发式守门、命中才请模型、失败静默回退 CODE 结果)。
服务端默认 code(web/main.py 的 convert 端点),未知 method 兜底也是 CODE。
另一个新人要知道的事实:convert2md 启动不强依赖 LLM——启动预检只告警不阻断
(对比 generator:LLM 不可达直接拒绝启动)。没有 LLM key 也能做纯文本转换,只是图片理解会降级成占位符。
拼接也是零语义的:转换器按文档流原序逐块判定(每块走"表格 → 标题 → 列表 → 普通段落"
的判定链),每块产出的 md 片段自带空行结尾,最后按序 join 成整篇——没有重排、没有跨块合并,
原序即真相序。后续所有"这块内容上下文是什么"的判断都建立在这个原序假设上。
这是纯确定性代码(core/md_converter.py),但藏着 Word 格式的两个大坑,恰好是"为什么转换是专业问题"的例证:
坑一:标题不总是"标题样式"。规范文档用 Heading N 样式,映射到 md 的 #×N 很直接;
但很多策划文档的标题没有样式,得靠内容特征兜底(行很短、无句号、像标题)。反过来,文档的第一个标题
会被降格成粗体——md 语法里每篇只能有一个 H1,而这个位置留给文档名,防止层级污染。
策划文档里的图(UI 截图、流程图、图表)必须被"看懂"才能进入下游。管线是三环:
抽取环:遍历段落/表格/页眉页脚里的图片 run,原图先落盘 assets/{md主名}/img-NNN.*
理解环:每张图 → 判定五类(flowchart/chart/ui_screenshot/text_screenshot/decorative)
→ VLM(glm 视觉模型)按类型化 prompt 生成描述 → 拒识幻觉检测+重试
落块环:描述包装成 <ImgThinking> 块(头部带"图片类型/源文件"),原位替换图片 run
docx 段落: "战斗流程如下图所示 [图片Run]"
│ ① 提取图片引用 rId(blip 正则解析 → 对象遍历 → XPath,三级回退)
│ ② 按 rId 从 docx 关系表取图片二进制
│ ③ 原图落盘 assets/(分析失败也可重跑)
│ ④ VLM 识图 → (描述 desc, 流程图结构 flow, 图片类型)
│ ⑤ paragraph.add_run("<ImgThinking>…</ImgThinking>" + flow) ← 文字插回原段落
│ ⑥ 从 XML 删除原图片 Run
▼
docx 段落: "战斗流程如下图所示\n<ImgThinking>图为三阶段循环…</ImgThinking>"
│ 阶段二格式转换:<ImgThinking> 就是普通文本,随段落自然进 md
▼
out.md 携带 <ImgThinking> 块
│ generator 预处理(4.2 ②)正则抽走块、原位留 IMG_REF 占位符
▼
实体提取按占位符就近把图片理解挂回对应小节(两跳协议)
多图场景的处理节奏是逐张串行、当场回插:碰到一张图就完成"取 rId → 取字节 → 落盘 →
VLM 识图 → 描述回插"全程,再处理下一张——不存在"攒齐 a/b/c 一批再统一回填"(VLM 本就
单张调用,逐张也天然做到一张失败不拖累后续、图元级进度可上报)。两个精确到实现的事实:
①回插调的是 paragraph.add_run,即追加到所在段落末尾——同段多图时各描述按处理顺序
依次排在段末(策划文档的图通常独占一段,实际无感知);②删除原图片 Run 是按段落攒批的:
该段所有图处理完后统一从 XML 删掉,回插与删除不混在同一个循环里。
表格是策划文档的重头(数值表、配置表)。本工程对两类来源用可靠性等级不同的两条通道:
| a | b |)。结构化程度为零,进正文 section,
下游 LLM 按 prompt 规则自行理解表格行——灵活但随模型波动。ExcelParser 单跳直转,每行升格为 <ExcelTableThinking> 结构化块
(带 sheet 名/行号/跨表引用),下游用确定性代码把行合成 ConfigItem 配置实体,不经 LLM——
稳定可重复,适合大批量数值配置(BOSS 技能表 930 行这种)。一句话记住设计意图:轻表可读(md 表格给人看),重表可算(结构块给机器算)。