¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Pruebas A/B y pruebas en la sombra

Después de esta lección: Puedo comparar dos versiones sin que me engañe el azar.

Lección de 70 min6 comandosLaboratorio de agente de programación con IA: usa opencode para explicar y corregir código, y comprueba su trabajo

Cómo comparar dos versiones de IA con justicia

Una prueba A/B da la versión A a un grupo de usuarios y la B a otro. Después compara con qué frecuencia funciona cada una. Una prueba en la sombra ejecuta la versión nueva con peticiones reales, pero nadie ve sus respuestas.

Las dos pueden engañarte. Una diferencia de nueve puntos puede ser solo ruido.

Al final de esta lección

Nota

Puedo comparar dos versiones sin que me engañe el azar.

Palabras clave

PalabraQué significa
Prueba A/Bdos grupos de usuarios, una versión cada uno
Prueba en la sombrauna versión nueva que se ejecuta sin que nadie la vea
Tasa de aprobadosla parte de peticiones que funcionaron
Diferenciauna tasa menos la otra, en puntos
Oscilacióncuánto se mueve una diferencia por azar

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Una diferencia debe superar la oscilación

La versión B aprueba 138 de 200 y la A aprueba 120 de 200. La diferencia es de 9 puntos. Pero dos grupos de 200 usuarios también difieren por azar.

La oscilación es cuánto se mueve una diferencia por azar. Una regla práctica: fíate de una diferencia solo cuando sea al menos el doble de la oscilación.

Ejemplo resuelto: dos pruebas

PruebaUsuarios por grupoDiferenciaOscilaciónDoble de la oscilaciónVeredicto
A frente a B2009,04,89,6No probado
A frente a C10005,02,24,3Fiable

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Un error frecuente

Advertencia

Mucha gente cree que gana la nota más alta. Una nota más alta en una prueba pequeña puede ser azar. Declara un ganador solo cuando la diferencia sea al menos el doble de la oscilación; si no, di «no probado» y reúne más datos.

La sombra halla fallos nuevos sin riesgo

Ejecuta la versión nueva con las mismas peticiones reales y mantén ocultas sus respuestas. Por cada petición tienes un par: el resultado antiguo y el nuevo.

Dos totales iguales pueden esconder un cambio. Dos casos pueden empeorar mientras otros dos mejoran. Cuenta los que empeoran y lee cada uno.

Ejemplo resuelto: doce pares

Par (antiguo, nuevo)SignificadoCuántos
aprueba, apruebaIgual7
falla, fallaIgual1
falla, apruebaLa nueva mejora2
aprueba, fallaLa nueva empeora, léelos2

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Escribe el ayudante del modelo, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// Los tokens de una respuesta, o null si no trae ninguno.' 'function count(data, name) {' '  return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribe el ayudante del modelo, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"estado \" + res.status);' '    const d = await res.json();' '    return { text: d.choices[0].message.content, inTokens: count(d, \"prompt_tokens\"), outTokens: count(d, \"completion_tokens\"), recorded: false };' '  } catch (error) {' '    console.log(\"Muestra grabada: ningún modelo respondió (\" + error.message + \").\");' '    return { text: sample, inTokens: null, outTokens: null, recorded: true };' '  }' '}' 'module.exports = { ask };' >> model.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribe el script de comparación, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'function wobble(a, an, b, bn) {' '  const p = (a + b) / (an + bn);' '  return Math.sqrt(p * (1 - p) * (1 / an + 1 / bn)) * 100;' '}' 'function gap(a, an, b, bn) { return (b / bn - a / an) * 100; }' 'function verdict(a, an, b, bn) {' '  const ok = Math.abs(gap(a, an, b, bn)) >= 2 * wobble(a, an, b, bn);' '  return ok ? \"fiable\" : \"no probado\";' '}' > ab.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribe el script de comparación, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const tests = [' '  { name: \"A frente a B\", a: 120, an: 200, b: 138, bn: 200 },' '  { name: \"A frente a C\", a: 600, an: 1000, b: 650, bn: 1000 },' '];' 'const pairs = \"pp pp pf pp fp pp ff pp pf pp pp fp\".split(\" \");' 'function count(kind) { return pairs.filter(function (p) { return p === kind; }).length; }' >> ab.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribe el script de comparación, parte 3

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  tests.forEach(function (t) {' '    console.log(t.name + \": diferencia \" + gap(t.a, t.an, t.b, t.bn).toFixed(1) + \" puntos, oscilación \" + wobble(t.a, t.an, t.b, t.bn).toFixed(1) + \" -> \" + verdict(t.a, t.an, t.b, t.bn));' '  });' '  console.log(\"sombra: iguales \" + (count(\"pp\") + count(\"ff\")) + \", la nueva mejor \" + count(\"fp\") + \", la nueva peor \" + count(\"pf\"));' '  const q = \"En una frase corta, ¿por qué una diferencia de 9 puntos puede ser solo ruido?\";' '  const sample = \"Con solo 200 usuarios por grupo, el azar por sí solo puede mover una nota tanto.\";' '  const reply = await ask([{ role: \"user\", content: q }], sample, 60);' '  console.log(\"el modelo dijo: \" + reply.text);' '}' 'main();' >> ab.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ejecuta la comparación

Comando
docker exec -w /home/node/project agent node ab.js

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Lo que imprime el Run

LíneaQué muestra
A frente a B: diferencia 9.0 puntos, oscilación 4.8 -> no probadoUna diferencia grande, una prueba pequeña
A frente a C: diferencia 5.0 puntos, oscilación 2.2 -> fiableUna diferencia menor, una prueba mayor
sombra: iguales 8, la nueva mejor 2, la nueva peor 2Contado sobre doce pares grabados
el modelo dijo: ...Una frase del laboratorio. Una muestra grabada si ningún modelo responde

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Sobre este laboratorio y su código: Laboratorio de agente de programación con IA: usa opencode para explicar y corregir código, y comprueba su trabajo

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.