自定义模型
通过 ~/.pi/agent/models.json 添加自定义模型提供方和模型(Ollama、vLLM、LM Studio、代理等)。
- 最小示例
- 完整示例
- Google AI Studio 示例
- 支持的 API
- 模型提供方配置
- 模型配置
- 覆盖内置模型提供方
- 按模型的覆盖
- Anthropic Messages 兼容性
- OpenAI 兼容性
对于本地模型(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 示例
Section titled “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
Section titled “支持的 API”| API | 说明 |
|---|---|
openai-completions |
OpenAI 聊天补全(Chat Completions,兼容性最好) |
openai-responses |
OpenAI Responses API |
anthropic-messages |
Anthropic Messages API |
google-generative-ai |
Google 生成式 AI(Generative AI) |
api 可在模型提供方级别设置(作为所有模型的默认值),也可在模型级别设置(覆盖单个模型)。
模型提供方配置
Section titled “模型提供方配置”| 字段 | 说明 |
|---|---|
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、CLI 的 --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;当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 命令。
自定义请求头
Section titled “自定义请求头”{ "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 |
否 | 全为零 | 每百万 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。
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 按键与基础模型的取值合并。
思考级别映射
Section titled “思考级别映射”在模型上使用 thinkingLevelMap 来描述模型特有的思考控制。键为 Pi 的思考级别:off、minimal、low、medium、high、xhigh、max。映射中允许有空洞;例如,模型可以暴露 high 和 max,而不暴露 xhigh。
取值为三态:
| 取值 | 含义 |
|---|---|
| 省略 | high 及以下的标准级别使用提供方的默认映射;扩展的 xhigh 和 max 级别不受支持 |
| 字符串 | 该级别受支持,此值会发送给模型提供方 |
null |
该级别不受支持,会被隐藏/跳过/钳制掉 |
仅支持 off、high、max 推理级别的模型示例:
{ "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。不希望出现在界面中的级别请使用 null。
覆盖内置模型提供方
Section titled “覆盖内置模型提供方”通过代理路由内置模型提供方,而无需重新定义模型:
{ "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在该模型提供方内执行 upsert(存在则更新,不存在则新增)。 - 如果自定义模型的
id与内置模型的id相同,则自定义模型替换该内置模型。 - 如果自定义模型的
id是新的,则将其添加到内置模型旁边。
按模型的覆盖
Section titled “按模型的覆盖”使用 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 } } } }}该覆盖会保留内置的定价元数据。总输入 token 超过 272K 的请求将按 GPT-5.6 的长上下文费率对整个请求计费。需要时,可对 gpt-5.6-terra 或 gpt-5.6-luna 应用相同的覆盖。
行为说明:
modelOverrides应用于内置模型提供方的模型,以及匹配的扩展注册模型。- 未知的模型 ID 会被忽略。
- 可将提供方级别的
baseUrl/headers与modelOverrides结合使用。 - 覆盖
name只会改变模型匹配和次要的详情文本;页脚和主模型列表仍显示模型id。 - 如果某模型提供方也定义了
models,自定义模型会在内置覆盖之后合并。同id的自定义模型会替换已被覆盖的内置模型条目。
Anthropic Messages 兼容性
Section titled “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 的模型提供方会输出签名(signature)为空的思考块,并在重放时仍期望这些空签名。仅针对这些模型提供方将 allowEmptySignature 设为 true;真正的 Anthropic 会拒绝空思考签名。
内置 Anthropic 模型在其模型元数据中启用了 supportsStrictTools。当自定义的兼容 Anthropic 模型端点接受严格的 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 |
模型提供方是否接受每工具的 eager_input_streaming。默认:true。设为 false 可省略该字段,并在启用工具的请求中使用旧的细粒度工具流式传输(fine-grained tool streaming)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。 |
supportsStrictTools |
模型提供方是否接受严格的 JSON-schema 工具定义。默认:false;内置 Anthropic 模型在生成的元数据中会启用此项。 |
OpenAI 兼容性
Section titled “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 |
thinkingFormat: "chat-template" 时使用的 chat_template_kwargs 取值;对于 Pi 控制的思考取值,使用 { "$var": "thinking.enabled" } 或 { "$var": "thinking.effort" } |
chatTemplateArgs |
thinkingFormat: "baseten" 时使用的 chat_template_args 取值;对于 Pi 控制的思考取值,使用 { "$var": "thinking.enabled" } 或 { "$var": "thinking.effort" } |
cacheControlFormat |
在系统提示词、最后一个工具定义以及最后一条用户/助手/工具结果文本内容上使用 Anthropic 风格的 cache_control 标记。目前仅支持 anthropic。 |
sendSessionAffinityHeaders |
对于 openai-completions,启用缓存时从会话 id 发送会话亲和性(session-affinity)请求头。默认:false。 |
sessionAffinityFormat |
对于 openai-completions 和 openai-responses,会话亲和性请求头格式:openai 发送 session_id/x-client-request-id(completions 还发送 x-session-affinity),openai-nosession 省略含下划线的 session_id 请求头,openrouter 发送 x-session-id。不影响 prompt_cache_key 请求体参数。默认:自动检测。 |
supportsStrictMode |
模型提供方是否接受严格的 JSON-schema 函数工具定义。默认值取决于 API;内置 OpenAI 模型带有显式的能力元数据。 |
supportsOpenAIGrammarTools |
兼容 OpenAI 的 API 是否输出自定义 Lark/regex 语法工具。设为 false 时,受语法约束的工具回退为普通函数工具。默认:false;内置模型目录会在 OpenAI、OpenAI Codex、Azure OpenAI、GitHub Copilot、opencode 和 Cloudflare AI Gateway 上为 GPT-5+ 模型启用此项。 |
deferredToolsMode |
使用提供方特有的延迟工具序列化。目前仅对 Kimi 的 OpenAI 兼容 Chat Completions 格式支持 "kimi"。 |
supportsLongCacheRetention |
当缓存保留策略为 long 时,模型提供方是否接受长缓存保留:OpenAI 提示缓存使用 prompt_cache_retention: "24h",或当 cacheControlFormat 为 anthropic 时使用 cache_control.ttl: "1h"。默认:true。 |
openRouterRouting |
OpenRouter 模型提供方的路由偏好。该对象会原样发送到 OpenRouter API 请求 的 provider 字段中。 |
vercelGatewayRouting |
用于模型提供方选择(only、order)的 Vercel AI Gateway 路由配置 |
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 的模型提供方,请将 thinkingFormat 设为 "baseten" 并配合 chatTemplateArgs。
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"] } } } ] } }}