Windows 用 WSL 部署 DeepSeek Harness + Hermes Agent 实战避坑指南

Windows 用 WSL 部署 DeepSeek Harness + Hermes Agent 实战避坑指南


Windows11+WSL2 部署 dsh 与 Hermes 并 7x24 常驻的实战避坑(2026-09 实测)

Windows 上跑 DeepSeek Harness + Hermes Agent:用 WSL 部署的实战避坑指南

写作日期:2026-09-05 · 实测版本:DeepSeek Harness @deepseek-ai/dsh@0.1.2-rc.1、Hermes Agent v0.21.0、Node v26、Windows 11 + WSL2(Ubuntu 24.04)

本文不抄官方文档,全部来自在一台 Windows 11(GPD 掌机)上把两套 Agent 完整跑起来并“7×24 常驻”的真实踩坑记录。


一、先说结论:为什么一定要用 WSL,而不是 Windows 原生

DeepSeek Harness(dsh)和 Hermes Agent 的工具链(终端检查、路径语义、bash/子进程、浏览器后端、各色 CLI)都是 Linux-first。

Windows 原生能装(dsh 官方有 PowerShell 支持、Hermes 有 install.ps1),但社区实测 + 我们实测的结论一致:

  • dsh 在 Windows 原生终端跑,会出现 BashError: subprocess-local: terminal inspection is unsupported on platform win32、The path . is not an absolute path 等持续报错;
  • 而 WSL2 是完整 Linux 内核,等于官方“最佳工况”,且和 macOS/Linux 服务器环境几乎同构——你从 mac/服务器迁移配置可以整包平移。

所以:装进 WSL2 Ubuntu,浏览器从 Windows 侧打开(界面走网络端口,不依赖图形系统)。

资源占用(大家最关心)

  • WSL 空闲常驻内存约 1.5~2.5GB(Ubuntu 系统 + dsh/hermes 两个 node/python 进程),CPU 空闲接近 0,磁盘 3~6GB;
  • 一台 16~24GB 内存的机器常年挂着完全无感;
  • 可以封顶限流,见下文 .wslconfig 模板。

二、WSL 前置配置(决定能不能“常驻”)

WSL2 有两大坑,必须先处理,否则服务要么休眠、要么随会话死掉:

1. 关掉 WSL 空闲自动关机

默认 WSL2 在最后一个进程退出(或没有 wsl 客户端连接)约 60 秒后会把整个虚拟机休眠,带走你所有后台服务。

在 C:\Users\<你>\\.wslconfig 写:

[wsl2]
vmIdleTimeout=-1        # 禁用空闲自动关机(关键)
memory=6GB             # 内存上限(按需)
processors=8
autoMemoryReclaim=gradual
swap=2GB

然后 wsl --shutdown 重启一次 WSL 生效。

2. 无头服务可以关掉 WSLg(可选但推荐)

WSLg/Weston 是 WSL 里跑 Linux 图形程序用的。dsh / hermes 都是无头服务,根本用不到图形,而 Weston 偶尔会段错误把整个 WSL 虚拟机带崩(我们一天崩了 3 次,dmesg 里全是 weston segfault)。

在 .wslconfig 加:

guiApplications=false    # 关闭 WSLg

两个服务照常跑,浏览器访问不受任何影响(那是网络服务)。

3. 在 Ubuntu 里开 systemd?——不推荐(重要)

很多教程让你 systemd=true 后把服务交给 systemd。实测坑:这台 WSL 里 systemd 会在 wsl 会话断开时把服务优雅停掉(journal 里出现 Stopping dsh-web.service ... Deactivated successfully),服务照样消失。

我们的最终方案是绕开 systemd,用“Windows 任务计划保持一条常驻 wsl 会话”,见第五节——比 systemd 可靠得多。


三、安装 DeepSeek Harness(dsh)

1. Node 26 + 全局安装

Ubuntu 里先装 Node 26(源机/服务机建议同版本):

curl -fsSL https://deb.nodesource.com/setup_26.x | bash
apt-get install -y nodejs build-essential python3

然后装 dsh + pnpm(npm 11 会拦截原生模块构建脚本,必须带 --allow-scripts 白名单,否则 node-pty/ssh2/koffi 装完缺二进制):

npm install -g --allow-scripts=@deepseek-ai/dsh-subprocess-local,koffi,node-pty,@google/genai,protobufjs @deepseek-ai/dsh@0.1.2-rc.1 pnpm@11.22.0

Hermes Agent 一条命令:curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash(自动装 uv + Python 3.11 + Node 等,装到 ~/.hermes)。

2. 从 mac/服务器迁移配置(最省事)

dsh 是“配置即文本”架构,迁移别拷整个 ~/.dsh(几百 MB 的 node_modules 是平台相关二进制,拷了会坏)。打包这些即可:

~/.dsh/settings.yaml            # 设置/供应商/默认模型
~/.dsh/profiles/web/package.json   # 插件“配方”(dependencies + dsh.profile.bundles 顺序)
~/.dsh/profiles/web/cordis.patch.yml
~/.dsh/profiles/web/pnpm-lock.yaml / pnpm-workspace.yaml
~/.dsh/skills、~/.dsh/.agent-presets、皮肤等
~/.modlens/config.json  ~/.modsearch/config.json   # 视觉/搜索桥(易漏!在 ~/.dsh 之外)

目标机解压到对应位置后:

cd ~/.dsh/profiles/web && pnpm install

三个必踩的坑:

  1. pnpm 11 有 30 天发布年龄门,新版本解析不到 → 在 pnpm-workspace.yaml 顶部加:
    minimumReleaseAge: 0
    
  2. dsh plugin add/remove 会把“已从 bundles 手动摘除的插件”自动加回去(依赖还在就按 dsh.bundle 重新收录)→ 每次动完插件复查 package.json 的 dsh.profile.bundles。我们因为插件不兼容 0.1.2 停用两个插件,被它反复“复活”,重启就崩。
  3. 密钥 ~/.dsh/.credentials.yaml 单独 scp + chmod 600;不要迁移 telegram bot token(每台机器配自己的)。

3. 验证

dsh --profile web --dump-config   # 看组合树; 无 "not found" 噪音
dsh web --no-open                 # 前台启动试跑

四、远程/局域网访问的三个坑(dsh)

坑 A:横幅打印的 LAN 地址是假的

dsh 启动会打印 (LAN: http://172.17.x.x:3080)——那是 WSL 的 NAT 内网地址,局域网其他设备根本路由不到。这是 WSL 拓扑限制(Linux 侧看不到 Windows 物理网卡),不是配置错误。

解法(Windows 侧转发 + 防火墙):

netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=3080 connectaddress=<WSL的IP> connectport=3080
netsh advfirewall firewall add rule name="DSH-3080" dir=in action=allow protocol=TCP localport=3080

WSL 的 IP 会随 VM 重启变化,转发断了用 wsl hostname -I 取新 IP 刷新即可。

坑 B:远程打开 Web UI 一直“连接中”

页面能开但永远“连接中”——这是 trustedHosts 信任围栏:实时通道(WebSocket/SSE)只放行 回环 + dsh 检测到的 LAN IP + 显式白名单。你从 192.168.x.x 访问,必须把它加白名单。

在 ~/.dsh/profiles/web/cordis.patch.yml 加:

- id: web-runtime
  config:
    trustedHosts:
      - "192.168.38.58"   # 换成你的 Windows 物理网卡 IP

重启后远程即不再卡“连接中”。本机访问始终走 127.0.0.1:3080/?token=...(token 是官方鉴权,每次重启会换,记下启动日志里的 URL;手机/平板推荐用 dsh-pocket 插件开在 3081 端口的入口,有独立 PIN)。

坑 C:想让横幅也打正确地址(可选补丁)

改 WSL 里全局包 .../node_modules/@deepseek-ai/dsh-web-app/lib/index.js 三处:Config 加 lanHost、resolveLanTrust 加 override 参数、调用处传 config.lanHost,再在 cordis.patch 里配 lanHost: "你的IP"。

⚠️ 注意该包 schema 用的是 Schemastery 不是 zod——写 .optional() 会直接崩启动(z.string(...).optional is not a function),要用 .default("")。dsh 升级会覆盖此补丁,需重打,非必需可不做。


五、让 dsh / hermes 7×24 常驻(任务计划 + 隐藏窗口 + 自愈)

这是最容易翻车的一环,把最终验证可用的方案完整给你:

1. WSL 内的循环脚本(带单实例锁)

/home/<user>/run-dsh-loop.sh:

#!/bin/bash
export PATH="$HOME/.local/bin:$PATH"
exec 9>/home/<user>/.dsh-loop.lock
flock -n 9 || { echo "已有实例,退出"; exit 0; }   # 单实例锁
while true; do
  source ~/.dsh/.env
  dsh web --no-open >> ~/.dsh-web.log 2>&1 &
  pid=$!
  sleep 6
  grep -oE "http://127.0.0.1:3080/\?token=[A-Za-z0-9_-]+" ~/.dsh-web.log | tail -1 > ~/dsh-web-url.txt
  wait $pid
  sleep 5   # 崩溃自动重启
done

hermes 同理(hermes gateway run --accept-hooks,官方推荐 WSL 前台模式)。

2. 隐藏窗口启动器

SSH/任务计划起的控制台程序默认会在桌面弹黑窗口。用一个 vbs 隐藏:

' C:\Users\<you>\run-hidden.vbs
CreateObject("WScript.Shell").Run WScript.Arguments(0), 0, False

3. Windows 计划任务(5 分钟自愈看门狗)

关键设计:不要用 ONLOGON(只在登录时拉一次,VM 中途重启不会复活);改成每 5 分钟触发——wsl.exe 每次触发会自己把 VM 拉起来,flock 保证只有一份真跑,其余秒退。VM 任何时刻重启,5 分钟内自动满血复活。

schtasks /Create /F /TN DSH-Web /SC MINUTE /MO 5 /RL HIGHEST /TR "\"wscript.exe\" \"C:\Users\<you>\run-hidden.vbs\" \"wsl.exe -d <发行版> -u <用户> -- bash -lc /home/<user>/run-dsh-loop.sh\""
schtasks /Run /TN DSH-Web

4. 运维必须知道的 schtasks 坑

  • /Change /TR 的嵌套引号会被 cmd 吞掉、静默无效 → 用 /Delete + /Create 重建,建完 schtasks /Query /XML 验证;
  • /Delete / /End 杀不掉已在运行的子进程树(wsl 会话变成孤儿继续跑,还会反复 \/Run攒出一堆抢服务的僵尸循环)→ 真正重启用taskkill /PID /T /F或进 WSLpkill`;
  • 排查进程用 PowerShell:Get-CimInstance Win32_Process | ? { $_.Name -match 'wsl|cmd' } 按 SessionId/命令行过滤。

六、Hermes Agent 的模型与网关配置

1. 填模型凭据

hermes 读 ~/.hermes/.env(原生 env 文件,注意不是 config):

# ~/.hermes/.env
DEEPSEEK_API_KEY=sk-xxx
# KIMI_API_KEY=sk-xxx   # 备用

设置默认模型:

hermes config set model.provider deepseek
hermes config set model.default deepseek-v4-flash
hermes config set model.base_url https://api.deepseek.com
hermes -z "测试"      # 无头验证

经验:aux 每次探测 nous/OpenRouter 未配置的报错是纯日志噪音;DeepSeek 不支持 structured-output 时标题生成会自动降级重试——都是预期行为,别被吓到。

2. Telegram 网关

  • 每台机器用自己的 bot(两个网关共用同一 bot 会抢消息);
  • token 写 ~/.hermes/.env:TELEGRAM_BOT_TOKEN=...;
  • 发送者白名单:TELEGRAM_ALLOWED_USERS=<你的数字ID>(不配会被 deny);
  • 运行:hermes gateway run --accept-hooks(WSL 前台,配进上面的任务计划);验证:hermes gateway status / hermes doctor。

七、维护速查

# dsh 最新访问 URL(token 每次重启轮换)
cat ~/dsh-web-url.txt

# 服务状态
hermes gateway status
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3080/

# 干净重启一个服务(别用 schtasks /End)
wsl -d <发行版> -u <用户> -- pkill -f "dsh web --no-open"   # 循环脚本会自愈重启
  • 两套都处 developer preview,升级前先备份 ~/.dsh 配置与 ~/.hermes,升级后重跑 hermes doctor、复查 bundles;
  • 插件若与新版不兼容,优先从 bundles 摘除等作者适配(依赖保留),别硬留导致启动崩溃循环。

参考

本文为个人实战记录,版本迭代快,以官方文档为准。

33400举报0子龙•23天前
被收录:

暂无评论