A newer version of the Gradio SDK is available: 6.20.0
license: apache-2.0
language:
- es
tags:
- agent-trace
- conversational
- education
- spanish
- build-small-hackathon
pretty_name: Sofía — Agent Trace
size_categories:
- n<1K
Open Trace — Sofía (mérito 5, "Sharing is Caring")
TL;DR (EN): 12 end-to-end turns of the real Sofía pipeline (intent router →
curated content from content/ → safety guard → small fine-tuned LLM), captured
as JSONL with the exact prompt sent to the model at each step. Shows the LLM is
a small, replaceable "conversational glue" component, not the source of facts —
including a turn where the model refuses to invent a story and offers curated
content instead, and a turn blocked entirely before reaching the LLM. Part of the
sofia-educational-companion
project (Build Small Hackathon, track Backyard AI).
agent_trace.jsonl son 12 turnos representativos corridos contra el pipeline
real (safety.guard + llm.engine.LumiEngine + content.loader.ContentLibrary),
generados con export_trace.py. Cada línea es un turno completo, de punta a punta.
Objetivo: que se vea, con datos reales, lo que dice el "Principio inviolable" de
CLAUDE.md: el LLM es solo el pegamento conversacional dentro
de un pipeline mayormente determinista (router de intención → contenido curado de
content/ → guard de seguridad). El modelo nunca es la fuente de hechos, cuentos
ni números.
Formato (JSONL, un turno por línea)
| campo | qué es |
|---|---|
turn |
número de turno (1-12) |
child_age |
edad simulada (3) |
user_message |
lo que "dice" la niña |
safety_input_blocked |
true si safety.guard.blocks_input frenó el mensaje antes de llegar al motor |
intent |
intención detectada por el router (llm/engine.py:_intent); null si se bloqueó en la entrada |
prompt_messages |
los messages exactos que recibe el LLM: system (persona de Sofía) + historial + bloques <contenido>/<contexto>/<nota> armados por LumiEngine.respond; null si se bloqueó en la entrada |
activity |
la actividad curada elegida de content/ (si aplica), con su id, title y script |
reply |
la respuesta final que recibiría la niña |
safety_output_blocked |
true si safety.guard.blocks_output reemplazó la respuesta por el fallback |
Turnos destacados
- Turno 10 (
"¿Qué es una pistola?"):safety_input_blocked: true,prompt_messages: null. El mensaje ni llega al LLM: lo frenasafety.guard.blocks_inputy respondegentle_redirect(). - Turno 11 (
"Contame un cuento de un dragón que come autos"): no existe ese cuento encontent/stories.json. El modelo no inventa —LumiEngineelige otro cuento curado existente ("La tortuguita paciente") y el LLM solo lo presenta, con una<nota>que le prohíbe inventar contenido. - Turnos 3-9: cada
<contenido>es texto literal decontent/(conteo, formas, colores, animales, canción, emoción, cambio de color); el LLM reformula/celebra pero los datos vienen del JSON curado.
Cómo se generó
LUMI_LLM_BACKEND=ollama python trace/export_trace.py
Corre contra Ollama (qwen2.5:7b) en local, usando el mismo SYSTEM_PROMPT y
los mismos bloques <contenido>/<contexto>/<nota> que arma llm/engine.py
en producción (Qwen2.5-7B-Instruct fine-tuneado vía ZeroGPU). Usa un SQLite
temporal para el historial conversacional — no toca parental/lumi.db.