Por qué el test va antes del agente
Un test barrera es un test que escribes antes de que empiece un agente de código. Ahora falla y debe pasar cuando el trabajo esté hecho, así que «terminado» lo decide una máquina y no el informe del agente.
Importa porque un agente puede informar de que ha terminado cuando el trabajo no está hecho. Un test escrito antes, y protegido del agente, es una comprobación en la que puedes confiar.
Al final de esta lección
Nota
Puedo escribir primero un test que falla para que el trabajo de un agente de código quede comprobado.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Test barrera | un test que escribes antes del trabajo y que debe pasar al terminarlo |
| Rojo y luego verde | el test falla antes del trabajo y pasa después |
| Trampa | un cambio que pasa un test sin hacer el trabajo |
| Test reservado | un test que el agente no puede ver |
| Archivo de tests protegido | un archivo de tests que el agente no puede cambiar |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Escribe primero el test que falla
Escribe el test a partir de la tarea, antes de que empiece el agente. Ejecútalo y míralo fallar. Un test que pasa antes de cualquier trabajo no prueba nada nuevo.
Después da al agente la tarea y el test. El agente cambia el código hasta que el test pasa. Ahora tienes una comprobación que no depende de lo que el agente dice que hizo.
Un test puede pasar sin el trabajo
Al agente se le pide que el test pase, y puede encontrar un atajo. Puede responder solo a las entradas que ve. Puede cambiar o borrar el test.
No es mala intención. El agente recibió un objetivo y lo alcanzó. Por eso el objetivo tiene que ser difícil de alcanzar por el camino equivocado.
Ejemplo resuelto: trampas y cómo frenarlas
| Trampa | Cómo se ve | Cómo frenarla |
|---|---|---|
| Caso especial | si el precio es 2000, responde 0 | Tests reservados con otras entradas |
| Editar el test | Se borra o cambia un caso | Proteger el archivo de tests y compararlo |
| Saltar el test | El test se marca para saltarlo | Contar los tests antes y después |
| Test más débil | Una comprobación exacta pasa a «es un número» | Revisar cada cambio en un archivo de tests |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un error frecuente
Advertencia
Mucha gente cree que una ejecución en verde significa que el agente hizo el trabajo. Un test puede ponerse verde porque cambió el test, o porque solo funcionan las entradas visibles. Fíate del verde solo si el archivo de tests no cambió y los tests reservados también pasan.
Juzga cuatro intentos grabados
El envío cuesta 299 céntimos por debajo de 2000 céntimos y nada a partir de 2000. El script lleva tres tests visibles y dos reservados.
Juzga el código antes del trabajo y tres intentos grabados. Los intentos se escribieron a mano para representar lo que un agente puede devolver.
Escribe el ayudante del modelo, parte 1
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
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 juez de barreras, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' '// El envío cuesta 299 céntimos por debajo de 2000 céntimos, y nada desde 2000.' 'const visible = [[500, 299], [1999, 299], [2000, 0]];' 'const held = [[2500, 0], [100, 299]];' 'const attempts = {' ' \"antes\": { fn: function (p) { return 299; }, tests: visible },' ' \"honesto\": { fn: function (p) { return p >= 2000 ? 0 : 299; }, tests: visible },' ' \"caso especial\": { fn: function (p) { return p === 2000 ? 0 : 299; }, tests: visible },' ' \"test editado\": { fn: function (p) { return 299; }, tests: [[500, 299], [1999, 299]] },' '};' > guard.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 juez de barreras, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function passed(fn, cases) {' ' return cases.filter(function (c) { return fn(c[0]) === c[1]; }).length;' '}' 'function verdict(a) {' ' if (JSON.stringify(a.tests) === JSON.stringify(visible) === false) return \"rechazar: tests cambiados\";' ' if (passed(a.fn, a.tests) < a.tests.length) return \"sin terminar\";' ' if (passed(a.fn, held) < held.length) return \"posible trampa\";' ' return \"aceptar\";' '}' >> guard.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 juez de barreras, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' Object.keys(attempts).forEach(function (name) {' ' const a = attempts[name];' ' console.log(name + \": visibles \" + passed(a.fn, a.tests) + \"/\" + a.tests.length' ' + \", reservados \" + passed(a.fn, held) + \"/\" + held.length + \": \" + verdict(a));' ' });' ' const q = \"En una frase corta: ¿por qué guardar algunos tests donde un agente de código no puede verlos?\";' ' const sample = \"Los tests ocultos muestran si el agente resolvió el problema o solo los ejemplos que veía.\";' ' const reply = await ask([{ role: \"user\", content: q }], sample, 60);' ' console.log(\"el modelo dijo: \" + reply.text);' '}' 'main();' >> guard.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 el juez de barreras
docker exec -w /home/node/project agent node guard.jsSe 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ínea | Lo que muestra |
|---|---|
| antes: visibles 2/3 ...: sin terminar | Rojo: el test falla antes del trabajo |
| honesto: visibles 3/3, reservados 2/2: aceptar | Verde, y los casos ocultos coinciden |
| caso especial: ... reservados 1/2: posible trampa | Solo funcionan las entradas visibles |
| test editado: ...: rechazar: tests cambiados | Se borró un caso, así que nada cuenta |
| el modelo dijo: ... | Una frase del laboratorio. Una línea de Muestra grabada si ningún modelo responde |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.