# 自己的模型服务器

> 在 nsq 中让 Claude Code、Codex CLI 或 OpenCode 智能体运行在你自己的模型服务器上——llama.cpp、Ollama、LM Studio、vLLM、SGLang、Unsloth Studio，或任何兼容 OpenAI 或 Anthropic 的 API。

Source: https://docs.neurosquad.ai/zh/cli/providers

除了 [OpenRouter](https://docs.neurosquad.ai/zh/cli/openrouter)，智能体还可以运行在你自己的服务器上：本地的——**llama.cpp**、**Ollama**、**LM Studio**、**vLLM**、**SGLang**、**Unsloth Studio**——或任何支持 **OpenAI** API（chat completions 或 responses）或 **Anthropic** Messages API 的远程 API。按智能体单独设置，不改动 CLI 自己的配置和登录。

## 添加服务器

```sh
nsq provider add lmstudio --url http://localhost:1234
nsq provider add box --url http://192.168.1.20:8000 --ask-key     # 询问密钥，输入时不显示
echo "$KEY" | nsq provider add work --url https://llm.example.com/v1 --key-stdin
```

`add` 在保存任何内容之前会先测试服务器：列出模型（`GET /v1/models`），并检测服务器提供哪些端点——OpenAI `POST /v1/chat/completions`、OpenAI `POST /v1/responses`、Anthropic `POST /v1/messages`。你无需选择 API：只要服务器有某个 CLI 需要的端点，就会向该 CLI 提供这台服务器，`add` 会打印出是哪些 CLI：

```text
added lmstudio: localhost:1234 — 12 models, endpoints: chat, responses, messages (9 ms)
  Claude Code  yes
  Codex        yes
  OpenCode     yes (chat completions)
```

地址可以带 `/v1` 也可以不带（甚至可以粘贴完整的 `…/v1/chat/completions`）；位于子路径下的服务器会保留该路径（`https://api.example.com/anthropic`）。没有写协议时，本地地址补上 `http://`，其他地址补上 `https://`。

```sh
nsq provider list                    # 地址、端点、模型、是否已保存密钥
nsq provider models lmstudio [qwen]  # 服务器当前的模型（以及它提供的上下文窗口）
nsq provider test lmstudio           # 重新测试：新模型、升级后的服务器
nsq provider test lmstudio --ask-key # ……并换用新密钥（--clear-key 会删除密钥）
nsq provider remove lmstudio
```

## 在上面运行智能体

```sh
nsq run claude   --provider lmstudio --model qwen/qwen3-coder-30b
nsq run codex    --provider ollama   --model qwen3-coder:30b
nsq run opencode --provider vllm     --model Qwen/Qwen3-Coder-30B-A3B-Instruct
nsq set api-fix  --provider lmstudio --model qwen/qwen3-coder-30b   # 迁移已有的智能体
nsq set api-fix  --provider none --model none                       # 回到 CLI 自己的登录
```

模型是服务器自己列表中的 id。只有一个模型的服务器不需要 `--model`。迁移后的智能体会在空闲时以同一会话重启，对话得以保留。

在仪表盘中：`c`（新建智能体）→ **Provider**——`←` `→` 在 _自己的登录_、_OpenRouter_ 以及适合所选 CLI 的每台服务器之间切换（不适合的会列出并注明原因）——`F2` 列出该服务器的模型。在智能体上按 `m` 列出其服务器的模型。`P` 打开服务商界面：`a` 添加服务器（`F2` 填入下表中的默认地址，密钥输入框会被遮盖），`t` 重新测试，`Enter` 查看其模型，`x` 删除。

## 各 CLI 使用哪个 API

| CLI | 使用 |
| --- | --- |
| Claude Code | 仅 Anthropic Messages（`/v1/messages`）——没有该端点的服务器不会提供给它 |
| Codex | OpenAI Responses（`/v1/responses`）；如果服务器只有 chat completions，nsq 会运行一个本地网关，在 Responses 与 chat completions 之间转换（密钥留在 nsq 手里，Codex 永远看不到） |
| OpenCode | OpenAI chat completions（`@ai-sdk/openai-compatible`），服务器没有 chat 端点时则用 Anthropic Messages API（`@ai-sdk/anthropic`） |

只提供 `/v1/responses` 的服务器也会被接受，但只会提供给 Codex。

## 服务器

各服务器目前提供的内容，依据其自身文档（2026 年 10 月核对）——对你的版本以连接测试的结果为准：

| 服务器 | 默认地址 | Chat completions | Responses | Anthropic messages | 模型列表中的上下文窗口 | 默认是否需要密钥 |
| --- | --- | --- | --- | --- | --- | --- |
| llama.cpp（`llama-server`） | `http://127.0.0.1:8080`（自 b11521 版本起为 `:9931`，2026 年 10 月） | 是 | 是 | 是 | `meta.n_ctx` | 否（`--api-key`） |
| Ollama | `http://localhost:11434` | 是 | 是（0.13.3+） | 是（0.14.0+） | 未列出 | 否 |
| LM Studio | `http://localhost:1234` | 是 | 是（0.3.29+） | 是（0.4.1+） | 未列出 | 否（可选 API 令牌，0.4.0+） |
| vLLM（`vllm serve`） | `http://localhost:8000` | 是 | 是（0.10.0+） | 是（0.11.1+） | `max_model_len` | 否（`--api-key`） |
| SGLang | `http://localhost:30000` | 是 | 是 | 是（0.5.9+） | `max_model_len` | 否（`--api-key`） |
| Unsloth Studio | `http://localhost:8888` | 是 | 是 | 是 | `context_length` | **是**（`sk-unsloth-…`） |

因此，只要用的是其中任何一个的当前版本，三个 CLI 都能直接运行。已用真实 CLI 对 llama.cpp（`llama-server` b11524）做过端到端测试：Claude Code 走 `/v1/messages`，Codex 走 `/v1/responses` 以及经网关走 `/v1/chat/completions`，OpenCode 走 `/v1/chat/completions`。llama.cpp 需要 `--jinja` 才能进行工具调用。

**上下文窗口。** 如果服务器的模型列表说明了它以多大的上下文提供该模型，nsq 会告诉每个 CLI——Claude Code（`CLAUDE_CODE_MAX_CONTEXT_TOKENS`）、Codex（`model_context_window`，在 85% 时压缩）、OpenCode（模型的 `limit.context`）——这样长会话会在服务器窗口占满之前压缩，而不是直接失败。智能体类 CLI 发送的提示词很长（仅 Claude Code 自己的就远超 10 000 个 token）：请以足够大的上下文启动服务器（`llama-server -c 32768`、Ollama 的 `OLLAMA_CONTEXT_LENGTH`、LM Studio 的上下文长度设置）。

## 密钥的去向

- 密钥是可选的（本地服务器不需要）。它以不回显的方式询问（`--ask-key`）或从 stdin 读取（`--key-stdin`）——**绝不**作为命令行参数传入，因为机器上的任何进程都能读到命令行；`--key <值>` 会被拒绝。
- 它保存在操作系统的密钥库中（Windows 凭据管理器、macOS 钥匙串、Linux 上的 Secret Service）。没有密钥库时，改为在守护进程启动的地方设置 `NSQ_PROVIDER_KEY_<NAME>`（例如 `NSQ_PROVIDER_KEY_LMSTUDIO`）。
- 智能体只在启动时通过自己的环境变量获得密钥——绝不会出现在 argv、日志或 nsq 的文件里（`providers.json` 只保存地址、端点和模型列表，不含机密）。经网关运行的 Codex 拿到的是网关为该智能体单独发放的凭据，而不是密钥本身。
- 普通的 `http://` 只接受本机和局域网地址（局域网会给出警告：提示词、你的代码和密钥都以明文传输）。其他地址必须用 `https://`。nsq 从不跟随重定向——否则密钥会被发往重定向指向的任何地方。
- 永远不会向你的服务器发送 OpenRouter 归属请求头。
- 如果服务器被删除，或不再提供该 CLI 需要的端点，智能体就不会启动——它绝不会退回到 CLI 自己的登录（那会把你的代码发到云端）。
- Claude Code：服务器地址和模型还会写入该智能体自己的设置层，并关闭 `CLAUDE_CODE_USE_BEDROCK` / `_VERTEX` / `_FOUNDRY`——因此你环境或 `~/.claude/settings.json` 中的 `ANTHROPIC_BASE_URL`、`ANTHROPIC_AUTH_TOKEN` 或云端后端都不会把智能体引到别处。CLI 自身的其他配置（Codex 配置档、OpenCode 插件）归你所有，nsq 不会检查。

## 花费

nsq 不知道你的服务器怎么收费：发往它的请求在 `nsq cost` 和仪表盘中显示为 **no price**（无价格），绝不是 $0——即使模型名称与某个有价格的模型相同。这也包括智能体在迁移到该服务器之前发出的请求（nsq 无法判断是哪台服务器回答了它们）。
