跳至内容

自定义模型

创建于 2025-07-16·更新于 2026-07-16

通过 ~/.pi/agent/models.json 添加自定义提供商和模型(Ollama, vLLM, LM Studio, 代理等)。

目录 Table of Contents

最小示例 Minimal Example

对于本地模型(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 中出现之前通过身份验证,因此无密钥的本地服务器应保留一个虚拟值,通过 /login 为该提供商保存密钥,或在选择模型时传递 --api-key

某些兼容 OpenAI 的服务器不支持用于推理能力模型的 developer 角色。对于这些提供商,请设置 compat.supportsDeveloperRolefalse,这样 pi 会将系统提示作为 system 消息发送。如果服务器也不支持 reasoning_effort,请同时将 compat.supportsReasoningEffort 设为 false

您可以在提供商级别设置 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
        }
      ]
    }
  }
}

完整示例 Full Example

当需要特定值时覆盖默认值:

{
  "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 AI Studio Example

使用 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 Supported APIs

API描述
openai-completionsOpenAI Chat Completions(兼容性最广)
openai-responsesOpenAI Responses API
anthropic-messagesAnthropic Messages API
google-generative-aiGoogle Generative AI

在提供商级别(所有模型的默认值)或模型级别(逐模型覆盖)设置 api

提供商配置 Provider Configuration

字段描述
baseUrlAPI 端点 URL
apiAPI 类型(见上文)
apiKey可选的 API 密钥配置(参见下面的值解析)。如果通过 /login/auth.json 或 CLI --api-key 提供身份验证,则可省略此项。
oauth动态 OAuth 提供商类型。目前支持 "radius";需要网关 baseUrl
headers自定义请求头(参见下面的值解析)
authHeader设置为 true 可自动添加 Authorization: Bearer <apiKey>
models模型配置数组
modelOverrides对此提供商上的内置或扩展注册模型进行逐模型覆盖

对于包含 models 的提供商,非内置提供商配置需要 baseUrl 以及在提供商或模型级别设置 api 值。加载文件时不需要 apiKey:当通过 /login/auth.json、CLI --api-key 或提供商 apiKey 配置了身份验证后,模型才会变为可用。如果未配置身份验证,模型会加载,但在 /model--list-models 中保持不可用状态。

值解析 Value Resolution

apiKeyheaders 字段支持命令执行、环境变量插值和字面量:

  • 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。缺失的环境变量会使值无法解析。

  • 转义: "$$" 输出字面量 "$""$!" 输出字面量 "!" 而不触发命令执行。

    "apiKey": "$$literal-dollar-prefix"
    "apiKey": "$!literal-bang-prefix"
  • 字面量: 直接使用。纯大写字符串如 MY_API_KEY 是字面量;使用 $MY_API_KEY 表示环境变量。

    "apiKey": "sk-..."

对于 models.json,shell 命令在请求时解析。pi 有意不为任意命令应用内置的 TTL、过期重用或恢复逻辑。不同命令需要不同的缓存和失败策略,pi 无法推断出正确的策略。

如果您的命令速度慢、开销大、有速率限制,或者希望在临时失败时继续使用先前的值,请将其封装在实现所需缓存或 TTL 行为的自有脚本或命令中。

/model 可用性检查使用已配置的身份验证状态,不执行 shell 命令。

自定义请求头 Custom Headers

{
  "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": [...]
    }
  }
}

模型配置 Model Configuration

字段必需默认值描述
id模型标识符(传递给 API)
nameid人类可读的模型标签。用于匹配(--model 模式),并作为模型详情副文本显示。
api提供商的 api覆盖此模型的提供商 API
reasoningfalse是否支持扩展思考
thinkingLevelMap省略将 pi 思考级别映射到提供商的值,并标记不支持的级别(见下文)
input["text"]输入类型:["text"]["text", "image"]
contextWindow128000上下文窗口大小(以 token 计)
maxTokens16384最大输出 token 数
cost全零每百万 token 费率,带有可选的请求级输入定价层级
compat提供商的 compat提供商兼容性覆盖。当两者都设置时,与提供商级别的 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。

思考级别映射 Thinking Level Map

在模型上使用 thinkingLevelMap 来描述特定模型的思考控制。键是 pi 思考级别:offminimallowmediumhighxhighmax。映射中可能包含空缺;例如,模型可以公开 highmax 而不公开 xhigh

值是三态的:

含义
省略通过 high 的标准级别使用提供商的默认映射;扩展的 xhighmax 级别不受支持
字符串支持该级别,并将此值发送给提供商
null不支持该级别,将被隐藏/跳过/夹紧去除

仅支持关闭、高和最大推理的模型示例:

{
  "id": "deepseek-v4-pro",
  "reasoning": true,
  "thinkingLevelMap": {
    "minimal": null,
    "low": null,
    "medium": null,
    "high": "high",
    "xhigh": null,
    "max": "max"
  }
}

思考无法禁用的模型示例:

{
  "id": "always-thinking-model",
  "reasoning": true,
  "thinkingLevelMap": {
    "off": null
  }
}

迁移:使用 compat.reasoningEffortMap 的旧配置应将该映射迁移到模型级别的 thinkingLevelMap。对于不应在 UI 中显示的级别使用 null

覆盖内置提供商 Overriding Built-in Providers

通过代理路由内置提供商,无需重新定义模型:

{
  "providers": {
    "anthropic": {
      "baseUrl": "https://my-proxy.example.com/v1"
    }
  }
}

所有内置的 Anthropic 模型仍然可用。现有的 OAuth 或 API 密钥身份验证继续有效。

要将自定义模型合并到内置提供商中,请包含 models 数组:

{
  "providers": {
    "anthropic": {
      "baseUrl": "https://my-proxy.example.com/v1",
      "apiKey": "$ANTHROPIC_API_KEY",
      "api": "anthropic-messages",
      "models": [...]
    }
  }
}

合并语义:

  • 内置模型被保留。
  • 自定义模型在提供商标识 id 内按 id 更新插入。
  • 如果自定义模型的 id 与内置模型的 id 匹配,则自定义模型替换该内置模型。
  • 如果自定义模型的 id 是新的,则将其与内置模型一同添加。

逐模型覆盖 Per-model Overrides

使用 modelOverrides 自定义内置模型和匹配的扩展注册模型,而无需替换提供商的完整模型列表。

{
  "providers": {
    "openrouter": {
      "modelOverrides": {
        "anthropic/claude-sonnet-4": {
          "name": "Claude Sonnet 4 (Bedrock Route)",
          "compat": {
            "openRouterRouting": {
              "only": ["amazon-bedrock"]
            }
          }
        }
      }
    }
  }
}

modelOverrides 为每个模型支持以下字段:namereasoningthinkingLevelMapinputcost(部分)、contextWindowmaxTokensheaderscompat

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-terragpt-5.6-luna 应用相同的覆盖。

行为说明:

  • modelOverrides 应用于内置提供商模型和匹配的扩展注册提供商模型。
  • 未知的模型 ID 被忽略。
  • 您可以将提供商级别的 baseUrl/headersmodelOverrides 结合使用。
  • 覆盖 name 仅更改模型匹配和详情副文本;底部栏和主模型列表继续显示模型 id
  • 如果为提供商同时定义了 models,自定义模型会在内置覆盖之后合并。具有相同 id 的自定义模型会替换被覆盖的内置模型条目。

Anthropic Messages 兼容性 Anthropic Messages Compatibility

对于使用 api: "anthropic-messages" 的提供商或代理,使用 compat 控制 Anthropic 特定请求的兼容性。

默认情况下,pi 会发送每个工具的 eager_input_streaming: true。如果代理或兼容 Anthropic 的后端拒绝此字段,请设置 supportsEagerToolInputStreamingfalse。Pi 将省略 tools[].eager_input_streaming,并在启用工具请求时发送旧的 fine-grained-tool-streaming-2025-05-14 beta 请求头。

某些 Anthropic 模型需要自适应思考(thinking.type: "adaptive"output_config.effort),而不是传统的基于预算的思考负载。内置模型会自动设置此项。对于路由到这些模型的自定义提供商或别名,请设置 forceAdaptiveThinkingtrue

某些兼容 Anthropic 的提供商发送带有空签名的思考块,并且仍然希望其在重放时出现。仅对这些提供商设置 allowEmptySignaturetrue;真正的 Anthropic 会拒绝空的思考签名。

{
  "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提供商是否接受每个工具的 eager_input_streaming。默认值:true。设置为 false 以省略该字段,并在启用工具请求时使用旧的细粒度工具流式传输 beta 请求头。
supportsLongCacheRetention当缓存保留策略为 long 时,提供商是否接受 Anthropic 长缓存保留策略(cache_control.ttl: "1h")。默认值:true
sendSessionAffinityHeaders启用缓存时,是否从会话 ID 发送 x-session-affinity。默认值:已知提供商自动检测。
supportsCacheControlOnTools提供商是否接受工具定义上的 Anthropic 风格 cache_control 标记。默认值:true
forceAdaptiveThinking是否为此模型发送自适应思考(thinking.type: "adaptive"output_config.effort)。内置自适应模型会自动设置此项。默认值:false
allowEmptySignature是否将空的思考签名重放为 signature: "",而不是将思考转换为文本。默认值:false

OpenAI 兼容性 OpenAI Compatibility

对于具有部分 OpenAI 兼容性的提供商,使用 compat 字段。

  • 提供商级别的 compat 应用于该提供商下的所有模型。
  • 模型级别的 compat 覆盖该模型的提供商级别值。
{
  "providers": {
    "local-llm": {
      "baseUrl": "http://localhost:8080/v1",
      "api": "openai-completions",
      "compat": {
        "supportsUsageInStreaming": false,
        "maxTokensField": "max_tokens"
      },
      "models": [...]
    }
  }
}
字段描述
supportsStore提供商是否支持 store 字段
supportsDeveloperRole使用 developer 角色而非 system 角色
supportsReasoningEffort是否支持 reasoning_effort 参数
supportsUsageInStreaming是否支持 stream_options: { include_usage: true }(默认值:true
maxTokensField使用 max_completion_tokensmax_tokens
requiresToolResultName在工具结果消息中包含 name
requiresAssistantAfterToolResult在工具结果后、用户消息前插入一条助手消息
requiresThinkingAsText将思考块转换为纯文本
requiresReasoningContentOnAssistantMessages启用推理时,在所有重放的助手消息中包含空 reasoning_content
thinkingFormat使用 reasoning_effortopenrouterdeepseektogetherzaiqwenchat-templateqwen-chat-template 思考参数
chatTemplateKwargsthinkingFormat: "chat-template"chat_template_kwargs 值;使用 { "$var": "thinking.enabled" }{ "$var": "thinking.effort" } 表示 pi 控制的思考值
cacheControlFormat在系统提示、最后一个工具定义以及最后一个用户/助手文本内容上使用 Anthropic 风格 cache_control 标记。目前仅支持 anthropic
sendSessionAffinityHeaders对于 openai-completions,启用缓存时从会话 ID 发送会话亲和性请求头。默认值:false
sessionAffinityFormat对于 openai-completionsopenai-responses,会话亲和性请求头格式:openai 发送 session_id/x-client-request-id(completions 还发送 x-session-affinity),openai-nosession 省略包含下划线的 session_id 请求头,openrouter 发送 x-session-id。不影响 prompt_cache_key 主体参数。默认值:自动检测。
supportsStrictMode在工具定义中包含 strict 字段
supportsLongCacheRetention当缓存保留策略为 long 时,提供商是否接受长缓存保留策略:OpenAI 提示缓存的 prompt_cache_retention: "24h",或当 cacheControlFormatanthropic 时的 cache_control.ttl: "1h"。默认值:true
openRouterRoutingOpenRouter 提供商路由偏好。此对象按原样发送到 OpenRouter API 请求provider 字段中。
vercelGatewayRoutingVercel AI Gateway 路由配置用于提供商选择(onlyorder

openrouter 使用 reasoning: { effort }together 使用 reasoning: { enabled },并在启用 supportsReasoningEffort 时也使用 reasoning_effortqwen 使用顶级 enable_thinking。对于需要 chat_template_kwargs.enable_thinkingpreserve_thinking 的本地 Qwen 兼容服务器,使用 qwen-chat-template。对于需要可配置 chat_template_kwargs 的 vLLM/Hugging Face 聊天模板,使用 chat-template,例如 DeepSeek V3.x 模板的 chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } }

cacheControlFormat: "anthropic" 适用于通过文本内容和工具定义上的 cache_control 标记暴露 Anthropic 风格提示缓存的 OpenAI 兼容提供商。

示例:

{
  "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"]
            }
          }
        }
      ]
    }
  }
}