
用 PowerShell 自动维护 WorkBuddy models.json:备份、去重和批量写入模型
用 PowerShell 自动维护 WorkBuddy models.json:备份、去重和批量写入模型#
如果只是给 WorkBuddy 添加一个自定义模型,手动编辑 models.json 也能完成。
但如果你经常切换模型、批量添加模型、更新 API 地址,手动维护就容易变成重复劳动:
- 每次修改前要手动备份。
- 多个模型字段要反复复制。
- URL 可能忘记补
/v1。 - 同名模型可能重复写入。
- JSON 格式一旦写坏,WorkBuddy 可能读不到配置。
这篇文章用一个 PowerShell 脚本为例,拆解如何自动维护 WorkBuddy 的 models.json。
示例脚本仓库:
https://github.com/xujfcn/workbuddy-crazyrouter
本文重点讲脚本设计思路,不要求你一定使用同一个模型服务。你可以根据自己的环境修改 Base URL、模型列表和能力字段。
1. 脚本要解决什么问题?#
一个实用的 WorkBuddy 配置脚本,至少要解决这些问题:
| 问题 | 脚本处理方式 |
|---|---|
| 配置文件不存在 | 自动创建目录和文件 |
| 旧配置可能有用 | 写入前自动备份 |
| URL 写法不一致 | 自动规范化 Base URL |
| 模型重复 | 按模型 ID 去重 |
| 需要批量写入 | 支持模型列表参数 |
| 想重置旧配置 | 支持替换模式 |
| 不想交互输入 Key | 支持环境变量 |
这类脚本的目标不是“炫技”,而是减少手动编辑配置文件带来的不确定性。
2. 参数设计#
脚本开头定义了一组参数:
param(
[string]$ApiKey = $env:CRAZYROUTER_API_KEY,
[string]$BaseUrl = "https://cn.crazyrouter.com",
[string[]]$Models = @(
"claude-opus-4-8",
"claude-opus-4-7",
"claude-sonnet-4-6",
"gpt-5.5",
"gpt-5.4"
),
[string]$ConfigPath = (Join-Path $HOME ".workbuddy\models.json"),
[switch]$ReplaceCrazyrouter,
[switch]$NoBackup
)
这几个参数分别负责:
$ApiKey:模型服务 API Key$BaseUrl:接口基础地址$Models:要写入的模型 ID 列表$ConfigPath:WorkBuddy 配置文件路径$ReplaceCrazyrouter:是否替换旧的同类配置$NoBackup:是否跳过备份
参数化的好处是:脚本不用每次改源码。
例如你想换模型列表:
.\setup-workbuddy-crazyrouter.ps1 -Models "model-a", "model-b"
想换接口地址:
.\setup-workbuddy-crazyrouter.ps1 -BaseUrl "https://api.example.com"
3. 从环境变量读取 API Key#
脚本默认从环境变量读取 Key:
[string]$ApiKey = $env:CRAZYROUTER_API_KEY
这样可以避免把 Key 写死在脚本里。
临时设置方式:
$env:CRAZYROUTER_API_KEY="sk-你的Key"
如果没有环境变量,脚本会提示输入:
$secureKey = Read-Host "请输入 API Key" -AsSecureString
这里使用 SecureString,至少可以避免输入时明文显示在终端上。
不过要注意:最终 Key 仍然需要写入 WorkBuddy 本地配置文件,否则 WorkBuddy 无法调用模型。
所以真正的安全重点是:
- 不要把配置文件发给别人。
- 不要把 API Key 截图到公开平台。
- 不要把包含 Key 的
models.json提交到 Git 仓库。
4. Base URL 规范化#
很多接口地址需要以 /v1 结尾。
但用户输入可能是:
https://api.example.com
也可能是:
https://api.example.com/
或者已经是:
https://api.example.com/v1
脚本通过函数统一处理:
function Normalize-BaseUrl {
param([Parameter(Mandatory = $true)][string]$Url)
$normalized = $Url.Trim().TrimEnd("/")
if ([string]::IsNullOrWhiteSpace($normalized)) {
throw "BaseUrl cannot be empty."
}
if ($normalized -notmatch "^https?://") {
throw "BaseUrl must start with http:// or https://"
}
if ($normalized -notmatch "/v1$") {
$normalized = "$normalized/v1"
}
return $normalized
}
这段逻辑做了三件事:
- 去掉首尾空格和末尾
/。 - 检查是否以
http://或https://开头。 - 如果没有
/v1,自动补上。
这可以避免很多接口路径错误。
5. 读取已有模型配置#
配置文件可能不存在,也可能为空。
脚本先做兼容处理:
function Read-ExistingModels {
param([Parameter(Mandatory = $true)][string]$Path)
if (-not (Test-Path -LiteralPath $Path)) {
return @()
}
$raw = Get-Content -LiteralPath $Path -Raw
if ([string]::IsNullOrWhiteSpace($raw)) {
return @()
}
$json = ConvertFrom-Json -InputObject $raw -NoEnumerate
if ($json -is [array]) {
return @($json)
}
if ($null -ne $json.models -and $json.models -is [array]) {
return @($json.models)
}
throw "Unsupported WorkBuddy models.json format. Expected a JSON array."
}
这里有几个设计点:
- 文件不存在:返回空数组。
- 文件为空:返回空数组。
- 标准数组结构:直接返回。
- 如果是
{ models: [...] }结构:也尝试兼容。 - 其它结构:抛出错误,避免错误写入。
这比直接覆盖文件安全很多。
6. 写入前备份#
修改配置前,脚本会自动备份:
if ((Test-Path -LiteralPath $ConfigPath) -and -not $NoBackup) {
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$backupPath = "$ConfigPath.bak.$timestamp"
Copy-Item -LiteralPath $ConfigPath -Destination $backupPath -Force
Write-Host "已备份原配置:$backupPath"
}
备份文件类似:
models.json.bak.20260605-140000
这一步非常重要。
因为配置脚本再稳,也可能遇到:
- 用户传错模型列表
- 原配置结构特殊
- WorkBuddy 新版本变更字段
- API Key 或 URL 写错
有备份,就能恢复。
7. 模型列表去重#
脚本使用 HashSet 对模型 ID 去重:
$desiredModelIds = New-Object System.Collections.Generic.List[string]
$desiredModelSet = New-Object "System.Collections.Generic.HashSet[string]"
foreach ($model in $Models) {
$trimmed = $model.Trim()
if (-not [string]::IsNullOrWhiteSpace($trimmed) -and $desiredModelSet.Add($trimmed)) {
$desiredModelIds.Add($trimmed)
}
}
这样即使用户传入:
-Models "model-a", "model-a", "model-b"
最终也只会写入一次 model-a。
8. 合并旧配置和新配置#
脚本不是简单覆盖,而是先读取旧配置,再决定保留或移除哪些模型。
核心思路:
- 如果旧模型 ID 和本次要写入的模型 ID 相同,跳过旧模型。
- 如果开启替换模式,删除旧的同类模型。
- 其它模型保留。
- 最后追加本次新的模型配置。
这样可以避免重复模型,同时保留用户已有配置。
9. 写入 WorkBuddy 模型结构#
每个模型最终写成类似结构:
$merged.Add([ordered]@{
id = $modelId
name = $modelId
vendor = "Custom"
url = $targetUrl
apiKey = $ApiKey
supportsToolCall = $true
supportsImages = $false
supportsReasoning = $false
useCustomProtocol = $false
})
这里的能力字段可以根据模型实际能力调整。
例如:
- 支持图片输入:
supportsImages = $true - 支持推理模式:
supportsReasoning = $true - 需要特殊协议:
useCustomProtocol = $true
不确定时,先用保守配置,再逐步测试。
10. 输出 JSON#
最后脚本把模型列表转成 JSON:
$jsonOutput = $merged.ToArray() | ConvertTo-Json -Depth 10
Set-Content -LiteralPath $ConfigPath -Value $jsonOutput -Encoding UTF8
-Depth 10 是为了避免嵌套对象被截断。
写入完成后,脚本打印配置路径、接口地址和已配置模型,方便用户检查。
11. 使用方式#
一键执行:
iwr https://raw.githubusercontent.com/xujfcn/workbuddy-crazyrouter/main/setup-workbuddy-crazyrouter.ps1 -UseB | iex
先设置环境变量:
$env:CRAZYROUTER_API_KEY="sk-你的Key"
iwr https://raw.githubusercontent.com/xujfcn/workbuddy-crazyrouter/main/setup-workbuddy-crazyrouter.ps1 -UseB | iex
下载后本地执行:
iwr https://raw.githubusercontent.com/xujfcn/workbuddy-crazyrouter/main/setup-workbuddy-crazyrouter.ps1 -OutFile setup-workbuddy-crazyrouter.ps1
.\setup-workbuddy-crazyrouter.ps1
替换旧的同类模型:
.\setup-workbuddy-crazyrouter.ps1 -ReplaceCrazyrouter
自定义模型列表:
.\setup-workbuddy-crazyrouter.ps1 -Models "model-a", "model-b", "model-c"
总结#
维护 WorkBuddy models.json,最重要的不是“能不能写进去”,而是写得稳不稳。
一个可靠的配置脚本应该具备:
- 参数化
- API Key 不硬编码
- Base URL 自动规范化
- 写入前备份
- JSON 结构校验
- 模型去重
- 保留旧配置
- 支持恢复
示例脚本:
https://github.com/xujfcn/workbuddy-crazyrouter
你可以直接使用,也可以把它当作模板,改成适合自己团队的 WorkBuddy 配置维护工具。
附:使用 https://cn.crazyrouter.com 接入 WorkBuddy 的完整步骤#
如果你的目标是把 WorkBuddy 连接到 Crazyrouter,可以按下面流程配置。
第一步:准备 API Key#
在 Crazyrouter 控制台创建或复制一个可用 API Key。
为了避免把 Key 写进命令历史,也可以先在当前 PowerShell 会话里设置环境变量:
$env:CRAZYROUTER_API_KEY="sk-你的CrazyrouterKey"
第二步:确认接口地址#
WorkBuddy 自定义模型最终需要使用 OpenAI-compatible API 地址。
Crazyrouter 国内接口地址建议写成:
https://cn.crazyrouter.com/v1
如果你传入的是:
https://cn.crazyrouter.com
示例脚本会自动规范成:
https://cn.crazyrouter.com/v1
第三步:一键写入 WorkBuddy 配置#
打开 PowerShell,执行:
iwr https://raw.githubusercontent.com/xujfcn/workbuddy-crazyrouter/main/setup-workbuddy-crazyrouter.ps1 -UseB | iex
如果已经提前设置了环境变量,脚本会直接读取:
$env:CRAZYROUTER_API_KEY="sk-你的CrazyrouterKey"
iwr https://raw.githubusercontent.com/xujfcn/workbuddy-crazyrouter/main/setup-workbuddy-crazyrouter.ps1 -UseB | iex
脚本默认会写入这些模型:
claude-opus-4-8
claude-opus-4-7
claude-sonnet-4-6
gpt-5.5
gpt-5.4
第四步:重启 WorkBuddy#
执行完成后,完全退出 WorkBuddy,再重新打开。
然后在模型列表中选择:
Custom / 自定义模型
如果模型列表没有刷新,优先检查 WorkBuddy 是否仍有后台进程没有退出。
第五步:本地下载后执行(更适合谨慎场景)#
如果不想直接执行远程脚本,可以先下载:
iwr https://raw.githubusercontent.com/xujfcn/workbuddy-crazyrouter/main/setup-workbuddy-crazyrouter.ps1 -OutFile setup-workbuddy-crazyrouter.ps1
阅读脚本内容后再执行:
.\setup-workbuddy-crazyrouter.ps1 -BaseUrl "https://cn.crazyrouter.com"
如果想清理旧的 Crazyrouter 自定义模型,只保留本次写入的模型,可以加:
.\setup-workbuddy-crazyrouter.ps1 -BaseUrl "https://cn.crazyrouter.com" -ReplaceCrazyrouter
第六步:恢复旧配置#
脚本默认会备份旧配置,备份文件类似:
%USERPROFILE%\.workbuddy\models.json.bak.20260605-140000
如果新配置不符合预期:
- 完全退出 WorkBuddy。
- 打开
%USERPROFILE%\.workbuddy\。 - 删除或改名当前
models.json。 - 把备份文件改名为
models.json。 - 重新打开 WorkBuddy。
常见接入问题#
| 问题 | 处理方式 |
|---|---|
| 模型列表没出现 | 完全退出并重启 WorkBuddy |
| 调用报 401 | 检查 API Key 是否正确 |
| 调用报 404 | 检查 URL 是否为 https://cn.crazyrouter.com/v1 |
| 出现重复模型 | 使用 -ReplaceCrazyrouter 重新写入 |
| 配置改坏 | 用 .bak 备份恢复 |
开源脚本地址:
https://github.com/xujfcn/workbuddy-crazyrouter




