Personalizado Models
Agregue proveedores y modelos personalizados (Ollama, vLLM, LM Studio, proxies) a través de ~/.pi/agent/models.json.
Tabla de contenido
- Minimal Example
- Full Example
- Supported APIs
- Provider Configuration
- Model Configuration
- Overriding Built-in Providers
- Per-model Overrides
- Anthropic Messages Compatibility
- OpenAI Compatibility
Ejemplo mínimo
Para modelos locales (Ollama, LM Studio, vLLM), solo se requiere id por modelo:
{
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"api": "openai-completions",
"apiKey": "ollama",
"models": [
{ "id": "llama3.1:8b" },
{ "id": "qwen2.5-coder:7b" }
]
}
}
}El valor apiKey es un marcador de posición porque Ollama lo ignora. pi todavía trata los modelos como si requieren autenticación antes de que aparezcan en /model, por lo que los servidores locales sin clave deben mantener un valor ficticio, guardar una clave para ese proveedor con /login o pasar --api-key al seleccionar el modelo.
Algunos servidores compatibles con OpenAI no comprenden la función developer utilizada para modelos con capacidad de razonamiento. Para esos proveedores, configure compat.supportsDeveloperRole en false para que pi envíe el mensaje del sistema como un mensaje system. Si el servidor tampoco admite reasoning_effort, configure compat.supportsReasoningEffort en false también.
Puede configurar compat a nivel de proveedor para aplicarlo a todos los modelos, o a nivel de modelo para anular un modelo específico. Esto comúnmente se aplica a Ollama, vLLM, SGLang y servidores similares compatibles con 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
}
]
}
}
}Ejemplo completo
Anule los valores predeterminados cuando necesite 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 }
}
]
}
}
}El archivo se recarga cada vez que abres /model. Editar durante la sesión; no es necesario reiniciar.
Ejemplo de estudio de IA de Google
Utilice google-generative-ai con baseUrl para agregar modelos de Google AI Studio, incluidas entradas personalizadas de 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
}
]
}
}
}El baseUrl es necesario al agregar modelos personalizados al tipo google-generative-ai API.
Compatible APIs
| API | Descripción |
|---|---|
openai-completions |
Finalizaciones de OpenAI Chat (más compatibles) |
openai-responses |
Respuestas de OpenAI API |
anthropic-messages |
Mensajes antrópicos API |
google-generative-ai |
IA generativa de Google |
Establezca api a nivel de proveedor (predeterminado para todos los modelos) o a nivel de modelo (anulación por modelo).
Configuración del proveedor
| Campo | Descripción |
|---|---|
baseUrl |
API URL del punto final |
api |
API tipo (ver arriba) |
apiKey |
Configuración API key opcional (consulte la resolución del valor a continuación). Omítalo cuando la autenticación la proporcione /login/auth.json o CLI --api-key. |
oauth |
Tipo de proveedor dinámico OAuth. Actualmente admite "radius"; requiere la puerta de enlace baseUrl. |
headers |
Encabezados personalizados (consulte la resolución de valores a continuación) |
authHeader |
Configure true para agregar Authorization: Bearer <apiKey> automáticamente |
models |
Matriz de configuraciones de modelos |
modelOverrides |
Anulaciones por modelo para modelos integrados o registrados en extensión en este proveedor |
Para los proveedores con models, las configuraciones de proveedores no integradas necesitan un valor baseUrl y un api a nivel de proveedor o de modelo. No es necesario apiKey para cargar el archivo: los modelos están disponibles cuando se configura la autenticación a través de /login/auth.json, CLI --api-key o el proveedor apiKey. Si no se configura ninguna autenticación, los modelos se cargan pero no están disponibles en /model y --list-models.
Resolución de valor
Los campos apiKey y headers admiten la ejecución de comandos, la interpolación del entorno y los literales:
- Comando Shell:
"!command"al principio ejecuta el valor completo como un comando y usa stdout"apiKey": "!security find-generic-password -ws 'anthropic'" "apiKey": "!op read 'op://vault/item/credential'" - Interpolación del entorno:
"$ENV_VAR"o"${ENV_VAR}"usa el valor de la variable nombrada. La interpolación funciona dentro de literales más grandes."apiKey": "$MY_API_KEY" "apiKey": "${KEY_PREFIX}_${KEY_SUFFIX}"$FOO_BARes la variableFOO_BAR; use${FOO}_BARcuandoBARsea texto literal. Las variables de entorno que faltan hacen que el valor no se resuelva. - Escapa:
"quot;emite un literal"quot;;"$!"emite un literal"!"sin activar la ejecución del comando."apiKey": "$literal-dollar-prefix" "apiKey": "$!literal-bang-prefix" - Valor literal: Usado directamente. Las cadenas simples en mayúsculas como
MY_API_KEYson literales; utilice$MY_API_KEYpara las variables de entorno."apiKey": "sk-..."
Para models.json, los comandos de shell se resuelven en el momento de la solicitud. pi intencionalmente no aplica TTL incorporado, reutilización obsoleta o lógica de recuperación para comandos arbitrarios. Diferentes comandos necesitan diferentes estrategias de almacenamiento en caché y fallas, y pi no puede inferir cuál es la correcta.
Si su comando es lento, costoso, tiene una velocidad limitada o debe seguir usando un valor anterior en fallas transitorias, envuélvalo en su propio script o comando que implemente el comportamiento de almacenamiento en caché o TTL que desee.
/model las comprobaciones de disponibilidad utilizan la presencia de autenticación configurada y no ejecutan comandos de shell.
Encabezados 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": [...]
}
}
}Configuración del modelo
| Campo | Requerido | Por defecto | Descripción |
|---|---|---|---|
id |
Sí | — | Identificador de modelo (pasado al API) |
name |
No | id |
Etiqueta de modelo legible por humanos. Se utiliza para hacer coincidir (--model patrones) y se muestra como texto de detalle del modelo secundario. |
api |
No | del proveedor api |
Anular el API del proveedor para este modelo |
reasoning |
No | false |
Apoya el pensamiento extendido |
thinkingLevelMap |
No | omitido | Asigna los niveles de pensamiento de pi a los valores del proveedor y marca los niveles no admitidos (ver más abajo) |
input |
No | ["text"] |
Tipos de entrada: ["text"] o ["text", "image"] |
contextWindow |
No | 128000 |
Tamaño de la ventana de contexto en tokens |
maxTokens |
No | 16384 |
Tokens de salida máximos |
samplingParams |
No | omitido | Los parámetros de muestreo se fusionaron palabra por palabra en cada cuerpo de solicitud (ver más abajo) |
cost |
No | todos ceros | Tarifas por millón de tokens con niveles de precios de entrada opcionales para toda la solicitud |
compat |
No | proveedor compat |
Anulaciones de compatibilidad de proveedores. Combinado con el nivel de proveedor compat cuando ambos están configurados. |
Un nivel de costo proporciona un conjunto completo de tarifas alternativas y se aplica a la solicitud completa cuando el uso total de insumos (input + cacheRead + cacheWrite) excede inputTokensAbove. Cuando coinciden varios niveles, gana el umbral más alto.
{
"cost": {
"input": 5,
"output": 30,
"cacheRead": 0.5,
"cacheWrite": 6.25,
"tiers": [
{
"inputTokensAbove": 272000,
"input": 10,
"output": 45,
"cacheRead": 1,
"cacheWrite": 12.5
}
]
}
}Comportamiento actual:
/model,--list-modelsy el pie de página interactivo muestran las entradas por modeloid.- El
nameconfigurado se utiliza para la coincidencia de modelos y el texto de detalles del modelo secundario. No reemplaza la identificación del modelo de pie de página/barra de estado.
Parámetros de muestreo
samplingParams es un objeto de forma libre fusionado palabra por palabra en cada cuerpo de solicitud para el modelo, después de que los campos pi se configuran, por lo que sus claves ganan. Úselo para enviar parámetros de muestreo que pi no modela, incluidos los específicos del servidor como min_p de llama.cpp o top_k de vLLM:
{
"id": "deepseek-v4-flash",
"samplingParams": {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 0,
"min_p": 0.0
}
}Solo los API compatibles con OpenAI lo aplican (openai-completions, openai-responses, azure-openai-responses); otros API lo ignoran. Las claves anulan los campos de solicitud con nombre de pi (por ejemplo, una clave temperature aquí supera la temperatura del nivel de solicitud), así que prefiérala como la única fuente de verdad de muestreo para un modelo. En modelOverrides, samplingParams se fusiona por clave con el valor del modelo base.
Mapa de niveles de pensamiento
Utilice thinkingLevelMap en un modelo para describir controles de pensamiento específicos del modelo. Las claves son los niveles de pensamiento pi: off, minimal, low, medium, high, xhigh, max. Los mapas pueden contener agujeros; por ejemplo, un modelo puede exponer high y max sin exponer xhigh.
Los valores son triples:
| Valor | Significado |
|---|---|
| omitido | Los niveles estándar hasta high utilizan la asignación predeterminada del proveedor; Los niveles extendidos xhigh y max no son compatibles |
| cadena | El nivel es compatible y este valor se envía al proveedor. |
null |
El nivel no es compatible y está oculto/omitido/sujeto |
Ejemplo de un modelo que solo admite razonamiento apagado, alto y máximo:
{
"id": "deepseek-v4-pro",
"reasoning": true,
"thinkingLevelMap": {
"minimal": null,
"low": null,
"medium": null,
"high": "high",
"xhigh": null,
"max": "max"
}
}Ejemplo de un modelo en el que no se puede desactivar el pensamiento:
{
"id": "always-thinking-model",
"reasoning": true,
"thinkingLevelMap": {
"off": null
}
}Migración: las configuraciones anteriores que usaban compat.reasoningEffortMap deberían mover esa asignación al nivel de modelo thinkingLevelMap. Utilice null para niveles que no deberían aparecer en la interfaz de usuario.
Anulación incorporada Providers
Enrute un proveedor integrado a través de un proxy sin redefinir los modelos:
{
"providers": {
"anthropic": {
"baseUrl": "https://my-proxy.example.com/v1"
}
}
}Todos los modelos Anthropic integrados siguen estando disponibles. La autenticación OAuth o API key existente continúa funcionando.
Para fusionar modelos personalizados en un proveedor integrado, incluya la matriz models:
{
"providers": {
"anthropic": {
"baseUrl": "https://my-proxy.example.com/v1",
"apiKey": "$ANTHROPIC_API_KEY",
"api": "anthropic-messages",
"models": [...]
}
}
}Fusionar semántica:
- Se mantienen los modelos incorporados.
- Los modelos personalizados se insertan en
iddentro del proveedor. - Si un modelo personalizado
idcoincide con un modelo integradoid, el modelo personalizado reemplaza ese modelo integrado. - Si un modelo personalizado
ides nuevo, se agrega junto con los modelos integrados.
Anulaciones por modelo
Utilice modelOverrides para personalizar los modelos integrados y los modelos registrados en extensiones coincidentes sin reemplazar la lista completa de modelos del proveedor.
{
"providers": {
"openrouter": {
"modelOverrides": {
"anthropic/claude-sonnet-4": {
"name": "Claude Sonnet 4 (Bedrock Route)",
"compat": {
"openRouterRouting": {
"only": ["amazon-bedrock"]
}
}
}
}
}
}
}modelOverrides admite estos campos por modelo: name, reasoning, thinkingLevelMap, input, cost (parcial), contextWindow, maxTokens, samplingParams (combinado por clave), headers, compat.
Direct OpenAI GPT-5.6 Sol, Terra y Luna tienen de forma predeterminada una ventana de contexto 272000 para que las solicitudes permanezcan dentro del nivel de precios de contexto corto de OpenAI. Para optar por la ventana contextual de 1,05 M de OpenAI, auméntela para cada modelo que utilice:
{
"providers": {
"openai": {
"modelOverrides": {
"gpt-5.6-sol": {
"contextWindow": 1050000
}
}
}
}
}La anulación conserva los metadatos de precios integrados. Las solicitudes con más de 272 000 tokens de entrada en total utilizan las tarifas de contexto largo de GPT-5.6 para toda la solicitud. Aplique la misma anulación a gpt-5.6-terra o gpt-5.6-luna cuando sea necesario.
Notas de comportamiento:
modelOverridesse aplican a los modelos de proveedores integrados y a los modelos de proveedores registrados en extensiones coincidentes.- Se ignoran los ID de modelos desconocidos.
- Puede combinar el nivel de proveedor
baseUrl/headersconmodelOverrides. - Anular
namecambia la coincidencia del modelo y el texto de detalle secundario únicamente; el pie de página y las listas de modelos principales continúan mostrando el modeloid. - Si también se define
modelspara un proveedor, los modelos personalizados se fusionan después de las anulaciones integradas. Un modelo personalizado con el mismoidreemplaza la entrada del modelo integrado anulado.
Compatibilidad de mensajes antrópicos
Para proveedores o proxies que usan api: "anthropic-messages", use compat para controlar la compatibilidad de solicitudes específicas de Anthropic.
De forma predeterminada, pi envía por herramienta eager_input_streaming: true. Si un proxy o un backend compatible con Anthropic rechaza ese campo, establezca supportsEagerToolInputStreaming en false. Pi omitirá tools[].eager_input_streaming y en su lugar enviará el encabezado beta heredado fine-grained-tool-streaming-2025-05-14 para solicitudes habilitadas para herramientas.
Algunos modelos antrópicos requieren pensamiento adaptativo (thinking.type: "adaptive" más output_config.effort) en lugar del pensamiento heredado basado en el presupuesto. Los modelos integrados configuran esto automáticamente. Para proveedores personalizados o alias que se dirigen a esos modelos, establezca forceAdaptiveThinking en true.
Algunos proveedores compatibles con Anthropic emiten bloques de pensamiento con firmas vacías y aún esperan que se reproduzcan. Establezca allowEmptySignature en true solo para esos proveedores; El Antrópico real rechaza las firmas de pensamiento vacío.
Los modelos antrópicos integrados habilitan supportsStrictTools en los metadatos de su modelo. Los modelos personalizados compatibles con Anthropic deben configurarlo en true cuando su punto final acepte definiciones estrictas de herramientas 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 | Descripción |
|---|---|
supportsEagerToolInputStreaming |
Si el proveedor acepta por herramienta eager_input_streaming. Predeterminado: true. Configúrelo en false para omitir ese campo y usar el encabezado beta de transmisión detallada de la herramienta heredada en solicitudes habilitadas para la herramienta. |
supportsLongCacheRetention |
Si el proveedor acepta la retención de caché larga antrópica (cache_control.ttl: "1h") cuando la retención de caché es long. Predeterminado: true. |
sendSessionAffinityHeaders |
Si se debe enviar x-session-affinity desde la identificación de la sesión cuando el almacenamiento en caché está habilitado. Valor predeterminado: detectado automáticamente para proveedores conocidos. |
supportsCacheControlOnTools |
Si el proveedor acepta marcadores cache_control de estilo antrópico en las definiciones de herramientas. Predeterminado: true. |
forceAdaptiveThinking |
Ya sea para enviar pensamiento adaptativo (thinking.type: "adaptive" más output_config.effort) para este modelo. Los modelos adaptativos integrados configuran esto automáticamente. Predeterminado: false. |
allowEmptySignature |
Si se deben reproducir firmas de pensamiento vacías como signature: "" en lugar de convertir el pensamiento en texto. Predeterminado: false. |
supportsStrictTools |
Si el proveedor acepta definiciones estrictas de herramientas de esquema JSON. Predeterminado: false; Los modelos antrópicos incorporados lo habilitan en los metadatos generados. |
Compatibilidad con OpenAI
Para proveedores con compatibilidad parcial con OpenAI, utilice el campo compat.
- El nivel de proveedor
compataplica los valores predeterminados a todos los modelos de ese proveedor. - El nivel de modelo
compatanula los valores a nivel de proveedor para ese modelo.
{
"providers": {
"local-llm": {
"baseUrl": "http://localhost:8080/v1",
"api": "openai-completions",
"compat": {
"supportsUsageInStreaming": false,
"maxTokensField": "max_tokens"
},
"models": [...]
}
}
}| Campo | Descripción |
|---|---|
supportsStore |
El proveedor admite el campo store |
supportsDeveloperRole |
Utilice el rol developer frente a system |
supportsReasoningEffort |
Soporte para el parámetro reasoning_effort |
supportsUsageInStreaming |
Admite stream_options: { include_usage: true } (predeterminado: true) |
supportsFinishReason |
Si las respuestas transmitidas incluyen finish_reason. Cuando false, pi infiere stop o toolUse cuando finaliza la transmisión. Predeterminado: true. |
maxTokensField |
Utilice max_completion_tokens o max_tokens |
requiresToolResultName |
Incluir name en los mensajes de resultados de la herramienta |
requiresAssistantAfterToolResult |
Insertar un mensaje de asistente antes de un mensaje de usuario después de los resultados de la herramienta |
requiresThinkingAsText |
Convierta bloques de pensamiento en texto sin formato |
requiresReasoningContentOnAssistantMessages |
Incluya un reasoning_content vacío en todos los mensajes del asistente reproducidos cuando el razonamiento esté habilitado |
thinkingFormat |
Utilice los parámetros de pensamiento reasoning_effort, openrouter, deepseek, together, baseten, zai, qwen, chat-template o qwen-chat-template |
chatTemplateKwargs |
chat_template_kwargs valores para thinkingFormat: "chat-template"; use { "$var": "thinking.enabled" } o { "$var": "thinking.effort" } para valores de pensamiento controlados por pi |
chatTemplateArgs |
chat_template_args valores para thinkingFormat: "baseten"; use { "$var": "thinking.enabled" } o { "$var": "thinking.effort" } para valores de pensamiento controlados por pi |
cacheControlFormat |
Utilice marcadores cache_control de estilo antrópico en el mensaje del sistema, la última definición de herramienta y el contenido de texto del último usuario, asistente o resultado de la herramienta. Actualmente solo se admite anthropic. |
sendSessionAffinityHeaders |
Para openai-completions, envíe encabezados de afinidad de sesión desde la identificación de la sesión cuando el almacenamiento en caché esté habilitado. Predeterminado: false. |
sessionAffinityFormat |
Para openai-completions y openai-responses, el formato de encabezado de afinidad de sesión: openai envía session_id/x-client-request-id (las terminaciones también x-session-affinity), openai-nosession omite el encabezado session_id que contiene guión bajo, openrouter envía x-session-id. No afecta el parámetro corporal prompt_cache_key. Valor predeterminado: detectado automáticamente. |
supportsStrictMode |
Si el proveedor acepta definiciones estrictas de herramientas de función de esquema JSON. Los valores predeterminados dependen del API; Los modelos OpenAI integrados llevan metadatos de capacidad explícitos. |
supportsOpenAIGrammarTools |
Si los API compatibles con OpenAI emiten herramientas gramaticales personalizadas de Lark/regex. Cuando false, las herramientas con restricciones gramaticales vuelven a las herramientas de función normal. Predeterminado: false; el catálogo de modelos integrado lo habilita para modelos GPT-5+ en OpenAI, OpenAI Codex, Azure OpenAI, GitHub Copilot, opencode y Cloudflare AI Gateway. |
deferredToolsMode |
Utilice la serialización de herramientas diferida específica del proveedor. Actualmente, solo se admite "kimi" para el formato de finalización de chat compatible con OpenAI de Kimi. |
supportsLongCacheRetention |
Si el proveedor acepta una retención de caché prolongada cuando la retención de caché es long: prompt_cache_retention: "24h" para el almacenamiento en caché de solicitud de OpenAI, o cache_control.ttl: "1h" cuando cacheControlFormat es anthropic. Predeterminado: true. |
openRouterRouting |
Preferencias de enrutamiento del proveedor OpenRouter. Este objeto se envía tal cual en el campo provider del OpenRouter API request. |
vercelGatewayRouting |
Configuración de enrutamiento de Vercel AI Gateway para la selección de proveedor (only, order) |
openrouter usa reasoning: { effort }. together usa reasoning: { enabled } y también reasoning_effort cuando supportsReasoningEffort está habilitado. qwen utiliza el nivel superior enable_thinking. Utilice qwen-chat-template para servidores locales compatibles con Qwen que requieran chat_template_kwargs.enable_thinking y preserve_thinking. Utilice chat-template para plantillas de chat vLLM/Hugging Face que necesitan chat_template_kwargs configurables, como chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } } para plantillas de DeepSeek V3.x. Utilice thinkingFormat: "baseten" con chatTemplateArgs para proveedores que exponen controles de alternancia hasta chat_template_args y, opcionalmente, admiten el nivel superior reasoning_effort.
cacheControlFormat: "anthropic" es para proveedores compatibles con OpenAI que exponen el almacenamiento en caché de mensajes de estilo Anthropic a través de marcadores cache_control en contenido de texto y definiciones de herramientas.
Ejemplo:
{
"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
}
}
}
}
]
}
}
}Ejemplo de puerta de enlace AI de Vercel:
{
"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"]
}
}
}
]
}
}
}