Traza, evalúa y mejora agentes de IA desde la terminal
Project description
treval ⚡
Traza, evalúa y mejora agentes de IA desde la terminal.
Treval es un framework de observabilidad y evaluación para agentes de IA. Con una línea (import treval; treval.instrument()) obtienes trazado completo de cada llamada LLM, tool y operación. Además: evaluación LLM-as-judge, comparación multi-modelo con estadísticas, costes desde API, replay de spans, tests nativos para agentes, dashboard web, exportación OpenTelemetry y reportes HTML standalone.
Instalación
git clone <tu-repo>
cd treval
python -m venv .venv
source .venv/bin/activate
pip install -e .
**Dependencias:** `openai`, `rich` (el resto son stdlib de Python 3.11+).
Necesitas una API key de [OpenRouter](https://openrouter.ai/keys) (o de OpenAI si usas OpenAI directo).
```bash
# En tu ~/.bashrc o antes de ejecutar treval
export OPENROUTER_API_KEY=sk-or-v1-...
# Verificar instalación
treval --help # 15 comandos disponibles
treval prices # Precios actualizados de OpenRouter
Trazado básico
Auto-instrumentación (una línea)
import treval
treval.instrument() # Parchea OpenAI sync/async → spans LLM automáticos
# A partir de aquí, TODAS las llamadas a OpenAI se trazan solas
Decorador @agent
from treval import agent, operation, tool
@agent(name="WeatherBot")
class WeatherAgent:
def __init__(self, api_key: str):
from openai import OpenAI
# OpenRouter como provider por defecto
self.client = OpenAI(api_key=api_key, base_url="https://openrouter.ai/api/v1")
@operation
def get_forecast(self, city: str) -> str:
"""Cada llamada @operation se registra como span hijo del agente."""
return self._call_llm(f"clima en {city}")
@operation(name="call_llm")
def _call_llm(self, prompt: str) -> str:
"""Las llamadas LLM via OpenAI se trazan solas si llamaste instrument()."""
resp = self.client.chat.completions.create(
model="deepseek/deepseek-v4-flash",
messages=[{"role": "user", "content": prompt}],
)
return resp.choices[0].message.content
Decorador @tool
@tool(name="get_weather")
def get_weather(city: str) -> str:
"""Cada tool se registra como span TOOL."""
return f"28°C, soleado en {city}"
Ver spans
treval spans # Lista los 20 spans más recientes
treval spans -t LLM # Solo spans LLM
treval spans -l 50 # 50 spans
treval span 42 # Detalle completo de un span (input, output, hijos)
treval metrics # Métricas agregadas por tipo
treval count # Total de spans almacenados
treval clear # Borra todos los spans
Los spans tienen 4 tipos, representados como badges de colores en el dashboard:
| Tipo | Color | Significado |
|---|---|---|
| AGENT | 🔵 Azul | Instancia completa de un agente |
| OPERATION | 🟢 Verde | Operación dentro del agente |
| TOOL | 🟡 Amarillo | Tool o función ejecutada |
| LLM | 🟣 Púrpura | Llamada a modelo de lenguaje |
Los spans se organizan en jerarquía padre → hijo automáticamente mediante parent_id.
Evaluación LLM-as-judge
# Evaluar spans recientes con DeepSeek como juez
treval eval # Default: correctness
treval eval -c conciseness # Concisión
treval eval -c helpfulness # Utilidad
treval eval -t LLM -c correctness # Solo spans LLM
treval evals # Historial de evaluaciones
También desde Python:
from treval import LLMEvaluator, EvalStore
evaluator = LLMEvaluator(
model="deepseek/deepseek-v4-flash",
criteria="La respuesta debe ser correcta y útil",
)
results = evaluator.evaluate(spans)
store = EvalStore()
store.save(results[0])
stats = store.get_stats() # media, min, max
El juez usa un parser JSON tolerante que maneja JSON mal formado (strings sin cerrar, markdown, texto extra). Si falla, reintenta automáticamente hasta 2 veces.
Comparación de modelos (treval compare)
Compara N modelos sobre el mismo prompt, cada uno ejecutado M veces, con estadísticas (media σ) y costes reales desde la API de OpenRouter.
# 2 modelos, 3 ejecuciones cada uno
treval compare \
-p "Explica la diferencia entre CNN y Transformer" \
-m deepseek/deepseek-v4-flash,deepseek/deepseek-v4-pro \
-r 3
# 4 modelos, 5 ejecuciones, exportar a HTML
treval compare \
-p "¿qué es el fine-tuning?" \
-m deepseek/deepseek-v4-flash,deepseek/deepseek-v4-pro,anthropic/claude-sonnet-4,xiaomi/mimo-v2.5-pro \
-r 5 \
-o comparacion.html
# Con criterio personalizado
treval compare -p "resume esto" -m m1,m2 -c conciseness
Output en terminal: tabla con #, modelo, score medio, σ, duración, coste/ejec, tokens, runs. Ganador marcado con 🏆.
HTML exportado incluye:
- Banner del ganador con score
- Tabla resumen ordenable
- Detalle por modelo con cada run individual
- Output expandible por run
- Árbol de trazas (modo agente): jerarquía completa de spans con tipos coloreados
Modo agente
Compara ejecuciones completas de un script de agente que esté instrumentado con treval:
treval compare --agent "python mi_agente.py 'pregunta'" -r 5 -o agentes.html
Cada ejecución:
- Corre el script como subprocess
- Captura stdout (como output)
- Lee los spans nuevos que el agente guardó en la BD
- Evalúa el output con LLM-as-judge
- Renderiza el árbol jerárquico de trazas en el HTML
Replay (treval replay)
Re-ejecuta un span guardado cambiando modelo, temperatura o input:
treval replay 42 # Re-ejecutar con mismos params
treval replay 42 --model anthropic/claude-sonnet-4 # Cambiar modelo
treval replay 42 --input "nueva pregunta" # Cambiar input
treval replay 42 --temperature 0.5 # Cambiar temperatura
Muestra tabla comparativa: output original vs nuevo, duración, y uso de tokens.
Testing de agentes
Define tests para agentes usando LLM-as-judge:
# tests/test_mi_agente.py
from treval.testing import case, TestSuite
suite = TestSuite(name="WeatherTests")
@case(suite,
input="qué clima hace en Madrid?",
criteria="La respuesta debe mencionar el clima de Madrid")
def test_madrid(response: str) -> None:
assert "Madrid" in response
assert "28" in response or "soleado" in response
treval test run tests/test_mi_agente.py
Cada test ejecuta el agente, evalúa el output con LLM-as-judge, y muestra ✅/❌ con score y razón.
Dashboard
treval dashboard # Servidor web en http://127.0.0.1:8080
treval dashboard --port 3000 # Puerto personalizado
treval dashboard --no-open # Sin abrir navegador
treval dashboard --export reporte.html # HTML standalone (funciona desde file://)
El dashboard exportado es 100% standalone (sin servidor), responsive, con:
- Stats (total, agentes, operaciones, tools, LLMs, errores)
- Tabla ordenable por cualquier columna
- Panel de detalle con input/output y jerarquía de hijos
- Barras de duración codificadas por color
- Leyenda de tipos de span
- Diseño dark mode mobile-friendly
Gateway proxy
Intercepta tráfico LLM para trazarlo sin modificar código:
treval gateway # Proxy en :9090 → OpenRouter
treval gateway --port 9090 --upstream openai # → OpenAI
Útil para agentes que no puedes modificar: apunta sus llamadas al gateway y treval registra todo.
Exportación OpenTelemetry
treval export --console # Exporta spans a consola (formato OTEL)
treval export --endpoint http://localhost:4317 # Envía a collector OTEL
Comparación A/B (legacy)
treval ab "mi pregunta" --model-a flash --model-b pro
Comparación simple de 2 modelos sobre el mismo input. Recomendado usar treval compare para 2+ modelos con estadísticas.
Precios en tiempo real (treval prices)
Obtiene los precios actualizados de OpenRouter API automáticamente, sin hardcode:
treval prices # Todos los modelos disponibles
treval prices --search flash # Filtra por nombre
treval prices --search deepseek # Solo modelos DeepSeek
treval prices --search xiaomi # Solo Xiaomi MiMo
Los precios se cachean 1 hora en memoria. Si la API no responde, se usa un fallback local con ~20 modelos comunes. Los costes en treval compare usan estos precios automáticamente.
API pública (Python)
import treval
# Decoradores
treval.instrument() # Auto-instrumentación OpenAI
treval.agent # @treval.agent — marca una clase como agente
treval.operation # @treval.operation — marca un método como operación
treval.tool # @treval.tool — marca una función como tool
treval.wrap(client) # Envuelve un cliente OpenAI ya existente
treval.wrap_anthropic(client) # Envuelve un cliente Anthropic ya existente
# Evaluación
treval.LLMEvaluator # Evaluador LLM-as-judge
treval.EvalStore # Almacén de evaluaciones en SQLite
# Callbacks
treval.trace # Callback de trazado
treval.on_tool_start / on_tool_end
treval.on_llm_start / on_llm_end
# Comparación (desde Python)
from treval.compare import compare_models, compare_agents, build_report_html
results = compare_models(prompt="...", models=["m1", "m2"], runs=3)
html = build_report_html(results, prompt="...", criteria="correctness")
Demo: Agente ReAct
export OPENROUTER_API_KEY=sk-or-...
cd py
python demo_react.py "qué clima hace en Madrid?"
python demo_react.py "3 * 7 + 12"
python demo_react.py "cuál es la capital de España?"
Demo funcional de un agente ReAct con 3 tools (clima, calculadora, búsqueda) instrumentado con treval. Después de ejecutarlo:
treval spans # Ver todos los spans generados
treval span 1 # Detalle del agente
treval eval # Evaluar con LLM-as-judge
Comandos (13)
| Comando | Descripción |
|---|---|
treval spans |
Lista spans recientes (filtro por tipo) |
treval span <id> |
Detalle de un span con hijos |
treval count |
Total de spans almacenados |
treval clear |
Borra todos los spans |
treval eval |
Evalúa spans con LLM-as-judge |
treval evals |
Historial de evaluaciones |
treval compare |
Compara N modelos × M ejecuciones |
treval ab |
Comparación A/B simple (legacy) |
treval replay <id> |
Re-ejecuta un span con nuevos params |
treval test run <file> |
Ejecuta tests de agente |
treval dashboard |
Dashboard web / export HTML |
treval metrics |
Métricas agregadas |
treval prices |
Precios de OpenRouter API |
treval export |
Exporta spans a OTEL |
treval gateway |
Proxy para interceptar tráfico LLM |
Almacenamiento
Todo se guarda localmente en ~/.treval/:
~/.treval/
├── spans.db # Trazas (spans con jerarquía padre→hijo)
└── evals.db # Evaluaciones LLM-as-judge
SQLite, thread-safe, sin servidor. Puedes borrar los archivos en cualquier momento o usar treval clear (solo borra spans; las evaluaciones están en evals.db aparte).
Arquitectura
treval/
├── py/
│ ├── treval/
│ │ ├── __init__.py # API pública (decoradores + instrument + eval)
│ │ ├── agent.py # @agent — decorador para clases agente
│ │ ├── operation.py # @operation — decorador para métodos
│ │ ├── tool.py # @tool — decorador para funciones
│ │ ├── instrument.py # Auto-instrumentación OpenAI sync/async
│ │ ├── wrap.py # Wrappers para clientes existentes
│ │ ├── context.py # Stack thread-local de span_ids
│ │ ├── db.py # SQLite local (~/.treval/spans.db)
│ │ ├── eval.py # LLM-as-judge (parser JSON tolerante) + EvalStore
│ │ ├── compare.py # Comparación multi-modelo + agente + HTML report
│ │ ├── replay.py # Re-ejecutar spans con params modificados
│ │ ├── testing.py # TestRunner nativo con @case y TestSuite
│ │ ├── callbacks.py # Callbacks de trazado (LangChain compatible)
│ │ ├── otel.py # Exportador OpenTelemetry
│ │ ├── gateway.py # Proxy HTTP para interceptar tráfico LLM
│ │ ├── dashboard.py # Dashboard web + export HTML standalone
│ │ └── cli.py # CLI con Rich (13 comandos)
│ ├── tests/ # 88 tests, todos pasando
│ └── demo_react.py # Demo: agente ReAct funcional con 3 tools
├── ts/ # Esqueleto TypeScript (futuro)
└── pyproject.toml # Configuración del paquete
Flujo de datos
LLM call
│
├─ instrument() parchea OpenAI → span LLM guardado en SpanStore
├─ @agent / @operation / @tool → span AGENT/OPERATION/TOOL
│
▼
SpanStore (SQLite) ─→ CLI (treval spans / span / metrics)
─→ Dashboard (localhost:8080 o HTML standalone)
─→ LLM-as-judge → EvalStore
─→ compare_models() → HTML report con stats y costes
─→ OTEL export (console o collector)
─→ Replay (re-ejecutar con nuevos params)
Tests
cd py
python -m pytest tests/ -v
88 tests, todos pasando. Desarrollo con TDD estricto: cada feature nueva empieza con un test en ROJO, luego implementación en VERDE, luego refactor.
Cobertura: decoradores (@agent, @operation, @tool), auto-instrumentación, almacenamiento, evaluación, comparación (modelos + agente + precios API), replay, testing, generación HTML, parser JSON tolerante.
Licencia
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file treval-0.2.0.tar.gz.
File metadata
- Download URL: treval-0.2.0.tar.gz
- Upload date:
- Size: 69.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
07d0c2ca5510dd8544069347d22de40849707eab0eb81764489a89560e01a99e
|
|
| MD5 |
f21ca36bc7efa0e630da771a4d36a56b
|
|
| BLAKE2b-256 |
09de80e01771cd07e3007cfc41730bbccc6e5c13ac41025198eca7fc7b84bfa3
|
File details
Details for the file treval-0.2.0-py3-none-any.whl.
File metadata
- Download URL: treval-0.2.0-py3-none-any.whl
- Upload date:
- Size: 78.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
013cd71dbcfca3c2a6ccd0219507738dab87ba49cad5c01aa75ca700b46b7446
|
|
| MD5 |
83f5a1afd7b3c2c292371ea8a8e7cb00
|
|
| BLAKE2b-256 |
a3abe8447e007c3b8e3760b20d0b189ff105d231bd1c1740dbb79aea0377813f
|