低损耗虚拟化:在 macOS 上的 Linux 虚拟机中安全运行 AI 智能体

0 阅读9分钟

1. 引言:安全与性能的两难困境

在macOS 机器上原生运行自主 AI 编程智能体,会带来严重的安全隐患。现代智能体会执行终端命令、通过 pip 和 npm 安装未经审核的依赖、随意修改文件,并且可能通过提示注入攻击被诱导泄露环境变量、dotfiles 或 macOS Keychain 中的机密信息。

业界标准的补救措施,是将智能体沙箱化到 Linux 虚拟机或容器中。然而在 Apple Silicon 上,这会立刻撞上一道虚拟化层面的壁垒。

  • 无计算直通: Apple 原生的 Virtualization.framework 不会将宿主机的 Metal GPU 暴露给 Linux 客户机。Linux 虚拟机只能获得一个 2D 半虚拟化帧缓冲(virtio-gpu)。
  • “虚拟化税”: 试图直接在 Linux 虚拟机内运行 LLM,会迫使模型推理落在虚拟化的 CPU 核心上。生成速度暴跌 80% 以上,使多轮智能体循环变得无法使用。
  • 容器面临同样的限制: Docker Desktop、OrbStack 和 Colima 都运行在 Linux 客户机内核之上,面临完全相同的 GPU 计算真空。

解耦式解决方案:Velo Workspaces AI Bridge

Velo Workspaces 通过将智能体执行环境模型推理引擎分离,解决了这一两难问题:

  1. 模型留在宿主机: 推理服务器——OllamaApple MLX——原生运行在 macOS 上,保留对统一内存带宽和 Metal GPU 加速的完整访问权。
  2. 智能体在虚拟机中: 智能体框架在隔离的 Ubuntu Linux 客户机内执行,将所有文件修改和终端执行限制在沙箱化文件系统中。
  3. VirtIO-vsock 传输: 流量通过虚拟机监控器内存缓冲区经由 vsock 传输,而非传统的虚拟化 NAT 网络栈,将桥接开销降至个位数毫秒。

本指南并排涵盖两种引擎。在第 5 节中任选其一——后续所有内容(虚拟机设置、vsock 桥接、智能体配置)在两种情况下完全相同,只需替换你所选引擎监听的端口即可。

MLXOllama
默认端口808011434
模型来源huggingface.co/models?libr…ollama.com/library
最适合Apple Silicon 原生性能,当前最丰富的首日 MLX 量化发布选择最简单的一条命令安装与模型管理(ollama pullollama run

2. 架构拓扑

┌──────────────────────────────────────────────────────────────────────────────────────┐
│                                 EXTERNAL CLIENT (LAN)                                │
│         ┌───────────────────── Browser: http://<HOST_IP>:8081                        │
└─────────┼────────────────────────────────────────────────────────────────────────────┘
          │                                                                
┌─────────│──────────────────────────── macOS HOST ────────────────────────────────────┐
│         │                                                                            │
│   Incoming LAN Traffic                                                               │
│         │                                                                            │
│         ▼                                                                            │
│  ┌───────────────┐                  ┌──────────────────────────────────────────────┐ │
│  │ Port Forward  │                  │ Inference Server — Ollama or MLX (pick one)  │ │
│  │ (Caddy)       │                  │ - Unified Memory / Metal GPU compute         │ │
│  │ :8081 ─► :4096│                  │ - Listening: 127.0.0.1:<PORT> (TCP)          │ │
│  └──────┬────────┘                  │   MLX default 8080 · Ollama default 11434    │ │
│         │                           │ - Models cached on disk (see Section 3)      │ │
│         │                           └───────────────────────▲──────────────────────┘ │
│         │ Forwarded LAN                                     │ Host Loopback TCP      │
│         │ Traffic (Port 4096)                               │                        │
│         │                                 ┌─────────────────┴──────────────────┐     │
│         │                                 │ Velo AI Bridge (Swift Host Agent)  │     │
│         │                                 │ - VirtIO-vsock Host Listener       │     │
│         │                                 │ - Forwards to whichever engine     │     │
│         │                                 │   and port you selected as         │     │
│         │                                 │   Host Provider                    │     │
│         │                                 └─────────────────▲──────────────────┘     │
│         │                                                   │                        │
│         │ Direct VM Access                                  │ VirtIO-vsock           │
│         │ http://<VM_IP>:4096                               │ Channel (CID 2:<PORT>) │
│         │ (from Host Browser)                               │                        │
│         ▼                                                   ▼                        │
│  ┌─────────────────────────────────────────────────────────────────────────────────┐ │
│  │ LINUX GUEST VM (Ubuntu 26.04)                                                   │ │
│  │                                                                                 │ │
│  │  [Optional] Agent Web UI            AI Forwarding Proxy (socat / daemon)        │ │
│  │   - For agents like OpenCode        - 127.0.0.1:<PORT> ⇄ vsock:2:<PORT>         │ │
│  │   - Listening on: 0.0.0.0:4096      - OPENAI_API_BASE=http://127.0.0.1:<PORT>/v1│ │
│  │             │                                                   ▲               │ │
│  │             └──────────────────── Local IPC ────────────────────┘               │ │ 
│  │                                        │                                        │ │
│  │   Isolated Agent Sandbox: Terminal / Any AI Agent (e.g., Python REPL, Shell)    │ │
│  └─────────────────────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────────────┘

注:在 VM 内,Agent 的流量通过 VirtIO-vsock 通道转发到 macOS宿主机上的 AI Bridge,然后由 AI Bridge 转发到宿主机上的推理服务器(Ollama 或 MLX)。另外,单独的 Caddy 端口转发允许外部 LAN 客户端访问 VM 的可选 Web UI。

网络流量说明

  • 推理路径: 智能体向 VM 内的 127.0.0.1:<PORT> 发送标准 OpenAI-compatible HTTP 请求——MLX 使用 8080,Ollama 使用 11434。本地 socat 代理将该负载通过 vsock 路由到宿主机。Swift AI Bridge 接收连接,并将其转发到你为该 Workspace 选择的引擎。
  • 主机 UI 访问: 宿主机浏览器通过标准虚拟机监控器桥接网络,经 http://<VM_IP>:4096 直接连接 Guest 的虚拟网络接口。
  • 外部 LAN 访问: 由于外部机器无法直接路由到 VM 的私有虚拟子网,因此宿主机会将外部端口(8081)转发到 Guest 的 Web UI 端口(4096)。使用 8081 是为了避免与宿主机已经使用的推理端口(808011434)发生冲突。

3. 选择模型

两种引擎都动态使用 macOS 统一内存。由于操作系统、显示合成器和模型的 KV Cache 共享这一内存池,建议至少预留主机总 RAM 的 20–25% 用于系统开销。

以下模型标识符已在本文撰写时进行验证——在拉取模型之前,请始终在 huggingface.co/models?libr…(MLX)或 ollama.com/library(Ollama)确认当前可用性和确切标签,因为模型库会发生变化。

Mac 统一内存MLX(Hugging Face)Ollama(ollama pull ...量化使用场景
16 GBmlx-community/Qwen2.5-Coder-7B-Instruct-4bitqwen2.5-coder:7b4-bit快速代码补全、轻量级脚本生成、单文件编辑。
24 GB / 32 GBmlx-community/Qwen2.5-Coder-32B-Instruct-4bit
mlx-community/Mistral-Small-24B-Instruct-4bit
qwen2.5-coder:32b
mistral-small
4-bit多文件推理、重构,以及复杂逻辑调试。
36 GB / 48 GBmlx-community/Qwen3.8-27B-4bit*qwen3.8:27b*4-bit高级 Agent 任务、架构设计、全仓库索引。
64 GB / 96 GBmlx-community/Llama-3.3-70B-Instruct-4bitllama3.3:70b4-bit深度推理、零样本完整仓库综合、复杂规划。
128 GB+mlx-community/Qwen3.8-2.4T-A95B-*bit
deepseek-ai/DeepSeek-V3
deepseek-v3*1-bit 至 4-bit全规模自主流水线、重型并发 Agent 集群。

* 这些是非常新的(2026)或非常大的模型——在拉取之前,请通过模型库链接检查当前准确的标签/量化版本;MLX 和 Ollama 对新版本的转换可能会延迟数天至数周。


4. VM 配置指南

由于庞大的 LLM 权重和 KV 缓存都留在 macOS 统一内存中,Linux 虚拟机只需要足够的资源来执行智能体生成的代码。

重要(会话持续时间): 长时间运行的自主会话会逐渐泄漏资源。智能体会持续生成临时文件、编译依赖、膨胀 pip/npm 缓存并保留执行日志。为长寿命环境分配额外的内存缓冲,以防 Linux 内存不足(OOM)杀手终止任务。

场景vCPU内存存储主要工作负载与原因
临时 / 轻量自动化2 vCPUs2 GB – 3 GB15 GB – 20 GBCLI 自动化和简单脚本。适合短时、一次性任务。
全栈 Web 开发4 vCPUs4 GB – 6 GB30 GB – 40 GBNode.js、Django、SQLite、Vite。可容纳构建工具和后台服务器。
长时间运行的 Agent 会话4 – 6 vCPUs8 GB – 12 GB50 GB – 60 GB持续自主循环。为缓存的构建产物和日志提供内存缓冲。
系统编程与 Docker6 – 8 vCPUs12 GB – 16 GB60 GB – 80 GBRust/Go/C++ 编译、VM 内 Docker 服务。避免编译过程因资源不足而卡死。

5. 在 macOS 宿主机上安装推理引擎

选择一个引擎。本节中的所有步骤都在宿主机的 macOS Terminal 中运行。

5.1 选项 A — MLX

使用 Python(3.10+)安装官方 Apple MLX 语言模型包:

# 创建并激活隔离的虚拟环境
python3 -m venv ~/.mlx-env
source ~/.mlx-env/bin/activate

# 安装 MLX LM server 包
pip install --upgrade mlx-lm

启动绑定到回环地址(127.0.0.1)的服务器,并使用端口 8080。首次运行时,它会自动从 Hugging Face 下载模型。下面的 mlx-community/Qwen2.5-Coder-7B-Instruct-4bit 仅作为示例——请替换为你在第 3 节中根据 RAM 配置选择的标签:

mlx_lm.server \
  --model mlx-community/Qwen2.5-Coder-7B-Instruct-4bit \
  --host 127.0.0.1 \
  --port 8080

在第二个 macOS Terminal 中,验证它是否响应 OpenAI-compatible 请求:

curl -s http://127.0.0.1:8080/v1/models | grep "id"

5.2 选项 B — Ollama

ollama.com 安装 Ollama(或运行 brew install ollama)。下面的 qwen2.5-coder:7b 仅作为示例——请改为第 3 节中根据 RAM 配置选择的标签:

brew install ollama
ollama serve &          # 或直接启动 Ollama App——它会自动运行此服务
ollama pull qwen2.5-coder:7b

Ollama 默认监听 127.0.0.1:11434。验证它是否响应:

curl -s http://127.0.0.1:11434/v1/models | grep "id"

6. 在 Velo Workspaces 中创建 VM

  1. 在 macOS 上启动 Velo Workspaces
  2. 在侧边栏选择 AI Workspace,点击右上角的 +
  3. 选择镜像来源:下载官方镜像、选择本地 OS 镜像文件,或从已有虚拟磁盘启动。这里选择 Ubuntu 26.04 LTS(Server 或 Desktop)。
  4. 选择 AI Sandbox 配置,然后点击 “Show Advanced Settings”
  5. 根据第 4 节的配置指南分配硬件参数(例如 4 vCPUs、6 GB RAM、40 GB Disk)。确保勾选 AI Bridge,并让 Host Provider 与你在第 5 节中启动的引擎一致——MLXOllama

ai_workspace_config.png 示例:AI Sandbox 配置,已启用 AI Bridge,并将 Host Provider 设置为 MLX。如果你在第 5 节启动的是 Ollama,则在此处选择 Ollama。

  1. 点击 Continue,安装 Guest OS,然后启动虚拟机并登录。

7. 在虚拟机内安装和配置 AI 智能体

本节中的所有步骤都在 VM 内的 Ubuntu Linux Terminal 中运行。在本节中,<PORT> 对 MLX 为 8080,对 Ollama 为 11434——即你在第 5 节中选择的端口。

7.1 建立客户机 Vsock 代理

无需手动输入这些命令,只需在 Velo Workspaces 中打开正在运行的 Workspace 的 AI Bridge 标签页——其中已经填好了准确的端口,每个命令块旁都有 Copy 按钮。运行步骤 1,然后运行步骤 2(在当前 Terminal 会话的整个生命周期内转发——最简单,适合快速测试)或步骤 3(将其安装为重启后仍然存在的 systemd 服务——更适合以后还会继续使用的环境):

ai-bridge-tab.png

# 1. 安装 socat
sudo apt-get install -y socat

# 2. 在当前会话中转发端口
socat -d -d TCP-LISTEN:<PORT>,fork,reuseaddr,bind=127.0.0.1,nodelay VSOCK-CONNECT:2:<PORT>

— 或者,要让它在重启后继续运行 —

# 3. 安装为 systemd 服务,而不是执行步骤 2
sudo tee /etc/systemd/system/velo-ai-bridge.service >/dev/null <<'EOF'
[Unit]
Description=Velo Workspaces AI Bridge (127.0.0.1:<PORT> to the host over the high speed channel)
After=network.target

[Service]
ExecStart=/usr/bin/socat TCP-LISTEN:<PORT>,fork,reuseaddr,bind=127.0.0.1,nodelay VSOCK-CONNECT:2:<PORT>
Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable velo-ai-bridge
sudo systemctl restart velo-ai-bridge

然后,无论哪种方式,验证跨 vsock 边界的客户机到宿主机连接:

# 4. 在 Workspace 内检查
curl -sS http://127.0.0.1:<PORT>/v1/models

如果它返回了你的模型信息,说明桥接已生效——下面每个智能体都指向 http://127.0.0.1:/v1,并且每个智能体都会在下一节中自行配置该地址,因此这里无需单独设置全局环境变量。


7.2 配置智能体框架

智能体选项 A:OpenCode(CLI 与 Web UI)

OpenCode 同时提供自动化 CLI 智能体和交互式 Web 工作区。

  1. 安装 OpenCode 及其构建依赖:

    sudo apt install -y curl git build-essential
    curl -fsSL https://opencode.ai/install | bash
    source ~/.bashrc
    
  2. 将推理引擎注册为 Provider。 创建 ~/.config/opencode/opencode.json

    mkdir -p ~/.config/opencode
    nano ~/.config/opencode/opencode.json
    

    粘贴以下内容,并将 <PORT> 和模型名称替换为你所选引擎对应的值(来自第 3 节):

    {
      "$schema": "https://opencode.ai/config.json",
      "provider": {
        "local": {
          "npm": "@ai-sdk/openai-compatible",
          "name": "Local Server",
          "options": {
            "baseURL": "http://127.0.0.1:<PORT>/v1"
          },
          "models": {
            "<model-name>": {
              "name": "<Display Name>"
            }
          }
        }
      },
      "model": "local/<model-name>"
    }
    
  3. 以非交互式 CLI 模式运行——--auto 会自动批准沙箱内的工具执行:

    opencode run --auto "Write a python script to benchmark disk I/O, execute it, and print the results."
    
  4. 或者启动交互式 TUI,然后通过向导连接,而不是(或同时)使用配置文件:

    opencode
    

    在 TUI 中输入 /connect,选择 Local Server,当系统提示输入 API key 时输入任意值(例如 local)——本地服务器不会检查该值。

  5. 或者运行 Web 界面,绑定到 0.0.0.0,使其可以通过虚拟机监控器网络访问:

    opencode web --port 4096 --hostname 0.0.0.0
    

    在 Mac 浏览器中访问:http://<VM_IP>:4096

    从 LAN 上的另一台 PC 访问 Web UI: 外部机器无法直接路由到 VM 的私有子网,因此需要在宿主机上转发一个端口。在 macOS 宿主机上:

    brew install caddy
    caddy reverse-proxy --from :8081 --to <VM_IP>:4096
    

    此后,LAN 上的任何机器都可以访问 http://<HOST_IP>:8081


智能体选项 B:Open Interpreter

Open Interpreter 提供专为代码执行设计的直接终端智能体循环。

  1. 安装:

    pip install open-interpreter
    
  2. 连接到本地 endpoint 启动——-y 会在每次执行时自动批准代码执行,而无需反复确认:

    interpreter \
      --api_base http://127.0.0.1:<PORT>/v1 \
      --model <model-name> \
      --api_key local \
      -y
    

智能体选项 C:Aider

Aider 专为 Git 集成的结对编程和仓库修改而设计。它从环境变量读取端点,而非专用 CLI 标志,并且需要在模型名称前加 openai/ 前缀,以便通过其 OpenAI-compatible 路径进行路由:

  1. 安装:

    python3 -m pip install aider-chat
    
  2. 在 Git 仓库中运行:

    cd /path/to/project
    export OPENAI_API_BASE=http://127.0.0.1:<PORT>/v1
    export OPENAI_API_KEY=local
    aider --model openai/<model-name>
    

智能体选项 D:Goose

Goose 是由 Block 开发的可扩展开源自主智能体。

  1. 安装:

    curl -fsSL https://github.com/block/goose/releases/download/stable/download_cli.sh | CONFIGURE=false bash
    export PATH="$HOME/.local/bin:$PATH"
    
  2. 配置自定义 OpenAI-compatible Provider:

    goose configure
    # 选择:Add Provider → Custom / OpenAI-compatible
    # Base URL: http://127.0.0.1:<PORT>/v1
    # API Key:  local
    # Model:    <model-name>
    
  3. 启动一次性的自主运行:

    goose run --text "Audit this directory, find security misconfigurations in JSON files, and correct them."
    

原文:dev.to/wango/zero-…