¿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

Cómo enrutar peticiones entre varios modelos

Después de esta lección: Puedo enrutar cada petición al modelo más barato que sea suficiente y comprobar la elección con casos grabados.

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

Envía cada petición al más barato que sirva

Enrutar modelos es elegir, para cada petición, el modelo más barato que sea suficiente. Importa porque el más caro cuesta muchas veces lo que el más pequeño, y la mayoría de las peticiones no lo necesitan.

Una herramienta de soporte clasifica tickets, responde preguntas cortas y redacta respuestas largas. Clasificar no necesita el modelo que redacta. Mandarlo todo a un modelo grande paga una potencia que casi nadie usa.

Al final de esta lección

Nota

Puedo enrutar cada petición al modelo más barato que sea suficiente y comprobar la elección con casos grabados.

Palabras clave

PalabraQué significa
Enrutadorla regla que elige un modelo para una petición
Nivelun grupo de modelos por tamaño y precio
Suficienteacierta con la frecuencia que esa tarea pide
Caso grabadouna petición con el nivel que eligió una persona
Desacuerdoun caso donde el enrutador y la persona difieren
Envoltorioel código alrededor de una llamada que añade las reglas

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

Un enrutador es una regla simple

Empieza con una regla que se pueda leer. Un texto corto o una tarea de clasificar va al nivel small. Un texto largo o una tarea de razonar va al nivel large. El resto va al nivel medium.

Una regla sobre tamaño y tarea es barata, instantánea y fácil de explicar. También puedes pedir a un modelo pequeño que elija, pero eso añade una llamada a cada petición, así que prueba antes la regla.

Ejemplo resuelto: la regla con cuatro peticiones

PeticiónTareaTamañoNivel
Clasificar un ticketclassify150 caracteressmall
Resumir una páginasummarise1500 caracteresmedium
Planear una migraciónreason900 caractereslarge
Resumir un informe largosummarise5000 caractereslarge

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

Comprueba la regla con casos

Un enrutador ahorra dinero y puede costar calidad, así que pruébalo. Guarda casos grabados: una petición, su tamaño y su tarea, y el nivel que una persona dice que necesita. Pasa el enrutador por ellos. Lista los desacuerdos y suma el coste.

Un desacuerdo no siempre es un fallo de la regla. Lee cada uno. Luego cambia la regla, o cambia el caso.

Un error frecuente

Advertencia

Mucha gente cree que el modelo más barato es siempre el mejor ahorro. Un modelo barato que responde mal cuesta un reintento, una queja o un usuario perdido. Baja de nivel solo donde los casos grabados muestren que la respuesta sigue siendo suficiente.

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 la comprobación, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' '' '// Precios inventados: euros por millón de tokens, así que tokens por precio = microeuros.' 'const PRICE = { small: { in: 1, out: 4 }, medium: { in: 3, out: 12 }, large: { in: 10, out: 40 } };' 'function route(request) {' '  if (request.task === \"classify\" || request.chars <= 200) return \"small\";' '  if (request.task === \"reason\" || request.chars > 2000) return \"large\";' '  return \"medium\";' '}' 'function cost(tier, c) { return c.in * PRICE[tier].in + c.out * PRICE[tier].out; }' > route6.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 la comprobación, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// Casos grabados: qué es cada petición y el nivel que un revisor dice que necesita.' 'const CASES = [' '  { id: 1, task: \"classify\", chars: 150, in: 60, out: 5, expected: \"small\" },' '  { id: 2, task: \"qa\", chars: 180, in: 70, out: 40, expected: \"small\" },' '  { id: 3, task: \"summarise\", chars: 1500, in: 500, out: 150, expected: \"medium\" },' '  { id: 4, task: \"reason\", chars: 900, in: 400, out: 600, expected: \"large\" },' '];' >> route6.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 la comprobación, parte 3

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const MORE = [' '  { id: 5, task: \"summarise\", chars: 5000, in: 1400, out: 300, expected: \"large\" },' '  { id: 6, task: \"classify\", chars: 3000, in: 800, out: 5, expected: \"small\" },' '  { id: 7, task: \"qa\", chars: 700, in: 250, out: 120, expected: \"medium\" },' '  { id: 8, task: \"summarise\", chars: 190, in: 80, out: 30, expected: \"medium\" },' '];' >> route6.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 la comprobación, parte 4

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const all = CASES.concat(MORE);' '  let total = 0, dear = 0, wrong = [];' '  for (const c of all) {' '    const tier = route(c);' '    total = total + cost(tier, c);' '    dear = dear + cost(\"large\", c);' '    if (tier === c.expected) console.log(\"#\" + c.id + \" \" + c.task + \": \" + tier + \" ok\");' '    else { wrong.push(c.id); console.log(\"#\" + c.id + \" \" + c.task + \": \" + tier + \", se esperaba \" + c.expected); }' '  }' '  console.log(\"Desacuerdos: \" + wrong.length + \" de \" + all.length + \", casos \" + wrong.join(\", \"));' '  console.log(\"Coste enrutado: \" + total + \". Todo en large: \" + dear + \". Ahorro: \" + (dear - total));' >> route6.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 la comprobación, parte 5

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  const reply = await ask([{ role: \"user\", content: \"Clasifica como facturación, error u otro: me cobraron dos veces.\" }], \"facturación\", 10);' '  console.log(\"Enrutado a \" + route(all[0]) + \", respuesta: \" + reply.text.slice(0, 40));' '}' 'main();' >> route6.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 comprobación

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

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

El laboratorio tiene un solo modelo

En el laboratorio responde un solo modelo sea cual sea el nivel que elija la regla, y lo elige la plataforma. Así que el Run muestra la elección y el coste, y la única llamada real solo muestra que una petición enrutada recibe respuesta.

Los precios y los ocho casos son inventados y están grabados, así que todos los estudiantes imprimen las mismas líneas.

Una salida posible

LíneaQué muestra
#1 classify: small okEl enrutador y la persona coinciden
#8 summarise: small, se esperaba mediumUn desacuerdo que hay que leer y decidir
Desacuerdos: 1 de 8, casos 8El recuento y los números de caso
Coste enrutado: 60820. Todo en large: 85600. Ahorro: 24780El total, en microeuros
Enrutado a small, respuesta: ...Una llamada real. Las palabras cambian en cada Run

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.