AI含量声明:本文内容基本全部由AI生成,根据我实际创建这个沙箱docker过程中使用AI解决问题的过程对话整理,在此我要感谢KIMI,助理我快速制作好这个沙箱。(虽然我是个华为云计算HCIE,学的就是docker,但是到用的时候是真忘光了dockerfile了啊魂淡!)

前言

最近在折腾内网环境下的 Hermes Agent(一个 AI Agent 框架),需要给 Agent 提供一个能处理 Office 文档(PPT/Word/Excel)、做数据分析(Pandas)、连国产数据库(达梦/人大金仓/Oracle)、画流程图、做 OCR、还能正确渲染中文图表的 Python 沙箱。

由于是完全离线环境,没法 apt installpip install 直接拉取,整个构建过程踩了不少坑。这篇文章把关键问题和解决过程记录下来,方便后续复现,也希望能帮到有同样需求的同学。


目标环境

  • 宿主机:Windows 10 + WSL2 + Docker Desktop

  • 网络:纯内网,无互联网访问

  • 基础镜像python:3.12-slim-bookworm

  • 核心需求

    • Office 处理:PPT 文本提取、Word 读写、Excel 读写、PDF 转换

    • 数据处理:Pandas、Numpy、Matplotlib(中文渲染)

    • 数据库:PostgreSQL、MySQL、MongoDB、Redis、Oracle、达梦、人大金仓、某内部IM的加密 SQLite

    • 可视化:流程图、思维导图、架构图

    • OCR

    • 文档转换:Pandoc

成果

详见我的github项目

沙箱能力速查:

能力工具/包
PPT 文本提取markitdown[pptx]
PPT 生成(Python)python-pptx
PPT 生成(JS)pptxgenjs
Word 读写python-docx
Word 模板渲染(邮件合并/合同)docxtpl
Excel 读写openpyxlxlsxwriterpython-calamine
PDF 转换sofficepdftoppm
PDF 文本/表格提取PyMuPDFpdfplumber
OCRtesseract-ocrpytesseract
数据处理pandasnumpyscipy
可视化matplotlibseabornplotlykaleido
流程图/架构图graphvizdiagramsnetworkx
思维导图xmindxmindparser
数据库(通用)psycopg2pymongoredissqlalchemypymysql
数据库(国产)sqlcipher3(微信/钉钉), oracledbdmPython
文档转换pandocpypandoc
游戏/多媒体引擎pygame

效果


一、pip 分批安装导致 numpy 被反复卸载(不影响,所以没处理,但可优化)

做了什么

Dockerfile 中用了多个独立的 RUN pip install 分批装包:

dockerfile

RUN pip install markitdown[pptx] Pillow defusedxml lxml python-pptx python-docx ...
RUN pip install pandas numpy scipy chardet python-magic ...
RUN pip install matplotlib seaborn plotly kaleido ...

遇到的问题

构建日志中出现 Attempting uninstall: numpy

plain

Attempting uninstall: numpy
Found existing installation: numpy 2.5.2
Uninstalling numpy-2.5.2

原因分析

每个 RUN pip install 独立解析依赖树。后安装的包(如 unstructured)依赖的 numpy 版本与前面已装的不兼容,pip 只能先卸载再重装。

可以做的优化(未采用)

合并为一个 RUN,让 pip 一次性计算最优版本,避免反复卸载:

dockerfile

RUN pip install --no-cache-dir -i https://... \
    markitdown[pptx] Pillow pandas numpy scipy matplotlib ...(所有包)

但由于最终构建结果正确,只是多耗一点时间,所以未做调整。


二、pysqlcipher3 编译失败:转向 sqlcipher3

做了什么

需要连接加密 SQLite 数据库,尝试安装 pysqlcipher3

dockerfile

RUN pip install pysqlcipher3

遇到的问题

运行时阶段报错 gcc: not found。移到 builder 阶段后,又报:

fatal error: sqlcipher/sqlite3.h: No such file or directory

原因分析

pysqlcipher3 在 PyPI 上没有预编译 wheel,必须从源码编译。即使 builder 阶段装了 libsqlcipher-devpysqlcipher3 的 setup.py 对 Debian 12 的兼容性仍有问题,找不到头文件路径。

解决方法

放弃 pysqlcipher3,改用 sqlcipher3sqlcipher3cp312 的预编译 wheel,运行时阶段无需 gcc 直接安装

RUN pip install sqlcipher3

但运行时仍需保留 libsqlcipher-dev(提供 libsqlcipher.so.0 动态库),否则 import sqlcipher3 会报:

libsqlcipher.so.0: cannot open shared object file

三、LibreOffice headless 在容器中无法运行

做了什么

在 Dockerfile 中安装了 LibreOffice:

RUN apt-get install -y libreoffice libreoffice-impress ...

遇到的问题

在内网Hermes Agent中使用这个沙箱,让hermes打开wps文件时报错,hermes说libreoffice必须要X11图像环境才能运行。

原因分析

内网的Qwen3.6-35B模型能力有限,没有摸索出无图形环境运行libreoffice的方法

解决方法

我在外网使用deepseek-v4-flash,用这个沙箱成功打开了WPS文件,于是让deepseek-v4-flash写了个用这个沙箱读写.wps .et文件的SKILL,导入内网使用,并让内网的Qwen3.6-35B对这个SKILL进行了验证和优化,优化后的SKILL也上传到我的github上了


四、matplotlib 中文字体渲染:配置文件覆盖导致 KeyError

做了什么

为了让 matplotlib 正确显示中文,写了一个精简的 matplotlibrc

font.family: sans-serif
font.sans-serif: WenQuanYi Zen Hei, Noto Sans CJK SC, SimHei, DejaVu Sans, sans-serif
axes.unicode_minus: False

然后在 Dockerfile 中覆盖:

COPY matplotlibrc /usr/local/lib/python3.12/site-packages/matplotlib/mpl-data/matplotlibrc

遇到的问题

import matplotlib 阶段直接报错 KeyError: 'backend_fallback',完全无法导入,后续所有绘图代码都无法运行。

原因分析

matplotlib 3.11 在 __init__.py 加载时会遍历 rcsetup._validators 中的所有参数键,从 rcParamsDefault 读取默认值。精简版 matplotlibrc 只有 3 行,缺失了 backend_fallback 等上百个默认参数,导致键缺失直接抛异常,模块根本加载不起来。

解决方法

不要覆盖整个文件。在完整版 matplotlibrc基础上用 sed 替换目标行:

COPY matplotlibrc /usr/local/lib/python3.12/site-packages/matplotlib/mpl-data/matplotlibrc
RUN sed -i 's/^#*font.family:.*/font.family: sans-serif/' \
    /usr/local/lib/python3.12/site-packages/matplotlib/mpl-data/matplotlibrc && \
    sed -i 's/^#*font.sans-serif:.*/font.sans-serif: WenQuanYi Zen Hei, Noto Sans CJK SC, SimHei, DejaVu Sans, sans-serif/' ... && \
    sed -i 's/^#*axes.unicode_minus:.*/axes.unicode_minus: False/' ...

系统层面安装 fonts-wqy-zenhei + fonts-wqy-microhei 作为中文字体兜底。


五、apt 换源同步延迟导致构建失败

做了什么

为了加速构建,把 Debian 源换成了华科镜像:

RUN sed -i 's|http://deb.debian.org|https://mirrors.hust.edu.cn|g' \
    /etc/apt/sources.list.d/debian.sources

遇到的问题

apt-get update 报错:

plain

File has unexpected size (325500 != 325552). Mirror sync in progress?

原因分析

国内镜像的 security 子源同步有延迟,Release 文件和实际 Packages 文件不一致。bookworm-security 更新频繁,镜像站还没同步完就被拉取。

解决方法

只替换 deb.debian.org(main 源),保留 security.debian.org 官方源

RUN sed -i 's|http://deb.debian.org|https://mirrors.tuna.tsinghua.edu.cn|g' \
    /etc/apt/sources.list.d/debian.sources

或者统一用清华源,但遇到同步问题时重试即可。


六、离线二进制(Pandoc)的集成

做了什么

需要 Pandoc 做 Markdown ↔ Word/PDF 转换。Debian 12 官方源的 Pandoc 版本太旧(2.x),不支持新特性。

遇到的问题

Debian 12 官方源的 Pandoc 版本太旧(2.x),必须从 GitHub Releases 下载二进制。

解决方法

  1. 在能联网的机器下载 pandoc-3.1.11-linux-amd64.tar.gz

  2. Dockerfile 中 COPY + tar 解压到 /usr/local/

COPY pandoc-3.1.11-linux-amd64.tar.gz /tmp/
RUN tar xvzf /tmp/pandoc-3.1.11-linux-amd64.tar.gz --strip-components 1 -C /usr/local/ \
    && rm /tmp/pandoc-3.1.11-linux-amd64.tar.gz \
    && pandoc --version

pypandoc 作为 Python 调用层,版本无需与 Pandoc 严格绑定。


总结

表格

核心教训
pip 分批安装可以合并优化,但无伤大雅
pysqlcipher3 编译失败优先找预编译 wheel(sqlcipher3),减少编译依赖
LibreOffice 无头模式处理WPS文档外网能力强的模型写出使用方法SKILL,交给内网Agent使用
matplotlib 中文渲染不要覆盖完整配置文件,用 sed 替换目标行
apt 换源延迟security 源保持官方,避免同步延迟
Pandoc 离线集成下载二进制 + tar 解压

构建命令

# 前置:下载 pandoc 二进制到 Dockerfile 同级目录
.\download-deps.ps1

# 构建
docker build -t hermes-sandbox-python312:20260812v2 -f Dockerfile .

# 验证
docker run --rm hermes-sandbox-python312:20260812v2 python3 /tmp/verify.py

更多推荐