¿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

Comprobar el SQL de un modelo ejecutándolo

Después de esta lección: Puedo comprobar la consulta de un modelo ejecutándola con datos de respuesta conocida.

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

Ejecuta la consulta con una respuesta conocida

Comprobar SQL ejecutándolo es probar la consulta de un modelo con unos datos pequeños cuya respuesta has calculado a mano. Leer la consulta encuentra algunos fallos; ejecutarla encuentra los que parecen correctos en la página.

El módulo 43 comprueba la consulta de una persona por sus filas. Esta lección comprueba las candidatas de un modelo y se pregunta si los datos separan lo correcto de lo erróneo.

Al final de esta lección

Nota

Puedo comprobar la consulta de un modelo ejecutándola con datos de respuesta conocida.

Palabras clave

PalabraQué significa
Respuesta conocidael resultado calculado a mano
Candidatauna consulta propuesta como respuesta
Filas del resultadolo que devuelve una consulta
Datos de pruebadatos pequeños y fijos que se guardan para comprobar
Separardar resultados distintos a la consulta correcta y a la errónea

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

Compara las filas con una respuesta conocida

Calcula la respuesta a mano con unos datos de prueba pequeños. Nueve préstamos se cuentan en papel. Luego ejecuta cada candidata y compara sus filas con las tuyas.

Hay tres veredictos. Pasa significa que las filas coinciden. Filas incorrectas significa que se ejecutó y dio otra cosa. Error significa que SQLite la rechazó.

Ejemplo resuelto: respuestas conocidas de la biblioteca

PreguntaCalculado a manoRespuesta conocida
Socios distintos en el mes 3Préstamos 1 a 4: Alba, Alba, Bruno, Carmen3
Libros que siguen prestadosLos préstamos 3, 5, 6, 8 y 9 tienen returned = 05
Títulos que tomó el socio 2Préstamos 3, 6 y 8: libros 3, 4 y 5Mapa de la lluvia, Motores en calma, Siete teteras

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

El orden solo importa si se pide

Una lista de títulos en cualquier orden responde a «qué títulos». Compara copias ordenadas de las dos listas: otro orden también pasa.

Si la pregunta dice «el más reciente primero», el orden forma parte de la respuesta. Entonces compara las filas tal como llegan.

Datos que separan lo correcto de lo erróneo

Pregunta cuántos préstamos del mes 5 siguen fuera. Los dos préstamos del mes 5 están fuera, así que una consulta sin filtro sobre returned también da 2.

Estos datos no separan las dos consultas. Añade una fila que las separe, como un préstamo devuelto en el mes 5, y vuelve a comprobar.

Un error frecuente

Advertencia

Mucha gente cree que una candidata que pasa con los datos de prueba es correcta. Es correcta para esos datos. Comprueba que los datos de prueba dan otra respuesta a la consulta errónea probable y solo entonces fíate del pase.

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;' '}' '// Una respuesta puede envolver la consulta en un bloque delimitado: nos quedamos con el interior.' 'function sqlOf(text) {' '  const parts = text.split(String.fromCharCode(96).repeat(3));' '  const inner = (parts.length > 2 ? parts[1] : text).trim();' '  return inner.toLowerCase().startsWith(\"sql\") ? inner.slice(3).trim() : inner;' '}' > 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, sqlOf };' >> 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 base de la biblioteca, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { DatabaseSync } = require(\"node:sqlite\");' '// Una biblioteca inventada: seis libros, cuatro socios, nueve préstamos.' 'const BOOKS = [[1, \"La calle de la sal\", 2019], [2, \"Puerto de cristal\", 2021], [3, \"Mapa de la lluvia\", 2015],' '  [4, \"Motores en calma\", 2023], [5, \"Siete teteras\", 2018], [6, \"Al norte del mediodía\", 2022]];' 'const MEMBERS = [[1, \"Alba\"], [2, \"Bruno\"], [3, \"Carmen\"], [4, \"Diego\"]];' '// id, book_id, member_id, month, returned (1 devuelto, 0 aún fuera)' 'const LOANS = [[1, 1, 1, 3, 1], [2, 2, 1, 3, 1], [3, 3, 2, 3, 0], [4, 1, 3, 3, 1], [5, 1, 1, 4, 0],' '  [6, 4, 2, 4, 0], [7, 2, 3, 4, 1], [8, 5, 2, 5, 0], [9, 2, 4, 5, 0]];' > library.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 base de la biblioteca, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function put(db, table, rows) {' '  const marks = rows[0].map(function () { return \"?\"; }).join(\", \");' '  const insert = db.prepare(\"INSERT INTO \" + table + \" VALUES (\" + marks + \")\");' '  rows.forEach(function (row) { insert.run(...row); });' '}' 'function open(file) {' '  const db = new DatabaseSync(file || \":memory:\");' '  db.exec(\"CREATE TABLE books (id INTEGER PRIMARY KEY, title TEXT, year INTEGER)\");' '  db.exec(\"CREATE TABLE members (id INTEGER PRIMARY KEY, name TEXT)\");' '  db.exec(\"CREATE TABLE loans (id INTEGER PRIMARY KEY, book_id INTEGER REFERENCES books(id), \"' '    + \"member_id INTEGER REFERENCES members(id), month INTEGER, returned INTEGER)\");' '  put(db, \"books\", BOOKS);' '  put(db, \"members\", MEMBERS);' '  put(db, \"loans\", LOANS);' '  return db;' '}' 'module.exports = { open };' >> library.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 comprobación, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask, sqlOf } = require(\"./model\");' 'const { open } = require(\"./library\");' 'const db = open();' 'function rowsOf(sql) {' '  try {' '    return db.prepare(sql).all().map(function (r) { return JSON.stringify(Object.values(r)); }).sort();' '  } catch (error) { return null; }' '}' 'function check(sql, want) {' '  const got = rowsOf(sql);' '  if (got === null) return \"error\";' '  const wanted = want.map(function (r) { return JSON.stringify(r); }).sort();' '  return got.join(\"|\") === wanted.join(\"|\") ? \"pasa\" : \"filas incorrectas \" + got.join(\" \");' '}' > check.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 comprobación, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const L = \"SELECT COUNT(*) FROM loans WHERE \";' 'const T = \"SELECT b.title FROM loans l JOIN books b ON \";' 'const cases = [' '  { want: [[3]], sql: [\"SELECT COUNT(member_id) FROM loans WHERE month = 3\",' '    \"SELECT COUNT(DISTINCT member_id) FROM loans WHERE month = 3\",' '    \"SELECT COUNT(DISTINCT member) FROM loans WHERE month = 3\"] },' '  { want: [[5]], sql: [\"SELECT COUNT(*) FROM loans\", L + \"returned = 0\", L + \"returned = 1\"] },' '  { want: [[\"Mapa de la lluvia\"], [\"Motores en calma\"], [\"Siete teteras\"]],' '    sql: [T + \"l.id = b.id WHERE l.member_id = 2\", T + \"l.book_id = b.id WHERE l.member_id = 2\",' '      T + \"l.book_id = b.id WHERE l.member_id = 2 ORDER BY b.title DESC\"] },' '  { want: [[2]], sql: [L + \"month = 5 AND returned = 0\", L + \"month = 5\"] },' '];' >> check.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 comprobación, parte 3

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  cases.forEach(function (c, i) {' '    c.sql.forEach(function (sql, j) { console.log((i + 1) + \"abc\"[j] + \": \" + check(sql, c.want)); });' '  });' '  db.exec(\"UPDATE loans SET returned = 1 WHERE id = 8\");' '  console.log(\"cuando vuelve el préstamo 8, la respuesta a 4 es 1:\");' '  cases[3].sql.forEach(function (sql, j) { console.log(\"4\" + \"ab\"[j] + \": \" + check(sql, [[1]])); });' '  db.exec(\"UPDATE loans SET returned = 0 WHERE id = 8\");' '  await live();' '}' >> check.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 comprobación, parte 4

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function live() {' '  const q = \"loans(id, book_id, member_id, month, returned)\nPregunta: ¿Cuántos socios distintos tomaron prestado un libro en el mes 3?\";' '  const sample = \"SELECT COUNT(DISTINCT member_id) FROM loans WHERE month = 3;\";' '  const reply = await ask([{ role: \"system\", content: \"Responde con una sola consulta SELECT de SQLite y nada más.\" },' '    { role: \"user\", content: q }], sample, 120);' '  const sql = sqlOf(reply.text);' '  console.log(\"el modelo escribió: \" + sql);' '  console.log(\"  comprobada con datos conocidos: \" + check(sql, [[3]]));' '}' 'main();' >> check.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 cada candidata con datos conocidos

Comando
docker exec -w /home/node/project agent node --experimental-sqlite --no-warnings check.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
1a: filas incorrectas [4]Alba contada dos veces
1c: errorNinguna columna se llama member
2c: filas incorrectas [4]Se contaron los libros devueltos
3a: filas incorrectas ["Al norte del mediodía"] ["Mapa de la lluvia"]La unión de id con id
3c: pasaOtro orden también pasa
4a: pasa y 4b: pasaLos datos no las separan
4b: filas incorrectas [2], cuando vuelve el préstamo 8Una fila nueva las separa

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.