Custom Models(自定义模型)

本页面是 Pi 官方文档 的中文翻译。仅供学习参考。

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

目录

最小示例

对于本地模型(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 会忽略它,所以任意值都可以。

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

你可以在 Provider 级别设置 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-completionsOpenAI Chat Completions(最兼容)
openai-responsesOpenAI Responses API
anthropic-messagesAnthropic Messages API
google-generative-aiGoogle Generative AI

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

Provider 配置

字段说明
baseUrlAPI 端点 URL
apiAPI 类型(见上表)
apiKeyAPI Key(见下面的值解析)
headers自定义请求头(见下面的值解析)
authHeader设为 true 自动添加 Authorization: Bearer <apiKey>
models模型配置数组
modelOverrides此 Provider 上内置模型的逐模型覆盖

值解析

apiKeyheaders 字段支持三种格式:

  • Shell 命令: "!command" 执行命令并使用 stdout
    "apiKey": "!security find-generic-password -ws 'anthropic'"
    "apiKey": "!op read 'op://vault/item/credential'"
  • 环境变量: 使用命名变量的值
    "apiKey": "MY_API_KEY"
  • 字面值: 直接使用
    "apiKey": "sk-..."

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

如果你的命令较慢、昂贵、受速率限制,或者希望在瞬态失败时继续使用之前的值,请将其包装在你自己的脚本或命令中,实现所需的缓存或 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)
nameid人类可读的模型标签。用于匹配(--model 模式)并显示在模型详情/状态文本中
apiProvider 的 api为此模型覆盖 Provider 的 API
reasoningfalse是否支持 extended thinking
thinkingLevelMap省略将 Pi 的 thinking level 映射到 Provider 值,并标记不支持的 level(见下文)
input["text"]输入类型:["text"]["text", "image"]
contextWindow128000上下文窗口大小(Token)
maxTokens16384最大输出 Token
cost全零{"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0}(每百万 Token)
compatProvider 的 compatProvider 兼容性覆盖。当两者都设置时,与 Provider 级别的 compat 合并

当前行为:

  • /model--list-models 按模型 id 列出条目。
  • 配置的 name 用于模型匹配和详情/状态文本。

Thinking Level Map

在模型上使用 thinkingLevelMap 来描述模型特定的 thinking 控制。键是 Pi 的 thinking level:offminimallowmediumhighxhigh

值为三态:

含义
省略该 level 受支持,使用 Provider 的默认映射
字符串该 level 受支持,此值被发送给 Provider
null该 level 不受支持,被隐藏/跳过/固定到最近值

仅支持 off、high 和 max 推理的模型示例:

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

不可禁用 thinking 的模型示例:

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

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

覆盖内置 Provider

通过代理路由内置 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": [...]
    }
  }
}

合并语义:

  • 内置模型被保留。
  • 自定义模型按 Provider 内的 id 进行更新(upsert)。
  • 如果自定义模型 id 与内置模型 id 匹配,则替换该内置模型。
  • 如果自定义模型 id 是新的,则与内置模型并列添加。

逐模型覆盖

使用 modelOverrides 自定义特定内置模型,无需替换 Provider 的完整模型列表。

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

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

行为说明:

  • modelOverrides 应用于内置 Provider 的模型。
  • 未知模型 ID 被忽略。
  • 你可以将 Provider 级别的 baseUrl/headersmodelOverrides 结合使用。
  • 如果 Provider 也定义了 models,自定义模型在内置覆盖之后合并。具有相同 id 的自定义模型会替换已覆盖的内置模型条目。

Anthropic Messages 兼容性

对于使用 api: "anthropic-messages" 的 Provider 或代理,使用 compat.supportsEagerToolInputStreaming 控制 Anthropic 细粒度工具流兼容性。

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

{
  "providers": {
    "anthropic-proxy": {
      "baseUrl": "https://proxy.example.com",
      "api": "anthropic-messages",
      "apiKey": "ANTHROPIC_PROXY_KEY",
      "compat": {
        "supportsEagerToolInputStreaming": false,
        "supportsLongCacheRetention": true
      },
      "models": [
        {
          "id": "claude-opus-4-7",
          "reasoning": true,
          "input": ["text", "image"]
        }
      ]
    }
  }
}
字段说明
supportsEagerToolInputStreamingProvider 是否接受每个工具的 eager_input_streaming。默认:true。设为 false 可省略该字段,并在启用工具的请求中使用旧的细粒度工具流 beta 头
supportsLongCacheRetentionProvider 是否在缓存保留为 long 时接受 Anthropic 长缓存保留(cache_control.ttl: "1h")。默认:true

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": [...]
    }
  }
}
字段说明
supportsStoreProvider 支持 store 字段
supportsDeveloperRole使用 developer 角色而非 system
supportsReasoningEffort支持 reasoning_effort 参数
supportsUsageInStreaming支持 stream_options: { include_usage: true }(默认:true
maxTokensField使用 max_completion_tokensmax_tokens
requiresToolResultName在工具结果消息中包含 name
requiresAssistantAfterToolResult在工具结果后、用户消息前插入一条助手消息
requiresThinkingAsText将 thinking 块转换为纯文本
requiresReasoningContentOnAssistantMessages在启用推理时,在所有重放的助手消息上包含空的 reasoning_content
thinkingFormat使用 reasoning_effortopenrouterdeepseektogetherzaiqwenqwen-chat-template thinking 参数
cacheControlFormat在系统提示、最后一个工具定义和最后一个用户/助手文本内容上使用 Anthropic 风格的 cache_control 标记。目前仅支持 anthropic
supportsStrictMode在工具定义中包含 strict 字段
supportsLongCacheRetentionProvider 是否在缓存保留为 long 时接受长缓存保留:OpenAI 提示缓存的 prompt_cache_retention: "24h",或当 cacheControlFormatanthropic 时的 cache_control.ttl: "1h"。默认:true
openRouterRoutingOpenRouter Provider 路由偏好。此对象按原样作为 OpenRouter API 请求provider 字段发送
vercelGatewayRoutingVercel AI Gateway 路由配置,用于 Provider 选择(onlyorder

openrouter 使用 reasoning: { effort }together 使用 reasoning: { enabled },并在 supportsReasoningEffort 启用时也使用 reasoning_effortqwen 使用顶级 enable_thinking。对需要 chat_template_kwargs.enable_thinking 的本地 Qwen 兼容服务器,使用 qwen-chat-template

cacheControlFormat: "anthropic" 适用于那些在文本内容和工具定义上通过 cache_control 标记暴露 Anthropic 风格提示缓存的 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"]
            }
          }
        }
      ]
    }
  }
}

法律声明:本页面是 pi.dev 官方文档的中文翻译版本,仅供学习参考。本网站与 pi.dev 及 Earendil Inc. 无任何法律关系。