Cómo el Chat de Nammu sabe de qué ley está hablando
Cada jurisdicción tiene su propia persona de system-prompt, sus propias barreras de seguridad legal y su propia colección de recuperación normativa. Así se combinan el ensamblaje de prompts en dos capas, el pipeline de enrutamiento determinista y el copiloto de jurisprudencia Nexus.PJ — y dónde están las brechas honestas.
Inventum P5
Ingeniería · Galictis-Legal
10 de julio de 2026
9 min de lectura
Cada jurisdicción que Nammu soporta tiene su propia persona de Chat — un system prompt fundamentado en el código rector de esa rama, con las salvaguardas legales de seguridad de esa rama, y recuperado contra la propia normativa vectorizada de esa rama. Una capa de fundamentación compartida, añadida a todas ellas, mantiene consistente la disciplina de “responder solo desde documentos, no desde la memoria” en cada rama. Así funciona el ensamblaje, así decide el enrutamiento qué ruta toma cada turno del usuario, y aquí están las brechas honestas de hoy.
Dos capas, no un prompt gigante
No existe un único system prompt de chat codificado a mano, ni tampoco una gigantesca escalera if/elif por jurisdicción. resolve_chat_system_prompt() ensambla el prompt concatenando dos capas obtenidas de forma independiente:
Fuente: config/legal/<branch>/*_prompts_rev*.yaml → CHAT_SYSTEM_PROMPT
- Varía por jurisdicción — tono, código rector, advertencias éticas específicas de la rama
- Escrita desde cero por rama, no una plantilla con sustantivos intercambiados
- 7 ramas hoy: civil, penal, laboral, familia, notarial, tránsito, contencioso
- Agrario y constitucional recurren al respaldo genérico integrado
Fuente: config/legal/prompts_rev01.yaml → CHAT_SYSTEM_GUARDRAILS
- Se añade a cada persona de rama — agnóstica de jurisdicción
- Disciplina de fundamentación: responder solo desde los documentos del workspace y la normativa recuperada, no desde la memoria de entrenamiento
- Una variante separada CHAT_SYSTEM_GUARDRAILS_MILVUS adapta las reglas de citación para el modo legado de Milvus
- Una corrección aquí se aplica automáticamente a las 7 ramas a la vez
El descubrimiento busca con glob config/legal/**/*_prompts_rev*.yaml, conserva el archivo de mayor revisión por carpeta de rama, y mapea nombres de carpeta a slugs de esquema. Hoy existen exactamente 7 archivos de prompt de rama — el mismo conjunto de ramas que tienen esquemas de proceso cargados. Agrario y constitucional no tienen ni esquema ni persona de chat; un caso en cualquiera de las dos recurre al respaldo genérico integrado.
Cada system prompt resuelto y sus metadatos (fuente: rama vs. respaldo; qué archivo) se registran por turno en intermediate_data/legal/<workspace>/chat_system_prompt_log.jsonl — un rastro de auditoría por caso para que la procedencia de cualquier respuesta siempre pueda reconstruirse después.
Qué difiere realmente entre las personas de rama
La persona de cada rama está escrita desde cero contra su propio código rector — no una plantilla con sustantivos intercambiados. Penal y familia ilustran por qué la diferencia no es cosmética:
Persona penal
Código rector: CPP Ley 7594
Eres un asistente jurídico experimentado en derecho procesal penal de Costa Rica (Código Procesal Penal, Ley N.º 7594).
Respeta la presunción de inocencia y no presentes a ninguna persona imputada como culpable.
Persona de familia
Códigos rectores: CF 5476 · CPF 9747
Eres un asistente jurídico experimentado en derecho de familia de Costa Rica (Código de Familia, Ley N.º 5476; Código Procesal de Familia, Ley N.º 9747).
Ante menores de edad, prioriza el interés superior del menor. No sugieras conciliación ante violencia doméstica ni relaciones de poder desigual.
La persona de penal lleva una salvaguarda constitucional específica (nunca presentar al acusado como culpable — presunción de inocencia). La de familia lleva un par completamente distinto (interés superior del menor; sin sugerencias de conciliación en contextos de violencia) que sería sin sentido — o activamente erróneo — si se insertara en una persona penal. Esta es la misma disciplina que los campos notes de los hitos de Trayectorias: la instrucción de seguridad legal vive en la capa donde es operacionalmente relevante, no como un disclaimer general.
BORRADOR para el abogado, y todas marcan los artículos citados como SINALEVI_VERIFIED pero aún no ATTORNEY_VERIFIED — la misma advertencia de borrador-pendiente-de-validación que recorre los esquemas, los análisis y los hitos de Trayectorias.process_type es una brecha documentada, no una omisión silenciosa
Solo jurisdiction selecciona la persona. process_type — que determina los topes de análisis en la interfaz y la selección de plantilla de Trayectorias — no está conectado a resolve_chat_system_prompt(). Un caso ordinario civil y un caso sumario civil reciben hoy la misma persona civil idéntica en el Chat. El propio docstring del código de recuperación explica exactamente por qué:
Routing key is jurisdiction branch → collection; process_type drives app behaviour (UI caps, trayectorias, prompts) but is NOT used as a vector filter because normativa chunks are ingested at branch level without process_tags metadata.
La causa raíz está aguas arriba de la capa del prompt: los fragmentos normativos en Milvus se ingieren por rama, no por process_type, así que no existe una porción normativa más granular que recuperar aunque el prompt quisiera una.
Cómo se enruta un turno
No existe un enrutador impulsado por LLM que elija libremente entre documentos del caso, normativa y búsqueda de jurisprudencia. El enrutamiento es un pipeline fijo y ordenado — determinista y auditable antes de que cualquier modelo vea el mensaje.
is_jurisprudence_question()
Filtro de expresión regular — corre primero, antes de cualquier detección de modo o recuperación
Sí: → jurisprudence_copilot_turn (omite por completo el pipeline del workspace)
No: ↓ continúa a la detección de modo
detect_chat_mode()
Auto-detecta el modo de fundamentación a partir del cliente de API y la disponibilidad de la colección Milvus
Sí: Legado: existe una colección Milvus con nombre de workspace y tiene datos → milvus_turn
No: Normal: colección normativa de la rama o ninguna → workspace_turn
workspace_turn
Búsqueda de documentos del caso FTS5 BM25 + RAG normativo de retrieve_jurisdiction_context()
El filtro de expresión regular de jurisprudencia
is_jurisprudence_question() es un clasificador de expresión regular deliberadamente estrecho y de alta precisión — no una llamada al LLM. Opera en tres niveles: señales explícitas fuertes (jurisprudencia, casación, nexuspj, criterio jurisprudencial…), un requisito de coocurrencia para menciones de sala (requiere tanto un nombre de tribunal como una palabra de intención de investigación — evita que “la Sala Primera resolvió admitir el escrito” se dispare falsamente solo porque se nombra una sala), y frases explícitas de fallos. Este filtro es agnóstico de jurisdicción — la misma expresión regular aplica a un caso penal que pregunta sobre la Sala Tercera y a un caso civil que pregunta sobre casación de la Sala Primera. Si coincide, el turno va al copiloto de jurisprudencia y omite por completo el pipeline del workspace — las dos rutas son mutuamente excluyentes por turno.
Recuperación normativa — una colección por rama, nunca filtrada por process_type
retrieve_jurisdiction_context() vectoriza la consulta del usuario, busca en la colección normativa de Milvus de la rama, y da formato a los mejores resultados como texto de contexto. Nunca se aplica un filtro de metadatos — consistente con la brecha de process_type mencionada arriba. Las ramas sin colección vectorizada (agrario, constitucional — de nuevo, las mismas dos ramas sin esquema y sin persona de chat) se omiten limpiamente mediante uses_vectorized_normativa() en lugar de generar un error.
Una etiqueta que vale la pena señalar con precisión: el encabezado de contexto orientado al usuario dice “Normativa y jurisprudencia,” pero lo que se inyecta ahí son solo fragmentos de estatutos normativos — nunca se recupera texto de jurisprudencia en los turnos de chat regulares. La etiqueta es aspiracional, no actualmente exacta.
El chat como copiloto de análisis — mayormente todavía no
No hay tool-calling en ninguna parte del código base. Una revisión de todo el repositorio buscando la superficie estándar de tool-calling de OpenAI (tools=, function_call, tool_choice) devuelve cero coincidencias. Cada llamada de completado de chat es una llamada plana de messages=. No existe ningún mecanismo para que el modelo decida a mitad de la conversación “déjame ejecutar compute_legal_plazo para este caso” — los análisis corren solo mediante sus propios disparadores dedicados de interfaz, completamente fuera del ciclo del chat.
| Capacidad | Estado | Notas |
|---|---|---|
| El chat lee controversia / hechos / estado / plazo ya calculados como contexto | Parcial | Solo dentro del copiloto de jurisprudencia, no en el chat regular |
| El chat puede disparar un cálculo de análisis en vivo | Todavía no | No implementado — los análisis corren solo mediante sus propios disparadores de interfaz |
| Function-calling / herramientas del LLM para cualquier análisis | Todavía no | Cero coincidencias de tools= / function_call / tool_choice en el código base |
| poder_especial / confidence_provenance accesibles desde el chat | Todavía no | No se usan en ninguna parte del chat |
| Sidecars de análisis usados en preguntas y respuestas normales del chat | Todavía no | El chat vuelve a derivar respuestas desde documentos en bruto + normativa |
controversy que el agente de análisis dedicado ya calculó (y que el abogado puede haber ya revisado y quizás editado). El análisis como contexto es real pero limitado hoy: controversia/hechos/estado/plazo alimentan solo al copiloto de jurisprudencia, no al chat regular.El copiloto de jurisprudencia Nexus.PJ
El propio docstring del módulo del copiloto lo declara con claridad: “Copiloto de consultas Nexus.PJ — briefs de búsqueda estructurados desde el Chat (sin scraping en vivo).” No hay integración de API con Nexus.PJ, no hay scraping, y no hay índice vectorial de jurisprudencia en Milvus hoy. El trabajo completo del copiloto es convertir una pregunta en lenguaje natural en un plan de búsqueda bien formado que un abogado humano luego ejecuta en una pestaña real del navegador.
La llamada al LLM para el brief de búsqueda
Un único system prompt estático — no perfilado por jurisdicción — instruye al modelo a devolver un objeto JSON: un resumen en lenguaje simple, una consulta primaria (texto libre más rango opcional de norma/artículo/fecha), hasta 3 consultas alternas, pistas de filtro de tribunal, y notas de texto libre para cualquier cosa que la búsqueda avanzada de Nexus no exponga vía parámetros de URL.
El prompt lleva una prohibición estricta:
NO inventes números de sentencia, expedientes ni extractos de fallos. Si el contexto del caso es escaso, indícalo en summary y propón búsquedas genéricas prudentes.
La llamada usa solo los últimos 4 turnos de memoria (vs. 6 para el chat regular — una ventana más ajustada, ya que el refinamiento del plan de búsqueda necesita menos contexto previo que las preguntas legales sustantivas) y temperature=0.2 para una construcción de consulta reproducible y conservadora. Si la salida del modelo no es JSON válido, se construye un brief de respaldo determinista directamente a partir del texto en bruto del usuario como consulta primaria — el copiloto siempre devuelve algo útil en lugar de fallar el turno.
Del brief JSON a la acción en el navegador
La construcción de la URL arma el parámetro q usando la propia sintaxis de tokens de consulta de Nexus (norma:, articulo:, @desde/@hasta), así que los botones abren una búsqueda real y pre-llenada en Nexus.PJ en lugar de una página de inicio genérica. Cada respuesta también lleva un disclaimer explícito y una sugerencia de “pega la resolución de vuelta en el chat” — el flujo de trabajo es deliberadamente con humano en el ciclo: el copiloto planea la búsqueda, el abogado la ejecuta y juzga los resultados, y luego puede reintroducir una resolución real en la conversación.
La jurisdicción aparece en el copiloto de forma indirecta: dado que el bloque de contexto del caso (_gather_case_context_for_jurisprudence()) toma datos de la controversia/hechos/estado/plazo ya calculados — que a su vez se generaron bajo prompts de análisis específicos de rama — el copiloto hereda el matiz de jurisdicción a través de los hechos del caso de los que dispone para razonar, aunque su propia estrategia de búsqueda es idéntica para cada rama.
Principios rectores
La jurisdicción perfila el tono y las salvaguardas de seguridad legal, no el alcance de recuperación
La persona cambia por rama. Las fuentes de fundamentación (documentos del caso vía FTS + RAG normativo de la rama) son estructuralmente idénticas entre ramas — solo cambia qué colección normativa se busca.
process_type es una brecha documentada y explícita
No una omisión silenciosa — el código de recuperación explica exactamente por qué no se filtra por él (sin metadatos process_tags al momento de la ingesta), acorde con el estándar de transparencia establecido en los demás documentos de arquitectura.
Nunca se alucina jurisprudencia
El copiloto de jurisprudencia es un asistente de planeación de búsqueda con una prohibición estricta de inventar números de sentencia o expediente. La brecha entre "ayúdame a encontrar la búsqueda correcta" y "dime qué dice la jurisprudencia" es deliberada y se aplica en el propio system prompt.
El enrutamiento es determinista y auditable, no improvisado por el modelo
La ruta de un turno (copiloto de jurisprudencia vs. workspace vs. Milvus legado) se decide por expresiones regulares y búsquedas de configuración antes de que cualquier LLM vea el mensaje. Cada system prompt resuelto se registra por turno.
El análisis como contexto es real pero limitado hoy
La controversia/hechos/estado/plazo ya calculados alimentan el contexto del caso del copiloto de jurisprudencia, pero nada en el chat puede invocar, refrescar o razonar de forma nativa sobre toda la superficie de análisis. Una dirección clara y documentada para trabajo futuro de tool-calling, no una capacidad actualmente disponible.
¿Quieres ver al agente de Chat funcionando con archivos de caso reales?
Podemos correr una sesión en vivo con un caso de tu jurisdicción — incluyendo la pestaña Trayectorias, el panel de análisis y el copiloto de jurisprudencia Nexus.PJ.
Solicita una demo →