OpenJarvis 原生 Windows 部署指南:无需 WSL2 与 Docker 的 PowerShell 安装与服务化
【免费下载链接】OpenJarvisPersonal AI, On Personal Devices项目地址: https://gitcode.com/gh_mirrors/op/OpenJarvis
OpenJarvis 是一个"Personal AI, On Personal Devices"的个人 AI 项目。本文面向 Windows 用户,完整讲解如何在原生 Windows 上通过 PowerShell 安装 OpenJarvis、将其注册为开机自启的 Windows 计划任务服务,并安全地决定是仅限本机(loopback)还是暴露到局域网(LAN)。文章以 deploy/windows/README.md 为主线,并结合 deploy/windows/install.ps1、deploy/windows/jarvis-service.ps1 以及系统级服务定义文件,给出源码级佐证。读完本文,你将掌握:一条命令完成安装、计划任务服务的注册/查询/卸载、以及"loopback 默认免密钥 / 局域网暴露必须配 API Key"的完整安全模型。
背景:为什么需要原生 Windows 部署
OpenJarvis 在 Linux 和 macOS 上分别通过 systemd(deploy/systemd/openjarvis.service)与 launchd(deploy/launchd/com.openjarvis.plist)来管理常驻的 API 服务进程。Windows 侧的部署是其原生支持(Native-Windows Support RFC)的 Phase-1,目标是在不依赖 WSL2、不依赖 Docker、不依赖 MSYS2的前提下,用 PowerShell 提供与 Linux/macOS 对等的"安装 → 服务化 → 自启 → 守护"体验。
从 deploy/windows/install.ps1 的头部注释可以确认,它是 Linux/macOS 安装脚本 scripts/install/install.sh 的 PowerShell 对等实现,二者保持相同的步骤骨架(环境检查、依赖安装、仓库克隆、依赖同步、启动模型拉取、服务注册),只是把"systemd unit / launchd plist"替换为"Windows 计划任务(Scheduled Task)"。
一、一行命令安装(One-liner install)
在普通或管理员权限的 PowerShell 中执行:
irm https://open-jarvis.github.io/OpenJarvis/install.ps1 | iex其中irm是Invoke-RestMethod的别名,iex是Invoke-Expression的别名:先远程下载脚本内容,再直接在当前会话中执行。
安装脚本执行的 7 个步骤
对照 deploy/windows/install.ps1 的源码,安装过程依次完成:
- 拒绝非 Windows 主机与过老系统:通过
$PSVersionTable.Platform -ne 'Win32NT'判断平台;通过[System.Environment]::OSVersion.Version.Build校验系统版本,要求Windows 10 1809(build 17763)或更新。 - 检查 Python 3.10 – 3.13:优先探测
python3,回退到python;若未安装,会用 winget 自动安装Python.Python.3.13。值得注意:Python 3.14 目前不被支持(因为 numpy 尚未提供 cp314 Windows wheels,见源码中的#432注释)。 - 检查
git是否在 PATH:缺失时用 winget 安装Git.Git。 - 检查/安装
uv:若uv不在 PATH,脚本会调用 Astral 官方 PowerShell 安装脚本(https://astral.sh/uv/install.ps1),并手动把%USERPROFILE%\.local\bin追加到当前会话 PATH,以便后续步骤立即使用。 - 克隆仓库到
%LOCALAPPDATA%\OpenJarvis:实际源码目录为%LOCALAPPDATA%\OpenJarvis\src,可通过$env:OPENJARVIS_HOME覆盖安装根目录。若目录已存在,脚本会跳过克隆(-Force时改为git pull --ff-only更新)。 - 执行
uv sync --extra desktop --group desktop-native:安装 FastAPI 服务端、语音后端(faster-whisper、sounddevice 等)以及原生扩展。关于--group desktop-native的语义,见 pyproject.toml:openjarvis-rust(PyO3 原生扩展)被放在 PEP 735 依赖组而非desktopextra 中,因此只有显式--group desktop-native才会从本地 Rust workspace 源码构建,而pip install openjarvis[desktop]不会尝试从 PyPI 解析它。 - 可选地注册计划任务:注册一个登录时自动启动
jarvis serve的计划任务(详见第三节)。
此外,安装脚本还会做两件 README 未展开讲但源码中明确存在的事:
- 自动安装并启动 Ollama、拉取入门模型:若
ollama不在 PATH,会下载官方OllamaSetup.exe(约 150 MB)并以 NSIS 静默参数/S安装;随后轮询等待 Ollama 守护进程就绪(最多 60 秒,期间若 5 秒仍未就绪会自动以ollama serve兜底启动),再拉取入门模型qwen3.5:2b(约 1.5 GB),保证首次运行jarvis即可对话。 - 生成
jarvis.cmdshim:在%LOCALAPPDATA%\OpenJarvis\bin\jarvis.cmd写入自定位 shim(内容为uv run --project "%~dp0..\src" jarvis %*),并把bin目录追加到用户级 PATH,使任何新开的 PowerShell 都能直接敲jarvis命令。
安装完成后,脚本会提示:模型拉取成功则直接运行jarvis,失败则运行jarvis doctor查看进度。
安装结束后的 PATH 注意事项
安装脚本会把bin目录写入用户级PATH,但当前已打开的 PowerShell 进程不会立即感知(Windows 进程环境继承自父 shell)。因此安装完成后请新开一个 PowerShell 窗口再执行jarvis。
二、安装参数:Flags 与环境变量双通道
由于irm | iex的管道方式无法把param()参数传入脚本字符串,install.ps1 提供了两套控制方式,见 deploy/windows/install.ps1 的参数解析逻辑:
| Flag(直接运行脚本文件时) | 作用 |
|---|---|
-Service | 无条件注册计划任务(不弹交互式询问) |
-SkipService | 不询问、不注册计划任务 |
-Force | 即使已完成也重新执行所有步骤(含重新git pull) |
环境变量通道(irm | iex时生效,与 Flag 同名语义一一对应):
| 环境变量 | 等效 Flag | 说明 |
|---|---|---|
OPENJARVIS_SKIP_SERVICE=1 | -SkipService | 跳过服务注册 |
OPENJARVIS_SERVICE=1 | -Service | 强制注册服务 |
OPENJARVIS_FORCE=1 | -Force | 强制重跑 |
源码中明确:"Any explicit -switch wins; env vars only fill in the gaps",即显式 Flag 优先,环境变量仅在 Flag 未给出时兜底。典型用法:
$env:OPENJARVIS_SKIP_SERVICE = '1' irm https://open-jarvis.github.io/OpenJarvis/install.ps1 | iex如果需要对安装过程做更细粒度的控制(例如组合-Force与-SkipService),建议先把脚本保存到本地再执行:
irm https://open-jarvis.github.io/OpenJarvis/install.ps1 -OutFile install.ps1 .\install.ps1 -Force -SkipService交互式提示的判定细节
当用户既没给-Service也没给-SkipService时,脚本只在"存在真实键盘会话"([Environment]::UserInteractive为真且 stdin 未被重定向)时才弹出Register OpenJarvis as a Windows scheduled task (auto-start at logon, loopback only)? [y/N]。对于非交互环境(如 CI、管道),会自动跳过服务注册并打印后续手动注册的提示。同时脚本会预先检查管理员权限——Register-ScheduledTask需要提升权限,若用户显式要求-Service但当前 PowerShell 未提升,会直接报错退出,避免"询问后再因 Access Denied 失败"的糟糕体验。
三、计划任务服务:jarvis-service.ps1
若安装时跳过了服务注册,或后续需要查看/删除服务,可使用 deploy/windows/jarvis-service.ps1 手动管理。该脚本是 Windows 侧对 systemd unit 与 launchd plist 的对等实现,通过子命令驱动:
$srv = "$env:LOCALAPPDATA\OpenJarvis\src\deploy\windows\jarvis-service.ps1" # 安装(幂等——已存在则替换) powershell -ExecutionPolicy Bypass -File $srv install # 查询状态 powershell -ExecutionPolicy Bypass -File $srv status # 卸载 powershell -ExecutionPolicy Bypass -File $srv uninstallinstall 的参数
install子命令支持三个参数(见 jarvis-service.ps1):
| 参数 | 默认值 | 说明 |
|---|---|---|
-InstallRoot | %LOCALAPPDATA%\OpenJarvis(或$env:OPENJARVIS_HOME) | 源码根目录,须先运行过 install.ps1 |
-ListenHost | 127.0.0.1 | 绑定地址;仅当设置了OPENJARVIS_API_KEY时才允许0.0.0.0 |
-ListenPort | 8000 | 监听端口 |
计划任务的运行语义
从 Install-Task 函数 可以看出任务的关键配置:
- 触发方式:
New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME,即登录时启动; - 执行主体:
uv run jarvis serve --host <ListenHost> --port <ListenPort>,工作目录为src目录; - 失败重启:
-RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)——最多重启 3 次,间隔 1 分钟; - 无执行时限:
-ExecutionTimeLimit (New-TimeSpan -Seconds 0),即任务可无限期运行; - 错过补跑:
-StartWhenAvailable,登录被跳过时下次机会到来即补跑; - 最低权限:Principal 使用
LogonType Interactive+RunLevel Limited,以当前用户身份、受限权限运行; - 电池友好:
-AllowStartIfOnBatteries与-DontStopIfGoingOnBatteries,笔记本在电池供电下也能保持服务。
install是幂等的:若任务已存在,会先Unregister-ScheduledTask再重新注册。status子命令会输出任务状态(State)、上次运行时间(LastRun)、上次结果(LastRes,十六进制错误码)与下次运行时间(NextRun)。
提示:任务注册后立即手动启动可用
Start-ScheduledTask -TaskName OpenJarvis。
四、Loopback 与 LAN 暴露:安全模型
默认行为:仅本机可访问
默认情况下,计划任务把服务绑定到127.0.0.1,仅本机可访问,无需 API Key。这与 macOS launchd 的对等配置一致——deploy/launchd/com.openjarvis.plist 同样默认--host 127.0.0.1,并在注释中写明:绑定本机回环地址即可免去 API Key 的负担。
暴露到局域网:必须先生成 API Key
要在局域网内访问,需要两步:
# 1. 生成 API Key。服务端拒绝在未配置 Key 的情况下绑定 0.0.0.0。 $env:OPENJARVIS_API_KEY = (uv run jarvis auth generate-key) # 2. 以 -ListenHost 0.0.0.0 重新注册任务。 powershell -ExecutionPolicy Bypass -File $srv install -ListenHost 0.0.0.0这条强制规则的底层实现可以精确追溯到源码:
- 服务端在 src/openjarvis/cli/serve.py 启动前调用
check_bind_safety(bind_host, api_key=api_key); - src/openjarvis/server/auth_middleware.py 中
check_bind_safety的实现:当绑定地址不是 loopback(ipaddress.ip_address(host).is_loopback为假)且 API Key 为空时,直接打印错误并以SystemExit(1)拒绝启动,提示语即为Run: jarvis auth generate-key; - 同理,systemd 侧通过 deploy/systemd/openjarvis.service 的
EnvironmentFile=/etc/openjarvis/env强制要求存在包含OPENJARVIS_API_KEY的环境文件,缺失则 unit 启动失败——三者(Windows / launchd / systemd)在"非回环必须鉴权"这一安全边界上完全对齐。
在 jarvis-service.ps1 中还有第二道防线:install -ListenHost 0.0.0.0若发现$env:OPENJARVIS_API_KEY未设置,会直接失败并给出指引,而不是注册一个"每次登录都会因无密钥而拒绝启动"的坏任务。
一个关键的 Windows 平台细节:计划任务不继承环境变量
jarvis-service.ps1 的注释解释了 Windows 特有的坑:计划任务启动的进程不会继承注册时会话的环境变量。因此若你设置了OPENJARVIS_API_KEY来绑定0.0.0.0,脚本会额外把该 Key 持久化写入用户级环境变量([System.Environment]::SetEnvironmentVariable(..., 'User')),确保登录会话中的任务能读到它。这是只写回环地址时不需要、但 LAN 暴露时必须处理的步骤。
五、与 systemd / launchd 的对等关系(Parity Table)
| 关注点 | systemd(Linux) | launchd(macOS) | Windows |
|---|---|---|---|
| 服务定义 | deploy/systemd/openjarvis.service | deploy/launchd/com.openjarvis.plist | deploy/windows/jarvis-service.ps1(cmdlet 驱动) |
| 默认绑定 | 0.0.0.0(配 API Key) | 127.0.0.1(无 API Key) | 127.0.0.1(无 API Key) |
| 失败重启 | Restart=on-failure RestartSec=5 | KeepAlive=true | RestartCount=3 RestartInterval=PT1M |
| 自动启动 | multi-user.target | RunAtLoad=true | AtLogOn触发器 |
从上表可以看到一个有趣的设计差异:systemd 默认绑定0.0.0.0但强制要求 API Key(EnvironmentFile缺失则失败),而 launchd 与 Windows 默认回环绑定、无密钥即可用。三者的共同底线是:任何非回环暴露都必须有鉴权,只是"默认是否暴露"的取向不同。systemd 的 unit 还额外带了一套沙箱加固(ProtectSystem=strict、PrivateTmp=true、NoNewPrivileges=true等,见 openjarvis.service),Windows 侧则以"受限权限计划任务"作为对应。
六、更新 OpenJarvis
两种更新方式任选其一:
方式一:git 手动更新
cd "$env:LOCALAPPDATA\OpenJarvis\src" git pull --ff-only uv sync --extra desktop --group desktop-native--ff-only保证只做快进合并,避免本地改动导致更新失败。
方式二:重跑安装器并加-Force
irm https://open-jarvis.github.io/OpenJarvis/install.ps1 | iex # 再以文件方式重跑并传 -Force: # irm ... -OutFile install.ps1; .\install.ps1 -Force-Force会强制重新执行所有步骤,包括git pull --ff-only与重新uv sync(依赖变化会在此生效)。注意更新后若服务依赖的命令或环境有变,建议重新执行一次jarvis-service.ps1 install以刷新计划任务。
七、卸载
powershell -ExecutionPolicy Bypass -File "$env:LOCALAPPDATA\OpenJarvis\src\deploy\windows\jarvis-service.ps1" uninstall Remove-Item -Recurse -Force "$env:LOCALAPPDATA\OpenJarvis"卸载分两步:先通过uninstall子命令停止并注销计划任务(源码中会先Stop-ScheduledTask再Unregister-ScheduledTask),再删除整个安装目录。需要特别说明的是:卸载不会移除uv——它是独立工具,可能被你的其他 Python 项目共用;同理,Ollama 及其拉取的模型也不在卸载范围内,如需清理请另行处理。
八、常见问题与排障
jarvis命令找不到:安装脚本将bin目录写入了用户 PATH,但当前会话不生效。请新开 PowerShell 窗口;若仍不行,手动确认%LOCALAPPDATA%\OpenJarvis\bin\jarvis.cmd存在且 PATH 中包含该目录。- 首次对话失败:大概率是入门模型
qwen3.5:2b未拉取完成。运行jarvis doctor查看模型与后台编排器(bg-orchestrator)的重试进度。 install -ListenHost 0.0.0.0报错:请先执行$env:OPENJARVIS_API_KEY = (uv run jarvis auth generate-key),再重试。服务端与脚本的双重防线都不允许无密钥的非回环绑定。- 任务启动后立刻退出且日志显示拒绝绑定:检查用户环境变量中是否持久化了
OPENJARVIS_API_KEY(LAN 场景必需),以及jarvis serve依赖的引擎(如 Ollama)是否在运行。 - Python 版本不符:当前仅支持 3.10–3.13(3.14 因 numpy 无 Windows wheels 暂不支持)。可通过
winget install Python.Python.3.13安装后重跑安装器。
【免费下载链接】OpenJarvisPersonal AI, On Personal Devices项目地址: https://gitcode.com/gh_mirrors/op/OpenJarvis
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考