Personalizado Models
Adicione provedores e modelos personalizados (Ollama, vLLM, LM Studio, proxies) via ~/.pi/agent/models.json.
Índice
- Minimal Example
- Full Example
- Supported APIs
- Provider Configuration
- Model Configuration
- Overriding Built-in Providers
- Per-model Overrides
- Anthropic Messages Compatibility
- OpenAI Compatibility
Exemplo Mínimo
Para modelos locais (Ollama, LM Studio, vLLM), apenas id é necessário por modelo:
{
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"api": "openai-completions",
"apiKey": "ollama",
"models": [
{ "id": "llama3.1:8b" },
{ "id": "qwen2.5-coder:7b" }
]
}
}
}O valor apiKey é um espaço reservado porque Ollama o ignora. pi ainda trata os modelos como exigindo autenticação antes de aparecerem em /model, portanto, os servidores locais sem chave devem manter um valor fictício, salvar uma chave para esse provedor com /login ou passar --api-key ao selecionar o modelo.
Alguns servidores compatíveis com OpenAI não entendem a função developer usada para modelos com capacidade de raciocínio. Para esses provedores, defina compat.supportsDeveloperRole como false para que pi envie o prompt do sistema como uma mensagem system. Se o servidor também não suportar reasoning_effort, defina compat.supportsReasoningEffort para false também.
Você pode definir compat no nível do provedor para aplicar a todos os modelos ou no nível do modelo para substituir um modelo específico. Isso geralmente se aplica a Ollama, vLLM, SGLang e servidores semelhantes compatíveis com 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
}
]
}
}
}Exemplo completo
Substitua os padrões quando precisar de valores específicos:
{
"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 }
}
]
}
}
}O arquivo é recarregado cada vez que você abre /model. Editar durante a sessão; não é necessário reiniciar.
Exemplo do Google AI Studio
Use google-generative-ai com baseUrl para adicionar modelos do Google AI Studio, incluindo entradas personalizadas do 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
}
]
}
}
}O baseUrl é necessário ao adicionar modelos personalizados ao tipo google-generative-ai API.
APIs suportados
| API | Descrição |
|---|---|
openai-completions |
Conclusões de bate-papo OpenAI (mais compatíveis) |
openai-responses |
Respostas OpenAI API |
anthropic-messages |
Mensagens Antrópicas API |
google-generative-ai |
IA generativa do Google |
Defina api no nível do provedor (padrão para todos os modelos) ou no nível do modelo (substituição por modelo).
Configuração do provedor
| Campo | Descrição |
|---|---|
baseUrl |
API URL do terminal |
api |
API tipo (veja acima) |
apiKey |
Configuração API key opcional (veja a resolução do valor abaixo). Omita quando a autenticação for fornecida por /login/auth.json ou CLI --api-key. |
oauth |
Tipo de provedor dinâmico OAuth. Atualmente suporta "radius"; requer o gateway baseUrl. |
headers |
Cabeçalhos personalizados (veja a resolução do valor abaixo) |
authHeader |
Defina true para adicionar Authorization: Bearer <apiKey> automaticamente |
models |
Matriz de configurações de modelo |
modelOverrides |
Substituições por modelo para modelos integrados ou registrados em extensão neste provedor |
Para provedores com models, as configurações de provedor não integradas precisam de baseUrl e um valor api no nível do provedor ou do modelo. apiKey não é necessário para carregar o arquivo: os modelos ficam disponíveis quando a autenticação é configurada por meio de /login/auth.json, CLI --api-key ou provedor apiKey. Se nenhuma autenticação estiver configurada, os modelos serão carregados, mas permanecerão indisponíveis em /model e --list-models.
Resolução de valor
Os campos apiKey e headers suportam execução de comandos, interpolação de ambiente e literais:
- Comando Shell:
"!command"no início executa todo o valor como um comando e usa stdout"apiKey": "!security find-generic-password -ws 'anthropic'" "apiKey": "!op read 'op://vault/item/credential'" - Interpolação de ambiente:
"$ENV_VAR"ou"${ENV_VAR}"usa o valor da variável nomeada. A interpolação funciona dentro de literais maiores."apiKey": "$MY_API_KEY" "apiKey": "${KEY_PREFIX}_${KEY_SUFFIX}"$FOO_BARé a variávelFOO_BAR; use${FOO}_BARquandoBARfor texto literal. Variáveis de ambiente ausentes tornam o valor não resolvido. - Escapes:
"quot;emite um literal"quot;;"$!"emite um literal"!"sem acionar a execução do comando."apiKey": "$literal-dollar-prefix" "apiKey": "$!literal-bang-prefix" - Valor literal: Usado diretamente. Strings simples em maiúsculas como
MY_API_KEYsão literais; use$MY_API_KEYpara variáveis de ambiente."apiKey": "sk-..."
Para models.json, os comandos shell são resolvidos no momento da solicitação. pi intencionalmente não aplica TTL integrado, reutilização obsoleta ou lógica de recuperação para comandos arbitrários. Comandos diferentes precisam de estratégias diferentes de cache e falha, e pi não consegue inferir qual é a correta.
Se o seu comando for lento, caro, com taxa limitada ou precisar continuar usando um valor anterior em falhas transitórias, envolva-o em seu próprio script ou comando que implemente o cache ou o comportamento TTL desejado.
/model verificações de disponibilidade usam presença de autenticação configurada e não executam comandos shell.
Cabeçalhos personalizados
{
"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": [...]
}
}
}Configuração do modelo
| Campo | Obrigatório | Padrão | Descrição |
|---|---|---|---|
id |
Sim | — | Identificador do modelo (passado para API) |
name |
Não | id |
Etiqueta do modelo legível por humanos. Usado para correspondência (padrões --model) e mostrado como texto de detalhe do modelo secundário. |
api |
Não | provedor api |
Substituir API do provedor para este modelo |
reasoning |
Não | false |
Suporta pensamento estendido |
thinkingLevelMap |
Não | omitido | Mapeia os níveis de pensamento pi para os valores do provedor e marca os níveis não suportados (veja abaixo) |
input |
Não | ["text"] |
Tipos de entrada: ["text"] ou ["text", "image"] |
contextWindow |
Não | 128000 |
Tamanho da janela de contexto em tokens |
maxTokens |
Não | 16384 |
Tokens de saída máximo |
samplingParams |
Não | omitido | Parâmetros de amostragem mesclados literalmente em cada corpo da solicitação (veja abaixo) |
cost |
Não | todos os zeros | Taxas por milhão de tokens com níveis opcionais de preços de entrada para toda a solicitação |
compat |
Não | provedor compat |
Substituições de compatibilidade do provedor. Mesclado com o nível do provedor compat quando ambos estão definidos. |
Uma camada de custo fornece um conjunto completo de taxas alternativas e se aplica à solicitação completa quando o uso total de entrada (input + cacheRead + cacheWrite) excede inputTokensAbove. Quando vários níveis coincidem, o limite mais alto vence.
{
"cost": {
"input": 5,
"output": 30,
"cacheRead": 0.5,
"cacheWrite": 6.25,
"tiers": [
{
"inputTokensAbove": 272000,
"input": 10,
"output": 45,
"cacheRead": 1,
"cacheWrite": 12.5
}
]
}
}Comportamento atual:
/model,--list-modelse o rodapé interativo exibem entradas por modeloid.- O
nameconfigurado é usado para correspondência de modelo e texto de detalhes do modelo secundário. Ele não substitui o ID do modelo do rodapé/barra de status.
Parâmetros de Amostragem
samplingParams é um objeto de formato livre mesclado literalmente em cada corpo de solicitação do modelo, depois que os campos pi se definem, para que suas chaves ganhem. Use-o para enviar parâmetros de amostragem que pi não modela - incluindo aqueles específicos do servidor, como llama.cpp's min_p ou vLLM's top_k:
{
"id": "deepseek-v4-flash",
"samplingParams": {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 0,
"min_p": 0.0
}
}Somente APIs compatíveis com OpenAI o aplicam (openai-completions, openai-responses, azure-openai-responses); outros APIs ignoram. As chaves substituem os campos de solicitação nomeados do pi (por exemplo, uma chave temperature aqui supera a temperatura no nível da solicitação), portanto, prefira-a como a única fonte de amostragem verdadeira para um modelo. Em modelOverrides, samplingParams mescla por chave com o valor do modelo base.
Mapa de nível de pensamento
Use thinkingLevelMap em um modelo para descrever controles de pensamento específicos do modelo. As chaves são níveis de pensamento pi: off, minimal, low, medium, high, xhigh, max. Os mapas podem conter buracos; por exemplo, um modelo pode expor high e max sem expor xhigh.
Os valores são tristate:
| Valor | Significado |
|---|---|
| omitido | Os níveis padrão até high usam o mapeamento padrão do provedor; níveis estendidos xhigh e max não são suportados |
| corda | O nível é suportado e esse valor é enviado ao provedor |
null |
O nível não é suportado e está oculto/ignorado/fixado |
Exemplo de um modelo que suporta apenas raciocínios off, high e max:
{
"id": "deepseek-v4-pro",
"reasoning": true,
"thinkingLevelMap": {
"minimal": null,
"low": null,
"medium": null,
"high": "high",
"xhigh": null,
"max": "max"
}
}Exemplo de um modelo onde o pensamento não pode ser desativado:
{
"id": "always-thinking-model",
"reasoning": true,
"thinkingLevelMap": {
"off": null
}
}Migração: configurações mais antigas que usavam compat.reasoningEffortMap deveriam mover esse mapeamento para o nível de modelo thinkingLevelMap. Use null para níveis que não devem aparecer na UI.
Substituindo o integrado Providers
Roteie um provedor integrado por meio de um proxy sem redefinir modelos:
{
"providers": {
"anthropic": {
"baseUrl": "https://my-proxy.example.com/v1"
}
}
}Todos os modelos Antrópicos integrados permanecem disponíveis. A autenticação OAuth ou API key existente continua funcionando.
Para mesclar modelos personalizados em um provedor integrado, inclua o array models:
{
"providers": {
"anthropic": {
"baseUrl": "https://my-proxy.example.com/v1",
"apiKey": "$ANTHROPIC_API_KEY",
"api": "anthropic-messages",
"models": [...]
}
}
}Mesclar semântica:
- Os modelos integrados são mantidos.
- Os modelos personalizados são atualizados por
idno provedor. - Se um modelo customizado
idcorresponder a um modelo integradoid, o modelo customizado substituirá esse modelo integrado. - Se um modelo personalizado
idfor novo, ele será adicionado junto com os modelos integrados.
Substituições por modelo
Use modelOverrides para personalizar modelos integrados e combinar modelos registrados em extensão sem substituir a lista completa de modelos do provedor.
{
"providers": {
"openrouter": {
"modelOverrides": {
"anthropic/claude-sonnet-4": {
"name": "Claude Sonnet 4 (Bedrock Route)",
"compat": {
"openRouterRouting": {
"only": ["amazon-bedrock"]
}
}
}
}
}
}
}modelOverrides suporta estes campos por modelo: name, reasoning, thinkingLevelMap, input, cost (parcial), contextWindow, maxTokens, samplingParams (mesclado por chave), headers, compat.
Direct OpenAI GPT-5.6 Sol, Terra e Luna têm como padrão uma janela de contexto 272000 para que as solicitações permaneçam dentro do nível de preços de contexto curto do OpenAI. Para aceitar a janela de contexto de 1,05M do OpenAI, aumente-a para cada modelo que você usar:
{
"providers": {
"openai": {
"modelOverrides": {
"gpt-5.6-sol": {
"contextWindow": 1050000
}
}
}
}
}A substituição preserva os metadados de preços integrados. Solicitações com mais de 272 mil tokens de entrada totais usam as taxas de contexto longo do GPT-5.6 para toda a solicitação. Aplique a mesma substituição a gpt-5.6-terra ou gpt-5.6-luna quando necessário.
Notas de comportamento:
modelOverridessão aplicados a modelos de provedores integrados e modelos de provedores registrados em extensão correspondentes.- IDs de modelo desconhecidos são ignorados.
- Você pode combinar
baseUrl/headersde nível de provedor commodelOverrides. - A substituição de
namealtera apenas a correspondência do modelo e o texto de detalhes secundários; o rodapé e as listas de modelos primários continuam mostrando o modeloid. - Se
modelstambém for definido para um provedor, os modelos customizados serão mesclados após substituições integradas. Um modelo personalizado com o mesmoidsubstitui a entrada do modelo integrado substituída.
Compatibilidade de Mensagens Antrópicas
Para provedores ou proxies que usam api: "anthropic-messages", use compat para controlar a compatibilidade de solicitações específicas do Antrópico.
Por padrão, pi envia por ferramenta eager_input_streaming: true. Se um proxy ou back-end compatível com Anthropic rejeitar esse campo, defina supportsEagerToolInputStreaming como false. Pi omitirá tools[].eager_input_streaming e enviará o cabeçalho beta fine-grained-tool-streaming-2025-05-14 herdado para solicitações habilitadas para ferramenta.
Alguns modelos antrópicos requerem pensamento adaptativo (thinking.type: "adaptive" mais output_config.effort) em vez da carga útil de pensamento legado baseado em orçamento. Os modelos integrados definem isso automaticamente. Para provedores personalizados ou aliases que roteiam para esses modelos, defina forceAdaptiveThinking como true.
Alguns provedores compatíveis com o Anthropic emitem blocos de pensamento com assinaturas vazias e ainda os esperam na repetição. Defina allowEmptySignature como true apenas para esses provedores; o verdadeiro Antrópico rejeita assinaturas de pensamento vazias.
Os modelos Antrópicos integrados habilitam supportsStrictTools em seus metadados de modelo. Modelos customizados compatíveis com Anthropic devem defini-lo como true quando seu endpoint aceita definições estritas de ferramenta de esquema JSON.
{
"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"]
}
]
}
}
}| Campo | Descrição |
|---|---|
supportsEagerToolInputStreaming |
Se o provedor aceita eager_input_streaming por ferramenta. Padrão: true. Defina como false para omitir esse campo e usar o cabeçalho beta de streaming da ferramenta legada e refinada em solicitações habilitadas para ferramenta. |
supportsLongCacheRetention |
Se o provedor aceita retenção de cache longa antrópica (cache_control.ttl: "1h") quando a retenção de cache é long. Padrão: true. |
sendSessionAffinityHeaders |
Se deve ser enviado x-session-affinity do ID da sessão quando o cache estiver habilitado. Padrão: detectado automaticamente para provedores conhecidos. |
supportsCacheControlOnTools |
Se o provedor aceita marcadores cache_control de estilo antrópico nas definições de ferramentas. Padrão: true. |
forceAdaptiveThinking |
Se deve enviar pensamento adaptativo (thinking.type: "adaptive" mais output_config.effort) para este modelo. Os modelos adaptativos integrados definem isso automaticamente. Padrão: false. |
allowEmptySignature |
Se deve reproduzir assinaturas de pensamento vazias como signature: "" em vez de converter o pensamento em texto. Padrão: false. |
supportsStrictTools |
Se o provedor aceita definições estritas de ferramentas de esquema JSON. Padrão: false; modelos antrópicos integrados permitem isso nos metadados gerados. |
Compatibilidade OpenAI
Para provedores com compatibilidade parcial com OpenAI, use o campo compat.
- O nível de provedor
compataplica padrões a todos os modelos desse provedor. - O nível do modelo
compatsubstitui os valores do nível do provedor para esse modelo.
{
"providers": {
"local-llm": {
"baseUrl": "http://localhost:8080/v1",
"api": "openai-completions",
"compat": {
"supportsUsageInStreaming": false,
"maxTokensField": "max_tokens"
},
"models": [...]
}
}
}| Campo | Descrição |
|---|---|
supportsStore |
O provedor suporta o campo store |
supportsDeveloperRole |
Use a função developer vs system |
supportsReasoningEffort |
Suporte para parâmetro reasoning_effort |
supportsUsageInStreaming |
Suporta stream_options: { include_usage: true } (padrão: true) |
supportsFinishReason |
Se as respostas transmitidas incluem finish_reason. Quando false, pi infere stop ou toolUse quando o fluxo termina. Padrão: true. |
maxTokensField |
Use max_completion_tokens ou max_tokens |
requiresToolResultName |
Incluir name nas mensagens de resultados da ferramenta |
requiresAssistantAfterToolResult |
Insira uma mensagem do assistente antes de uma mensagem do usuário após os resultados da ferramenta |
requiresThinkingAsText |
Converta blocos de pensamento em texto simples |
requiresReasoningContentOnAssistantMessages |
Incluir reasoning_content vazio em todas as mensagens do assistente reproduzidas quando o raciocínio estiver ativado |
thinkingFormat |
Use parâmetros de pensamento reasoning_effort, openrouter, deepseek, together, baseten, zai, qwen, chat-template ou qwen-chat-template |
chatTemplateKwargs |
chat_template_kwargs valores para thinkingFormat: "chat-template"; use { "$var": "thinking.enabled" } ou { "$var": "thinking.effort" } para valores de pensamento controlados por pi |
chatTemplateArgs |
chat_template_args valores para thinkingFormat: "baseten"; use { "$var": "thinking.enabled" } ou { "$var": "thinking.effort" } para valores de pensamento controlados por pi |
cacheControlFormat |
Use marcadores cache_control de estilo antrópico no prompt do sistema, na última definição de ferramenta e no conteúdo de texto do último usuário, assistente ou resultado da ferramenta. Atualmente apenas anthropic é suportado. |
sendSessionAffinityHeaders |
Para openai-completions, envie cabeçalhos de afinidade de sessão do ID da sessão quando o cache estiver ativado. Padrão: false. |
sessionAffinityFormat |
Para openai-completions e openai-responses, o formato do cabeçalho de afinidade de sessão: openai envia session_id/x-client-request-id (conclusões também x-session-affinity), openai-nosession omite o cabeçalho session_id contendo sublinhado, openrouter envia x-session-id. Não afeta o parâmetro do corpo prompt_cache_key. Padrão: detectado automaticamente. |
supportsStrictMode |
Se o provedor aceita definições estritas de ferramentas de função de esquema JSON. Os padrões dependem de API; modelos OpenAI integrados carregam metadados de capacidade explícitos. |
supportsOpenAIGrammarTools |
Se APIs compatíveis com OpenAI emitem ferramentas gramaticais Lark/regex personalizadas. Quando false, as ferramentas com restrição gramatical voltam às ferramentas de função normais. Padrão: false; o catálogo de modelos integrado permite modelos GPT-5+ em OpenAI, OpenAI Codex, Azure OpenAI, GitHub Copilot, opencode e Cloudflare AI Gateway. |
deferredToolsMode |
Use serialização de ferramenta adiada específica do provedor. Atualmente, apenas "kimi" é compatível com o formato de conclusão de bate-papo compatível com OpenAI do Kimi. |
supportsLongCacheRetention |
Se o provedor aceita retenção de cache longa quando a retenção de cache é long: prompt_cache_retention: "24h" para cache de prompt OpenAI ou cache_control.ttl: "1h" quando cacheControlFormat é anthropic. Padrão: true. |
openRouterRouting |
Preferências de roteamento do provedor OpenRouter. Este objeto é enviado como está no campo provider do OpenRouter API request. |
vercelGatewayRouting |
Configuração de roteamento do Vercel AI Gateway para seleção de provedor (only, order) |
openrouter usa reasoning: { effort }. together usa reasoning: { enabled } e também reasoning_effort quando supportsReasoningEffort está habilitado. qwen usa enable_thinking de nível superior. Use qwen-chat-template para servidores locais compatíveis com Qwen que requerem chat_template_kwargs.enable_thinking e preserve_thinking. Use chat-template para modelos de bate-papo vLLM/Hugging Face que precisam de chat_template_kwargs configurável, como chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } } para modelos DeepSeek V3.x. Use thinkingFormat: "baseten" com chatTemplateArgs para provedores que expõem controles de alternância por meio de chat_template_args e, opcionalmente, suportam reasoning_effort de nível superior.
cacheControlFormat: "anthropic" é para provedores compatíveis com OpenAI que expõem o cache de prompt no estilo Anthropic por meio de marcadores cache_control no conteúdo de texto e definições de ferramentas.
Exemplo:
{
"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
}
}
}
}
]
}
}
}Exemplo de gateway Vercel AI:
{
"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"]
}
}
}
]
}
}
}