自动化交付

同一段 PDF 代码换台机器就失败,先交出环境信息

“同一段代码在我电脑上能跑”不是一份复现报告。PDF 渲染与文档转换还受库版本、系统字体、OCR 语言包和外部组件影响。把这些信息收集完整,才能判断差异来自输入、代码还是环境。

阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。 “同一段代码在我电脑上能跑”不是一份复现报告。PDF 渲染与文档转换还受库版本、系统字体、OCR 语言包和外部组件影响。把这些信息收集完整,才能判断差异来自输入、代码还是环境。 分开记录 Python 包与系统资源 importlib.metadata 可以读取已安装发行包版本,但看不到所有字体、系统动态库或外部 OCR 数据文件。不要把一张 pip freeze 清单称为完整环境。包的发行名与导入名也可能不同,例如导入 PIL 对应的发行包是 Pillow 。 一个不会因缺包而崩溃的报告器 import json import platform from importlib import metadata def package_version(name): try: return metadata.version(name) except metadata.PackageNotFoundError: return "not-installed" def report(names): return {"python": platform.python_version(), "system": platform.system(), "packages": {name: package_version(name) for name in names}, "fonts_manifest": "not-collected", "ocr_language_data": "not-collected"} data = report(["PyMuPDF", "Pillow", "omnidoc-synthetic-missing-package"]) assert data["packages"]["omnidoc-synthetic-missing-package"] == "not-installed" assert data["python"] assert data["fonts_manifest"] == "not-collected" assert json.loads(json.dumps(data)) == data 代码只读取当前环境,不安装依赖,也不联网。结果中的未收集项目应保持明确标记,不能自动填成“默认字体”或“最新版”。报告可以另外关联容器镜像摘要、锁文件和输入文件摘要,但不要导出认证配置或全部环境变量。 比较时先找最有区分度的信息 差异 常见影响方向 后续验证 字体缺失 替代字体与排版改变 比对字体清单和渲染样本 OCR 语言包不同 识别路径改变 用相同语言数据复测 PDF 库版本不同 接口或解析行为变化 查版本说明并跑最小样本 输入摘要不同 根本不是同一文件 先统一输入再讨论环境 环境相同不保证所有输出逐字节相同 时间戳、随机 ID 和压缩元数据也可能造成产物哈希变化。需要区分“字节级可复现”和“内容及版式满足同一验收标准”。先确定需要哪种保证,再选比较方法,避免用错指标。 让文档翻译问题更容易沟通 当本地预处理结果与 OmniDoc(产品入口) 工作流出现差异,可以附上脱敏样本、处理阶段和环境报告。这样的反馈比一句“格式乱了”更容易定位,也便于判断是否需要更新依赖、补字体或调整输入准备。 参考: Python importlib.metadata 。 - 1 -
更新于 2026-10-08