在基于 AMD GPU 的 Podman 无根环境中,使用 Ollama 本地运行 Hermes Agent
在本地安全地运行 Hermes Agent:无根 Podman、一个挂载文件夹、内部网络、基于 ROCm 的 AMD GPU 上的 Ollama,以及一个 systemd 单元。
来源: Run Hermes Agent Locally (and securely) with Ollama and Rootless Podman on Arch Linux
用人工智能代理处理本地的 Markdown 和 Obsidian 笔记听起来很简单,但一旦涉及到访问权限问题就麻烦了。Nous Research 开发的 Hermes Agent 能够运行终端命令、编辑文件、执行代码以及调用其他工具。即便给它设定只能操作某个文件夹的指令,也无法形成真正的安全隔离,因为指令终究只是文本而已。Hermes 自身的文档也提到了这一点:虽然 HERMES_WRITE_SAFE_ROOT 设置可以保护常规的文件编辑工具,但终端工具依然能够访问运行 Hermes 的操作系统账户所能访问的所有内容。
下面的配置将 Hermes 放入无根 Podman 容器中,与在 AMD GPU 上运行本地模型的 Ollama 服务器并存。Hermes 只能编辑特意挂载的某个文件夹,主机文件系统的其余部分根本不存在于其容器命名空间中,因此它无法访问那些区域。Hermes 官方支持在容器中运行,会将持久化状态保存在 /opt/data 目录下,并可通过兼容 OpenAI 的接口与 Ollama 等自托管推理服务器协同工作。
本演示是在 Arch 的衍生版 EndeavourOS 上完成的,其他发行版需相应调整包管理命令。
安装无根 Podman
在 Arch 或 EndeavourOS 上,可使用 Pacman 安装 Podman:
sudo pacman -Syu podman
Pacman 可能会询问要使用哪种 OCI 运行时,并提供以下三种选项:
1) crun
2) krun
3) runc
此处选择的是第一个选项:
1
那个运行时是 crun。它日后会带来好处,因为 Podman 的 keep-groups 功能可以将额外的主机组传递到无根容器中,而该功能能与 crun 配合使用。
通过打印版本号并询问 Podman 它使用的是哪种运行时来确认安装情况:
podman --version
podman info --format '{{.Host.OCIRuntime.Name}}'
第二个命令应返回运行时名称:
crun
无根容器也需要该用户的从属UID和GID映射,因此请确认这两个文件中都存在相关条目:
grep "^$USER:" /etc/subuid
grep "^$USER:" /etc/subgid
从现在开始,所有 Podman 命令都应以普通用户身份运行,无需在命令前加上 sudo。
必要时修复无根 OverlayFS
首次在此机器上拉取镜像时失败,错误信息表明内核不支持在 ext 文件系统上使用 overlay 功能:
kernel does not support overlay fs:
'overlay' is not supported over extfs
当这种情况发生时,安装用户空间实现版本:
sudo pacman -S fuse-overlayfs
在无法使用原生 overlay 的无根环境中,Podman 推荐使用 fuse-overlayfs,且可明确指定其为无根挂载程序。请确认该程序已安装:
which fuse-overlayfs
预期路径为:
/usr/bin/fuse-overlayfs
配置保存在每个用户的对应文件中:
~/.config/containers/storage.conf
如果该文件已存在,请直接编辑而非盲目替换。存储部分应选择叠加驱动程序:
[storage]
driver = "overlay"
第二部分应注明挂载程序的名称:
[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs"
然后通过过滤 Podman 的调试输出来验证有效设置:
podman info --debug | grep -Ei 'graphDriverName|mount_program|overlay'
将存储迁移到更大的驱动器
对于这个项目而言,几乎立刻就需要进行这一步操作。仅Ollama容器镜像就占了几GB空间,模型文件通常还会额外占用5到20GB甚至更多的空间,而Podman在下载和解压各层时也会使用临时磁盘空间。首次尝试拉取Ollama时最终失败了,错误信息表明临时目录下的某个路径已没有剩余空间:
write /var/tmp/container_images_storage...:
no space left on device
涉及两个独立的路径,很容易被忽略。用于存储图像、容器和卷的永久性无根存储通常位于主目录下:
$HOME/.local/share/containers/storage
不过,下载的图层会暂时保存在:
/var/tmp
更改 Podman 的 --tmpdir 参数并不会移动该下载目录。Podman 的文档建议改用 TMPDIR 环境变量。
在拥有更大本地文件系统的环境下,建议设置一个目录用于存储文件,另一个目录用于临时文件:
/path/to/large-drive/podman/
├── storage/
└── tmp/
同时创建两者并将所有权交给当前用户:
sudo mkdir -p /path/to/large-drive/podman/storage
sudo mkdir -p /path/to/large-drive/podman/tmp
sudo chown -R "$USER:$USER" /path/to/large-drive/podman
然后打开存储配置进行编辑:
mkdir -p ~/.config/containers
nano ~/.config/containers/storage.conf
在保留叠加驱动程序的同时,将图表根目录指向新的存储目录:
[storage]
driver = "overlay"
graphroot = "/path/to/large-drive/podman/storage"
请保持 fuse-overlayfs 的挂载程序设置不变:
[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs"
请为此选择本地文件系统。Podman的文档警告称,NFS及其他网络文件系统在作为无根容器的存储介质时会出现异常行为。
临时下载的文件也需要重新定位,因此请为当前shell设置TMPDIR:
export TMPDIR=/path/to/large-drive/podman/tmp
要在 Bash 中使其永久生效,需将其添加到配置文件中并重新加载:
echo 'export TMPDIR=/path/to/large-drive/podman/tmp' >> ~/.bashrc
source ~/.bashrc
在从旧位置删除任何内容之前,请先验证新位置。打印出图形根节点,并筛选出与临时目录及挂载程序相关的调试输出:
podman info --format 'GraphRoot: {{.Store.GraphRoot}}'
podman info --debug | grep -Ei 'graphRoot|imageCopyTmpDir|mount_program'
仅在全新安装的 Podman 环境中,且确认新的图形根目录完全正确时,才应考虑删除旧位置中已被废弃的存储空间:
~/.local/share/containers/storage
不要在现有安装环境中随意这样做。这也是为什么在创建 Ollama 模型卷之前必须先确定存储位置的原因。
Hermes 使用一个文件夹,状态数据使用两个卷
请选择 Hermes 可以访问的单一主机目录,并且要慎重选择。将该路径导出为变量,然后创建对应文件夹:
export HERMES_WORKSPACE="$HOME/path/to/Hermes-Workspace"
mkdir -p "$HERMES_WORKSPACE"
使用 Obsidian 时,一个不错的选择是在存储库中设置一个专用文件夹,比如将研究目录放在个人文件夹和工作文件夹旁边:
Obsidian Vault/
├── Personal/
├── Work/
├── Research/
└── Agent Workspace/ ← only this folder is exposed
保险库中的其他所有内容对代理程序来说都是不可见的。
接下来,创建两个由 Podman 自行管理的卷:
podman volume create hermes-data
podman volume create ollama-models
第一个存储着赫尔墨斯的配置、内存及持久化状态,第二个则存储本地模型。这两种情况均无需向代理程序暴露额外的主机目录。
为容器授予 AMD GPU 访问权限
此设置针对的是 AMD ROCm,而非 NVIDIA CUDA。在 AMD 显卡上,请勿安装 nvidia-container-toolkit,因为在发现错误之前曾采用过这种绕行方式。Ollama 的容器使用指南为 AMD GPU 指定了 ollama/ollama:rocm 镜像,并将两个设备节点传递给容器:
/dev/kfd
/dev/dri
检查它们是否存在于主机上:
ls -l /dev/kfd
ls -l /dev/dri/render*
然后查看该账户所属的群组:
groups
如果该账户未出现在视频和渲染组中,请将其添加进去:
sudo usermod -aG video,render "$USER"
然后完全登出后再重新登录。在同一个终端中再次运行群组列表时,不会显示新的成员信息,这就会让人白白烦恼不已:
groups
重新登录后,再运行一次:
groups
现在的输出应同时包含这两组内容:
video render
Podman的--group-add keep-groups选项会将这些附加群组传递给无根容器,使其能够使用GPU设备。
检查TUN设备
另一处故障源于无根网络问题。Podman默认的无根网络机制Pasta报告称无法打开TUN设备:
pasta failed with exit code 1:
Failed to open() /dev/net/tun: No such device
查找设备节点:
ls -l /dev/net/tun
如果缺失,请加载内核模块:
sudo modprobe tun
然后再次检查。如果 modprobe 显示该模块在当前运行的内核中不存在,且系统近期有过升级,那么请将当前内核版本与模块目录中的版本进行对比:
uname -r
ls /usr/lib/modules/
在像 Arch 这样基于滚动更新的发行版中,机器可能仍在运行较旧的内核,而那些内核的模块在升级过程中已被移除。请重启后重试。
选择本地模型
对于拥有约 16 GB VRAM 的显卡,Ollama 目前推荐使用 gemma4 作为 Hermes 的本地模型;而拥有接近 24 GB VRAM 的系统则可以考虑 qwen3.6 等模型。此处的示例使用的是参数量为 120 亿的 gemma4 变体:
gemma4:12b
将其存储在变量中,并根据实际硬件调整模型:
export HERMES_MODEL="gemma4:12b"
另一个重要的参数是上下文长度。Ollama 默认将显存小于 24 GiB 的 GPU 的上下文长度限制在 4K,而这两个项目都建议在涉及智能体时至少使用 64,000 个标记。具体配置方式将在后文详细说明。
加载图像与模型
需要三种图像:普通的 Ollama 图像、ROCm 版本以及 Hermes 图像:
podman pull docker.io/ollama/ollama:latest
podman pull docker.io/ollama/ollama:rocm
podman pull docker.io/nousresearch/hermes-agent:latest
普通的 Ollama 镜像用于一次性下载模型。而 ROCm 镜像则可作为永久性的 AMD 推理服务器使用。
可使用临时容器将模型下载到其持久卷中。首先需清除任何过期的容器:
podman rm -f ollama-bootstrap 2>/dev/null
然后在仅挂载模型卷的情况下启动下载器,无需其他操作:
podman run -d \
--name ollama-bootstrap \
-v ollama-models:/root/.ollama \
docker.io/ollama/ollama:latest
如果无根模式下的 Pasta 网络仍然无法使用,那么仅对于这个临时下载器而言,使用主机网络是可行的。请再次删除该容器:
podman rm -f ollama-bootstrap 2>/dev/null
首先从主机网络开始:
podman run -d \
--network host \
--name ollama-bootstrap \
-v ollama-models:/root/.ollama \
docker.io/ollama/ollama:latest
此容器中未挂载任何 Hermes 工作空间。请通过它拉取模型:
podman exec -it ollama-bootstrap \
ollama pull "$HERMES_MODEL"
通过列表进行确认:
podman exec ollama-bootstrap ollama list
选定的模型应会显示出来:
gemma4:12b
移除临时容器。模型仍保留在该卷中:
podman rm -f ollama-bootstrap
如果 Podman 报告容器名称已被占用:
container name "ollama-bootstrap" is already in use
不要不断编造新名称,直接清空旧的容器即可:
podman rm -f ollama-bootstrap
或者添加 --replace 标志。
内部网络与容器
最初的设计完全不使用网络:
--network none
这已被改为专用的内部 Podman 桥接网络。Hermes 和 Ollama 共享一个网络命名空间,从而能够互相通信,而 Podman 则限制对外部的访问。--internal 选项正是为限制桥接网络上的外部访问而设计的。创建方法如下:
podman network create \
--ignore \
--internal \
hermes-internal
然后在该网络上创建 Pod:
podman pod create \
--name hermes-local \
--network hermes-internal \
--userns=keep-id:uid=10000,gid=10000
keep-id选项会将权限较低的宿主账户置于容器的用户命名空间中,其显示的数值是可以自行选择的。Hermes容器以10000:10000的权限运行,因此才会显示这些数值。
使用ROCm启动Ollama
这里出现了一个不太明显的问题。最终可行的命令如下:
podman run -d \
--name ollama \
--pod hermes-local \
--device /dev/kfd \
--device /dev/dri \
--group-add keep-groups \
-e HOME=/root \
-e OLLAMA_MODELS=/root/.ollama/models \
-e OLLAMA_CONTEXT_LENGTH=64000 \
-v ollama-models:/root/.ollama \
docker.io/ollama/ollama:rocm
其针对 AMD 的产品线包括:
--device /dev/kfd
--device /dev/dri
--group-add keep-groups
ollama/ollama:rocm
在この Podman レイアウトでは、2 つの環境変数を省略してはなりません:
HOME=/root
OLLAMA_MODELS=/root/.ollama/models
原因是一次令人费解的故障。模型已成功下载,数据块和清单文件也存在,卷也已正确挂载。然而列出模型时却一无所获:
podman exec ollama ollama list
容器的日志记录了整个过程:
podman logs ollama
它显示 Ollama 使用了文件系统根目录作为主目录,以及由此派生的模型路径:
HOME=/
OLLAMA_MODELS=/.ollama/models
而该模型实际位于:
/root/.ollama/models
Ollama 会以用户主目录加上 .ollama/models 作为默认模型路径,除非 OLLAMA_MODELS 指定了其他路径。因此模型从未缺失,只是 Ollama 找错了位置。明确设置这两个变量后立即解决了问题:
HOME=/root
OLLAMA_MODELS=/root/.ollama/models
现在列表应显示型号:
podman exec ollama ollama list
确认正在使用 GPU
在日志中查找 ROCm 和 GPU 相关的行:
podman logs ollama 2>&1 | grep -Ei 'gpu|rocm|amd|gfx'
一个正常的 AMD 环境能够识别 ROCm 计算设备。随后运行一个快速测试指令,要求模型给出精确的回复:
podman exec -it ollama \
ollama run gemma4:12b \
"Reply with exactly: AMD GPU test successful"
紧接着,查看正在运行的模型:
podman exec ollama ollama ps
有两列值得关注:
PROCESSOR
CONTEXT
理想情况下,处理器一列应显示GPU而非CPU卸载功能,相关背景信息如下:
64000
Ollama 自身建议查看其进程列表,以了解分配的上下文量以及卸载情况。那些宣称拥有巨大原生上下文的模型,并不一定真的获得了那么多分配资源。
使用一个挂载点启动 Hermes
现在在同一个容器中创建 Hermes 容器:
podman run -d \
--name hermes \
--pod hermes-local \
--security-opt=no-new-privileges \
--pids-limit 512 \
-v hermes-data:/opt/data \
-v "$HERMES_WORKSPACE:/opt/data/workspace:rw,nodev,nosuid" \
-w /opt/data/workspace \
docker.io/nousresearch/hermes-agent:latest \
sleep infinity
重要的是其中缺少了什么。这些内容均没有出现:
/:/host
/home:/home
~/.ssh
~/.config
Docker socket
Podman socket
唯一需要手动绑定的主机是工作区文件夹,它会被映射到容器的数据目录中:
$HERMES_WORKSPACE
↓
/opt/data/workspace
Hermes自身的状态存储在指定的卷中,该卷挂载于其数据路径下:
hermes-data
↓
/opt/data
官方容器使用 /opt/data 作为持久化状态存储,并会自动将 HERMES_WRITE_SAFE_ROOT 设置为此路径。该写入保护机制属于多层防御措施之一,而非主要的沙箱机制,因为 Hermes 的文档中明确指出终端命令可以绕过其对文件操作的限制。真正的边界在于 Podman 的文件系统命名空间。
验证挂载边界
查看主机实际向 Hermes 暴露了哪些内容:
podman inspect hermes \
--format '{{range .Mounts}}{{println .Type .Source "->" .Destination}}{{end}}'
将会显示两行内容,一行是数据量,另一行是允许的文件夹路径:
Podman volume -> /opt/data
your allowed folder -> /opt/data/workspace
不应出现主目录和容器运行时套接字。请明确检查套接字情况:
podman exec hermes sh -c \
'test ! -S /var/run/docker.sock && echo "No Docker socket exposed"'
也可以探测与主机相关的路径,例如查看某个 SSH 目录是否可见:
podman exec hermes sh -lc \
'test -e "$HOME/.ssh" && echo "SSH directory visible" || echo "Host SSH directory not visible"'
请记住,容器拥有自己的系统目录。看到这些目录是正常的,因为它们属于容器而非主机。
Hermes 连接 Ollama
这两个容器共享 Pod 的网络命名空间,因此通过回环接口进行通信。可以在 Hermes 容器内部测试 Ollama 兼容 OpenAI 的 API:
podman exec hermes python -c \
'import urllib.request; print(urllib.request.urlopen("http://127.0.0.1:11434/v1/models").read().decode())'
回复内容应为包含本地模型的 JSON 格式。首次尝试时使用了 Python 的 heredoc 语法,但并未输出任何内容:
podman exec hermes python - <<'PY'
...
PY
原因很简单。Python会以那种形式从标准输入读取程序,但podman exec并未被指示连接标准输入。加上交互式标志后,heredoc版本就能正常使用了:
podman exec -i hermes python - <<'PY'
import urllib.request
print(
urllib.request.urlopen(
"http://127.0.0.1:11434/v1/models"
).read().decode()
)
PY
缺少那个标志导致多花了几分钟时间。
证明外部世界无法访问
试着从 Hermes 容器内部获取一个外部网站:
podman exec hermes python -c \
'import urllib.request; print(urllib.request.urlopen("https://example.com", timeout=5).read())'
它应该会失败,这是有意为之。Hermes可以连接到舱内的Ollama,但网络不允许正常的外部访问。
如果容器列表出现异常,请不要惊慌:
podman ps
在 Ollama 旁边显示一个端口:
11434/tcp
那并不意味着该端口已发布到主机上。已发布的端口看起来会更像这样:
0.0.0.0:11434->11434/tcp
此配置中并未使用 -p 11434:11434。
将 Hermes 指向本地的 Ollama
以容器的用户身份在工作区中启动 Hermes 的配置:
podman exec -it \
--user 10000:10000 \
-w /opt/data/workspace \
hermes \
hermes model
服务提供商选择器列出了许多云服务。请不要选择云服务选项:
Ollama Cloud
请选择手动端点输入方式:
Custom endpoint (enter URL manually)
对于基础网址,请使用回环地址和 v1 路径:
http://127.0.0.1:11434/v1
如果需要 API 密钥,请保持空白。Ollama 目前的 Hermes 集成说明中,本地服务器正是采用这种带有空密钥的定制端点流程。在询问 API 兼容性时,选择与 OpenAI 兼容的聊天补全路径。模型名称请输入:
gemma4:12b
关于上下文长度:
64000
Hermes的官方文档指出,本地Ollama应使用v1接口,且对于需要使用工具的智能体工作流,至少需要64K的上下文容量。
在容器内使用本地终端后端
乍听之下这似乎有些奇怪。Hermes通常会警告其本地终端后端设置的问题:
terminal:
backend: local
会在与Hermes相同的机器上直接运行终端命令,且没有隔离机制。在直接安装了Hermes的系统上,这种做法会很危险。由于Hermes本身已处于Podman容器中,因此本地后端会指向Hermes容器:
Hermes "local"
↓
Hermes container
而非工作站:
Hermes "local"
↓
your Arch workstation
设置后端:
podman exec --user 10000:10000 hermes \
hermes config set terminal.backend local
工作目录为:
podman exec --user 10000:10000 hermes \
hermes config set terminal.cwd /opt/data/workspace
建议也设置基于个人资料的首页模式:
podman exec --user 10000:10000 hermes \
hermes config set terminal.home_mode profile
对于此设计,无需配置 Hermes 的 Docker 后端。那样做需要让 Hermes 能够访问容器运行时,从而违背了主要的隔离设计原则之一。
启动 Hermes
交互式会话的启动方式与设置时使用的执行模式相同:
podman exec -it \
--user 10000:10000 \
-w /opt/data/workspace \
hermes \
hermes
为整理笔记,提示词可要求 Hermes 审核工作区中的 Markdown 笔记,优化结构与标题,修正格式与语法,保留所有技术细节、命令、链接及 Obsidian 维基链接,绝不能仅为了缩短笔记长度而删减实际内容。所有更改会直接保存到已挂载的主文件夹中。
开机时启动环境
当一切都能交互式运行后,重启后无需手动启动 Ollama 和 Hermes,Pod 就会自动恢复运行。可创建一个用户级的 systemd 单元:
mkdir -p ~/.config/systemd/user
nano ~/.config/systemd/user/hermes-local.service
该单元以一段描述和一条排序行开始:
[Unit]
Description=Hermes Local AI Pod
After=default.target
服务阶段为一次性操作,会启动容器,给予30秒的停机缓冲时间,并允许2分钟的时间来重新启动:
[Service]
Type=oneshot
RemainAfterExit=yesExecStart=/usr/bin/podman pod start hermes-local
ExecStop=/usr/bin/podman pod stop -t 30 hermes-localTimeoutStartSec=120
TimeoutStopSec=60[Install]
WantedBy=default.target
如果 Podman 的图形界面根目录位于独立的驱动器上,该驱动器必须是可靠的启动时挂载点,而非桌面环境在登录后交互式挂载的驱动器。可根据文件系统情况添加可选的 ExecStartPre 挂载检查。
重新加载 systemd:
systemctl --user daemon-reload
启用该单位:
systemctl --user enable hermes-local.service
启动它:
systemctl --user start hermes-local.service
去检查一下:
systemctl --user status hermes-local.service
由于这是设置了RemainAfterExit的一次性服务,此状态属于正常现象:
Active: active (exited)
Podman 中存在一种更新的 Quadlet 机制,可用于在 systemd 下以声明式方式定义容器。不过,既然环境已经由人工搭建并测试过,那么使用一个已知能正常启动容器的微型用户服务带来的干扰最小。
若希望无根用户服务在登录桌面之前、系统启动时就立即运行,需启用 lingering 功能:
sudo loginctl enable-linger "$USER"
验证它:
loginctl show-user "$USER" -p Linger
预期结果:
Linger=yes
Systemd的linger功能可使用户的服务管理器在系统启动时自动运行,并在正常登录会话之外保持可用状态。重启后,容器列表如下:
podman ps
应该已经显示出正在运行 Ollama 和 Hermes 的容器。交互式 Hermes 会话仍需通过 exec 命令来启动:
podman exec -it \
--user 10000:10000 \
-w /opt/data/workspace \
hermes \
hermes
引导服务用于启动系统环境,不会打开交互式聊天窗口。
实际出现的问题
以下是过程中遇到的故障简述列表,每条均包含问题描述及解决方案。
来自内核的覆盖层错误:
Problem:
kernel does not support overlay fs
通过安装 fuse-overlayfs 并将其设置为叠加挂载程序即可解决:
Fix:
Install fuse-overlayfs and configure it as the overlay mount program.
临时目录下的空间即将用尽:
Problem:
no space left on device under /var/tmp
需要根据情况调整图形根目录的位置,同时设置TMPDIR,因为Podman的tmpdir标志是另一个概念:
Fix:
Move Podman's graphroot if needed AND set TMPDIR.
Changing Podman's --tmpdir is not the same thing.
Bootstrap 容器存在名称冲突:
Problem:
ollama-bootstrap name already in use
通过移除过期的容器即可解决:
Fix:
podman rm -f ollama-bootstrap
Pasta无法打开TUN设备:
Problem:
pasta cannot open /dev/net/tun
可通过加载tun模块来解决,如果已安装的模块与正在运行的内核不匹配,则需要重启:
Fix:
sudo modprobe tun
If the installed modules don't match the running kernel, reboot.
在 AMD 机器上安装的 NVIDIA 工具包:
Problem:
Installed nvidia-container-toolkit on an AMD machine
根本就不应该这么做,应该改用 ROCm 图像以及 kfd 和 dri 设备:
Fix:
Don't.
Use ollama/ollama:rocm with /dev/kfd and /dev/dri.
在群组列表中未显示的新视频及渲染群组成员资格:
Problem:
Added myself to video/render but `groups` still didn't show them
需要退出登录再重新登录,因为现有的会话会保留其原有的组别:
Fix:
Log out and back in.
The existing login session retains its original supplementary groups.
Ollama的列表为空,但模型文件和清单仍然存在:
Problem:
Ollama model files and manifest exist, but `ollama list` is empty
通过读取日志进行诊断,如果 home 和 models 路径指向文件系统根目录,而卷又挂载在根用户的目录下,则需要明确设置这两个变量:
Fix:
Check:
podman logs ollamaIf Ollama is using:
OLLAMA_MODELS=/.ollama/modelswhile the volume is mounted under:
/root/.ollamaset explicitly:
HOME=/root
OLLAMA_MODELS=/root/.ollama/models
一个从 Hermes 到 Ollama 的 Python 测试,却静默地没有输出任何内容:
Problem:
Hermes → Ollama Python test silently prints nothing
通过在使用 heredoc 时添加交互标志,或直接使用内联命令形式即可解决:
Fix:
If using `python -` with a heredoc, add `podman exec -i`.
Or simply use `python -c`.
一个没有明显本地 Ollama 选项的提供商菜单:
Problem:
The Hermes provider menu doesn't contain "local Ollama"
通过选择手动自定义端点并输入本地 v1 URL 即可解决:
Fix:
Choose:
Custom endpoint (enter URL manually)Then:
http://127.0.0.1:11434/v1
赫尔墨斯抱怨上下文窗口太小,尽管其他功能都正常运行:
Problem:
Everything works, but Hermes reports an inadequate context window
可通过在服务器端将上下文长度设置为64000,将Hermes配置为相同值,再通过Ollama的进程列表查看实际分配情况来解决该问题:
Fix:
Set OLLAMA_CONTEXT_LENGTH=64000 server-side and configure Hermes for the same value.
Verify the real allocation with:
ollama ps
信任边界应设置在何处
这里的关键并非Ollama或ROCm,而是如何确定信任边界的位置。要求绝不读取目录之外的任何内容的指令属于行为规范;而从未被赋予主机其他文件系统访问权限的Podman容器则构成了操作系统层面的边界。Hermes提供的写保护根目录固然有用,但Hermes本身将其视为额外层而非真正的沙箱,因为shell命令仍能绕过文件工具的防护机制。
由此形成的信任模型将各层从弱到强依次叠加,从指令限制与Hermes的文件写保护开始,最终以容器边界作为终点:
Prompt restrictions
↓
Hermes file write protections
↓
Hermes container filesystem
↓
Rootless Podman user namespace
↓
Host filesystem permissions
即便模型收到了隐藏在 Markdown 文件中的恶意指令,关键问题不在于它是否会遵从原始提示,而在于被攻破的代理实际上能够访问什么。在这种设计下,答案被刻意限制在很小的范围内。
分层调试
Hermes 和 Ollama 都在快速变化。Hermes 的当前文档支持自托管的 OpenAI 兼容端点,Ollama 也不例外,但也有上游报告提到通过自定义 Ollama 端点进行工具调用的行为。如果普通聊天功能正常,但 Hermes 似乎仅描述工具调用而不实际执行,那么在认定 Podman 沙箱出问题之前,应先查看当前的 Hermes 问题追踪器。
正因如此,需要以一系列问题来测试整个技术栈:从 Podman 是否能识别 GPU,到 Ollama 是否能加载模型,再到 Hermes 是否能与 Ollama 进行通信:
Does Podman see the GPU?
↓
Does Ollama see the model?
↓
Does Ollama actually use the GPU?
↓
Is the context really 64K?
↓
Can Hermes reach /v1/models?
↓
Can Hermes perform an actual file operation?
↓
Can Hermes reach anything it shouldn't?
不要试图同时调试全部六层。
完整配置带来的功能
该配置可实现本地推理、AMD GPU加速、持久化的Hermes内存以及一个可写入的主机工作空间:
Local inference YES
AMD GPU acceleration YES
Hermes persistent memory YES
One writable host workspace YES
它不需要云模型,不暴露主机文件系统,不暴露 Podman 或 Docker 套接字,也没有常规的互联网出口连接:
Cloud LLM required NO
Host filesystem exposed NO
Podman/Docker socket exposed NO
Normal Internet egress NO
Entire Obsidian vault exposed NO
这是一种更便捷的方式,可用于测试功能强大的本地智能体。Hermes仍拥有足够的访问权限以发挥作用,只是它无法自行决定“足够”的访问权限标准是什么。
相关阅读
- 使用LangGraph和Ollama构建具备自我修正功能的文档智能体 —— 一种本地反射式处理流程,其中一个模型负责起草Python API文档,第二个模型对其进行评审,第三个模型则整合结果,所有环节通过Ollama上的LangGraph循环实现连接。