Guía práctica para respuestas en texto plano y formato JSON
Lecciones aprendidas al construir una simulación de Jeopardy con IA para 12 jugadores impulsada por Ministral-3-14B-Instruct-2512.
Ejecutar Ministral-3 en vLLM resulta sorprendentemente potente. El modelo es rápido, creativo y capaz de generar respuestas de alta calidad incluso bajo cargas de trabajo intensivas.
Pero una vez que pasas de simples indicaciones en formato chat a salidas estructuradas, automatización o uso programático, las cosas se complican rápidamente.
Durante el desarrollo de un juego de Jeopardy impulsado por IA con 12 jugadores simultáneos y cientos de llamadas al modelo, nos encontramos con varios problemas prácticos:
Esta guía resume las lecciones prácticas aprendidas al resolver estos problemas, junto con patrones concretos que puedes reutilizar en tus propios proyectos.
Nuestro proyecto de referencia simula un juego completo de Jeopardy! donde:
Una sola ejecución del juego puede superar fácilmente 800 llamadas de API.
Este entorno expuso casos límite que rara vez aparecen en demostraciones simples — convirtiéndolo en una excelente cama de pruebas para entender cómo Ministral se comporta bajo cargas reales de producción.
Los modelos Ministral no utilizan la configuración estándar del tokenizador de HuggingFace
Esto significa que el comando de inicio debe habilitar explícitamente el formato del tokenizador de Mistral.
vllm serve mistralai/Ministral-3-14B-Instruct-2512 \
--tokenizer_mode mistral \
--config_format mistral \
--load_format mistral
Si su aplicación depende de llamadas a funciones, agregue las banderas de herramientas:
--enable-auto-tool-choice
--tool-call-parser mistral
A diferencia de otros modelos, Ministral no admite chat_template_kwargs
Si envías una solicitud como esta:
{
"chat_template_kwargs": {
"enable_thinking": false
}
}
vLLM devuelve:
HTTP 400: chat_template is not supported for Mistral tokenizers
Eso significa que funciones como el ajuste explícito del modo "pensamiento" (utilizado en modelos como Qwen o DeepSeek) simplemente no están disponibles
Afortunadamente, esto rara vez es necesario porque Ministral ya genera salidas concisas por defecto.
La documentación oficial de vLLM utiliza consistentemente el siguiente valor con Ministral-3:
temperature = 0.15
A primera vista esto parece extremadamente bajo. Sin embargo, resulta ser crítico para tareas estructuradas.
Usando el valor predeterminado estilo OpenAI:
temperature: 0.7
el modelo se vuelve demasiado creativo con la estructura
Una solicitud sencilla como:
{ "expertise": "2-3 topics they know best" }
podría devolver algo como:
{
"expertise": [
{
"category": "Gourmet Pizza Alchemy",
"detail": "Can transform random ingredients into Michelin-star pizza"
},
{
"category": "Sumo Wrestling Physics",
"detail": "Understands body mechanics and center-of-gravity combat"
}
]
}
Aunque es JSON técnicamente válido, no cumple con lo que el esquema solicitó.
El resultado:
max_tokens se superan los límites0.15 funciona mejorA baja temperatura el modelo se vuelve estructuralmente disciplinado.
temperature: 0.15
Ventajas:
Incluso la generación creativa de texto sigue siendo sólida; el modelo simplemente deja de improvisar en la estructura.
Recomendación:
Usa temperatura: 0.15 como valor predeterminado para Ministral-3.
Generar JSON legible por máquina desde modelos de lenguaje es más difícil de lo que parece.
Ministral tiende a interpretar los campos del esquema de manera semántica en lugar de estructuralmente, lo que genera salidas profundamente anidadas.
Un prompt como:
Return JSON with these fields.
genera estructuras verbosas con frecuencia.
Ejemplo de solicitud:
{ "expertise": "2-3 topics they know best" }
Respuesta típica:
{
"expertise": [
{
"category": "Ancient Roman Engineering",
"detail": "Knows aqueduct systems in surprising detail"
},
{
"category": "Pizza Dough Chemistry",
"detail": "Obsessed with yeast fermentation dynamics"
}
]
}
Esto consume tres veces los tokens esperados.
La solución más fiable combina dos instrucciones.
Respond with ONLY valid JSON.
No markdown, no explanation, no text before or after the JSON.
Keep values as short plain strings — never use nested objects or arrays.
Justo al lado de la definición del esquema:
Every value MUST be a short plain string — NO arrays, NO nested objects.
Combinado con temperatura 0.15, esto genera JSON plano predecible
Incluso con restricciones, Ministral tiende a producir valores más largos que otros modelos
Observación de ejemplo en nuestro benchmark:
| Modelo | Tokens necesarios |
|---|---|
| GPT-4o | ~512 |
| Qwen | ~512 |
| Ministral-3 | ~1024 |
Una regla segura:
Presupuesta 1.5–2 veces los tokens para salidas en formato JSON.
Incluso con indicaciones perfectas, los modelos generan ocasionalmente JSON mal formado.
Una buena estrategia es añadir capas de análisis defensivo.
function extractJSON(raw, shape) {
var text = raw.replace(/^```(?:json)?\s*/i, '').replace(/\s*```$/i, '').trim();
if (shape === 'array') {
var m = text.match(/\[[\s\S]*\]/);
if (m) text = m[0];
} else {
var m = text.match(/\{[\s\S]*\}/);
if (m) text = m[0];
}
return text;
}
Rastrear corchetes abiertos y cerrarlos automáticamente:
var stack = [];
var inStr = false, esc = false;
for (var i = 0; i < text.length; i++) {
var ch = text[i];
if (esc) { esc = false; continue; }
if (ch === '\\') { esc = true; continue; }
if (ch === '"') { inStr = !inStr; continue; }
if (inStr) continue;
if (ch === '{') stack.push('}');
else if (ch === '[') stack.push(']');
else if (ch === '}' || ch === ']') stack.pop();
}
text = text.replace(/,\s*$/, '');
while (stack.length > 0)
text += stack.pop();
Si el modelo sigue devolviendo estructuras anidadas:
if (Array.isArray(value)) {
flat = value.map(function(item) {
if (typeof item === 'string') return item;
if (typeof item === 'object') return Object.values(item).join(' — ');
return String(item);
}).join(', ');
}
Un bucle de reintento sencillo aumenta drásticamente la fiabilidad.
Porque Ministral se comporta de manera consistente a baja temperatura, los reintentos suelen tener éxito.
Recomendado:
2–3 retry attempts
Ministral adora el formato.
Incluso al solicitar texto plano, suele generar:
Esto ocurre porque el modelo incluye una instrucción de sistema que fomenta el formato Markdown enriquecido
Muchos pipelines dependen de comprobaciones simples en cadenas.
Ejemplo:
verdict.toUpperCase().startsWith('CORRECT')
Pero si el modelo devuelve:
**CORRECT**
la verificación falla.
El enfoque más seguro es normalizar todas las salidas antes del procesamiento.
function stripMarkdown(text) {
if (!text) return text;
var s = text.replace(/\*\*([^*]+)\*\*/g, '$1');
s = s.replace(/__([^_]+)__/g, '$1');
s = s.replace(/\*([^*]+)\*/g, '$1');
s = s.replace(/^#{1,6}\s+/gm, '');
s = s.replace(/`([^`]+)`/g, '$1');
s = s.replace(/^```[a-z]*\s*$/gm, '');
return s.trim();
}
Aplica esto a cada respuesta del modelo, no solo para Ministral.
Evita la ramificación específica por modelo y mantiene los flujos de trabajo consistentes.
Si su sistema admite múltiples familias de modelos (como Mistral, Qwen, DeepSeek, Llama, etc.), el diseño más mantenible es centralizar el comportamiento del modelo en un solo lugar.
Ejemplo:
function buildModelProfile(modelName) {
var lower = modelName.toLowerCase();
var isMistral = lower.includes('mistral') || lower.includes('ministral');
return {
family: isMistral ? 'Mistral' : 'Generic',
jsonSystemInstruction: isMistral
? 'Respond with ONLY valid JSON. No markdown. Keep values as short plain strings.'
: 'You output only valid JSON. No markdown fences, no explanation.',
jsonSchemaHint: isMistral
? ' Every value MUST be a short plain string — NO arrays, NO nested objects.'
: '',
jsonTemperature: isMistral ? 0.15 : 0.7,
defaultTemperature: isMistral ? 0.15 : 0.7,
plainTextInstruction: ' Do not use markdown formatting.'
};
}
Esto permite que el resto de su sistema siga siendo model-agnostic
Añadir un nuevo modelo más adelante se vuelve trivial.
| Configuración | Valor recomendado | Razón |
|---|---|---|
| tokenizer_mode | ministral | Requerido para el tokenizador correcto |
| config_format | ministral | Obligatorio |
| load_format | ministral | Obligatorio |
| chat_template_kwargs | No enviar | No soportado |
| temperatura | 0.15 | Evita alucinaciones estructurales |
| instrucción en formato JSON | Valores explícitos y planos | Evitar objetos anidados |
| max_tokens | 1.5–2× lo típico | El modelo es prolijo |
| Eliminación de formato Markdown | Siempre | Evitar errores de formato |
| reintentos en formato JSON | 2–3 intentos | Recuperación confiable |
Mistral-3 rinde de manera excepcional cuando está correctamente ajustado.
Una vez que tú:
el modelo se vuelve notablemente predecible y listo para producción
En nuestro benchmark de Jeopardy, esta configuración soportó:
Todo ejecutándose localmente en la infraestructura de GPU de Trooper.AI.
Prueba la plantilla de despliegue completo de vLLM aquí: Servidor Compatible con OpenAI de vLLM
Alquila tu propio servidor con GPU hoy y comienza a construir aplicaciones de IA increíbles! Los servidores GPU de Trooper.AI están construidos con tecnología high-end reciclada al 100% de los últimos años, diseñados para ofrecerte el mejor rendimiento, seguridad y confiabilidad en todas tus necesidades de IA.
Ubicación en la UE · Alta privacidad · Alto rendimiento · Mejor soporte