¿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

Explicar una respuesta de texto a SQL

Después de esta lección: Puedo escribir una respuesta que muestra la consulta, admite una duda y pregunta cuando la petición es vaga.

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

Qué muestra una respuesta de texto a SQL

Explicar una respuesta de texto a SQL es enseñar al usuario la consulta y sus filas, no solo una frase. Una frase sola parece segura, incluso cuando la consulta era errónea.

El módulo 84 diseña funciones de IA para personas. Esta lección escribe la respuesta de una función de texto a SQL: qué muestra, cuándo admite una duda y cuándo pregunta primero.

Al final de esta lección

Nota

Puedo escribir una respuesta que muestra la consulta, admite una duda y pregunta cuando la petición es vaga.

Palabras clave

PalabraQué significaEjemplo
Respuestalo que ve el usuario después de su pregunta
Lecturauna forma de convertir una pregunta en consulta
Palabra vagauna palabra que aquí tiene más de un sentidopopular
Pregunta de aclaraciónuna pregunta de vuelta que evita suponer
Resultado vacíouna consulta que no devuelve ninguna fila

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

Muestra la consulta y las filas

Pon la consulta y sus filas junto a la frase. Un usuario que conoce los datos detecta enseguida una unión equivocada.

Mantén las filas cortas: enseña las primeras y di cuántas quedan. La frase sale de las filas, nunca de la memoria del modelo.

Ejemplo resuelto: dos respuestas a una pregunta

RespuestaLo que el usuario puede comprobar
Hay cinco libros prestados.Nada
Respuesta: 5. Consulta: SELECT COUNT(*) FROM loans WHERE returned = 0El filtro, la tabla y el número

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

Di cuándo no estás seguro

«¿Quién ha tomado prestados más libros?» tiene dos lecturas. Más préstamos da Alba, porque el empate se deshace por el nombre. Más libros distintos da Bruno.

Ejecuta las dos lecturas. Si coinciden, responde. Si no coinciden, di que no estás seguro y enseña las dos. Un resultado vacío también es una respuesta: di que ninguna fila coincide.

Pregunta antes de adivinar una palabra vaga

Palabras como popular, reciente, mejor o activo no tienen un único sentido en los datos. Popular puede querer decir prestado dos veces, o prestado este mes.

Cuando una pregunta lleva una, haz antes una pregunta de aclaración corta. Una pregunta de vuelta cuesta menos que una respuesta falsa y segura.

Un error frecuente

Advertencia

Mucha gente cree que una frase segura es la respuesta más útil. Una respuesta falsa y segura es peor que una pregunta de vuelta. Responde con firmeza solo si las lecturas coinciden y ninguna palabra es vaga.

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 respuesta, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const { open } = require(\"./library\");' 'const db = open();' 'const VAGUE = [\"popular\", \"reciente\", \"mejor\", \"activo\"];' 'const M = \"SELECT m.name, COUNT(\";' 'const J = \") AS n FROM loans l JOIN members m ON m.id = l.member_id GROUP BY m.name ORDER BY n DESC, m.name LIMIT 1\";' > explain.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 respuesta, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const asks = [' '  { q: \"¿Cuántos libros siguen prestados?\", a: \"SELECT COUNT(*) FROM loans WHERE returned = 0\" },' '  { q: \"¿Qué títulos ha tomado prestados el socio 2?\",' '    a: \"SELECT b.title FROM loans l JOIN books b ON l.book_id = b.id WHERE l.member_id = 2\" },' '  { q: \"¿Qué libros son populares?\", a: \"SELECT book_id FROM loans GROUP BY book_id HAVING COUNT(*) > 1\" },' '  { q: \"¿Quién ha tomado prestados más libros?\", a: M + \"*\" + J, b: M + \"DISTINCT l.book_id\" + J },' '  { q: \"¿Qué libros se prestaron en el mes 9?\",' '    a: \"SELECT b.title FROM loans l JOIN books b ON l.book_id = b.id WHERE l.month = 9\" },' '];' >> explain.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 respuesta, parte 3

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function rows(sql) {' '  return db.prepare(sql).all().map(function (r) { return Object.values(r).join(\" \"); });' '}' 'function reply(x) {' '  const vague = VAGUE.filter(function (w) { return x.q.toLowerCase().indexOf(w) >= 0; });' '  if (vague.length) return \"Antes de responder: ¿qué quieres decir con \" + vague[0] + \"?\";' '  const a = rows(x.a);' '  const b = x.b ? rows(x.b) : a;' '  if (a.join(\"|\") === b.join(\"|\")) {' '    if (a.length === 0) return \"Ninguna fila coincide. Consulta: \" + x.a;' '    return \"Respuesta: \" + a.join(\"; \") + \". Consulta: \" + x.a;' '  }' '  return \"No estoy seguro. Dos lecturas no coinciden: \" + a.join(\"; \") + \" o \" + b.join(\"; \");' '}' >> explain.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 respuesta, parte 4

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  asks.forEach(function (x, i) { console.log((i + 1) + \" \" + x.q + \"\n  \" + reply(x)); });' '  const facts = asks[0].q + \" Filas: \" + JSON.stringify(rows(asks[0].a));' '  const sample = \"Cinco libros siguen prestados.\";' '  const res = await ask([{ role: \"system\", content: \"Da la respuesta en una frase corta. Usa solo las filas que se te dan.\" },' '    { role: \"user\", content: facts }], sample, 60);' '  console.log(\"el modelo dijo: \" + res.text);' '  console.log(\"  se muestra con su consulta y sus filas, para que el usuario pueda comprobarla\");' '}' 'main();' >> explain.js"

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

Responde a cinco preguntas

Comando
docker exec -w /home/node/project agent node --experimental-sqlite --no-warnings explain.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

PreguntaRespuesta
1 ¿Cuántos libros siguen prestados?Respuesta: 5. Consulta: ...
2 ¿Qué títulos ha tomado prestados el socio 2?Respuesta: Mapa de la lluvia; Motores en calma; Siete teteras. Consulta: ...
3 ¿Qué libros son populares?Antes de responder: ¿qué quieres decir con popular?
4 ¿Quién ha tomado prestados más libros?No estoy seguro. Dos lecturas no coinciden: Alba 3 o Bruno 3
5 ¿Qué libros se prestaron en el mes 9?Ninguna fila coincide. Consulta: ...

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.