自定义模型
通过以下方式添加自定义提供商和模型(Ollama、vLLM、LM Studio、代理): ~/.pi/agent/models.json.
目录
最小示例
对于本地模型(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.supportsDeveloperRole 设置为 false ,以便 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
}
]
}
}
}完整示例
需要特定值时覆盖默认值:
{
"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
}
]
}
}
}向 baseUrl API 类型添加自定义模型时,需要 google-generative-ai API 类型。
支持的 API
| API | 描述 |
|---|---|
openai-completions | OpenAI Chat Completions(兼容性最佳) |
openai-responses | OpenAI 响应 API |
anthropic-messages | Anthropic 消息 API |
google-generative-ai | 谷歌生成式人工智能 |
在提供商级别(所有模型的默认值)或模型级别(按模型覆盖)设置 api 在提供商级别(所有模型的默认值)或模型级别(按模型覆盖)。
提供商配置
| 字段 | 描述 |
|---|---|
baseUrl | API 端点 URL |
api | API 类型(见上文) |
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,命令行界面 --api-key或提供商 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;当${FOO}_BAR是字面文本时使用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 命令。
自定义标头
{
"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 | 否 | 提供商的 api | 为此模型覆盖提供商的 API |
reasoning | 否 | false | 支持扩展思考 |
thinkingLevelMap | 否 | 省略 | 将 pi 思考级别映射到提供商值并标记不支持的级别(见下文) |
input | 否 | ["text"] | 输入类型: ["text"] 或 ["text", "image"] |
contextWindow | 否 | 128000 | 上下文窗口大小(以 token 计) |
maxTokens | 否 | 16384 | 最大输出 token 数 |
samplingParams | 否 | 省略 | 采样参数逐字合并到每个请求体中(见下文) |
cost | 否 | 全零 | 每百万令牌费率,可选请求级输入定价层级 |
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。
采样参数
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 键会覆盖请求级别的 temperature),因此最好将其作为模型采样真相的唯一来源。在 modelOverrides, samplingParams 中,会与基础模型的值按键合并。
思考级别映射
在模型上使用 thinkingLevelMap 来描述模型特定的思考控制。键是 pi 的思考级别: off, minimal, low, medium, high, xhigh, max。映射可以包含空缺;例如,模型可以暴露 high 和 max 而不暴露 xhigh.
值是三态的:
| 值 | 含义 |
|---|---|
| 省略 | 的标准级别使用提供商的默认映射;扩展的 high 和 xhigh 级别不受支持 max 字符串 |
| 级别受支持,此值将发送给提供商 | 级别不受支持,将被隐藏/跳过/限制 |
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 。对于不应出现在 UI 中的级别,使用 thinkingLevelMap。 null 覆盖内置提供商
通过代理路由内置提供商,无需重新定义模型:
所有内置 Anthropic 模型仍然可用。现有的 OAuth 或 API 密钥认证继续有效。
{
"providers": {
"anthropic": {
"baseUrl": "https://my-proxy.example.com/v1"
}
}
}要将自定义模型合并到内置提供商中,请包含
数组: models 合并语义:
{
"providers": {
"anthropic": {
"baseUrl": "https://my-proxy.example.com/v1",
"apiKey": "$ANTHROPIC_API_KEY",
"api": "anthropic-messages",
"models": [...]
}
}
}保留内置模型。
- 自定义模型在提供商内按
- 进行更新插入。
id如果自定义模型的 - 与内置模型的
id匹配id,自定义模型将替换该内置模型。 - 如果自定义模型
id是新的,它将与内置模型一起添加。
按模型覆盖
使用 modelOverrides 来自定义内置模型和匹配的扩展注册模型,而无需替换提供商的完整模型列表。
{
"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.
直接 OpenAI GPT-5.6 Sol、Terra 和 Luna 默认使用 272000 上下文窗口,以便请求保持在 OpenAI 的短上下文定价层内。要选择使用 OpenAI 的 1.05M 上下文窗口,请为您使用的每个模型增加它:
{
"providers": {
"openai": {
"modelOverrides": {
"gpt-5.6-sol": {
"contextWindow": 1050000
}
}
}
}
}覆盖会保留内置的定价元数据。总输入令牌超过 272K 的请求将对整个请求使用 GPT-5.6 的长上下文费率。在需要时对 gpt-5.6-terra 或 gpt-5.6-luna 应用相同的覆盖。
行为说明:
modelOverrides应用于内置提供商模型和匹配的扩展注册提供商模型。- 未知的模型 ID 将被忽略。
- 您可以将提供商级别的
baseUrl/headers与modelOverrides. - 覆盖
name仅更改模型匹配和次要详细信息文本;页脚和主要模型列表继续显示模型id. - 如果
models也为提供商定义,自定义模型将在内置覆盖之后合并。具有相同id的自定义模型将替换被覆盖的内置模型条目。
Anthropic Messages 兼容性
对于使用 api: "anthropic-messages"的提供商或代理,使用 compat 来控制 Anthropic 特定的请求兼容性。
默认情况下,pi 发送每个工具的 eager_input_streaming: true。如果代理或与 Anthropic 兼容的后端拒绝该字段,请将 supportsEagerToolInputStreaming 设置为 false。Pi 将省略 tools[].eager_input_streaming 并改为发送传统的 fine-grained-tool-streaming-2025-05-14 beta 标头用于启用工具的请求。
某些 Anthropic 模型需要自适应思考(thinking.type: "adaptive" 加上 output_config.effort)而不是传统的基于预算的思考负载。内置模型会自动设置此项。对于路由到这些模型的自定义提供商或别名,请将 forceAdaptiveThinking 设置为 true.
某些与 Anthropic 兼容的提供商会发出带有空签名的思考块,并且仍然期望在重放时使用它们。仅对这些提供商将 allowEmptySignature 设置为 true ;真正的 Anthropic 会拒绝空的思考签名。
内置的 Anthropic 模型在其模型元数据中启用 supportsStrictTools 。自定义的与 Anthropic 兼容的模型在其端点接受严格的 JSON 模式工具定义时,必须将其设置为 true 当其端点接受严格的 JSON-schema 工具定义时。
{
"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 | 提供商是否接受 Anthropic 长缓存保留(cache_control.ttl: "1h"),当缓存保留为 long时。默认值: true. |
sendSessionAffinityHeaders | 是否发送 x-session-affinity 从会话 ID 当启用缓存时。默认:对已知提供商自动检测。 |
supportsCacheControlOnTools | 提供商是否接受 Anthropic 风格的 cache_control 标记在工具定义上。默认: true. |
forceAdaptiveThinking | 是否为此模型发送自适应思考(thinking.type: "adaptive" 加 output_config.effort)。内置自适应模型会自动设置此项。默认: false. |
allowEmptySignature | 是否将空的思考签名重放为 signature: "" 而不是将思考转换为文本。默认: false. |
supportsStrictTools | 提供商是否接受严格的 JSON 模式工具定义。默认: false;内置 Anthropic 模型在生成的元数据中启用它。 |
OpenAI 兼容性
对于具有部分 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) |
supportsFinishReason | 流式响应是否包含 finish_reason。当 false时,pi 推断 stop 或 toolUse 当流结束时。默认: true. |
maxTokensField | 使用 max_completion_tokens 或 max_tokens |
requiresToolResultName | 在工具结果消息中包含 name 关于工具结果消息 |
requiresAssistantAfterToolResult | 在工具结果之后,在用户消息之前插入一条助手消息 |
requiresThinkingAsText | 将思考块转换为纯文本 |
requiresReasoningContentOnAssistantMessages | 在启用推理时,在所有重放的助手消息中包含空的 reasoning_content 在启用推理时,对所有重播的助手消息 |
thinkingFormat | 使用 reasoning_effort, openrouter, deepseek, together, baseten, zai, qwen, chat-template、或 qwen-chat-template 思考参数 |
chatTemplateKwargs | chat_template_kwargs 的值用于 thinkingFormat: "chat-template";使用 { "$var": "thinking.enabled" } 或 { "$var": "thinking.effort" } 用于 pi 控制的思考值 |
chatTemplateArgs | chat_template_args 的值用于 thinkingFormat: "baseten";使用 { "$var": "thinking.enabled" } 或 { "$var": "thinking.effort" } 用于 pi 控制的思考值 |
cacheControlFormat | 在系统提示、最后一个工具定义以及最后一个用户、助手或工具结果文本内容上使用 Anthropic 风格的 cache_control 标记。目前仅支持 anthropic 受支持。 |
sendSessionAffinityHeaders | 对于 openai-completions,当启用缓存时,从会话 ID 发送会话亲和性标头。默认: false. |
sessionAffinityFormat | 对于 openai-completions 和 openai-responses,会话亲和性标头格式: openai 发送 session_id/x-client-request-id (补全也 x-session-affinity), openai-nosession 省略包含下划线的 session_id 标头, openrouter 发送 x-session-id。不影响 prompt_cache_key 正文参数。默认:自动检测。 |
supportsStrictMode | 提供商是否接受严格的 JSON-schema 函数工具定义。默认值取决于 API;内置的 OpenAI 模型携带明确的能力元数据。 |
supportsOpenAIGrammarTools | OpenAI 兼容的 API 是否发出自定义 Lark/正则语法工具。当 false时,语法约束的工具会回退到普通函数工具。默认值: false;内置模型目录为 OpenAI、OpenAI Codex、Azure OpenAI、GitHub Copilot、opencode 和 Cloudflare AI Gateway 上的 GPT-5+ 模型启用它。 |
deferredToolsMode | 使用提供商特定的延迟工具序列化。目前仅支持 "kimi" 用于 Kimi 的 OpenAI 兼容 Chat Completions 格式。 |
supportsLongCacheRetention | 当缓存保留为 long: prompt_cache_retention: "24h" 用于 OpenAI 提示缓存时,提供商是否接受长缓存保留,或 cache_control.ttl: "1h" 当 cacheControlFormat 为 anthropic时。默认值: true. |
openRouterRouting | OpenRouter 提供商路由偏好。此对象按原样发送到 provider 字段的 OpenRouter API 请求. |
vercelGatewayRouting | Vercel AI Gateway 路由配置用于提供商选择(only, order) |
openrouter 使用 reasoning: { effort }. together 使用 reasoning: { enabled } 并且当 reasoning_effort 启用时也使用 supportsReasoningEffort 已启用。 qwen 使用顶层 enable_thinking。使用 qwen-chat-template 用于需要 chat_template_kwargs.enable_thinking 和 preserve_thinking的本地 Qwen 兼容服务器。使用 chat-template 用于需要可配置 chat_template_kwargs的 vLLM/Hugging Face 聊天模板,例如 chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } } 用于 DeepSeek V3.x 模板。使用 thinkingFormat: "baseten" 与 chatTemplateArgs 用于通过 chat_template_args 公开切换控件并可选支持顶层 reasoning_effort.
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"]
}
}
}
]
}
}
}