Pilar 2 — Modelo Soberano
La tesis. Construir un modelo soberano sobre los datos propietarios del fideicomiso. El conmutador de inferencia en-región sobre pesos abiertos ya está construido y probado detrás de la misma costura de proveedor: cuando se activa, los datos y la consulta nunca salen de la jurisdicción. El default de producción sigue siendo calidad frontier hasta alcanzar paridad en las evaluaciones; el ajuste fino y la destilación vienen después, cuando el corpus lo justifique. Los hechos viven en RAG con citas deterministas; los pesos solo aprenden comportamiento. Nunca horneamos hechos en el modelo, porque romperíamos el foso de la procedencia.
Es el segundo pilar del ciclo: consume el corpus del fideicomiso (1 → 2) y alimenta tanto la gobernanza (2 → 3) como la inteligencia de frontera (2 → 4).
Nota sobre el marco de tres pilares
En materiales de subvención la iniciativa se presenta como tres pilares: el Fideicomiso de Datos (1), el Modelo Soberano (2) y el Motor de Gobernanza, que agrupa la gobernanza democrática (3) con la capa de decisión del pilar 4. El canon de la plataforma sigue siendo el ciclo de cuatro pilares; el mapeo canónico vive en state/FOUR_PILLARS.md.
La soberanía es un toggle de proveedor, no una reescritura
El bucle del agente de chat está escrito en la Anthropic Messages API (system + cache_control + tool_use). La resolución de proveedor vive en un solo lugar — server/chat/provider.ts — y selecciona por primera coincidencia:
SOVEREIGN_INFERENCE_URL+SOVEREIGN_INFERENCE_KEYconfigurados → enruta a un endpoint autohospedado / en-región de pesos abiertos que habla la Messages API. Este es el modo soberano.OPENROUTER_API_KEYconfigurado → enruta vía OpenRouter (endpoint nativo Anthropic).ANTHROPIC_API_KEYconfigurado → llama aapi.anthropic.comdirectamente.- Ninguno → no configurado (el chat emite el evento
not_configured).
Esa lista elige el proveedor primario; desde la ola de robustez del chat, providerChain() construye además una cadena de failover ordenada: el primario primero y todo otro proveedor configurado detrás, como respaldo transparente. Con una sola clave el comportamiento es idéntico; con dos o más, un primario caído hace failover a mitad de la solicitud sin intervención — y el badge de proveedor se re-anuncia si el cambio ocurre a mitad de respuesta. Los ids de modelo se re-resuelven por proveedor (los namespaces difieren: anthropic/claude-sonnet-4.6 en OpenRouter vs. claude-sonnet-4-6 directo), y los overrides CHAT_MODEL / CHAT_FOLLOWUP_MODEL aplican solo al primario. El evento not_configured se emite cuando la cadena queda vacía — no ante la mera ausencia de una clave: una clave soberana sin su URL se diagnostica honestamente.
El failover a mitad de solicitud (server/chat/handler.ts) obedece cuatro invariantes:
| Invariante | Por qué |
|---|---|
Solo dispara ante Anthropic.APIError | Un abort propio (tab cerrada, presupuesto de reloj agotado) nunca provoca un cambio de proveedor. |
Solo si la ronda no ha emitido texto visible (roundText vacío) | Una vez que hay tokens en pantalla, un segundo proveedor re-transmitiendo duplicaría el texto visible. La narración de rondas anteriores ya fue borrada en el cliente (reset_text). |
Reintenta la misma ronda (round -= 1) | Un failover no consume presupuesto de recuperación de herramientas. |
Re-emite el evento provider | El badge siempre nombra al host que realmente respondió — y las sugerencias de seguimiento también corren en el proveedor sobreviviente, en su namespace de modelos. |
Re-resolución de ids de modelo por proveedor
Cada ChatProvider de la cadena lleva sus propios ids nativos — reutilizar el slug de OpenRouter contra api.anthropic.com daría 404, por eso el failover re-resuelve modelo junto con el cliente:
| Proveedor | Modelo de respuesta | Modelo de seguimientos |
|---|---|---|
sovereign | SOVEREIGN_INFERENCE_MODEL (default local-model) | el mismo modelo servido |
openrouter | anthropic/claude-sonnet-4.6 | anthropic/claude-haiku-4.5 |
anthropic | claude-sonnet-4-6 | claude-haiku-4-5 |
CHAT_MODEL / CHAT_FOLLOWUP_MODEL sobreescriben solo la entrada primaria de la cadena: un override cruzado arrastraría el namespace equivocado a un respaldo.
Endurecimiento del cliente SDK (CLIENT_OPTS)
Todo cliente Anthropic que construye la costura — soberano, OpenRouter o directo — se crea con { timeout: 20_000, maxRetries: 2 } en lugar de los defaults del SDK (timeout 10 min):
timeout: 20sacota solo conexión + tiempo-al-primer-byte, no la generación de tokens: el SDK desarma el temporizador en cuanto llegan las cabeceras de la respuesta, antes de que fluya un solo token. Por eso este timeout nunca puede abortar una respuesta larga legítima en streaming — su único trabajo es hacer que un upstream muerto o colgado aflore rápido comoAPIConnectionTimeoutErrorpara queproviderChain()haga failover, en vez de que el default de 10 minutos derive en unFUNCTION_INVOCATION_TIMEOUTopaco de Vercel con el stream SSE truncado en silencio. La cota real de duración del stream es el presupuesto de reloj del handler + elmaxDurationde la función.maxRetries: 2reintenta solo fallas transitorias: el SDK reintenta 408/409/429/5xx pero no 400/401/402/403 — así una caída por autenticación o créditos agotados en el primario hace failover al instante, sin dormir entre reintentos, mientras un parpadeo transitorio se auto-repara en el mismo proveedor.- Las llamadas cortas post-respuesta (seguimientos con Haiku, no-streaming) llevan además su propia cota más estricta en el sitio de llamada (
server/chat/followups.ts,Promise.racecon deadline), porque para una llamada no-streaming el timeout del SDK sigue cubriendo solo hasta las cabeceras y puede no ver una lectura de cuerpo estancada — y esas llamadas jamás deben retrasar el evento terminaldone.
La rama soberana es la costura de sovereignty del pilar: apunta el mismo bucle Messages a una pasarela en jurisdicción (LiteLLM/vLLM detrás de un shim Messages, sirviendo Llama, Qwen, DeepSeek o Mistral) de modo que el corpus y la consulta nunca dejan el host soberano. Solo cambia el baseURL — el bucle del agente, las herramientas y la disciplina de fundamentación son idénticos.
Por qué esto importa
La soberanía de datos no se consigue con una promesa contractual de "no miramos tus datos". Se consigue haciendo que los datos y la inferencia vivan físicamente dentro de la jurisdicción de la región. Como el bucle es idéntico entre proveedores, cambiar a soberano no degrada la lógica — solo cambia dónde ocurre el cómputo.
El badge "modo soberano" en el chat
El evento SSE provider lleva al cliente la identidad de la entrada activa de la cadena (y se re-emite si un failover cambia de proveedor a mitad de respuesta); la interfaz muestra un badge de "modo soberano" cuando sovereign: true. El usuario ve, en cada respuesta, dónde corrió la inferencia. La garantía es visible, no una nota al pie.
El código separa deliberadamente dos afirmaciones que suelen confundirse:
sovereign: true= la inferencia corre autohospedada, bajo control del operador.inRegion= la afirmación geográfica más fuerte — "los datos permanecen en la región" — y solo se asevera cuandoSOVEREIGN_INFERENCE_REGIONestá declarada. La residencia en-región nunca se infiere de la mera presencia de un endpoint, porque la costura podría apuntar a un host fuera de LATAM.
Variables de entorno de la costura soberana
| Variable | Qué controla |
|---|---|
SOVEREIGN_INFERENCE_URL / _KEY | Activan el modo soberano (gateway Messages-compatible). |
SOVEREIGN_INFERENCE_MODEL | Nombre del modelo servido (default local-model). |
SOVEREIGN_INFERENCE_LABEL | Etiqueta del badge (default Soberano). |
SOVEREIGN_INFERENCE_REGION | Declara la región del gateway; es la única vía para asertar inRegion. |
CHAT_MODEL / CHAT_FOLLOWUP_MODEL | Overrides de modelo, ligados al proveedor primario. |
El asistente usa dos modelos: uno para la respuesta fundamentada (default Sonnet) y uno menor para las sugerencias de seguimiento descartables (default Haiku); un despliegue soberano reutiliza su único modelo servido para ambos salvo que CHAT_FOLLOWUP_MODEL diga otra cosa.
La regla RAG-no-fine-tune: el foso de la procedencia
La decisión de arquitectura más importante del pilar: los hechos nunca se hornean en los pesos.
- Los hechos viven en RAG. Cada figura que el modelo cita proviene del corpus recuperado en tiempo de consulta, ligada a un
citation_iddeterminista. La respuesta es fundamentada y verificable contra la fuente primaria. - Los pesos solo aprenden comportamiento. El ajuste fino, cuando llegue, enseña cómo razonar y responder — no qué es cierto. Un peso no puede citar su fuente; un pasaje recuperado sí.
Hornear hechos en los pesos rompería el foso: un número generado desde los pesos no se puede rastrear hasta una fuente primaria, y la trazabilidad en dos clics es el contrato de toda la plataforma. Por eso el modelo por defecto (Sonnet en la ruta directa/OpenRouter) prioriza la disciplina de fundamentación — ligar el citation_id correcto a cada cifra y aflorar contradicciones entre fuentes — sobre la fluidez cruda.
El camino por fases
| Fase | Qué |
|---|---|
| Ahora | Conmutador de inferencia en-región construido y probado (toggle + failover + tests); el default de producción sigue siendo calidad frontier hasta paridad en las evaluaciones. |
| Hoja de ruta | Inferencia en la región sobre pesos abiertos como default de producción, cuando las evaluaciones muestren paridad. |
| Hoja de ruta | Pasada de adaptación regional: ajuste fino / destilación sobre el corpus del fideicomiso, con puerta: solo cuando el harness de evaluación (fidelidad / recuperación) demuestre que el corpus lo justifica. |
| Hoja de ruta | Inferencia ZK sobre registros cifrados: responder consultas sin descifrar el registro subyacente, alineada con la fase ZK de la hoja de ruta de procedencia avanzada. |
El ajuste fino no es un objetivo por sí mismo. Está condicionado por el harness de evaluación existente: mientras un modelo abierto ajustado no iguale la fidelidad y la calidad de recuperación medidas, la calidad frontier sigue siendo el default. Se avanza cuando los números lo permiten, no antes.
Las puertas de evaluación ya existen como harnesses en el repositorio: scripts/chat-eval.ts (calidad de respuesta), scripts/chat-faithfulness.ts (precisión de atribución, umbral CHAT_FAITH_MIN, default 0.85) y scripts/eval-retrieval.ts (calidad de recuperación). La advertencia honesta: sus resultados todavía no se publican como artefacto público; hoy corren como verificaciones internas del repositorio.
Por qué el foso es el corpus, no los pesos base
Cualquiera puede descargar Llama o Qwen. Los pesos base son un commodity. Lo que no es un commodity es un corpus con procedencia verificada y licencia limpia de 25 países — construido por el fideicomiso, imposible de raspar, y ligado cifra por cifra a su fuente. El modelo soberano es valioso no porque sus pesos sean secretos, sino porque está fundamentado en datos que nadie más tiene y que puede citar de forma determinista.
Esto invierte la intuición habitual sobre modelos: el activo defendible no está adentro del modelo, está en el corpus que lo fundamenta y en la disciplina que garantiza que cada respuesta se remonta a él.
Verificación
Todo lo anterior se verifica contra server/chat/provider.ts (selección de proveedor, providerChain(), usingSovereign()) y los tests de failover del handler (server/chat/handler-failover.test.ts). La disciplina de fundamentación y el harness de evaluación se detallan en la página del asistente y en metodología.
Superficies relacionadas
- El asistente fundamentado vive en /sala y a lo largo de la plataforma.
- El badge de proveedor aparece en cada respuesta del chat.
- La pierna física de la soberanía: /soberania-computo — el Índice de Soberanía de Cómputo (ISC) clasifica a los 25 países por su preparación para hospedar cómputo soberano, sobre 4 componentes con pesos publicados (energía limpia, conectividad, financiamiento, escala) y la restricción vinculante por país; cada insumo citado. Tratamiento completo en el Pilar 4.
Sigue el ciclo: los resultados de este modelo sirven a la gobernanza democrática y a la inteligencia de frontera.