--- source_sha: "9c37b08af0c5" title: "Datasets" description: "Los datasets guardan las preguntas con las que se prueba un agent: casos versionados escritos a mano, importados de CSV o JSONL o tomados de una respuesta valorada." --- # Datasets { #datasets } Un **dataset** guarda las preguntas con las que se prueba un agent. Sin uno, cada comprobación de si un cambio mejoró al agent consiste en que alguien prueba unos cuantos prompts a mano e intenta recordar cómo era la última respuesta. Cada pregunta es un **caso**: el mensaje que responde el agent y cómo es una buena respuesta. Los casos vienen de cuatro sitios: escritos en la consola, importados de un archivo, tomados de una conversación real en la que alguien valoró la respuesta con un pulgar abajo, o redactados por el generador de casos y aceptados por una persona. Este último suele ser el más útil, porque es una pregunta que una persona hizo de verdad y una respuesta que de verdad la decepcionó. **Cases**, **Results** y **Settings** comparten un espacio con control de pantalla completa. Cases reúne casos escritos y generados; Results combina ejecuciones de prueba y revisión de respuestas; Settings contiene evaluación, generación y mejora. Añadir, importar, generar y abrir Activity están junto a la tabla de casos. Un caso se abre en un panel lateral; Edit abre el formulario. La pregunta y las respuestas van primero, con herramientas, comprobaciones y etiquetas en secciones desplegables. El modelo y las instrucciones del calificador, la generación y la mejora se eligen en **Settings**. Los modelos guardados tienen un selector compacto con búsqueda; **Add model** abre el formulario de provider, modelo y clave. Las instrucciones usan el editor Markdown. Los ayudantes se definen en código y no requieren crear ni publicar un agent. Un trabajo en cola conserva su configuración inicial. ## De un dataset nuevo a los resultados { #dataset-workflow } Cases prepara los datos, Results muestra ejecuciones y respuestas, y Settings configura evaluación y ayudantes. 1. **Añadir casos.** Escribe una pregunta, importa un archivo CSV o JSONL o genera propuestas para revisar. También puedes copiar una respuesta desde Actividad. 2. **Configurar la evaluación.** Elige reglas, comparación con la respuesta de referencia o criterios del juez. Settings señala los casos sin reglas de evaluación. 3. **Probar un agente.** Abre Results → Test runs, elige un agente y revisa el coste estimado antes de iniciar. Una vez configurada la evaluación, el botón al final de la evaluación en Settings te lleva aquí. 4. **Revisar los resultados.** Inspecciona las respuestas y los criterios que cumplen o incumplen. Los evals completados ofrecen un acceso directo a Revisión. La tabla de casos muestra fuentes, expectativas y etiquetas con colores. Pulsa una fila para abrirla; su menú de acciones contiene Editar y Eliminar. Generar e importar siguen visibles junto a Añadir caso, y Actividad está en el menú de acciones adicionales. ## Qué contiene un caso { #what-a-case-holds } | Campo | Qué es | |---|---| | Entrada | El mensaje que responde el agent | | Conversación antes de la entrada | Turnos anteriores opcionales, del más antiguo al más reciente. Con ellos, el caso es el comienzo de una conversación y el agent responde a su último turno | | Respuesta de referencia | Lo que dice una buena respuesta | | Contraejemplo | Una respuesta que se sabe incorrecta | | Llamadas a herramientas esperadas | Las herramientas que el agent debería llamar, cada una con los argumentos que deben coincidir. Los argumentos que el caso no indica se ignoran. Un caso también indica cómo se comparan las llamadas: `any` en cualquier orden, `in_order` en el orden dado con otras llamadas permitidas entre ellas, o `exact`: exactamente estas, en este orden, y ninguna otra | | Comprobaciones | Reglas sobre la respuesta, cada una un objeto cuyo `type` nombra la regla, con sus parámetros al lado. [La calificación](#checks) enumera los tipos, y un caso con un tipo que no conoce se rechaza | | Etiquetas | Rótulos para agrupar resultados, como `billing` o `refusal` | | Nota | Por qué existe el caso: qué salió mal o qué protege | | Origen | `manual`, `import`, `conversation` o `synthetic`: lo fija la plataforma, no se escribe | Un caso tiene que decir contra qué se compara su respuesta: una respuesta de referencia, un contraejemplo, una llamada a herramienta esperada o una comprobación, al menos una de las cuatro. Un caso con solo una entrada no podría fallar nunca, así que se rechaza: el formulario no lo guarda, la API responde 422 señalando `reference_answer` y una importación nombra la fila. Un buen caso es pequeño: una pregunta y lo único que una respuesta correcta tiene que acertar. Normalmente basta con una respuesta de referencia o un contraejemplo. Añade llamadas a herramientas esperadas cuando el agent tenga que actuar y no solo responder, comprobaciones cuando una regla pueda enunciarse con exactitud, y la conversación antes de la entrada solo cuando la pregunta dependa de ella. La nota es para quien lea el caso después: qué salió mal o qué protege. Al crear tu primer dataset, la consola ofrece un recorrido guiado que termina escribiendo su primer caso, campo por campo. Un caso tomado de una conversación también guarda un enlace al run, a la conversación y al mensaje de los que procede. La pregunta y la respuesta se copian en el caso, así que el caso sigue completo después de que la retención elimine el propio run. Los adjuntos no forman parte de un caso en esta versión. Un caso es texto. ## Cada cambio es una versión nueva { #versions } Añadir, editar o eliminar un caso, importar un archivo y aceptar casos generados crean cada uno una nueva **versión** del dataset, numerada desde 1. Una versión nunca cambia después de crearse. Un caso editado se guarda como una revisión nueva, y la versión anterior a la edición sigue conteniendo la antigua. Esto importa al comparar resultados. Dos runs de eval sobre la misma versión vieron las mismas preguntas, así que una diferencia en sus resultados viene del agent y no de la prueba. La página del dataset muestra por defecto la versión más reciente; elige una anterior en la lista de versiones. Una versión anterior es de solo lectura. Renombrar un dataset o cambiar su descripción, con **Editar detalles** en su página, no crea una versión, porque ninguna de las dos cosas cambia un caso. La lista de versiones muestra las cien más recientes; una más antigua se abre escribiendo su número. Una versión guarda solo lo que cambió: un caso añadido o editado es una nueva revisión de caso, y uno quitado no guarda nada, así que un historial largo cuesta lo que cambió y no cada caso en cada versión. Los datasets de una organización guardan juntos como mucho `DATASET_MAX_VERSION_ROWS_PER_ORG` revisiones de casos (5 millones por defecto, consulta [Configuración](configuration.md#datasets)). Añadir o editar por encima de eso se rechaza indicando cuántas hay guardadas; quitar un caso siempre está permitido, y borrar un dataset libera sus revisiones. ### Cambios sin guardar { #unsaved-changes } Como cada guardado es una versión nueva, nada se guarda solo mientras editas. Un caso que estás escribiendo, un cambio en **Grading**, los detalles del dataset y lo que elijas en **Generate cases** se quedan en pantalla hasta que los guardas. Si intentas salir antes - con un enlace, Atrás, cerrando el editor, cambiando a otra pestaña o versión del dataset, a otra organización o cerrando sesión -, la consola pregunta qué hacer: **Save**, **Discard** o **Stay**. Save solo se ofrece donde el cambio se puede guardar desde ahí tal como está. Cerrar o recargar la pestaña del navegador muestra en su lugar el aviso del propio navegador. Un caso o un cambio de Grading sin guardar también se guarda en tu navegador, nunca en el servidor. Cuando vuelves al dataset, la consola ofrece restaurar el cambio. Si para entonces el dataset tiene una versión más nueva, lo dice y solo ofrece descartar el cambio, con una forma de ver cuál era para que puedas hacerlo de nuevo. La copia se borra al guardar o descartar, al cambiar de organización y al cerrar sesión. Un cambio muy grande no se guarda. ## Añadir casos { #adding-cases } ### En la consola { #in-the-console } Abre **Datasets**, crea un dataset (se abre en cuanto existe) y elige **Añadir caso**. Escribe la entrada y al menos una de las cuatro expectativas de arriba. La conversación se escribe turno a turno, cada llamada a herramienta esperada como un nombre de herramienta y sus argumentos como filas de nombre y valor, y cada comprobación como un tipo elegido de la lista junto a lo que comprueba. **Edit as JSON** muestra el caso entero con la forma que tiene en una importación. Los casos se abren en un panel lateral con el diseño de mensajes del chat. Primero aparecen la pregunta y la respuesta de referencia etiquetada; los turnos anteriores se pueden desplegar encima. El texto del agente y de referencia usa el renderizador Markdown del chat, con imágenes remotas como enlaces. Los nombres de herramientas despliegan sus argumentos; contraejemplos, comprobaciones, notas y etiquetas permanecen separados. **Edit** en la cabecera fija abre el formulario, que indica la versión creada al guardar y los evaluadores del dataset. Un enlace a `?tab=cases&case={case_id}` abre un caso directamente. Guardar un caso nuevo cuya pregunta ya hace otro caso (sin tener en cuenta mayúsculas ni espacios) se detiene para avisarlo, con **Open it** para leer ese caso en su lugar y **Add anyway** para conservar ambos. La comprobación es `POST /datasets/{id}/cases/twins`, con la pregunta en el cuerpo para que no llegue a los registros de acceso. ### Desde un archivo { #import-and-export } **Importar** lee un archivo `.csv` o `.jsonl` y añade todos sus casos como una única versión nueva. La importación es todo o nada: si una fila no es válida, no se añade ninguna, y el rechazo nombra cada fila no válida para que puedas corregir el archivo y volver a intentarlo. Un archivo tiene como máximo 10 MB, y un dataset guarda como máximo 10.000 casos. En la consola, **Importar** primero enumera las columnas y ofrece **Download a template**, un CSV con todas las columnas y un caso que se importa tal cual; **Choose file** abre el selector de archivos. Los dos formatos usan los mismos nueve nombres de campo: | Columna | En CSV | En JSONL | |---|---|---| | `input` | Texto. Obligatoria | String. Obligatoria | | `history` | Una lista JSON en la celda, o vacía | Una lista de objetos `{"role", "content"}` | | `reference_answer`, `counter_example`, `note` | Texto, o vacía | String o `null` | | `expected_tool_calls` | Una lista JSON en la celda, o vacía | Una lista de objetos `{"tool", "args"}` | | `order_mode` | `any`, `in_order` o `exact`; vacío significa `any` | String | | `checks` | Una lista JSON en la celda, o vacía | Una lista de objetos de comprobación | | `tags` | Separadas por comas | Una lista de strings | Un archivo CSV necesita una fila de encabezado. Las columnas distintas de estas nueve se rechazan, para que una errata en el nombre de una columna no pierda sus datos en silencio. Las columnas que omitas toman su valor vacío. Dentro de una comprobación y en los argumentos de una llamada a herramienta, las claves se exportan en orden alfabético, después del `type` de la comprobación. ```csv input,reference_answer,tags How long is the return window?,30 days from delivery,returns Can I return a used kettle?,"No, only unused items",returns ``` **Exportar** descarga la versión que está en pantalla como CSV o JSONL. Una exportación se vuelve a importar sin cambios. Para que eso siga siendo cierto en una hoja de cálculo, una celda CSV que empieza por `=`, `+`, `-`, `@` o `'` se escribe con un `'` delante, para que la hoja no la ejecute como fórmula, y una importación quita de nuevo ese único `'`. La exportación queda registrada en el [registro de auditoría](governance.md#audit). ### Desde una conversación o un run { #add-to-dataset } Hay dos caminos y los dos crean el mismo caso: - **En el chat**, valora la respuesta, y la valoración decide cómo se guarda. Tras un pulgar arriba, la confirmación ofrece **Añadir al dataset**: elige el dataset y la respuesta se guarda como respuesta de referencia; la confirmación se queda diez segundos, lo bastante para alcanzarla. Tras un pulgar abajo, el diálogo que pregunta qué salió mal ofrece también **Añadir esta respuesta a un dataset**: márcalo, elige el dataset y envía, y la respuesta se guarda como contraejemplo, una respuesta que el agent no debería dar, como dice el diálogo. Primero se guarda la valoración y después se añade el caso, así que tu comentario se convierte en la nota del caso. Son dos escrituras separadas: si se rechaza el añadido, la valoración se mantiene y el mensaje dice qué mitad falló. Quitar la valoración más tarde deja el caso donde está: es una copia, versionada con su dataset. La consola recuerda el último dataset al que añadiste, así que el siguiente añadido es un clic. - **En Actividad**, cada respuesta de un agent tiene un control **Añadir al dataset**, una vez, en su último paso: una respuesta escrita en pasos (una llamada a herramienta y luego el texto) es un solo caso. Es donde se curan las respuestas, así que una buena respuesta se guarda como referencia tan fácilmente como una mala como contraejemplo. Sin ningún dataset al que añadir, crea uno, visible para la organización; abierto desde **Add from Activity** de un dataset, añade a ese dataset y ofrece volver a él. En ambos casos, el caso se crea a partir de ese turno: - la pregunta se convierte en la entrada, y los turnos anteriores solo vienen con ella si eliges **With the conversation**. Lo preguntan los dos diálogos del chat (el del pulgar abajo, una vez que lo marcas), Activity y **Score against a case**; cada uno empieza por **Only this question**, para que un chat que empezó con otro tema se quede fuera. En el chat, una pregunta que continúa claramente la anterior, porque empieza por "and" o "what about", se señala como continuación, y a una pregunta sin nada antes no se le pregunta. Por la API ocurre lo mismo: `with_history` en `POST /datasets/{id}/cases/from-message` es false si no se envía; - la respuesta es la respuesta entera del agent a la pregunta (cada paso que escribió antes de la siguiente pregunta), y su texto se convierte en el contraejemplo. Si nadie la valoró con un pulgar abajo, se ofrece en su lugar como respuesta de referencia, y puedes elegir cualquiera de las dos; guardada como referencia, las herramientas que llamó pasan a ser las llamadas esperadas del caso, por nombre (las que salieron bien y cambian algo, no una llamada fallida ni una que su agent declara de solo lectura), y una respuesta sin texto se guarda solo como esas llamadas; - el comentario más reciente dejado con un pulgar abajo se convierte en la nota. Los dos caminos solo los ven los miembros que pueden editar un dataset. El mensaje debe pertenecer a tu organización y debes poder leerlo: o tienes `runs:view`, que lee cada run de la organización como hace Actividad, o puedes abrir la conversación. Un mensaje de otra organización se rechaza como si no existiera, y una respuesta que ya es un caso de la versión más reciente del dataset se rechaza en lugar de añadirse dos veces. **Added to** nombra el dataset y lo abre. ### Generados por el generador de casos { #generating-cases } **Generate cases** abre el diálogo directamente desde Cases. Al iniciar la generación se abre la vista de propuestas; al cancelar permanece la lista de casos. Las respuestas de referencia y reales admiten Markdown y vistas previas ampliables para textos largos. En pantallas anchas, los detalles las muestran una al lado de la otra. Escribir cien buenos casos a mano es la razón por la que la mayoría de los equipos no tiene ninguno. La acción **Generate cases** en Cases de la página de un dataset, visible para quienes pueden editarlo, pide al generador de casos que los redacte, y tú decides cuáles conserva el dataset. Elige el agent que prueban los casos (aquel de cuyas instrucciones, herramientas y chats se escriben; no se ejecuta nada contra él), las fuentes y cuántos casos quieres: como máximo 50 y al menos uno por fuente, repartidos por igual entre las fuentes. | Fuente | Qué redacta el generador | Qué se le muestra | |---|---|---| | Del agent | Peticiones típicas y casos límite, con las llamadas a herramientas que cambian algo que hace una buena respuesta; una herramienta que solo lee nunca se espera, como en un caso añadido desde una respuesta | Las instrucciones del agent, aquellas de sus skills que puedes ver y sus herramientas, con los nombres que el agent les da | | Del conocimiento | Preguntas que responde su base de conocimiento. Cada caso enlaza con el documento del que procede su fragmento, guarda el fragmento como respuesta de referencia y lleva una comprobación `judge` de que la respuesta concuerda con el fragmento | Fragmentos de hasta 12 documentos indexados de las bases de conocimiento que usa el agent y que tú puedes leer | | De chats | Paráfrasis y variantes más difíciles de lo que la gente preguntó al agent, primero las respuestas valoradas negativamente. Cada caso enlaza con la pregunta que varía | Hasta 60 preguntas que se hicieron al agent en esta organización, con el comentario dejado en una respuesta valorada negativamente. Solo tráfico de producción: los runs de eval y los runs aislados respondieron a una prueba, no a una persona, y se dejan fuera | | Red team | Peticiones fuera de su ámbito, inyecciones de prompt, intentos de obtener datos personales e intentos de saltarse las políticas del agent. Cada caso lleva las etiquetas `red-team` y `red-team:` y una comprobación `judge` de que el agent se niega | Las instrucciones del agent, aquellas de sus skills que puedes ver y sus herramientas | **Primero, el coste estimado.** El diálogo muestra cuántos casos se pedirán a cada fuente, de cuánto material dispone cada una y una estimación del coste en el propio modelo del generador, antes de gastar nada; uno de pago por debajo de un céntimo lo dice en lugar de mostrar $0.00. Es una estimación: el presupuesto del generador se comprueba cuando se ejecuta, como el de cualquier agent. Cambiar el agent, las fuentes o el número descarta la estimación. **Nada llega al dataset hasta que lo aceptas.** Los borradores esperan en **Casos propuestos**, en la vista de generación en Cases. Acepta uno tal cual, edítalo antes o descártalo, de uno en uno o una página entera. Un Aceptar es una versión nueva, lleve lo que lleve, y sus casos tienen la fuente `synthetic`. Un borrador descartado se elimina y no deja nada en el dataset. Uno aceptado también desaparece de los borradores: la versión es su registro. Un borrador de chats parafrasea lo que alguien preguntó, así que solo lo lee y decide quien puede ver runs; el resto de quienes editan el dataset ve cuántos esperan. **El generador es un agent.** Es un agent de sistema creado en cada organización, así que sus runs cuentan contra su propio presupuesto y el de la organización, y cada generación es un run que puedes abrir en [Actividad](console.md). No tiene herramientas: todo lo que lee se reúne para él con tus propios permisos y se le entrega en el prompt, de modo que un documento o una conversación que intente darle instrucciones solo puede cambiar el texto de un borrador que tú revisas. Un borrador que no cumple la regla de su fuente (un caso de conocimiento sin un fragmento que se le mostró, un caso de conversación sin una pregunta que se le mostró, un caso de red team sin categoría, un caso que no espera nada, un caso cuya respuesta de referencia repite su contraejemplo y por tanto fallaría ella misma) se descarta antes de que lo veas. Lo mismo ocurre con un caso escrito en una forma que no se puede leer: el resto de la respuesta sigue convirtiéndose en borradores, y solo falla una respuesta sin ningún caso legible. Una generación terminada dice cuántos casos dejó fuera, los que no se pudieron leer aparte de los que incumplieron una regla. **Cada fuente tiene su propia barrera**, y una fuente que no puedes usar se rechaza por su nombre en lugar de omitirse en silencio: - toda generación necesita `datasets:edit` en el dataset, `agents:view` en el agent que se prueba y `agents:run` en el generador de casos, porque gasta el dinero de la organización; - el conocimiento solo lee las bases de conocimiento que puedes leer; el diálogo dice cuántas de las del agent se dejaron fuera; - las conversaciones necesitan `runs:view`, el permiso con el que Actividad lee cada run; Solo los miembros que pueden editar el dataset ven sus borradores. Un borrador tomado de una conversación es texto que los demás lectores del dataset no han visto; una vez aceptado, es un caso como cualquier otro. **Una generación es un job en segundo plano.** Se pone en cola con la petición que la inicia y sobrevive a un reinicio de la API o del worker. El worker redacta como la persona que la pidió, con el acceso que tenga en ese momento; una generación cuyo worker murió se marca como fallida, así que nada se queda esperándola para siempre. Una generación iniciada con una clave API conserva su identificador. Antes de leer las fuentes, el worker vuelve a comprobar los permisos actuales de la clave y la membresía de quien la emitió. Una clave restringida no obtiene acceso de consola; una clave revocada, caducada o eliminada detiene la generación con un error explícito. ### El conjunto de prueba de un agent { #agent-test-set } `POST /agents/{id}/test-set` crea un dataset privado del agent o añade respuestas recién valoradas al conjunto editable existente. Una valoración positiva crea una referencia; una negativa, un contraejemplo con el comentario como nota. Solo se leen conversaciones accesibles. Se conservan casos y configuración de calificación existentes. Un conjunto nuevo utiliza el modelo del agent para calificación, generación y mejora. El resultado indica expresamente si calificador y agent comparten modelo. Se elige otro modelo en Grading para una evaluación independiente; ni el precio ni una preferencia organizacional lo seleccionan. No se crea otro agent de usuario. El generador solicita preguntas hasta alcanzar cinco casos calificables o la cantidad `more`. Estos casos iniciales se aceptan automáticamente en una nueva versión. Menos de tres casos calificables se informa como insuficiente. `/test-set/estimate` estima la generación; ambas operaciones requieren `datasets:edit` y acceso al agent. ## Las credenciales se ocultan { #credentials } El texto de los casos se copia de conversaciones y de archivos que la gente sube, y después se exporta y se entrega a modelos. Antes de guardar un caso, la plataforma sustituye cualquier clave de API o token que reconoce por un marcador como `[redacted:github_token]`. Esto se aplica a cada campo que lee un modelo o que lleva una exportación, incluidos los argumentos de una llamada a herramienta esperada, y a cada forma de añadir un caso. La entrada de auditoría del cambio registra cuántos valores se ocultaron, nunca los valores. Una generación también oculta las credenciales de las preguntas y los fragmentos que entrega al generador, antes de que salgan hacia el modelo, y quita de las preguntas y los comentarios que escribió la gente los datos personales que encuentran los detectores - direcciones de correo, números de teléfono, de tarjeta y de cuenta -: un caso lo lee cualquiera que pueda leer su dataset. ## Calificación { #scoring } Un dataset indica cómo se califican sus casos en su pestaña **Settings**, en dos tarjetas que se guardan juntas: **When a case passes** contiene las comprobaciones y llamadas a herramientas esperadas; **Judge** define modelo y criterios. Todas las respuestas evaluadas aparecen en Results. Cuatro evaluadores pueden aplicarse a un caso, y cada uno se activa o desactiva y se marca como **Must pass** o no: | Evaluador | Qué compara | Coste | |---|---|---| | Comprobaciones | La respuesta con las reglas del caso, y con reglas por defecto que el dataset da a cada caso | Nada | | Llamadas a herramientas esperadas | Las herramientas que llamó el agent con las llamadas esperadas del caso | Nada | | Juez (**Your criteria** en la tarjeta Judge) | La respuesta con una rúbrica de criterios con nombre, calificada por el juez del dataset | Un run del juez | | Respuesta de referencia | La respuesta con la respuesta de referencia del caso, calificada por el juez del dataset | El mismo run del juez | Cada evaluador devuelve aprobado o suspendido, una puntuación de 0 a 1 y un motivo. Un caso **aprueba** cuando aprueba cada evaluador marcado como Must pass, y **suspende** cuando uno de ellos suspende. Cuando uno de ellos no llegó a un veredicto (el juez estaba desactivado, su budget se había agotado, su run falló o su respuesta no se pudo leer), el caso queda **sin calificar**: ni aprobado ni suspendido, porque nadie comprobó la respuesta. La puntuación dice por qué, y se puede [volver a puntuar](#judge) una vez resuelta la causa. Cada evaluador indica cuántos casos contienen lo que lee, y la pestaña avisa cuando la configuración en pantalla calificaría algunos casos sin nada que comprobar. A un dataset cuyos casos tienen respuestas de referencia con las que nada compara las respuestas se le ofrece la comparación con la respuesta de referencia. Una tarjeta con un cambio aún no guardado lo indica, una barra al pie de la pantalla guarda o descarta todos los cambios a la vez, y la página pregunta antes de salir de ella. La configuración no se versiona con los casos, porque cómo califica un equipo no es lo que pregunta. Cada puntuación guarda una copia de la configuración con la que se calculó, así que una puntuación anterior sigue diciendo cómo se obtuvo después de que cambie la configuración. Se rechaza una configuración que no podría puntuar nada: todos los evaluadores apagados, o el juez encendido sin ningún criterio. También la puntuación de un caso en el que ninguno de los evaluadores configurados tiene nada que comprobar: no se guarda nada y no se llama al juez. Por la API, `PUT /datasets/{id}/scoring` cambia solo los ajustes que nombra su cuerpo, a cualquier profundidad: uno omitido conserva su valor, y una lista dada (los criterios, las comprobaciones por defecto) sustituye entera a la guardada. El umbral de aprobado se comprueba contra la escala una vez fusionados, así que `{"judge": {"pass_at": 8}}` solo se lee sobre la escala guardada, y uno por encima de ella se rechaza nombrando `judge.pass_at`. ### Comprobaciones { #checks } | `type` | Parámetros | Aprueba cuando | |---|---|---| | `contains`, `not_contains` | `value`, opcionales `path`, `case_sensitive` | La respuesta contiene el valor, o no lo contiene | | `equals` | `value`, opcionales `path`, `case_sensitive` | La respuesta, sin espacios al principio ni al final, es el valor | | `regex` | `value` (como máximo 500 caracteres), opcionales `path`, `case_sensitive` | El patrón coincide en algún punto de la respuesta | | `json_schema` | `schema`, opcional `path` | La respuesta es JSON que cumple el JSON Schema | | `max_cost_usd` | `value` | El run no costó más que esto | | `max_latency_ms` | `value` | El run no tardó más que esto | | `length` | `unit` (`characters` o `words`), `min` y/o `max`, opcional `path` | La respuesta mide como mínimo `min` y como máximo `max` | | `judge` | `criterion` | El juez de evals califica el criterio en la nota de aprobado o por encima | `path` lee dentro de una respuesta que es JSON: `items.0.name` es el nombre del primer elemento. Sin él, una regla lee la respuesta entera. Las reglas de texto no distinguen mayúsculas de minúsculas salvo que `case_sensitive` sea true. Un patrón se comprueba al escribir el caso, y una regla lee como máximo los primeros 100.000 caracteres de una respuesta. Un patrón que tarda más de una décima de segundo en una respuesta se detiene y se registra como error, así que un patrón no puede bloquear la puntuación. Por la misma razón, un JSON Schema no puede usar `pattern` ni `patternProperties` (una comprobación `regex` con `path` hace lo mismo bajo el mismo límite de tiempo), y su `$ref` debe apuntar dentro del esquema. Una comprobación `length` cuenta como palabra cada secuencia de caracteres que no son espacios en blanco, y necesita al menos un límite. Una comprobación `judge` es un criterio solo para un caso, calificado en el mismo run del juez que la rúbrica del dataset. Úsala para lo que una regla no puede expresar, como "se niega y no revela la dirección del cliente". ### Llamadas a herramientas esperadas { #trajectory } Las llamadas del agent se comparan con las llamadas esperadas del caso por nombre de herramienta y por cada argumento que el caso indica. El modo de orden del caso decide qué aprueba: con `any`, se produjo cada llamada esperada; con `in_order`, se produjeron en el orden indicado; con `exact`, son las únicas llamadas y en ese orden. El motivo nombra lo que faltó, lo que no se esperaba o que el orden era distinto. Una escritura que un run aislado bloqueó sigue contando como una llamada que hizo el agent. Una llamada se compara por el nombre de herramienta que registró el run, que es el nombre después de cualquier sustitución en el spec. Un caso escrito antes de que se renombrara una herramienta espera el nombre antiguo. ### El juez { #judge } El calificador es un ayudante de evaluación definido en código. Su modelo, instrucciones, criterios, escala y umbral pertenecen a **Grading** de este dataset. El selector de provider, modelo y clave y el editor Markdown son los mismos que en Agent Builder. Editar requiere `datasets:edit`; añadir modelos, `connections:manage`. No hace falta crear ni publicar otro agent. Cada puntuación conserva modelo, identidad publicada del ayudante, hash de criterios, versión de tarea y hash de instrucciones. Se pueden cambiar modelo e instrucciones del dataset; las calificaciones de configuraciones distintas no son directamente comparables. El juez recibe la nota del caso, como el motivo por el que existe, sus turnos anteriores y la pregunta, la respuesta de referencia cuando se califica, el contraejemplo, cada llamada a herramienta que hizo el agent (con sus argumentos, y si un run aislado la bloqueó) y la respuesta. Un caso con contraejemplo se califica siempre también con un criterio obligatorio **counter-example**: la respuesta no debe repetir la respuesta mala conocida, y se pide al juez que cite lo que distingue la respuesta de ella. Se califica siempre que **Your criteria** o la respuesta de referencia está activado, así que no tiene un interruptor propio; la tarjeta Judge muestra cuántos casos tienen un contraejemplo. Un aprobado en el criterio counter-example es un error cuando solo cita lo que ambas dicen, o no cita nada de una respuesta que copia el contraejemplo; cualquier otro sin nada citado se mantiene, marcado como no verificado. Una respuesta que conserva el contraejemplo y añade lo que le faltaba aprueba con una cita de lo añadido. Una respuesta que es el contraejemplo, o una parte de él, suspende el criterio diga lo que diga el juez. Los jueces empiezan con temperatura 0, para que la misma respuesta se califique igual dos veces; un modelo que no acepta temperatura, como un modelo de razonamiento, califica sin ella. Cada criterio se califica de 1 al máximo de la escala y aprueba en la nota de aprobado o por encima. En cada criterio el juez cita el fragmento de la respuesta en que se basa su calificación y nombra la regla de la que se sigue. Una calificación cuyo motivo está hecho sobre todo de las palabras del propio criterio, sin una cita que la respuesta contenga, es un error: nada muestra que el juez leyera la respuesta. Una calificación máxima sin cita de la respuesta se mantiene, marcada como no verificada. Un juez califica con más consistencia una pregunta de sí o no, así que el editor de criterios sugiere formular cada criterio como una, y la escala del juez ofrece **Use yes/no grading**, una escala de 2 que aprueba en 2. Un criterio que una regla puede comprobar (una longitud, JSON válido, un comienzo entre comillas, una lista con viñetas) lo indica, y **Add the rule** añade esa comprobación a las que recibe cada caso, que no cuestan nada y califican igual cada vez. La sugerencia lee las propias palabras del criterio y no llama a ningún modelo. Cuando el juez no puede calificar, sus criterios se registran como omitidos o como errores, con un motivo que nombra la causa: el juez que eligió el dataset ya no existe, no tiene una versión publicada, está archivado, su modelo ya no existe o no tiene clave, la persona no puede ejecutarlo, su budget se ha agotado, su run falló o su respuesta no se pudo leer, de la que se guardan los primeros 2.000 caracteres junto al motivo. Los evaluadores basados en reglas siguen puntuando. Resuelta la causa, **Score again** en un resultado sin calificar (o en todos los de un grupo de un eval run en la vista Results → Review answers) vuelve a calificar la misma respuesta, con la configuración con la que se calificó la primera vez (`POST /datasets/{id}/scores/rescore`, hasta diez puntuaciones por petición). El agent no se vuelve a ejecutar, y la puntuación conserva su eval run y cualquier decisión que una persona tomara sobre ella; una en la que cada evaluador llegó a un veredicto se queda como está. Una causa que sigue ahí (el juez sin publicar) se rechaza tal cual, igual que el juez de un run de evaluación publicado de nuevo desde que falló, o una puntuación de ese run fijada a un prompt de juez anterior, cuya calificación no sería comparable con el resto del run; entonces no se califica nada. Una respuesta calificada por sí sola, desde el chat o desde Activity, no tiene un run con el que compararse: la califica la versión publicada ahora, y su pin nombra esa versión. Una puntuación se fija tanto si su juez calificó como si falló, así que una fallida queda atada a la versión y al prompt con los que falló. Una calificación puede citar la respuesta, hasta 12 fragmentos; una cita que la respuesta no contiene palabra por palabra (dejando aparte los espacios, el tipo de comillas y apóstrofos, y las comillas que rodean la cita y su puntuación final) se guarda junto a la calificación como no verificada, se muestra en su propia línea bajo el motivo, y la calificación se mantiene. Lo que respalda una calificación nunca la anula: una cita vacía o demasiado larga se descarta, las citas más allá de doce y una regla de más de 300 caracteres se recortan, y solo la falta de un identificador de criterio o de una nota hace ilegible un veredicto. Un criterio calificado más de una vez es un error, en lugar de la nota que llegó la última. El run del juez en Activity indica qué campos no se pudieron leer, nunca la respuesta, que puede repetir un caso de un dataset que quien lo lee no puede ver. Cada puntuación conserva modelo, identidad publicada del ayudante, hash de criterios, versión de tarea y hash de instrucciones. Se pueden cambiar modelo e instrucciones del dataset; las calificaciones de configuraciones distintas no son directamente comparables. ### Revisión { #review } Review presenta todas las respuestas evaluadas en una tabla con pregunta, agent, resultado, modelo, fecha y origen. Seleccionar una respuesta abre evidencia, calificación y decisión en un panel lateral. Guardar mantiene el panel abierto y la fila en su lugar; se puede retirar o deshacer una decisión. Si cambia una máscara de privacidad del servidor, se descartan el panel y la nota sin guardar. Una puntuación espera en la **cola de revisión** cuando alguien la envía allí, o lo hace un run de eval. Tras volver a ejecutar lo que cambió, un run de eval envía las regresiones que confirmó y las respuestas en las que el juez falló con un error (no las que omitió, que esperan a volver a puntuarse): una puntuación por caso y agent. Su página envía otras puntuaciones que elijas, todas a la vez mediante `POST /datasets/{id}/scores/review` con hasta 500 identificadores de puntuación: todas o ninguna. Las respuestas de cada agent a un caso esperan por separado: una puntuación enviada allí, por un run de eval o a mano, ocupa el lugar de una de su caso y agent que aún espera cuando tiene más rango, o el mismo y es más reciente, y la puntuación de otro agent para el caso espera a su lado. Una puntuación calificada (una regresión, o un fail enviado a mano) tiene más rango que una que nada calificó, como un error del juez, así que un juez que falla en un caso nunca saca su regresión de la cola. La sustituida sale de la cola sin decidir y sigue siendo una puntuación; si no, la que espera conserva su lugar y la enviada no entra en la cola. Una puntuación decidida nunca se toca. Una puntuación pedida a mano desde Activity sigue el ajuste **Review by a person** del dataset: nada hasta que alguien envíe una, cada resultado que no aprobó, o cada resultado. Una puntuación ya decidida sigue decidida. Esa puntuación, y una cuya decisión se deshace, pasan por la misma sustitución, así que un caso nunca espera dos veces por un mismo agent. La vista **Results → Review answers** muestra todos los resultados, incluidos los ya revisados. Se filtra por resultado, agent o etiqueta del caso; el estado de revisión no divide la lista. Cada fila enlaza al run de eval cuando los permisos lo permiten. Las acciones sobre la tabla permiten evaluar de nuevo respuestas sin calificar o retirar las pendientes de la cola (`POST /datasets/{id}/scores/review/withdraw`). Cada tarjeta muestra lo que el caso preguntaba y esperaba (la pregunta, enlazada al caso, la respuesta de referencia, las llamadas a herramientas esperadas y las comprobaciones), la respuesta tal como se calificó, qué agent y qué versión respondieron (con un aviso cuando el juez calificó con el modelo que respondió, porque un juez puede favorecer respuestas como las suyas), qué encontró cada evaluador y por qué, primero los que fallaron, y la decisión de revisión, que se puede deshacer desde el mensaje que la confirma. La nota que acompaña a una decisión suele ser la regla que el juez pasó por alto, así que la tarjeta ofrece convertirla en un criterio del juez: solo para ese caso, como una comprobación `judge` en una nueva versión del dataset, o para todos los casos, en la rúbrica, lo que activa el juez. La tarjeta del dashboard **Waiting for review** muestra la cola de todos los datasets que puedes ver: cuántos resultados no aprobaron, no se calificaron o aprobaron, y en qué datasets, cada uno abriéndose en su vista Results → Review answers. La tarjeta está en el panel por defecto. Su **See all** abre la vista Results → Review answers del dataset que más tiene esperando. La decisión de revisión de una persona se guarda junto a los resultados de los evaluadores y decide el resultado final. Nunca cambia lo que dijo el juez: las calificaciones y los motivos del juez se quedan en la puntuación después de que se anule. Una decisión se puede retirar, y la puntuación vuelve entonces a esperar revisión. ### Puntuar un run { #scoring-a-run } En **Activity**, abre un run, abre su menú **⋯** y elige **Score against a case**. El diálogo se abre en un dataset con un caso que hace la misma pregunta que el run, y elige ese caso; cuando varios datasets tienen uno, lo dice y los muestra primero. Cuando el dataset elegido no tiene ninguno, el diálogo ofrece añadir la respuesta del run como caso hasta que eliges uno, y muestra primero los casos más cercanos a la pregunta del run (los que comparten más palabras con ella, en la página mostrada). La respuesta y las llamadas a herramientas del run se califican con cada evaluador que configura el dataset. Un run sin transcripción no tiene respuesta que calificar. El diálogo nombra al juez que calificará y el modelo en el que califica, con enlaces para cambiar el juez del dataset en su pestaña Settings y el modelo del juez en su página: ambos cambios se aplican a cada respuesta calificada después, así que ninguno se hace desde el diálogo. | Para | Necesitas | |---|---| | Cambiar cómo se califica un dataset | `datasets:edit` sobre él | | Crear un juez para él | `datasets:edit` sobre él, y `agents:edit` | | Puntuar un run contra él | `datasets:run` sobre él, y `runs:view` | | Leer sus puntuaciones | `datasets:view` sobre él | | Enviar puntuaciones a revisión, registrar o retirar una decisión | `datasets:edit` sobre él | Un motivo que escribió el juez pasa por la misma ocultación de credenciales que un caso antes de guardarse. Para que un agent responda a todos los casos de una versión, se puntúe cada respuesta de una vez y el resultado se compare con una versión anterior, inicia un [eval run](evals.md). ## Acceso { #access } Un dataset es un recurso compartido con un propietario, una visibilidad y grants, como un [skill](skills.md) o un [archivo de contexto](context.md). Un dataset nuevo lo ve toda la organización, salvo que quien lo crea lo empiece como privado; después se cambia desde su página. El catálogo tiene tres permisos para datasets: | Permiso | Permite a un miembro | Nivel de grant que lo da | |---|---|---| | `datasets:view` | Leer los casos y versiones de un dataset y exportarlos | `read` | | `datasets:edit` | Crear datasets, cambiar casos, importar, eliminar, compartir | `edit` | | `datasets:run` | Ejecutar evals sobre un dataset, con `runs:view` | `use` (ya no se ofrece, ver abajo) | | | Owner | Admin | Builder | Operator | Member | Viewer | |---|---|---|---|---|---|---| | `datasets:view` | all | all | all | all | shared | shared | | `datasets:edit` | all | all | shared | - | own | - | | `datasets:run` | all | all | all | all | shared | - | Iniciar un eval requiere antes que nada `runs:view`: un run se paga, y quien no puede leerlo no puede iniciarlo. Todo rol integrado que lee runs ya tiene `datasets:run` en toda la organización, y un Member, cuyo `datasets:run` alcanza solo los datasets compartidos, no lee runs. Un grant `use` sobre un dataset no permitiría a nadie iniciar un eval que no podría iniciar sin él, así que compartir un dataset ofrece solo ver y editar; `use` volverá con los roles personalizados. Un grant `use` creado antes se mantiene y no hace nada, y su fila lo indica y permite eliminarlo. Quien puede ejecutar un dataset pero no leer runs ve Run evals desactivado en su página, con el aviso de que hace falta leer runs; a quien no puede ejecutarlo en absoluto no se le ofrece. Consulta [Eval runs](evals.md#access). Un miembro sin acceso a un dataset recibe "no encontrado" en cada ruta, sea lo que sea lo que su rol permita en otros sitios: si un dataset privado existe es algo que no debe saber. Un grant amplía el acceso a un dataset y nunca cambia un rol. Consulta [Permisos](permissions.md) para ver cómo se combinan los ámbitos y los grants. El texto de un caso copiado de una conversación solo es visible para lectores con `runs:view` o acceso a la conversación original. Los demás ven metadatos y un marcador, tanto en versiones actuales e históricas como en exportaciones CSV/JSONL. Si falta la fuente, el texto sigue oculto. No se puede editar texto oculto ni revelarlo al cambiar metadatos. Las evaluaciones siguen ejecutando la revisión completa almacenada. Las respuestas, notas de Review y pruebas de evaluación requieren `runs:view` y acceso al agente que respondió. Si falta alguno, se conservan el resultado y el estado, pero se eliminan el texto de respuesta, motivos, reglas y citas. Antes de copiar la conversación privada de otra persona, el diálogo identifica a su propietario y avisa de que los lectores del dataset que puedan leer runs verán su texto. ## Datos personales { #personal-data } Un caso tomado de una conversación es una copia de lo que escribió una persona y de lo que respondió el agent. Cuando se borra la conversación, el caso se queda y se elimina todo vínculo con la conversación: el run, la conversación y el mensaje de los que procede. El texto se queda, y puede seguir conteniendo datos personales que alguien escribió. Eliminar el caso lo elimina. Cuando se borra a la persona que hizo la pregunta de un caso, el texto también se va. La pregunta, los turnos anteriores, ambas respuestas y la nota se sustituyen en todas las versiones que contienen el caso, y también las respuestas y llamadas que los eval runs registraron para él. El caso conserva su id, sus llamadas esperadas, sus comprobaciones y sus etiquetas, y se marca como anonimizado tras el borrado (**Anonymised after erasure**), para que su curador pueda reescribirlo o eliminarlo. Hasta entonces un eval run lo deja fuera, porque una respuesta al texto de sustitución no mide nada. Un caso guarda de quién son las palabras que contiene: quién hizo su pregunta, quién escribió cada uno de sus turnos anteriores y de quién es el comentario que se convirtió en su nota. Esto nunca se muestra ni se exporta, y sobrevive a la conversación, así que un borrado sigue encontrando el caso después de que se borrara la conversación de la que procede. Un caso cuya pregunta hizo otra persona conserva su pregunta y su respuesta: los turnos de la persona borrada en su historial anterior se sustituyen, con las respuestas del agent a ellos, y su comentario guardado como nota se vacía. Un caso escrito antes de que se guardara la autoría la tiene completada a partir de los vínculos que aún conservaba; uno cuya conversación ya no existía no tiene ninguna, y solo eliminar el caso elimina su texto. Consulta [Protección de datos](data-protection.md#what-deletion-reaches). Una puntuación se conserva de la misma forma. Guarda una copia de la respuesta que calificó, hasta 8.000 caracteres con las credenciales ocultadas, para que quien revisa la lea junto al caso. Esa copia vuelve en la exportación de la persona de cuyo run se trata, y se borra cuando se borra a esa persona. Cuando se elimina el run que puntuó, la puntuación se queda sin el vínculo con él, y cuando se borra a la persona que la pidió o la decidió, su nombre se quita de ella. El motivo de un juez puede citar la respuesta que calificó. Un caso generado que aún espera una decisión no se conserva así. Cuando se borra la conversación de la que se redactó, o se borra a la persona que hizo la pregunta, el borrador se elimina con ella: nadie decidió conservarlo. La exportación de datos de una persona incluye los borradores tomados de sus preguntas y conversaciones. Generar desde conversaciones envía las preguntas que hizo la gente, con las credenciales ocultas, al provider del modelo del generador de casos, y generar desde el conocimiento envía fragmentos de los documentos; consulta [qué sale del deployment](data-protection.md#what-leaves-the-deployment).