MAS Test Addictive Sport Optics — Debug UI
Cerrar sesión

Resumen de conversación

turno(s) slot(s) contexto activo

            
Identidad óptico: · ·
Turno /
/
Sesión finalizada · turnos

Configura y haz clic en "Iniciar Sesión Bot"

Resumen de la sesión

Turnos
Promedio
Min–Max
Outcomes
Turnos con puntuación baja:
Último mensaje
Bot:
MAS:

Detalle de conversación

Envía un mensaje para comenzar
Latencia:
Inicia una sesión y ejecuta turnos
Latencia:

Pipeline Debug

Variaciones de la pregunta

Pregunta original:

Haz clic en una variación para cargarla:

Revisar conversación

Paquete diagnóstico


        

AG3 — Scores y Confianza (explicación detallada)

Pipeline Logs

No warning or error logs for this turn.

Diagrama del Turno

Rendering...

Exportar enmiendas

Cargando enmiendas...
No hay enmiendas registradas
Usa los iconos de edición en el panel Revisar para enmendar preguntas o respuestas

Eliminar sesión

¿Estás seguro de que quieres eliminar esta sesión?

La sesión se marcará como eliminada y dejará de aparecer en las listas.

Estado del Servicio

Retrieval Agent
Haz clic en "Actualizar" para verificar el estado de los servicios

n8n Webhook Tester

Respuesta:

      

Arquitectura del Sistema — Fase 2d

%%{init: {"theme": "dark"}}%%
flowchart TB
    subgraph ENTRADA["Canal de Entrada"]
        U["Usuario Humano\nOptico o Cliente Final"]
        BOT["Usuario Bot (MAS Test)\nLLM genera preguntas · Evalúa respuestas\nCatálogo MCP · MongoDB"]
        API["POST /v1/mas/turn\nconversation_id · user_message · slots_previos · historial"]
    end

    subgraph MAS["Pipeline MAS — Fase 2d (AG1→Verif→AG2→AG4→AG3→AG5)"]
        direction TB
        A1["AG1 — Router y Safety\nLLM + historial_conversacion\nAudiencia · Intencion + intenciones_secundarias · Riesgo · next_step\nconsulta_contextualizada (reformulacion)"]
        VERIF["Verificación Óptico\nExact match → Fuzzy + email tiebreaker\n_pending_query → Re-run AG1 post-verificacion"]
        A2["AG2 — Policy y Governance\nLLM\npermitir_respuesta · fuente_permitida\npermitir_accion · requiere_confirmacion"]
        A4["AG4 — State y Slots\nLLM con fast-path sin accion + historial\nSlots conocidos · Preguntas siguientes\nEjecuta ANTES de AG3"]
        A3["AG3 — Retrieval y Evidence\nPython + LLM Planner (3 fases paralelas)\nA: Milvus QA+Docs | Rerank opcional (Jina) | B: LLM plan + MCP Catalog | C: Score\nhits_qa · hits_evidencias · hits_catalogo · datos_en_vivo"]
        A5["AG5 — Orquestador\nLLM\nOutcome A B C D · Mensaje final\nPreferencia: hits_catalogo > hits_qa > hits_evidencias"]
    end

    subgraph OUTCOMES["Outcomes del Orquestador (AG5)"]
        OA["A: responder_ahora\nConfianza alta, sin accion pendiente"]
        OB["B: hacer_preguntas\nConfianza baja o slots faltantes"]
        OC["C: preparar_confirmacion\nResumen listo — esperar CONFIRMAR"]
        OD["D: ejecutar_accion\nToken CONFIRMAR valido y vigente\n(crear_pedido · ver_estado_pedido · email · cita)"]
    end

    subgraph DATOS["Fuentes de Datos"]
        MQ["Milvus — QA Opticos/Clientes\nrespuesta_corta · respuesta_larga · metadata"]
        MD["Milvus — Page Chunks + Products\nFragmentos web · pagina_seccion"]
        MCP["mcp-catalog :8003\nMCP Streamable HTTP\nHerramientas PostgreSQL en vivo\nPrecios · Specs · Repuestos · Modelos"]
        PG["PostgreSQL Catalogo\nv_precios_plano · v_precios_graduado\nv_catalogo_completo · repuestos · dip_graduar"]
        RD["Redis\nchat_model · ag3_catalog_model · qa_confidence_threshold\nreranker_enabled · reranker_model · reranker_top_n"]
        JINA["Jina Reranker API (opcional)\njina-reranker-v2-base-multilingual\nRequiere JINA_API_KEY"]
        YML["Config YAML\nmas-config.yaml · policies/rules.yaml"]
        MONGO["MongoDB — Bot Sessions\nbot_sessions collection\nTurnos · Evaluaciones · Enmiendas"]
    end

    U --> API
    BOT --> API
    BOT -.->|"gather_catalog_knowledge"| MCP
    BOT -.->|"save/load sessions"| MONGO
    API --> A1
    A1 -->|"next_step=aclarar_audiencia EARLY EXIT"| OB
    A1 -->|"opticos sin verificar"| VERIF
    A1 -->|"next_step=proceder (verificado o cliente)"| A2
    VERIF -->|"verificado: re-run AG1 con _pending_query"| A2
    VERIF -->|"pendiente / escalado EARLY EXIT"| OB
    A2 -->|"permitir_respuesta=false EARLY EXIT"| OA
    A2 --> A4
    A4 -->|"merged_slots"| A3
    A3 --> A5
    A5 --> OA
    A5 --> OB
    A5 --> OC
    A5 --> OD

    A3 -.->|"Phase A: search_qa_* + search_docs"| MQ
    A3 -.->|"Phase A: page_chunks + products"| MD
    A3 -.->|"Phase B: list_tools → LLM plan → MCP call_tool"| MCP
    MCP -.->|"SELECT … read-only"| PG
    VERIF -.->|"verify_optico_tool + search_candidates"| MCP
    A1 -.->|"get_mas_chat_model"| RD
    A3 -.->|"get_mas_ag3_catalog_model + reranker config"| RD
    A3 -.->|"rerank QA + docs (si habilitado)"| JINA
    A1 -.->|"intents · risk_levels"| YML
    A2 -.->|"policy rules"| YML

    style ENTRADA fill:#1e1040,stroke:#a855f7,color:#e4e8f0
    style MAS fill:#0f1a2e,stroke:#3b82f6,color:#e4e8f0
    style OUTCOMES fill:#0f2418,stroke:#22c55e,color:#e4e8f0
    style DATOS fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style A3 fill:#0d1f30,stroke:#06b6d4,color:#e4e8f0
    style MCP fill:#1a0f2e,stroke:#a855f7,color:#e4e8f0
    style VERIF fill:#1c1040,stroke:#a855f7,color:#e4e8f0
    style A5 fill:#1a2e1a,stroke:#22c55e,color:#e4e8f0
    style OA fill:#0f2418,stroke:#22c55e,color:#e4e8f0
    style OB fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style OC fill:#1c1040,stroke:#a855f7,color:#e4e8f0
    style OD fill:#1a2e1a,stroke:#22c55e,color:#e4e8f0
    style PG fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style BOT fill:#1a0f2e,stroke:#ec4899,color:#e4e8f0
    style JINA fill:#0f2418,stroke:#22c55e,color:#e4e8f0
    style MONGO fill:#1a0f2e,stroke:#ec4899,color:#e4e8f0

Flujo de Decisión por Turno

%%{init: {"theme": "dark"}}%%
flowchart TD
    BOT_SOURCE{"Fuente del\nmensaje?"}
    HUMAN_USER["Usuario humano\nEscribe pregunta"]
    BOT_USER["Usuario Bot\nLLM genera pregunta\nCatálogo MCP · Persona"]
    START["Mensaje entrante\nPOST /v1/mas/turn\n+ historial_conversacion + slots_previos"]

    BOT_SOURCE -->|"humano"| HUMAN_USER
    BOT_SOURCE -->|"bot"| BOT_USER
    HUMAN_USER --> START
    BOT_USER --> START

    BOT_EVAL["Bot: Evalúa respuesta\nScore 0-100 · next_action\nMongoDB persistence"]

    AG1_NODE["AG1: Router y Safety\nLLM + historial — Clasifica audiencia · intencion + intenciones_secundarias · riesgo\nProduce consulta_contextualizada para AG3"]

    AUD_OVERRIDE{"Audience override\n_optico_verificado o\n_audiencia en slots?"}

    NEXT_STEP{siguiente_paso}

    CLARIFY["EARLY EXIT\nOutcome B: hacer_preguntas\nPreguntar audiencia al usuario"]

    OPTICO_GATE{"optico sin\nverificar?"}

    VERIFY_PENDING{"verificacion\npendiente?"}

    ASK_CREDS["EARLY EXIT\nOutcome B: hacer_preguntas\nPedir nombre_comercial + codigo\nGuarda _pending_query en slots"]

    AG4_VERIFY["AG4: Extrae\n_optico_codigo +\n_optico_nombre_comercial"]

    MCP_VERIFY["MCP: verify_optico_tool\nExact match en DB"]

    VERIFY_OK{"match?"}

    RERUN_AG1["Re-run AG1\ncon _pending_query\n(pregunta original guardada)\nForza audiencia=opticos\nsiguiente_paso=proceder"]

    EMAIL_PENDING{"email\npendiente?"}

    AG4_EMAIL["AG4: Extrae\n_optico_email"]

    EMAIL_EXTRACTED{"email\nextraído?"}

    EMAIL_CHECK{"email\nmatch?"}

    CRED_REENTRY{"credenciales\nextraídas?"}

    MCP_VERIFY_REENTRY["MCP: verify_optico_tool\n(re-entry con nuevas creds)"]

    REENTRY_OK{"match?"}

    FUZZY_CHECK{"candidato\nfuzzy >= umbral?"}

    ASK_EMAIL["EARLY EXIT\nOutcome B: hacer_preguntas\nPedir email para verificar"]

    FALLBACK_EXTRACT["Fallback: regex en\nconsulta_contextualizada\nExtraer codigo + nombre"]

    FALLBACK_FOUND{"extrajo\ncredenciales?"}

    MCP_VERIFY_FALLBACK["MCP: verify_optico_tool\n(fallback creds)"]

    FALLBACK_OK{"match?"}

    ATTEMPT_CHECK{"intentos\n< max?"}

    RETRY_CREDS["EARLY EXIT\nOutcome B: hacer_preguntas\nPedir datos de nuevo"]

    ESCALATE["EARLY EXIT\nescalar a humano"]

    AG2_NODE["AG2: Policy y Governance\nLLM + validacion Python — Evalua politica · define fuente · gates"]
    POLICY_GATE{permitir_respuesta}

    BLOCKED_NODE["EARLY EXIT\nOutcome A: responder_ahora\nRespuesta de bloqueo sin informacion"]

    AG4_NODE["AG4: State y Slots\nLLM + historial — fast-path si accion=ninguna\nEjecuta ANTES de AG3 — produce merged_slots"]

    AG3_NODE["AG3: Retrieval y Evidence\nPython + LLM Planner\nFase A y B: paralelo via asyncio.gather\nA: Milvus QA + Docs | Rerank opcional (Jina) | B: LLM plan + MCP catalog\nFase C: merge + confianza intent-aware (multi-intent)\nhits_qa · hits_evidencias · hits_catalogo · datos_en_vivo"]

    AG5_NODE["AG5: Orquestador\nLLM — Decide outcome · compone mensaje final\nPreferencia: hits_catalogo > hits_qa > docs"]

    OA_N["Outcome A\nresponder_ahora\nConfianza alta, sin accion"]
    OB_N["Outcome B\nhacer_preguntas\nFaltan slots o confianza baja"]
    OC_N["Outcome C\npreparar_confirmacion\nResumen lista — pedir CONFIRMAR\n(crear_pedido · ver_estado_pedido · email · cita)"]
    OD_N["Outcome D\nejecutar_accion\nToken CONFIRMAR valido\n(crear_pedido · ver_estado_pedido · email · cita)"]

    RESP["MASTurnResponse\nreply_text · outcome · datos_en_vivo\nslots_actualizados · debug"]

    START --> AG1_NODE
    AG1_NODE --> AUD_OVERRIDE
    AUD_OVERRIDE -->|"si: forzar audiencia"| NEXT_STEP
    AUD_OVERRIDE -->|"no"| NEXT_STEP
    NEXT_STEP -->|"aclarar_audiencia"| CLARIFY
    NEXT_STEP -->|"proceder"| OPTICO_GATE
    CLARIFY --> RESP

    OPTICO_GATE -->|"si"| EMAIL_PENDING
    OPTICO_GATE -->|"no"| AG2_NODE

    EMAIL_PENDING -->|"si"| AG4_EMAIL
    EMAIL_PENDING -->|"no"| VERIFY_PENDING

    AG4_EMAIL --> EMAIL_EXTRACTED
    EMAIL_EXTRACTED -->|"si"| EMAIL_CHECK
    EMAIL_EXTRACTED -->|"no"| CRED_REENTRY
    EMAIL_CHECK -->|"si"| RERUN_AG1
    EMAIL_CHECK -->|"no"| ATTEMPT_CHECK

    CRED_REENTRY -->|"si: usuario reintrodujo creds"| MCP_VERIFY_REENTRY
    CRED_REENTRY -->|"no: pedir email de nuevo"| RESP
    MCP_VERIFY_REENTRY --> REENTRY_OK
    REENTRY_OK -->|"si"| RERUN_AG1
    REENTRY_OK -->|"no"| ATTEMPT_CHECK

    VERIFY_PENDING -->|"no: primera vez"| ASK_CREDS
    VERIFY_PENDING -->|"si"| AG4_VERIFY
    ASK_CREDS --> RESP

    AG4_VERIFY --> MCP_VERIFY

    MCP_VERIFY --> VERIFY_OK
    VERIFY_OK -->|"si"| RERUN_AG1
    VERIFY_OK -->|"no"| FUZZY_CHECK

    AG4_VERIFY -.->|"creds incompletas"| FALLBACK_EXTRACT
    FALLBACK_EXTRACT --> FALLBACK_FOUND
    FALLBACK_FOUND -->|"si"| MCP_VERIFY_FALLBACK
    FALLBACK_FOUND -->|"no: pedir de nuevo"| RESP
    MCP_VERIFY_FALLBACK --> FALLBACK_OK
    FALLBACK_OK -->|"si"| RERUN_AG1
    FALLBACK_OK -->|"no"| FUZZY_CHECK

    FUZZY_CHECK -->|"si: prob >= umbral"| ASK_EMAIL
    FUZZY_CHECK -->|"no"| ATTEMPT_CHECK
    ASK_EMAIL --> RESP
    ATTEMPT_CHECK -->|"si"| RETRY_CREDS
    ATTEMPT_CHECK -->|"no: max alcanzado"| ESCALATE
    RETRY_CREDS --> RESP
    ESCALATE --> RESP

    RERUN_AG1 --> AG2_NODE

    AG2_NODE --> POLICY_GATE
    POLICY_GATE -->|"false"| BLOCKED_NODE
    POLICY_GATE -->|"true"| AG4_NODE
    BLOCKED_NODE --> RESP

    AG4_NODE -->|"merged_slots"| AG3_NODE
    AG3_NODE --> AG5_NODE
    AG5_NODE --> OA_N
    AG5_NODE --> OB_N
    AG5_NODE --> OC_N
    AG5_NODE --> OD_N
    OA_N --> RESP
    OB_N --> RESP
    OC_N --> RESP
    OD_N --> RESP
    RESP -.->|"si fuente=bot"| BOT_EVAL

    style BOT_SOURCE fill:#1e1040,stroke:#ec4899,color:#e4e8f0
    style HUMAN_USER fill:#1e1040,stroke:#a855f7,color:#e4e8f0
    style BOT_USER fill:#1a0f2e,stroke:#ec4899,color:#e4e8f0
    style BOT_EVAL fill:#1a0f2e,stroke:#ec4899,color:#e4e8f0
    style START fill:#1e1040,stroke:#a855f7,color:#e4e8f0
    style RESP fill:#1e1040,stroke:#a855f7,color:#e4e8f0
    style CLARIFY fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style BLOCKED_NODE fill:#2e1414,stroke:#ef4444,color:#e4e8f0
    style AG4_NODE fill:#0d1f30,stroke:#06b6d4,color:#e4e8f0
    style AG3_NODE fill:#0d1f30,stroke:#06b6d4,color:#e4e8f0
    style AG5_NODE fill:#1a2e1a,stroke:#22c55e,color:#e4e8f0
    style OA_N fill:#0f2418,stroke:#22c55e,color:#e4e8f0
    style OB_N fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style OC_N fill:#1c1040,stroke:#a855f7,color:#e4e8f0
    style OD_N fill:#1a2e1a,stroke:#22c55e,color:#e4e8f0
    style AUD_OVERRIDE fill:#1c1040,stroke:#a855f7,color:#e4e8f0
    style OPTICO_GATE fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style VERIFY_PENDING fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style ASK_CREDS fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style AG4_VERIFY fill:#0d1f30,stroke:#06b6d4,color:#e4e8f0
    style MCP_VERIFY fill:#1c1040,stroke:#a855f7,color:#e4e8f0
    style VERIFY_OK fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style RERUN_AG1 fill:#0f1a2e,stroke:#3b82f6,color:#e4e8f0
    style ATTEMPT_CHECK fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style RETRY_CREDS fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style EMAIL_PENDING fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style AG4_EMAIL fill:#0d1f30,stroke:#06b6d4,color:#e4e8f0
    style EMAIL_EXTRACTED fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style EMAIL_CHECK fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style CRED_REENTRY fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style MCP_VERIFY_REENTRY fill:#1c1040,stroke:#a855f7,color:#e4e8f0
    style REENTRY_OK fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style FUZZY_CHECK fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style ASK_EMAIL fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style FALLBACK_EXTRACT fill:#0d1f30,stroke:#06b6d4,color:#e4e8f0
    style FALLBACK_FOUND fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style MCP_VERIFY_FALLBACK fill:#1c1040,stroke:#a855f7,color:#e4e8f0
    style FALLBACK_OK fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style ESCALATE fill:#2e1414,stroke:#ef4444,color:#e4e8f0
    style AG1_NODE fill:#0f1a2e,stroke:#3b82f6,color:#e4e8f0
    style AG2_NODE fill:#0f1a2e,stroke:#3b82f6,color:#e4e8f0

Secuencia de un Turno Completo

%%{init: {"theme": "dark"}}%%
sequenceDiagram
    participant U as Usuario (Optico)
    participant API as runner.py
    participant AG1 as AG1 Router
    participant AG2 as AG2 Policy
    participant AG4 as AG4 Slots
    participant AG3 as AG3 Evidence
    participant MIL as Milvus
    participant JINA as Jina Reranker
    participant MCP as mcp-catalog :8003
    participant AG5 as AG5 Orquestador

    U->>API: POST user_message="¿Cuánto cuesta el ALTEA en C1?"

    API->>AG1: run_ag1(user_message, chat_model, historial)
    Note over AG1: LLM clasifica:
audiencia=opticos
intencion=precio
intenciones_secundarias=[envio]
next_step=proceder
consulta_contextualizada=null (autoexplicativo) AG1-->>API: RouterOutput Note over API: Verification gate:
audiencia=opticos, not verified? alt first time opticos — ask credentials Note over API: _verificacion_pendiente = true
_pending_query = user_message
(guarda pregunta original) API-->>U: "¿Tu nombre comercial y código?" U->>API: "Soy OPTICA TYNDALL, código 00354" API->>AG1: run_ag1(credential message, chat_model, historial) AG1-->>API: RouterOutput (intencion=otros, audiencia=opticos) API->>AG4: extract _optico_codigo + _optico_nombre_comercial AG4-->>API: SlotOutput {codigo: "00354", nombre: "OPTICA TYNDALL"} API->>MCP: verify_optico_tool(codigo="00354", nombre="OPTICA TYNDALL") alt exact match verified MCP-->>API: {verified: true, optico_id: 42} Note over API: _optico_verificado = true
Pop _pending_query → re-run AG1 API->>AG1: run_ag1(_pending_query="¿Cuánto cuesta el ALTEA en C1?", chat_model, []) Note over AG1: LLM clasifica correctamente:
audiencia=opticos, intencion=precio
consulta_contextualizada incluye ALTEA C1 AG1-->>API: RouterOutput (forzado: audiencia=opticos, proceder) Note over API: Fall through to normal pipeline else no exact match — fuzzy MCP-->>API: {verified: false} API->>MCP: search_optico_candidates_tool(codigo, nombre) MCP-->>API: candidates[] Note over API: fuzzy scoring:
best_prob vs threshold alt fuzzy candidate found (prob >= threshold) API-->>U: "¿Me puedes indicar tu email?" U->>API: "mi@email.com" API->>AG4: extract _optico_email AG4-->>API: SlotOutput {email: "mi@email.com"} Note over API: compare UPPER(email)
vs candidate mail alt email matches Note over API: _optico_verificado = true
Pop _pending_query → re-run AG1 API->>AG1: run_ag1(_pending_query, chat_model, []) AG1-->>API: RouterOutput (forzado: audiencia=opticos, proceder) else email mismatch API-->>U: retry or escalate end else no fuzzy candidate API-->>U: retry or escalate end end else already verified or cliente Note over API: skip gate end API->>AG2: run_ag2(RouterOutput, chat_model) Note over AG2: LLM evalua politica:
permitir=true
fuente=qa_y_evidencias
requiere_confirmacion=false AG2-->>API: PolicyOutput API->>AG4: run_ag4(mensaje, RouterOutput, slots_previos, chat_model, historial) Note over AG4: fast-path: accion=ninguna
Extrae slots del mensaje
modelo_nombre="ALTEA", color="C1" AG4-->>API: SlotOutput (merged_slots={modelo_nombre: ALTEA, color: C1}) API->>AG3: run_ag3(search_query, audiencia, fuente, chat_model, slots=merged_slots, intent=precio, secondary=[envio]) Note over AG3: Fase A y B: paralelo via asyncio.gather par Fase A — Milvus QA search AG3->>MIL: search_qa_opticos("precio ALTEA") MIL-->>AG3: hits_qa (score L2 ~0.3) opt reranker_enabled=true AG3->>JINA: rerank_hits(query, hits_qa+chunks+products) JINA-->>AG3: reranked hits (top_n por fuente) end and Fase B — LLM plan + MCP catalog AG3->>MCP: list_tools() → tool discovery MCP-->>AG3: 8 herramientas disponibles Note over AG3: LLM planner (ag3_catalog_model):
CatalogPlan → get_product_price + get_graduation_price AG3->>MCP: call_tool("get_product_price", {modelo: "ALTEA"}) MCP-->>AG3: [{modelo:ALTEA, pvo:45.0, pvp:89.0, colores:[C1,C3]}] end Note over AG3: Fase C: merge + _compute_confidence
hits_catalogo=[CatalogHit(...)]
confianza=0.95, datos_en_vivo=true AG3-->>API: EvidenceOutput (hits_catalogo con precio real) API->>AG5: run_ag5(mensaje, AG1, AG2, AG3, AG4, chat_model) Note over AG5: LLM decide:
hits_catalogo con datos_en_vivo
= Outcome A, usar pvo=45€ exacto AG5-->>API: OrchestratorOutput (outcome=responder_ahora) API-->>U: MASTurnResponse
reply_text="El ALTEA en C1 tiene un precio de 45,00€ para ópticos."
outcome="responder_ahora"
datos_en_vivo=true

Máquina de Estados — Outcomes

%%{init: {"theme": "dark"}}%%
stateDiagram-v2
    [*] --> Evaluando : Nuevo turno recibido

    Evaluando --> EarlyExit_Audiencia : AG1 next_step=aclarar_audiencia
    Evaluando --> EarlyExit_Verificacion : optico sin verificar
    Evaluando --> EarlyExit_Politica : AG2 permitir_respuesta=false
    Evaluando --> Orquestando : AG3 + AG4 completados

    EarlyExit_Audiencia --> OutcomeB : Audiencia desconocida

    EarlyExit_Verificacion --> OutcomeB : Pedir credenciales (primera vez)\no pedir email (fuzzy match)\no reintentar (datos incorrectos)
    EarlyExit_Verificacion --> OutcomeD : Escalar a humano (max intentos)
    EarlyExit_Verificacion --> PostVerificacion : Verificacion exitosa\n(exact match / email tiebreaker / re-entry / fallback)

    PostVerificacion --> Orquestando : Re-run AG1 con _pending_query\n→ AG2 → AG4 → AG3 → AG5

    EarlyExit_Politica --> OutcomeA : Bloqueo de politica

    Orquestando --> OutcomeA : confianza alta AND sin accion solicitada
    Orquestando --> OutcomeB : confianza baja OR slots faltantes
    Orquestando --> OutcomeC : accion permitida AND slots completos AND sin token previo\n(crear_pedido · ver_estado_pedido · email · cita)
    Orquestando --> OutcomeD : token CONFIRMAR valido AND TTL vigente\n(crear_pedido · ver_estado_pedido · email · cita)

    OutcomeA --> [*] : responder_ahora
    OutcomeB --> [*] : hacer_preguntas
    OutcomeC --> [*] : preparar_confirmacion
    OutcomeD --> [*] : ejecutar_accion

Retrieval y Evidencia (AG3 + Catálogo)

%%{init: {"theme": "dark"}}%%
flowchart TD
    subgraph INPUT["Entradas a AG3 (LLM Planner + Python Executor)"]
        I1["consulta_contextualizada o user_message\n(AG1 reformula respuestas cortas)"]
        I2["fuente_permitida\nde AG2 Policy\nsolo_qa | qa_y_evidencias | solo_evidencias"]
        I3["audiencia\nde AG1 Router"]
        I4["merged_slots\nde AG4 (slots_previos + slots_conocidos)\nmodelo_nombre · color · tipo_graduacion …"]
        I5["intent + secondary_intents\nde AG1 Router\nprimaria + hasta 2 secundarias"]
        I6["ag3_catalog_model\nde Redis/Config\n(independiente de chat_model)"]
    end

    GATHER["asyncio.gather\nFase A y B en paralelo"]

    subgraph PHASE_A["Fase A — Milvus (Python asyncio.gather)"]
        direction LR
        QA["search_qa_opticos / search_qa_clientes\nBase Q&A vectorial"]
        PC["search_page_chunks + search_products\nFragmentos web"]
    end

    subgraph PHASE_B["Fase B — Catálogo MCP (LLM Planner + Python Executor)"]
        direction TB
        DISCOVER["_discover_tools(mcp_server)\nMCP list_tools() — obtiene esquemas\nAG3 customer-agnostic"]
        LLM_PLAN["_plan_catalog_calls_llm()\nSingle LLM structured-output call\nModelo: ag3_catalog_model\nOutput: CatalogPlan (list of tool calls)"]
        FALLBACK["_plan_catalog_calls_deterministic()\nFallback si LLM falla\n_INTENT_TOOL_MAP[intent] + slots"]
        subgraph MCP_TOOLS["MCP call_tool() — mcp-catalog:8003\nasyncio.gather concurrente"]
            CP["get_product_price\nget_graduation_price"]
            CS["get_product_specs\nlist_model_colors"]
            CR["get_spare_parts\nget_minimum_diopter"]
            CD["search_models\nlist_sports"]
        end
    end

    subgraph RERANK["Reranking opcional — Jina Reranker (Python asyncio.gather)"]
        direction LR
        RR_GATE{"mas.reranker_enabled?"}
        RR_QA["rerank_hits(qa)\nJina API concurrente"]
        RR_CHUNKS["rerank_hits(chunks)"]
        RR_PRODUCTS["rerank_hits(products)"]
        RR_SKIP["Sin rerank\nhits originales pasan directo"]
    end

    subgraph PHASE_C["Fase C — Merge y Scoring intent-aware (Python)"]
        SC1["hits_catalogo con datos → 0.95\n(boost a 0.97 si QA corrobora)"]
        SC2["QA hits: score + count + corroboracion\n(cap 0.75 solo si intent PRIMARIO es catalogo sin datos)"]
        SC3["Doc hits: score + boost si ANY intent es doc-heavy\n(DOCUMENTACION · ENVIO · DISTRIBUCION)"]
        SC4["sin resultados → 0.0"]
    end

    subgraph OUTPUT["EvidenceOutput al pipeline"]
        O1["hits_qa: EvidenceHitQA list"]
        O2["hits_evidencias: EvidenceHitDoc list"]
        O3["hits_catalogo: CatalogHit list\n(tool_name · params · resultado · columnas)\nPrioridad maxima para AG5"]
        O4["confianza: float 0–1"]
        O5["conflictos: list str"]
        O6["evidencia_faltante: bool"]
        O7["datos_en_vivo: bool\ntrue si hits_catalogo tiene filas"]
    end

    I1 --> GATHER
    I2 -->|"habilita fuentes"| GATHER
    GATHER --> PHASE_A
    GATHER --> PHASE_B
    I3 -->|"filtra coleccion QA"| QA
    I4 -->|"slots para LLM planner"| LLM_PLAN
    I5 -->|"intent para LLM planner"| LLM_PLAN
    I6 -->|"modelo LLM"| LLM_PLAN

    DISCOVER --> LLM_PLAN
    LLM_PLAN -->|"exito"| MCP_TOOLS
    LLM_PLAN -->|"fallo"| FALLBACK
    FALLBACK --> MCP_TOOLS

    QA --> RR_GATE
    PC --> RR_GATE
    RR_GATE -->|"true"| RR_QA
    RR_GATE -->|"true"| RR_CHUNKS
    RR_GATE -->|"true"| RR_PRODUCTS
    RR_GATE -->|"false"| RR_SKIP
    RR_QA --> O1
    RR_CHUNKS --> O2
    RR_PRODUCTS --> O2
    RR_SKIP --> O1
    RR_SKIP --> O2
    CP --> O3
    CS --> O3
    CR --> O3
    CD --> O3

    O1 --> PHASE_C
    O2 --> PHASE_C
    O3 --> PHASE_C
    PHASE_C --> SC1
    PHASE_C --> SC2
    PHASE_C --> SC3
    PHASE_C --> SC4
    SC1 --> O4
    SC2 --> O4
    SC3 --> O4
    SC4 --> O4

    O3 --> O7

    style INPUT fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style GATHER fill:#0d1f30,stroke:#06b6d4,color:#e4e8f0
    style PHASE_A fill:#0d1f30,stroke:#06b6d4,color:#e4e8f0
    style PHASE_B fill:#0f1a2e,stroke:#3b82f6,color:#e4e8f0
    style MCP_TOOLS fill:#1a0f2e,stroke:#a855f7,color:#e4e8f0
    style RERANK fill:#1a2e1a,stroke:#22c55e,color:#e4e8f0
    style RR_QA fill:#0f2418,stroke:#22c55e,color:#e4e8f0
    style RR_CHUNKS fill:#0f2418,stroke:#22c55e,color:#e4e8f0
    style RR_PRODUCTS fill:#0f2418,stroke:#22c55e,color:#e4e8f0
    style RR_SKIP fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style PHASE_C fill:#1c1040,stroke:#a855f7,color:#e4e8f0
    style OUTPUT fill:#0f1a2e,stroke:#3b82f6,color:#e4e8f0
    style O3 fill:#1a0f2e,stroke:#a855f7,color:#e4e8f0
    style O7 fill:#0f2418,stroke:#22c55e,color:#e4e8f0
    style CP fill:#1a1a0f,stroke:#f59e0b,color:#e4e8f0
    style DISCOVER fill:#0d1f30,stroke:#06b6d4,color:#e4e8f0
    style LLM_PLAN fill:#0f1a2e,stroke:#3b82f6,color:#e4e8f0
    style FALLBACK fill:#2e1414,stroke:#ef4444,color:#e4e8f0
Cargando ayuda…
ESC para cerrar