Skip to main content

Traza, evalúa y mejora agentes de IA desde la terminal

Project description

treval ⚡

treval logo

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:

  1. Corre el script como subprocess
  2. Captura stdout (como output)
  3. Lee los spans nuevos que el agente guardó en la BD
  4. Evalúa el output con LLM-as-judge
  5. 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

treval-0.2.0.tar.gz (69.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

treval-0.2.0-py3-none-any.whl (78.1 kB view details)

Uploaded Python 3

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

Hashes for treval-0.2.0.tar.gz
Algorithm Hash digest
SHA256 07d0c2ca5510dd8544069347d22de40849707eab0eb81764489a89560e01a99e
MD5 f21ca36bc7efa0e630da771a4d36a56b
BLAKE2b-256 09de80e01771cd07e3007cfc41730bbccc6e5c13ac41025198eca7fc7b84bfa3

See more details on using hashes here.

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

Hashes for treval-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 013cd71dbcfca3c2a6ccd0219507738dab87ba49cad5c01aa75ca700b46b7446
MD5 83f5a1afd7b3c2c292371ea8a8e7cb00
BLAKE2b-256 a3abe8447e007c3b8e3760b20d0b189ff105d231bd1c1740dbb79aea0377813f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page