Skip to main content

通过代理访问 SSH

LLM 智能体如何通过 SSH 代理 API(而不是裸 SSH 密钥)安全地在远程机器上执行命令。


通过代理访问 SSH

智能体需要在远程机器上执行命令——部署容器、读日志、修配置。把裸的 SSH 私钥交给 LLM 是个坏主意:密钥会落进上下文窗口、日志和转录文本。SSH 代理解决了这个问题:凭据由它掌管,智能体只说 HTTP。

模型

LLM ──HTTPS──► SSH 代理 ──SSH──► 目标机器
                (掌管密钥、
                  审计日志、
                  速率限制)

代理通过简单的 REST 面提供持久会话:

端点 用途
POST /connect?target=vps1 打开会话 → session_id
POST /<sid>/exec {command, timeout} 执行命令(异步)→ exec_id
GET /<sid>/exec/<exec_id> 轮询输出
SFTP 端点 文件上传/下载,ls,mkdir,rm

认证是 Bearer 令牌——和你用的其他 API 相同的模式。

执行模式

# 1. 连接一次,整个任务复用会话
SID=$(curl -s -H "Authorization: Bearer $KEY" \
  "https://ssh-proxy.example/connect?target=vps1" | jq -r .session_id)

# 2. 执行命令
EID=$(curl -s -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -X POST "https://ssh-proxy.example/$SID/exec" \
  -d '{"command": "docker ps --format \"{{.Names}}\"", "timeout": 120}' | jq -r .exec_id)

# 3. 轮询结果
curl -s -H "Authorization: Bearer $KEY" "https://ssh-proxy.example/$SID/exec/$EID"

行为准则

  1. 复用会话。 每条命令都连接一次会浪费资源并触发速率限制。保存 session_id(如 /tmp/vps1_sid),复用前先心跳确认。
  2. 给目标命名,而不是去发现它们。 目标是预先注册的(vps1、pi……)。代理是唯一的事实来源——永远不要把 IP 地址硬编码进智能体代码。
  3. 文件优先用 SFTP,而不是 shell 的 cat/heredoc。 通过 exec 转义二进制数据会损坏载荷。使用专用的上传/下载端点。
  4. 给你的命令加引号。 JSON 体会被解析两次(HTTP + shell)。远程命令用单引号包裹,并保持单行。
  5. 假设审计存在。 每次执行都会落入代理的审计日志——像人类在读一切那样行事(他确实可以)。

什么时候不要用 exec

  • 读取拥有 API 的结构化状态(Docker、数据库、Synapse 的 Mind API)——永远优先用 API,而不是解析 CLI 输出。
  • 长时间运行的交互式进程。exec 是带超时的即发即忘;改用目标机上的 nohup + 状态文件。
  • 没有明确指令的任何破坏性操作。代理给你能力——人类给你许可。

错误恢复

症状 处理
连接时 401 令牌过期——从 memory/settings 重新读取,绝不从转录文本
会话 404 会话过期(24 小时上限)——重新连接
exec 超时 提高 timeout 或拆分命令;检查目标机负载
文件内容损坏 你用了 exec 而不是 SFTP——改用 SFTP 端点