无网环境docker部署Hermes Agent笔记——番外篇 全功能沙箱:从 0 到 1 的踩坑实录(Docker + Python 3.12 + LibreOffice + 国产数据库)
AI含量声明:本文内容基本全部由AI生成,根据我实际创建这个沙箱docker过程中使用AI解决问题的过程对话整理,在此我要感谢KIMI,助理我快速制作好这个沙箱。(虽然我是个华为云计算HCIE,学的就是docker,但是到用的时候是真忘光了dockerfile了啊魂淡!)
前言
最近在折腾内网环境下的 Hermes Agent(一个 AI Agent 框架),需要给 Agent 提供一个能处理 Office 文档(PPT/Word/Excel)、做数据分析(Pandas)、连国产数据库(达梦/人大金仓/Oracle)、画流程图、做 OCR、还能正确渲染中文图表的 Python 沙箱。
由于是完全离线环境,没法 apt install 和 pip 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
-
成果

沙箱能力速查:
| 能力 | 工具/包 |
|---|---|
| PPT 文本提取 | markitdown[pptx] |
| PPT 生成(Python) | python-pptx |
| PPT 生成(JS) | pptxgenjs |
| Word 读写 | python-docx |
| Word 模板渲染(邮件合并/合同) | docxtpl |
| Excel 读写 | openpyxl, xlsxwriter, python-calamine |
| PDF 转换 | soffice, pdftoppm |
| PDF 文本/表格提取 | PyMuPDF, pdfplumber |
| OCR | tesseract-ocr, pytesseract |
| 数据处理 | pandas, numpy, scipy |
| 可视化 | matplotlib, seaborn, plotly, kaleido |
| 流程图/架构图 | graphviz, diagrams, networkx |
| 思维导图 | xmind, xmindparser |
| 数据库(通用) | psycopg2, pymongo, redis, sqlalchemy, pymysql |
| 数据库(国产) | sqlcipher3(微信/钉钉), oracledb, dmPython |
| 文档转换 | pandoc, pypandoc |
| 游戏/多媒体引擎 | 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-dev,pysqlcipher3 的 setup.py 对 Debian 12 的兼容性仍有问题,找不到头文件路径。
解决方法
放弃 pysqlcipher3,改用 sqlcipher3。sqlcipher3 有 cp312 的预编译 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 下载二进制。
解决方法
-
在能联网的机器下载
pandoc-3.1.11-linux-amd64.tar.gz。 -
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更多推荐
所有评论(0)