Please enable Javascript to view the contents

开发、运维好帮手 - deepseek-harness-remote-node

 ·  ☕ 8 分钟

1. 上下文不够是制约 AI Agent 使用的关键因素

Agent 完成工作的质量,既取决于模型能力,也受限于能触达的环境上下文。

对于开发、运维来说,更难的是环境可能还是分裂的,线上有完整日志、文档在知识库、代码在 Git 仓库。模型读不到这些信息,也就无法准确判断问题。所谓上下文不够,很大程度上不是模型窗口不够大,而是环境不在 Agent 的访问范围内。

由此给我们带来挑战:

  • 开发需要在本地环境改代码、跑测试,再传回线上进行部署测试
  • 运维需要在机器上执行命令、查看日志,然后把结果给 Agent 进行分析排查故障

人与 Agent 交替验证是现在普遍的 AI 工作流。

2. 将环境完全交给 AI Agent

目前常见的做法是在环境中安装 Agent 或者由中心的 Agent 通过 SSH 、MCP 执行 Job 进行操作。

前一种方式将 Agent 部署在每台机器上,泄漏模型访问凭证; 后一种方式使 Agent 能大面积访问主机,潜在风险巨大。

另外一个思路是,让 Agent 远程运行在环境上:

  • 超级大脑只需要一个。模型调用、会话状态、插件、密钥、审计都保留在一处集中管理
  • 更易管控。通过简单配置即可纳管目标机器,通过统一入口使用 Agent
  • 成本更低。目标机器上只运行一个轻量的转发进程,资源占有少
  • 接入更容易。通过上位端入口,可以轻松管控大批量机器

下面就是基于 deepseek-harness 实现的一个方案。

3. deepseek-harness-web

deepseek-harness-web 把 dsh 的 Web 界面打包成单个容器,一条命令就能起一个 Agent,自带 Web UI、模型路由和持久化存储。

简单说,它解决的是大脑在哪里,我的选择是 deepseek-harness + 容器 + 持久化。

┌─────────────────────────────────────────────────────────────┐
│                     dsh-web 容器                            │
│                                                             │
│  entrypoint.sh  ──  PID 1,自动重启循环                     │
│    ├─ sync-provider.sh   模型路由 → settings.yaml           │
│    ├─ sync-workspace.sh  启动拉取 + 退出时落盘              │
│    ├─ s3-sync.mjs        双向同步守护进程                    │
│    └─ dsh web            DeepSeek Harness Web UI            │
│                                                             │
│  /root  ⇄  ./home(bind mount)  ⇄   S3 bucket(可选)       │
└─────────────────────────────────────────────────────────────┘

对 remote-node 而言,它就是上位机,也是给人的操作入口。

通过配置环境变量,设置相关的配置文件。API_KEY 配置模型访问凭证;设置 BASE_URLMODEL 将自定义模型写入 /root/.dsh/settings.yamlMODEL 支持逗号分隔的多个模型 id,第一个为默认模型。工作区与 dsh 配置都落在 /root(bind mount ./home:/root),配置 S3 后再整体同步到 bucket。

deepseek harness 启动日志会打印带 token 的访问地址,替换为实际的域名或 IP 即可访问。若使用域名访问,需要把 TRUSTED_HOST 设置为浏览器请求携带的 Host 头(可包含端口)。

4. deepseek-harness-remote-node

deepseek-harness-remote-node 把一台远端机器变成 dsh 的执行环境。远端机器主动连接到 dsh 已有的 Web 入口,Agent 的文件读写、shell 命令、终端、语言服务器全部发生在那台机器上——而 Agent 循环、模型调用、会话状态、插件留在宿主。

正常deepseek-harness-remote-node
ctx.fs — 读、写、改dsh 宿主机的磁盘节点的磁盘
ctx.subprocess — 命令、终端、LSPdsh 宿主机的进程节点的进程
Agent 循环、模型调用、会话状态dsh 宿主机dsh 宿主机(不变)

没有它,Agent 只能改宿主机上的文件;有了它,Agent 改的是你指定的那台机器。

例如,问 Agent:「工作机还剩多少磁盘空间?」它会在远端节点上执行 df 命令,而不是在宿主上。

4.1 架构

宿主仍然是一个 dsh 进程,对外只暴露一个 Web 入口;节点是一条从目标机器拨入的连接。

        ┌───────────────────────────────────────────────────────┐
        │  dsh host                                             │
        │                                                       │
        │  webServer  :3080                                     │
        │    ├ /api/remote.mux   ← 浏览器 mux                   │
        │    └ /node/v1          ← 节点通道                     │
        │                                                       │
        │  ctx.nodeRegistry ── @shaowenchen/deepseek-harness-remote-node       │
        │  ctx.fs ........... @shaowenchen/deepseek-harness-remote-node/fs     │
        │  ctx.subprocess ... @shaowenchen/deepseek-harness-remote-node/subprocess │
        └───────────────────────▲───────────────────────────────┘
                                │ wss,由节点主动连接
        ┌───────────────────────┴───────────────────────────────┐
        │  执行环境(Pod / VM / 宿主机)                          │
        │  文件系统 · 进程 · 终端 · 语言服务器                     │
        └───────────────────────────────────────────────────────┘

节点可以是各种形态的执行环境,比如一个 Pod、Container、VM、物理机。

4.2 原理

dsh 的架构里,Agent 的一切环境操作都收敛到两个接口(seam):

接口覆盖范围
ctx.fs读、写、改、列目录、元信息
ctx.subprocess命令、终端、语言服务器

上层能力(bash 工具、PTY、LSP)都组合在这两个接口之上,不指定具体实现。两个接口合起来,就定义了一个执行环境。替换这两个 provider,等同于替换整个执行环境——bash、终端、LSP 一行都不用改,上层完全感知不到。

完整调用链:用户提问 → Agent 调用 bash 工具 → dsh-bash-local 调用 ctx.subprocess(它从不 import child_process)→ 本包的 subprocess 入口把调用转发过通道 → 节点上的 agent 执行。

4.3 安装

宿主和节点都要安装 Node 22+ 环境。

github.com 无法访问时,可以设置--proxy 标志代理两个安装脚本:

1
PROXY=  # 例如 https://ghproxy.chenshaowen.com
  • host

在 dsh-web 容器里执行脚本:

1
curl -fsSL "${PROXY:+$PROXY/}https://raw.githubusercontent.com/shaowenchen/deepseek-harness-remote-node/master/scripts/install-host.sh" | sh -s -- --proxy "$PROXY"

或者也可以通过 --cwd 指定工作目录,默认 $HOME/.deepseek-harness-remote-node

1
2
curl -fsSL "${PROXY:+$PROXY/}https://raw.githubusercontent.com/shaowenchen/deepseek-harness-remote-node/master/scripts/install-host.sh" \
  | sh -s -- --cwd /data/.deepseek-harness-remote-node --proxy "$PROXY"

patch 层会显式 disable 掉本机 provider。


装完重启 dsh。dsh-web 容器里:

```sh
dsh-restart
  • node 侧

在执行环境上执行:

1
curl -fsSL "${PROXY:+$PROXY/}https://raw.githubusercontent.com/shaowenchen/deepseek-harness-remote-node/master/scripts/install-node.sh" sh -s -- --bin-dir ~/.local/bin --proxy "$PROXY"

wss:// 是 dsh web 暴露的地址:

1
2
3
dsh-node --url wss://<host>/node/v1 \
  --credential <install-host.sh 打印出来的值> \
  --cwd ~/.deepseek-harness-remote-node

凭证由 host 安装脚本随机生成并打印,同时存在 $DSH_HOME/node-credentialdsh-node --describe 可以在不连接的情况下打印本机身份。

一台节点只跑一个 agent 进程。节点 id 默认取本机 hostname,同一个 id 的第二个 agent 会被当作 busy 拒掉。检查是否有重复进程。

  • 卸载脚本
1
2
3
4
5
6
7
# host 侧 —— 移除插件软链和配置项
curl -fsSL "${PROXY:+$PROXY/}https://raw.githubusercontent.com/shaowenchen/deepseek-harness-remote-node/master/scripts/uninstall.sh" \
  | sh -s -- --host

# node 侧 —— 移除命令和缓存源码
curl -fsSL "${PROXY:+$PROXY/}https://raw.githubusercontent.com/shaowenchen/deepseek-harness-remote-node/master/scripts/uninstall.sh" \
  | sh -s -- --node

4.5 使用

节点注册后,不需要调用任何东西。 像平时一样和 Agent 对话,它的工具就会在远端机器上运行。

节点上还剩多少磁盘空间?

在当前目录下生成一个 test.txt 文件,内容是 hello world

下面是我接入的一些环境和运行截图。

K8s Pod:

Linux 虚拟机:

macOS 宿主机:

5. 与其他方案的比较

5.1 直接安装 Agent

在每台目标机器上分别安装 Claude Code 或 dsh,彼此独立工作。该方案在功能上成立——每台机器上都是一个完整的 Agent 。

主要问题是:

  • 模型密钥扩散。N 台机器即 N 份密钥,泄露风险乘以 N,轮换需要改动 N 台。
  • 会话历史分散。会话历史只保存在产生它的那台机器上,跨机器检索需要逐台翻查。
  • 版本漂移。N 台各自升级,行为不一致,排查问题前先要确认目标机器的版本。
  • 配置与权限各自为政。若要统一收口,需要额外引入一层配置管理。

如果借助 Job 平台分发 Agent,端到端链路还会更长,需要经历安装、启动、回收各一次。

5.2 SSH 到主机

最直观的做法是复用现有的 SSH 通道:人能够 SSH 到目标机,Agent 也可以。对命令行工具而言 SSH 够用,但对一个要读代码、改代码、跑测试的编码 Agent,SSH 只解决了一半:

问题说明
密钥安全宿主机要持有到 N 台目标机的私钥,宿主机失守则横向可达
联通性目标机要能被宿主访问到,反向场景需要额外的跳板或穿透
文件读写要么靠 cat / sed 拼命令,要么另建一条文件传输通道
终端与 LSPSSH 给你一个 shell,但 PTY 语义、语言服务器的生命周期都要自己再搭一层

5.3 Web IDE

在目标机器上跑一个 Web IDE,人从浏览器进去写代码、做运维。这条路看起来轻量——IDE 自带文件树、终端、语言服务——但改造成本高,需要的资源多。

不只是需要大量开发、运维人员支撑平台,还要在每台目标机器上维护一套完整的 IDE 运行时:文件服务、终端网关、语言服务器进程管理、用户隔离、会话持久化,每一项都需要大量人力。

更关键的是,Web IDE 解决的是"人怎么访问远端环境",而不是"Agent 怎么执行在远端环境"。它把密钥、会话、权限的负担原封不动地搬到每台目标机器上——前面列出的模型密钥扩散、版本漂移、配置分散等问题一个也没少,只是又加了一层平台运维。

即使将 Agent 集成进 Web IDE,得到的也只是一个个孤立的工作空间。每个环境各自维护上下文,公共知识无法集中沉淀,跨机器协作仍然需要人去搬运。

6. 小结

回到最开始的问题:Agent 无法触达目标环境,人与 Agent 交替验证的闭环就不成立。这篇文章给出的方案是——让环境接入 Agent,而不是把 Agent 移动到环境。

具体来说:

  • deepseek-harness-web 把 dsh 的 Web 工作区装进单个容器,一条命令即可自托管,模型调用、会话状态、密钥全部收口在一处。
  • deepseek-harness-remote-node 让远端机器主动连接到 dsh,接管 ctx.fsctx.subprocess 两个接缝,Agent 的文件读写、命令执行、终端、LSP 全部落在远端机器上。
  • 凭证校验已落地,三个包合并为一个,全量 fs.* / proc.* / tty.* 操作族已实现。
  • fail-closed 绝不回退上位机,单槽注册防止冲突,对等测试保证与本地行为一致。

7. 参考链接


微信公众号
作者
微信公众号