最近在做知识库构建服务时,遇到一个很隐蔽的问题:源文档(Word)里明明是 Windows 共享路径,入库后在 Knowledge Base 的 chunk 里却在下划线前面多了一个反斜杠。
原文:\\12.254.13.112\Temp_Share
入库后的文本:\\12.254.13.112\Temp\_Share(注意下划线前被自动添加了反斜杠)
乍一看像是解析 bug,但仔细追链路后发现:这其实是 HTML 转 Markdown 转换库的「渲染安全」默认行为,在 RAG 场景里反而会伤害检索。
一、问题现象
上传 DOCX 后,在 chunk 预览里可以看到:
- 原文:Temp_Share
- 入库:Temp\_Share
搜索词 Temp 能命中,但精确匹配 Temp_Share 时就会受影响。尤其是 Windows 共享路径、变量名、邮箱本地部分这类包含下划线的内容,很容易踩坑。
二、根因定位
我们的 DOCX 处理链路是:
DOCX →(mammoth)→ HTML →(markdownify)→ Markdown → Chunk / Embedding
关键点在第二步:markdownify。本地验证非常直接:
import markdownify
print(markdownify.markdownify("Temp_Share"))
# Temp\_Share
对应源码逻辑大致是:只要开启了 escape_underscores,就会把所有下划线替换成带反斜杠的形式。也就是说,不是源文件写错了,也不是业务代码自己加的反斜杠,而是 markdownify 默认开启了下划线转义。
三、为什么默认要转义?
这不是 markdownify 的 bug,而是它的设计目标决定的。Markdown 里,下划线和星号都是强调语法:
- _this_ 会渲染成斜体
- *this* 也会渲染成斜体
如果 HTML 转 Markdown 后不做转义,后续再被 Markdown 渲染器解析时,像 foo_bar_baz 这类文本,在部分解析器下可能被误当成斜体。所以 markdownify 默认:
- escape_underscores = True:把 _ 转成 \_
- escape_asterisks = True:把 * 转成 \*
- escape_misc = False:其他特殊字符默认不转义
一句话总结:默认偏向「渲染正确」,不是「字面量正确」。这对博客、文档站点是合理的;对 RAG 知识库却不一定合适。
四、RAG 场景要不要转义?
结论:RAG 入库通常不需要、也不应该默认做这类 Markdown 渲染转义。
原因很简单:RAG 链路里,文本主要不是「给人看的 Markdown 渲染结果」,而是要经历切块、向量化、检索、再喂给大模型生成答案。在这些环节里,\_ 基本都是噪声:
- 切块:多出来的反斜杠没有语义价值
- Embedding:改变 tokenization,路径语义被污染
- 精确检索:用户搜 Temp_Share,库里却是 Temp\_Share
- 喂给 LLM:模型可能以为路径里真有反斜杠
Windows 路径尤其危险。原文本身已经有大量反斜杠,再叠加转义后的 \_,人和模型都更难分辨。
五、业界通行做法
不同库的默认值,其实已经反映出「面向渲染」和「面向 LLM / RAG」的分水岭:
|
库 |
默认转义下划线 |
定位 |
|
python-markdownify |
开启 |
通用 HTML→Markdown,偏渲染 |
|
html-to-markdown(Kreuzberg) |
关闭 |
明确面向 LLM / RAG |
另外,markdownify 的 escape_misc 也曾被默认打开,但社区反馈很差:过度转义会把 URL、标识符搞坏,后来又改回默认关闭。这说明一个趋势:为渲染器保平安的转义,不该无脑带到 LLM 数据预处理里。
当然,「不转义」不等于「不做清洗」。RAG 更该做的是:
- 去掉零宽字符、不可见 Unicode、bidi 控制符
- 规范化空白
- 保留标题、列表、表格结构
而不是给正文里的下划线和星号加反斜杠。
六、修复方式
官方已经提供开关,直接关掉即可:
markdownify.markdownify(
html,
heading_style="ATX",
table_infer_header=True,
escape_underscores=False,
escape_asterisks=False,
)
我们在项目里改了两处调用:
- HTML / DOCX 主转换路径
- PDF 表格转 Markdown 路径
效果对比:
- 修改前:Temp\_Share
- 修改后:Temp_Share
七、改完后要注意什么
- 已入库旧数据不会自动修复,需要重新上传或重建受影响文档。
- Markdown Preview 可能出现「真斜体」。如果原文本来就想用 _italic_,关闭转义后会按 Markdown 渲染成斜体。对 IT Wiki、路径、配置项、代码标识符为主的语料,这个代价通常可接受。
八、实践建议
如果你也在做文档入库 / RAG 预处理,可以按这个原则取舍:
- 面向页面渲染:保留 escape_underscores=True
- 面向检索和 LLM:关闭 escape_underscores 和 escape_asterisks
- 永远别盲目打开 escape_misc=True,很容易把 URL 和技术标识符污染掉
更实用的总结:Markdown 转义是为了「显示好看」;RAG 入库是为了「语义准确」。两者目标不同,默认策略不该混用。
参考
- python-markdownify 官方仓库
- html-to-markdown(Kreuzberg)API 文档
- CommonMark / GFM 关于下划线和星号强调语法的说明

352

被折叠的 条评论
为什么被折叠?



