Entidadactivecreado Mon Apr 27#workspace#d1#cloudflare#ai-evaluation#gemini#openrouter#database#gemini-lite-migration
Tabla D1: ai_eval_runs — Histórico de Evaluaciones de Modelos IA
Resumen
Tabla D1 del Workspace de CreaRack que persiste el histórico de ejecuciones de la Tool AI Eval. Introducida en la migración 0016 (2026-04-27) como parte del cierre de la Fase 4 del plan Gemini Lite Migration.
⚠️ Invariante de seguridad: las API keys de Gemini/OpenRouter NUNCA se almacenan en esta tabla. Solo se persisten identificadores de modelos, prompts, respuestas y metadatos de timing.
DDL
-- migrations/0016_create_ai_eval_runs.sql
CREATE TABLE IF NOT EXISTS ai_eval_runs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
user_email TEXT, -- CF Access email (informacional)
candidates TEXT NOT NULL, -- JSON: [{model, provider, label?}]
cases TEXT NOT NULL, -- JSON: [{name, prompt, has_image, ...}]
results TEXT NOT NULL, -- JSON: {[caseName]: {[model]: CellResult}}
total_cells INTEGER NOT NULL, -- candidates.length × cases.length
duration_ms INTEGER NOT NULL, -- wall-clock total del run
status TEXT NOT NULL DEFAULT 'completed'
CHECK (status IN ('completed','partial','failed')),
notes TEXT -- anotación libre del usuario
);
CREATE INDEX IF NOT EXISTS idx_ai_eval_runs_created ON ai_eval_runs(created_at);
CREATE INDEX IF NOT EXISTS idx_ai_eval_runs_user ON ai_eval_runs(user_email, created_at);
Esquema de columnas
| Columna | Tipo | Nullable | Descripción |
|---|---|---|---|
id | INTEGER PK AUTOINCREMENT | No | Identificador único del run |
created_at | TEXT (ISO 8601) | No | Timestamp UTC de inserción |
user_email | TEXT | Sí | Email Cloudflare Access del ejecutor (solo informacional) |
candidates | TEXT (JSON) | No | Array de modelos evaluados: [{provider, model, label?}] |
cases | TEXT (JSON) | No | Array de casos: [{name, prompt, system_instruction?, temperature?, max_tokens?, response_json?, has_image}] — image_b64 nunca se persiste |
results | TEXT (JSON) | No | Matriz resultado: {caseName → {modelKey → {answer, latency_ms, tokens_in?, tokens_out?, error?}}} |
total_cells | INTEGER | No | candidates.length × cases.length (cap: 25) |
duration_ms | INTEGER | No | Tiempo total de ejecución del run completo |
status | TEXT | No | completed | partial | failed |
notes | TEXT | Sí | Anotación libre introducida por el usuario en la UI |
Tipado JSON interno
candidates (array)
[
{ "provider": "gemini", "model": "gemini-2.0-flash-lite", "label": "Flash Lite" },
{ "provider": "openrouter", "model": "anthropic/claude-3-haiku" }
]
cases (array, versión almacenada)
[
{
"name": "mib_classify",
"prompt": "...",
"system_instruction": "...",
"temperature": 0.1,
"max_tokens": 8192,
"response_json": true,
"has_image": false
}
]
El campo
image_b64del request original se sustituye porhas_image: booleanen la versión almacenada.
results (objeto)
{
"mib_classify": {
"gemini:gemini-2.0-flash": {
"answer": "{ \"device_type\": \"access_point\", ... }",
"latency_ms": 1142,
"tokens_in": 890,
"tokens_out": 412
},
"openrouter:anthropic/claude-3-haiku": {
"answer": "",
"latency_ms": 3201,
"error": "Rate limit exceeded"
}
}
}
Índices
| Nombre | Columnas | Uso |
|---|---|---|
idx_ai_eval_runs_created | created_at | Paginación por fecha DESC (endpoint history) |
idx_ai_eval_runs_user | (user_email, created_at) | Filtros por usuario (uso futuro) |
Acceso desde endpoints
| Endpoint | Operación | Notas |
|---|---|---|
POST /api/tools/ai-eval/run | INSERT | Fallo D1 no rompe la respuesta al cliente (degradación graceful) |
GET /api/tools/ai-eval/history | SELECT paginado | Sin ?id: omite columna results en el listado para reducir payload |
GET /api/tools/ai-eval/history?id=N | SELECT por PK | Incluye results completos |
Consideraciones de crecimiento
- Cada run puede persistir hasta 25 celdas con respuestas completas. Con prompts MIB largos, cada fila puede pesar ~100-300 KB en
results. - No hay TTL ni política de purga automática en v0. Si el volumen crece, considerar
DELETE FROM ai_eval_runs WHERE created_at < datetime('now', '-90 days')vía cron Worker. - D1 tiene límite de 10 GB por base de datos en plan Workers Paid.
Véase también
- [[feature—workspace—ai-eval]]
- [[concept—general—que-paginas-wiki-existen-sobre-cloudflare-pages-fu]]