Canalización de evaluación
El arnés de evaluación lee un conjunto de datos golden JSONL fijado, ejecuta cada caso de extremo a extremo a través del mismo agente LangGraph compilado que usa la ruta de producción (construye el grafo una vez por ejecución, con HITL desactivado), despacha cada estado final del agente a un conjunto componible de puntuadores y emite tanto un resumen en markdown como un artefacto JSON. La barrera de CI consume el artefacto JSON; una falla determinista por caso o una violación de umbral del corpus respaldada por un juez produce un código de salida distinto de cero y hace fallar la verificación del PR.
La ejecución por defecto del runner usa dos grupos de puntuadores:
- Puntuadores deterministas siempre activos (sin LLM, sin clave requerida)
condicionan cada PR:
CitationCoverageScorer,CitationCorrectnessScorer,RefusalCorrectnessScorer,EscalationCorrectnessScoreryRetrievalRecallScorer. - Los puntuadores respaldados por un juez se adjuntan solo cuando se suministra
un cliente juez (se configura una clave de API de Anthropic):
GroundednessScoreryFaithfulnessScorer(puntuadores de rúbrica víaLLMAsJudgedirectamente) yHallucinationScorer(víaHallucinationMetricde DeepEval). Sin una clave de juez, la ejecución reporta el juez como deshabilitado y la barrera de umbral se ejecuta solo contra los puntuadores deterministas. El modelo juez es Anthropicclaude-haiku-4-5.
Consulta ADR-0003 para la política de umbrales y la elección del modelo juez.
Una compuerta de calibración aparte verifica al propio juez. Sobre un segmento reservado etiquetado por humanos mide el acuerdo por dimensión entre el juez y un experto de dominio; corre consultiva por defecto y armada en fail-closed sobre las dos dimensiones de seguridad (escalamiento y autolesión) en el carril de CI que exige, sin claves y determinista.
flowchart LR
A["Golden dataset<br/>(JSONL, pinned)"] --> B["evals/runner.py<br/>PytestEvalRunner"]
B --> C["Agent run<br/>(compiled LangGraph + LLMClient + RAG)"]
C --> D["Final AgentState per case<br/>(response, retrieved context,<br/>guardrail decisions, cost)"]
D --> E1["Deterministic scorers (always on)<br/>CitationCoverage, CitationCorrectness,<br/>RefusalCorrectness, EscalationCorrectness,<br/>RetrievalRecall"]
D --> E2["Judge-backed scorers (only when a judge key is set)<br/>Groundedness, Faithfulness (LLMAsJudge rubric),<br/>Hallucination (DeepEval)"]
E1 --> F["Report writer<br/>(write_reports)"]
E2 --> F
F --> G1["Markdown summary<br/>(evals/reports/latest.md)"]
F --> G2["JSON artifact<br/>(evals/reports/latest.json)"]
G2 --> H{"CI gate<br/>per-case deterministic gate +<br/>judge corpus thresholds"}
H -- "pass" --> I["PR check: pass"]
H -- "fail" --> J["PR check: fail"]
G2 --> K["Calibration gate (key-free)<br/>human-vs-judge agreement per dimension<br/>advisory; fail-closed on escalation + self-harm"]
K -- "agree" --> I
K -- "drift on a safety dim" --> J