自訂模型
透過 ~/.pi/agent/models.json 新增自訂 Provider 和模型(Ollama、vLLM、LM Studio、代理)。
目錄
- Minimal Example
- Full Example
- Supported APIs
- Provider Configuration
- Model Configuration
- Overriding Built-in Providers
- Per-model Overrides
- Anthropic Messages Compatibility
- OpenAI Compatibility
最小範例
對於本機模型(Ollama、LM Studio、vLLM),每個模型僅需要 id:
{
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"api": "openai-completions",
"apiKey": "ollama",
"models": [
{ "id": "llama3.1:8b" },
{ "id": "qwen2.5-coder:7b" }
]
}
}
}apiKey 值只是佔位符,因為 Ollama 會忽略它。pi 仍會把模型視為需要身分驗證後才會出現在 /model 中,因此無 API Key 的本機伺服器應保留一個虛擬值,使用 /login 為該 Provider 儲存 API Key,或者在選擇模型時傳入 --api-key。
一些 OpenAI 相容伺服器不理解推理模型使用的 developer 角色。對於這些 Provider,將 compat.supportsDeveloperRole 設定為 false,以便 pi 將系統提示作為 system 訊息傳送。如果伺服器也不支援 reasoning_effort,也請將 compat.supportsReasoningEffort 設定為 false。
可以在 Provider 層級設定 compat 以應用於所有模型,也可以在模型層級設定 compat 來覆寫特定模型。這通常適用於 Ollama、vLLM、SGLang 和類似的 OpenAI 相容伺服器。
{
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"api": "openai-completions",
"apiKey": "ollama",
"compat": {
"supportsDeveloperRole": false,
"supportsReasoningEffort": false
},
"models": [
{
"id": "gpt-oss:20b",
"reasoning": true
}
]
}
}
}完整範例
當你需要特定值時覆蓋預設值:
{
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"api": "openai-completions",
"apiKey": "ollama",
"models": [
{
"id": "llama3.1:8b",
"name": "Llama 3.1 8B (Local)",
"reasoning": false,
"input": ["text"],
"contextWindow": 128000,
"maxTokens": 32000,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
}
]
}
}
}每次開啟 /model 時,檔案都會重新載入。可以在工作階段期間編輯;無需重新啟動。
Google AI Studio 範例
使用 google-generative-ai 和 baseUrl 從 Google AI Studio 新增模型,包括自訂 Gemma 4 條目:
{
"providers": {
"my-google": {
"baseUrl": "https://generativelanguage.googleapis.com/v1beta",
"api": "google-generative-ai",
"apiKey": "$GEMINI_API_KEY",
"models": [
{
"id": "gemma-4-31b-it",
"name": "Gemma 4 31B",
"input": ["text", "image"],
"contextWindow": 262144,
"reasoning": true
}
]
}
}
}將自訂模型新增到 google-generative-ai API 類型時需要 baseUrl。
支援的 API
| API | 描述 |
|---|---|
openai-completions |
OpenAI Chat Completions(最相容) |
openai-responses |
OpenAI Responses API |
anthropic-messages |
Anthropic Messages API |
google-generative-ai |
Google Generative AI |
在 Provider 層級(所有模型的預設值)或模型層級(逐模型覆寫)設定 api。
Provider 設定
| 欄位 | 描述 |
|---|---|
baseUrl |
API 端點 URL |
api |
API 類型(見上文) |
apiKey |
選用的 API Key 設定(請參閱下面的值解析)。當 auth 由 /login/auth.json 或 CLI --api-key 提供時可以省略。 |
oauth |
動態 OAuth Provider 類型。目前支援 "radius";需要閘道 baseUrl。 |
headers |
自訂標頭(請參閱下面的值解析) |
authHeader |
設定 true 自動新增 Authorization: Bearer <apiKey> |
models |
模型設定陣列 |
modelOverrides |
每個模型覆寫此 Provider 上的內建或擴充註冊模型 |
對於包含 models 的 Provider,非內建 Provider 設定需要在 Provider 或模型層級提供 baseUrl 和 api 值。載入檔案不需要 apiKey:當透過 /login/auth.json、CLI --api-key 或 Provider apiKey 設定身分驗證後,模型才會可用。如果未設定身分驗證,模型會被載入,但在 /model 和 --list-models 中仍不可用。
值解析
apiKey 和 headers 欄位支援指令執行、環境插值和文字:
- Shell 指令: 開頭的
"!command"將整個值作為指令執行並使用 stdout"apiKey": "!security find-generic-password -ws 'anthropic'" "apiKey": "!op read 'op://vault/item/credential'" - 環境插值:
"$ENV_VAR"或"${ENV_VAR}"使用命名變數的值。插值適用於較大的文字。"apiKey": "$MY_API_KEY" "apiKey": "${KEY_PREFIX}_${KEY_SUFFIX}"$FOO_BAR是變數FOO_BAR;當BAR是文字時,使用${FOO}_BAR。缺少環境變數會導致該值無法解析。 - 轉義:
"$"發出 literal"quot;;"$!"發出 literal"!"而不觸發指令執行。"apiKey": "$literal-dollar-prefix" "apiKey": "$!literal-bang-prefix" - 字面值: 直接使用。一般大寫字串(例如
MY_API_KEY)是 literal;使用$MY_API_KEY作為環境變數。"apiKey": "sk-..."
對於 models.json,shell 指令在請求時解析。 pi 故意不對任意指令應用內建 TTL、過時重用或恢復邏輯。不同的指令需要不同的快取和失敗策略,並且 pi 無法推斷出正確的策略。
如果你的指令速度慢、成本高、速率受限,或者應該在暫時性故障時繼續使用先前的值,請將其包裝在你自己的script 或指令中,以實作你想要的快取或 TTL 行為。
/model 可用狀態檢查使用設定的身分驗證狀態並且不執行 shell 指令。
自訂標頭
{
"providers": {
"custom-proxy": {
"baseUrl": "https://proxy.example.com/v1",
"apiKey": "$MY_API_KEY",
"api": "anthropic-messages",
"headers": {
"x-portkey-api-key": "$PORTKEY_API_KEY",
"x-secret": "!op read 'op://vault/item/secret'"
},
"models": [...]
}
}
}模型設定
| 欄位 | 必需 | 預設 | 描述 |
|---|---|---|---|
id |
是 | — | 模型識別碼(傳遞給 API) |
name |
否 | id |
人類可讀的模型標籤。用於比對(--model 模式),並顯示為次要模型詳細資訊文字。 |
api |
否 | Provider 的 api |
覆寫此模型的 Provider API |
reasoning |
否 | false |
支援擴充思考 |
thinkingLevelMap |
否 | 省略 | 將 pi 的 thinking level 映射到 Provider 值,並標記不支援的等級(見下文) |
input |
否 | ["text"] |
輸入類型:["text"] 或 ["text", "image"] |
contextWindow |
否 | 128000 |
上下文視窗大小(以 token 為單位) |
maxTokens |
否 | 16384 |
最大輸出 token 數 |
samplingParams |
否 | 省略 | 採樣參數逐字合併到每個請求 body 中(見下文) |
cost |
否 | 全為零 | 每百萬 token 費率以及選用的請求範圍輸入定價層 |
compat |
否 | Provider compat |
Provider 相容性覆寫。當兩者都設定時,會與 Provider 層級的 compat 合併。 |
成本層提供完整的替代費率集,並在總輸入使用量 (input + cacheRead + cacheWrite) 超過 inputTokensAbove 時應用於完整請求。當多個等級比對時,臨界值最高的獲勝。
{
"cost": {
"input": 5,
"output": 30,
"cacheRead": 0.5,
"cacheWrite": 6.25,
"tiers": [
{
"inputTokensAbove": 272000,
"input": 10,
"output": 45,
"cacheRead": 1,
"cacheWrite": 12.5
}
]
}
}目前行為:
/model、--list-models和互動式頁尾按模型id顯示條目。- 設定的
name用於模型比對和次要模型詳細資訊文字。它不會替換頁尾/狀態欄中的模型 ID。
採樣參數
samplingParams 是一個自由格式的物件,在欄位 pi 設定自身之後,逐字合併到模型的每個請求主體中,因此它的鍵獲勝。使用它傳送 pi 不建模的採樣參數 - 包括特定於伺服器的參數,例如 llama.cpp 的 min_p 或 vLLM 的 top_k:
{
"id": "deepseek-v4-flash",
"samplingParams": {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 0,
"min_p": 0.0
}
}僅 OpenAI 相容 API 會應用它(openai-completions、openai-responses、azure-openai-responses);其他 API 會忽略它。鍵會覆寫 pi 自身命名的請求欄位(例如這裡的 temperature 鍵會覆蓋請求級溫度),因此建議將它作為該模型採樣參數的唯一來源。在 modelOverrides 中,samplingParams 會按鍵與基礎模型的值合併。
Thinking Level Map
在模型上使用 thinkingLevelMap 描述特定於模型的 thinking 控制。鍵是 pi thinking level:off、minimal、low、medium、high、xhigh、max。映射可以不完整;例如,模型可以暴露 high 和 max,但不暴露 xhigh。
值是三態的:
| 值 | 含義 |
|---|---|
| 省略 | 標準等級到 high 使用 Provider 的預設映射;擴充的 xhigh 和 max 等級不受支援 |
| 字串 | 該等級受支援,並將該值傳送給 Provider |
null |
該等級不受支援,會被隱藏、跳過或夾緊到其他等級 |
僅支援 off、high 和 max 推理的模型範例:
{
"id": "deepseek-v4-pro",
"reasoning": true,
"thinkingLevelMap": {
"minimal": null,
"low": null,
"medium": null,
"high": "high",
"xhigh": null,
"max": "max"
}
}thinking 不能被停用的模型範例:
{
"id": "always-thinking-model",
"reasoning": true,
"thinkingLevelMap": {
"off": null
}
}遷移:使用 compat.reasoningEffortMap 的舊設定應將該映射移動到模型層級的 thinkingLevelMap。對於不應出現在 UI 中的等級,請使用 null。
覆寫內建 Provider
透過 proxy路由內建 Provider,無需重新定義模型:
{
"providers": {
"anthropic": {
"baseUrl": "https://my-proxy.example.com/v1"
}
}
}所有內建 Anthropic 模型仍然可用。現有的 OAuth 或 API Key 身分驗證繼續有效。
要將自訂模型合併到內建 Provider 中,請包含 models 陣列:
{
"providers": {
"anthropic": {
"baseUrl": "https://my-proxy.example.com/v1",
"apiKey": "$ANTHROPIC_API_KEY",
"api": "anthropic-messages",
"models": [...]
}
}
}合併語義:
- 保留內建模型。
- 自訂模型由
id在 Provider 中更新。 - 如果自訂模型
id與內建模型id比對,則自訂模型將替換該內建模型。 - 如果自訂模型
id是新的,它將與內建模型一起新增。
每個模型的覆寫
使用 modelOverrides 自訂內建模型和比對擴充註冊的模型,而無需替換 Provider 的完整模型清單。
{
"providers": {
"openrouter": {
"modelOverrides": {
"anthropic/claude-sonnet-4": {
"name": "Claude Sonnet 4 (Bedrock Route)",
"compat": {
"openRouterRouting": {
"only": ["amazon-bedrock"]
}
}
}
}
}
}
}modelOverrides 每個模型支援以下欄位:name、reasoning、thinkingLevelMap、input、cost(部分)、contextWindow、maxTokens、samplingParams(每個鍵合併)、headers、compat。
Direct OpenAI GPT-5.6 Sol、Terra 和 Luna 預設為 272000 上下文視窗,因此請求保留在 OpenAI 的短上下文定價層內。要選擇 OpenAI 的 1.05M 上下文視窗,請為你使用的每個模型增加它:
{
"providers": {
"openai": {
"modelOverrides": {
"gpt-5.6-sol": {
"contextWindow": 1050000
}
}
}
}
}覆寫會保留內建定價元資料。總輸入 token超過 272K 的請求對整個請求使用 GPT-5.6 的長上下文速率。需要時,對 gpt-5.6-terra 或 gpt-5.6-luna 應用相同的覆寫。
行為注意事項:
modelOverrides適用於內建 Provider 模型和比對的擴充註冊 Provider 模型。- 未知的模型 ID 將被忽略。
- 你可以將 Provider 層級
baseUrl/headers與modelOverrides結合起來。 - 覆寫
name只會更改模型比對和次要詳細資訊文字;頁尾和主要模型清單仍會顯示模型id。 - 如果還為 Provider 定義了
models,則自訂模型會在內建覆寫後合併。具有相同id的自訂模型將替換覆寫後的內建模型條目。
Anthropic Messages 相容性
對於使用 api: "anthropic-messages" 的 Provider 或代理,請使用 compat 控制 Anthropic-specific request compatibility。
預設情況下 pi 傳送每個工具 eager_input_streaming: true。如果代理或與 Anthropic 相容的後端拒絕該欄位,請將 supportsEagerToolInputStreaming 設定為 false。 Pi 將省略 tools[].eager_input_streaming 並為支援工具的請求傳送舊版 fine-grained-tool-streaming-2025-05-14 beta 標頭。
一些 Anthropic 模型需要 adaptive thinking(thinking.type: "adaptive" 加 output_config.effort),而不是舊版基於預算的 thinking payload。內建模型會自動設定。對於路由至這些模型的自訂 Provider 或別名,請將 forceAdaptiveThinking 設定為 true。
一些 Anthropic-compatible Provider 會發出空 signature 的 thinking block,並且仍期望重放這些 signature。僅針對這些 Provider 將 allowEmptySignature 設定為 true;真正的 Anthropic 會拒絕空 thinking signature。
內建 Anthropic 模型會在模型元資料中啟用 supportsStrictTools。自訂 Anthropic-compatible 模型的端點接受嚴格 JSON-schema 工具定義時,必須將其設定為 true。
{
"providers": {
"anthropic-proxy": {
"baseUrl": "https://proxy.example.com",
"api": "anthropic-messages",
"apiKey": "$ANTHROPIC_PROXY_KEY",
"compat": {
"supportsEagerToolInputStreaming": false,
"supportsLongCacheRetention": true,
"forceAdaptiveThinking": true,
"allowEmptySignature": true
},
"models": [
{
"id": "claude-opus-4-7",
"reasoning": true,
"input": ["text", "image"]
}
]
}
}
}| 欄位 | 描述 |
|---|---|
supportsEagerToolInputStreaming |
Provider 是否接受每個工具的 eager_input_streaming。預設值:true。設定為 false 可省略該欄位,並在啟用工具的請求上使用舊版細粒度工具串流傳輸 beta header。 |
supportsLongCacheRetention |
當快取保留為 long 時,Provider 是否接受 Anthropic 長快取保留(cache_control.ttl: "1h")。預設值:true。 |
sendSessionAffinityHeaders |
啟用快取時是否從工作階段 ID 傳送 x-session-affinity。預設值:自動檢測已知 Provider。 |
supportsCacheControlOnTools |
Provider 是否接受工具定義上的 Anthropic 風格 cache_control 標記。預設值:true。 |
forceAdaptiveThinking |
是否為該模型傳送 adaptive thinking(thinking.type: "adaptive" 加 output_config.effort)。內建 adaptive 模型會自動設定此值。預設值:false。 |
allowEmptySignature |
是否將空 thinking signature 重放為 signature: "",而不是將 thinking 轉換為文字。預設值:false。 |
supportsStrictTools |
Provider 是否接受嚴格 JSON-schema 工具定義。預設值:false;內建 Anthropic 模型會在產生的元資料中啟用它。 |
OpenAI 相容性
對於具有部分 OpenAI 相容性的 Provider,請使用 compat 欄位。
- Provider 層級的
compat會將預設值應用於該 Provider 下的所有模型。 - 模型層級的
compat會覆寫該模型的 Provider 層級值。
{
"providers": {
"local-llm": {
"baseUrl": "http://localhost:8080/v1",
"api": "openai-completions",
"compat": {
"supportsUsageInStreaming": false,
"maxTokensField": "max_tokens"
},
"models": [...]
}
}
}| 欄位 | 描述 |
|---|---|
supportsStore |
Provider 支援 store 欄位 |
supportsDeveloperRole |
使用 developer 與 system 角色 |
supportsReasoningEffort |
支援 reasoning_effort 參數 |
supportsUsageInStreaming |
支援 stream_options: { include_usage: true }(預設:true) |
supportsFinishReason |
串流回應是否包含 finish_reason。當為 false 時,pi 會在資料流結束時推斷 stop 或 toolUse。預設值:true。 |
maxTokensField |
使用 max_completion_tokens 或 max_tokens |
requiresToolResultName |
在工具結果訊息中包含 name |
requiresAssistantAfterToolResult |
在工具結果之後、使用者訊息之前插入 assistant 訊息 |
requiresThinkingAsText |
將 thinking block 轉換為純文字 |
requiresReasoningContentOnAssistantMessages |
啟用推理時,在所有重播的助理訊息中包含空 reasoning_content |
thinkingFormat |
使用 reasoning_effort、openrouter、deepseek、together、baseten、zai、qwen、chat-template 或 qwen-chat-template thinking 參數 |
chatTemplateKwargs |
thinkingFormat: "chat-template" 使用的 chat_template_kwargs 值;使用 { "$var": "thinking.enabled" } 或 { "$var": "thinking.effort" } 取得 pi 控制的 thinking 值 |
chatTemplateArgs |
thinkingFormat: "baseten" 使用的 chat_template_args 值;使用 { "$var": "thinking.enabled" } 或 { "$var": "thinking.effort" } 取得 pi 控制的 thinking 值 |
cacheControlFormat |
在系統提示、最後一個工具定義以及最後一個使用者、assistant 或工具結果文字內容上使用 Anthropic 風格的 cache_control 標記。目前僅支援 anthropic。 |
sendSessionAffinityHeaders |
對於 openai-completions,啟用快取時從工作階段 ID 傳送 session-affinity header。預設值:false。 |
sessionAffinityFormat |
對於 openai-completions 和 openai-responses,session-affinity header 格式:openai 傳送 session_id/x-client-request-id(completions 還會傳送 x-session-affinity),openai-nosession 省略包含下划線的 session_id header,openrouter 傳送 x-session-id。不影響請求 body 中的 prompt_cache_key 參數。預設:自動檢測。 |
supportsStrictMode |
Provider 是否接受嚴格的 JSON Schema function tool 定義。預設值取決於 API;內建 OpenAI 模型攜帶明確的能力元資料。 |
supportsOpenAIGrammarTools |
相容 OpenAI 的 API 是否發出自訂 Lark/regex 語法工具。當 false 時,語法約束工具fallback 到正常功能工具。預設值:false;內建模型目錄支援 OpenAI、OpenAI Codex、Azure OpenAI、GitHub Copilot、opencode 和 Cloudflare AI Gateway 上的 GPT-5+ 模型。 |
deferredToolsMode |
使用 Provider 特定的延遲工具序列化。目前僅支援 Kimi 的 OpenAI 相容 Chat Completions 格式 "kimi"。 |
supportsLongCacheRetention |
當快取保留為 long 時,Provider 是否接受長快取保留:OpenAI prompt caching 使用 prompt_cache_retention: "24h",cacheControlFormat 為 anthropic 時使用 cache_control.ttl: "1h"。預設值:true。 |
openRouterRouting |
OpenRouter Provider 的路由偏好項。該物件按原樣傳送到 OpenRouter API request 的 provider 欄位中。 |
vercelGatewayRouting |
用於選擇 Provider 的 Vercel AI Gateway路由設定 (only、order) |
openrouter 使用 reasoning: { effort }。together 使用 reasoning: { enabled },並在啟用 supportsReasoningEffort 時同時使用 reasoning_effort。qwen 使用頂級 enable_thinking。對於需要 chat_template_kwargs.enable_thinking 和 preserve_thinking 的本機 Qwen 相容伺服器,請使用 qwen-chat-template。對於需要可設定 chat_template_kwargs 的 vLLM/Hugging Face 聊天模板,請使用 chat-template,例如 DeepSeek V3.x 模板可使用 chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } }。對於透過 chat_template_args 暴露開關值且選用支援頂級 reasoning_effort 的 Provider,請將 thinkingFormat: "baseten" 與 chatTemplateArgs 結合使用。
cacheControlFormat: "anthropic" 適用於透過文字內容和工具定義上的 cache_control 標記暴露 Anthropic 風格 prompt caching 的 OpenAI 相容 Provider。
例子:
{
"providers": {
"openrouter": {
"baseUrl": "https://openrouter.ai/api/v1",
"apiKey": "$OPENROUTER_API_KEY",
"api": "openai-completions",
"models": [
{
"id": "openrouter/anthropic/claude-3.5-sonnet",
"name": "OpenRouter Claude 3.5 Sonnet",
"compat": {
"openRouterRouting": {
"allow_fallbacks": true,
"require_parameters": false,
"data_collection": "deny",
"zdr": true,
"enforce_distillable_text": false,
"order": ["anthropic", "amazon-bedrock", "google-vertex"],
"only": ["anthropic", "amazon-bedrock"],
"ignore": ["gmicloud", "friendli"],
"quantizations": ["fp16", "bf16"],
"sort": {
"by": "price",
"partition": "model"
},
"max_price": {
"prompt": 10,
"completion": 20
},
"preferred_min_throughput": {
"p50": 100,
"p90": 50
},
"preferred_max_latency": {
"p50": 1,
"p90": 3,
"p99": 5
}
}
}
}
]
}
}
}Vercel AI Gateway範例:
{
"providers": {
"vercel-ai-gateway": {
"baseUrl": "https://ai-gateway.vercel.sh/v1",
"apiKey": "$AI_GATEWAY_API_KEY",
"api": "openai-completions",
"models": [
{
"id": "moonshotai/kimi-k2.5",
"name": "Kimi K2.5 (Fireworks via Vercel)",
"reasoning": true,
"input": ["text", "image"],
"cost": { "input": 0.6, "output": 3, "cacheRead": 0, "cacheWrite": 0 },
"contextWindow": 262144,
"maxTokens": 262144,
"compat": {
"vercelGatewayRouting": {
"only": ["fireworks", "novita"],
"order": ["fireworks", "novita"]
}
}
}
]
}
}
}