← volver a la web de Alma

Vivla · AlmaPlanteamiento técnico

Cómo está construida Alma por dentro, sin humo: los servicios y cómo se hablan, qué herramientas tiene cada agente, dónde vive cada pieza y qué técnicas usamos. Verificado contra el código a día de hoy.

El mapa: quién habla con quién

Tres capas: lo que toca la gente, el núcleo que orquesta y la plataforma de la que todo depende.

Lo que toca la gente App de propietarios iOS · Android: el chat del owner Panel de CX React · Vercel: con Fabián al lado CX-Móvil Expo: la bandeja, en el bolsillo Slack interno: habla con los agentes mensajes · api rest Stream Chat canales · presencia · webhooks: el transporte del chat webhook message.new El núcleo vivla-tools · backend NestJS · Railway: chat, tickets, avisos, encuestas 🤖 Fabián: el copiloto de CX 🔌 MCP de dominio: ~80 tools Sonnet 4.6 razona · Haiku 4.5 clasifica vivla-concierge Mastra · Railway Lola supervisora + especialistas delegados guardarraíles + kill-switch evals con juez Haiku vivla-atlas Hono + Astro · Railway conocimiento verificado RAG híbrido · fichas por casa MCP propio · 3 tools web: atlas.vivla.com mcp mcp La plataforma Supabase Postgres operativo Claude Sonnet + Haiku Auth0 identidad única Windmill crons y syncs Observabilidad Langfuse · PostHog Cloudflare Access + embeddings en producción hoy en producción desde el 12 de agosto (Lola)

Bajo nivel · una sugerencia de Fabián

Del mensaje del propietario a la respuesta sugerida en el panel. La persona decide; nada llega al cliente sin ella.

Propietario Stream Fabián Claude 1 · escribe «se quedó encendida la calefacción…» 2 · webhook message.new · espera 2,5 s · flag fail-closed 3 · junta el contexto real: historial · reserva · casa · ticket 4a · Sonnet 4.6 + tools de solo-lectura → 5 sugerencias 4b · Haiku 4.5 → tema · urgencia · sentimiento 5 · salida estructurada (JSON validado) 6 · al panel del equipo: nunca al cliente La persona acepta, edita o descarta → telemetría a PostHog · cada llamada LLM trazada en Langfuse con versión de prompt · sesión se cierra sola a las 24 h

Bajo nivel · una búsqueda en Atlas

Atlas no genera respuestas: recupera conocimiento verificado, con cita. Hoy: ~150 documentos del negocio en 8 áreas, más 26 fichas de casa y 5 de zona extraídas del propio chat, con filtro de seguridad por casa.

Pregunta del agente Haiku expande +2 variantes de la query Léxica · BM25 tsvector español, pesos A/B/C Semántica · vector pgvector HNSW · bge-m3 1024d Fusión RRF k=60, en SQL puro Rerank Haiku puntúa 0-10 · fail-soft búsqueda doble por variante → Respuesta: fragmentos + documento de origen + estado de verificación (verificado / caducado). Solo contenido canónico. Si una capa falla, la anterior responde (fail-soft).

Bajo nivel · qué hace Lola cuando no puede sola

Lola solo contesta si es la agente activa de ese canal. Desde ahí resuelve con lo que tiene a mano, y cada mensaje termina en uno de tres caminos. Y hay un atajo intermedio: si solo le falta un dato, pregunta al equipo por dentro (ask_team) y sigue ella cuando se lo responden, con recordatorios si nadie contesta.

El propietario escribe en el chat de la app gate duro ¿Lola es la agente activa del canal? si no, no responde: sigue la persona ya asignada Resuelve con sus herramientas Atlas el conocimiento verificado Tools de vivla-tools los datos vivos: reservas, casa, tickets Memoria la biografía del propietario y la conversación en curso el caso normal Lo resuelve ella responde en ráfaga de 1 a 3 mensajes cortos, con los datos reales que ya tiene cuando hace falta una persona Handoff a CX, en el chat chat_handoff_to_human cuando pide hablar con alguien, hay frustración, o el tema es sensible cuando el tema es de otro equipo Escalación por email chat_send_team_escalation no es tema de atención al cliente (finanzas, legal, ventas…) y el conocimiento no tiene respuesta failsafe Si Lola no llega a tiempo su turno falla, o tarda más de 180 segundos → el handoff se dispara solo, sin que nadie lo pida Qué pasa reasigna el canal a una persona: agente de la casa → guardia activa → agente por defecto → si no hay nadie, aviso a todos los admins la persona ve un banner en el panel, con «Entendido» tú recibes el horario del equipo, para saber cuándo esperar Qué pasa Lola manda un email interno, con plantilla fija: los datos del propietario y la casa los resuelve el sistema, nunca el modelo agent_escalations queda registrado ahí, y CX recibe el aviso en su buzón a ti te lo cuenta en 5 pasos, sin decir nunca una dirección de email lo resuelve la IA pasa a una persona del equipo pasa a otro equipo, por email

Bajo nivel · quién asegura que alguien responde

El handoff y la escalación no se quedan colgados: un barrido revisa cada 5 minutos si alguien ya respondió, y avisa cada vez más alto si nadie lo hizo. Dos válvulas lo paran cuando ya no hace falta.

El barrido cada 5 minutos, sin parar: sobrevive a los despliegues Handoff o escalación sin atender por una persona urgencia alta urgencia normal 15 minutos recordatorio a la CX asignada 30 minutos Slack + email al buzón general de CX 4 horas laborables email al equipo cualquiera para el barrido, en cualquier momento Auto-ack si una persona ya respondió en el canal, el barrido se calla solo Salvoconducto la CX marca «ya contacté por otro canal» + una nota el propietario recibe constancia en el chat, y Lola deja de perseguir

Los agentes y sus herramientas

AgenteDónde correModelosHerramientas y límites
Fabián (producción) vivla-tools · chat/copilot Sonnet 4.6 razona · Haiku 4.5 clasifica Allowlist de 22 herramientas de solo-lectura (reservas, casas, pagos, tickets). Persona y reglas de marca versionadas en código.
Lola (producción) vivla-concierge · Mastra Sonnet 4.6 Tool-search semántico (top-6) sobre el catálogo del MCP de tools: busca la herramienta que toca en vez de cargar 88. Supervisora: delega incidencias en el Fabián-especialista. Memoria por propietario (98 biografías, destiladas cada noche), 9 reglas de comportamiento pactadas con CX y presentación obligatoria como agente de IA (ley europea de IA).
Guardarraíles vivla-concierge , Filtro de prompt-injection y moderación a la entrada/salida + kill-switch de escrituras: en modo test, cualquier herramienta que cree/modifique/envíe queda bloqueada por patrón de verbo.
Calidad (evals) vivla-concierge · harness juez: Haiku 4.5 4 jueces LLM (uso de herramientas, fidelidad, persona, relevancia) sobre un dataset dorado de 18 casos; resultados a Langfuse. Con esto se decidió Sonnet vs Opus (ganó Sonnet).

Los MCPs: las herramientas que exponemos

MCP (Model Context Protocol) es el enchufe estándar entre agentes y sistemas. Tenemos tres.

88

MCP de vivla-tools

de 98 registradas · OAuth 2.1 + PKCE · solo lectura salvo 3
  • casas: list_properties, get_property
  • reservas: list_active_stays, property_occupancy_calendar
  • incidencias: create_ticket, update_ticket
  • chat: get_channel_messages, get_chat_analytics
  • encuestas: aggregate_survey_responses
3

MCP de Atlas

API-key o JWT Auth0 · en producción
  • buscar_atlas: fragmentos con cita y verificación
  • listar_areas: el mapa del conocimiento
  • obtener_documento: documento completo por ruta
2

MCP de la wiki

público · Mintlify
  • search_vivla_docs: busca en la documentación
  • query_docs_filesystem: navega el árbol de docs
  • los agentes lo usan para procesos y producto

Por qué MCP, y no una CLI o una API a medida

La pregunta de fondo: ¿cómo le das herramientas a un agente sin construir una integración nueva por cada agente y por cada cliente? MCP es el enchufe estándar; esto es lo que nos da frente a las alternativas.

MCP (lo elegido)CLI a medidaAPI + SDK propio
DescubrimientoEl agente se conecta y recibe el catálogo con schemas tipados; búsqueda semántica de la tool que tocaParsear un --help; frágil y sin contratoLeer docs y escribir un cliente por integración
IdentidadOAuth 2.1 + PKCE: el agente actúa con los permisos de una persona concretaAPI keys sueltas en cada máquinaTokens custom por integración
Dónde correNada que instalar: HTTP desde cualquier sitioInstalar y actualizar el binario allá donde corra cada agenteUn SDK por lenguaje/framework
Quién lo aprovechaCualquier cliente MCP: nuestros agentes Mastra, Claude, ChatGPT, Cursor, sin código nuevoSolo quien tenga la CLI instaladaSolo quien integre el SDK
Control y auditoríaCentralizados en el servidor: permisos por rol, log de escrituras, lecturas sensibles auditadasDispersos por máquinaRepetidos en cada integración
EvoluciónSe añade una tool en el servidor y todos los clientes la ven al momento; renombres con alias, sin romper a nadieRedistribuir el binarioRepublicar SDKs y avisar a los equipos
EstándarAbierto (Anthropic; adoptado por OpenAI, Google y Microsoft): sin lock-in de proveedorPropietario nuestroPropietario nuestro

La misma decisión, en una frase: una API pensada para que la consuma un modelo, con contrato, identidad y catálogo vivo, que además nos sirve para operar nosotros desde Claude o Cursor.

El catálogo del MCP de vivla-tools, tool a tool

98 tools registradas; 88 expuestas por MCP (las 10 restantes son de la interfaz del chat interno). Convención de nombres dominio_verbo, con alias para los nombres antiguos. Todo es de solo lectura salvo las 3 marcadas.

Casas 13 tools

  • list_properties · lista y busca casas
  • property_get · ficha completa de una casa
  • property_access_get · accesos, alarma, wifi sensible · lectura auditada
  • update_property · edita datos de la casa escritura
  • property_health_get / property_health_list · salud 0-100 y ranking
  • property_overview_get · resumen operativo agregado
  • list_property_assignments / get_property_main_agent · quién lleva cada casa
  • list_locations · destinos
  • list_property_photos / list_floor_plans / list_qr_codes · material de la casa

La casa por dentro 7 tools

  • list_rooms · habitaciones
  • get_inventory · inventario
  • get_cleaning_status · limpiezas y calendario
  • list_appliance_guides / get_appliance_guide · guías de electrodomésticos
  • list_items · catálogo de items
  • list_cleaning_templates · checklists de limpieza

Reservas y operación 9 tools

  • booking_list / booking_get · reservas por filtros y detalle
  • list_active_stays · quién está alojado hoy
  • list_check_ins / list_check_outs · llegadas y salidas por fechas
  • list_owner_stays · estancias de propietarios
  • property_occupancy_calendar · calendario libre/ocupado día a día
  • find_owner · busca un propietario
  • list_property_agents · agentes asignados

Incidencias 6 tools

  • ticket_list / ticket_get · partes por filtros y detalle
  • ticket_messages_get · hilo de mensajes del parte
  • ticket_create · crea el parte en Zendesk escritura
  • update_ticket · estado, prioridad, responsable escritura
  • propose_ticket · propone un borrador de parte

Chat y canales 11 tools

  • list_channels / get_channel · canales y detalle
  • list_channel_messages · mensajes de un canal
  • channel_members_list · quién está en el canal
  • channel_context_get · la foto completa del cliente del canal
  • get_chat_analytics · métricas del chat
  • list_quick_replies · respuestas rápidas de CX
  • list_invitations / list_shifts / list_chat_notifications / list_inbox_messages · operación del equipo

Encuestas 13 tools

  • survey_list · tipos de encuesta
  • survey_questions_get · preguntas de la versión activa
  • survey_scores_get / survey_summary_get · puntuaciones y resumen
  • survey_responses_aggregate · agregados por semana, casa o banda (incluye NPS)
  • list_survey_responses / survey_response_get · respuestas crudas y una en detalle
  • survey_responses_get · historial completo de un cliente o casa
  • survey_pending_get · encuestas pendientes de un cliente
  • get_survey_insights · hallazgos generados por IA
  • list_action_plans / list_survey_property_configs / list_survey_participation_exclusions · gestión

Avisos 9 tools

  • list_notification_templates / list_notification_automations · plantillas y automatismos
  • list_notification_history · qué se envió a quién
  • get_notification_dashboard · el panel del motor
  • list_deep_links · enlaces profundos de la app
  • list_email_blocks / list_email_assets / list_email_events · piezas y eventos de email
  • list_notification_suppressions · exclusiones de envío

Clientes y equipos 4 tools

  • list_users · busca usuarios
  • client_get · ficha de cliente
  • list_teams / get_team · equipos internos

Web pública 5 tools

  • get_property_web_data · la casa tal y como se publica
  • list_amenities / list_property_amenities · amenities
  • list_property_videos / list_web_texts · vídeos y textos

Con IA dentro 6 tools

  • summarize_conversation · resume una conversación
  • draft_reply · borrador de respuesta
  • compare_properties · compara casas
  • generate_report · informe a medida
  • daily_briefing · el día de un vistazo (llegadas, partes, encuestas)
  • get_audit_trail · qué hizo la IA y cuándo

Diagramas y admin 5 tools

  • property_hierarchy_diagram / team_org_chart_diagram · diagramas al vuelo
  • list_app_releases / get_app_store_status · versiones de la app
  • list_permissions · quién puede qué

Las preguntas que caerán (y sus respuestas)

¿Quién puede llamar a las tools?

Solo quien pase el guard OAuth 2.1 + PKCE contra Auth0 (issuer y audience verificados, RS256). El token es de una persona: el agente hereda exactamente sus permisos por módulo (viewer/editor/admin), los mismos que en el panel. Y cada agente interno lleva además su propia allowlist (Fabián: 22 tools de solo lectura).

¿Puede la IA escribir en producción?

Solo 3 tools escriben (crear/editar parte, editar casa) y toda escritura queda en el audit log con el nombre de la tool. En concierge hay un segundo cierre: el kill-switch bloquea por patrón cualquier verbo de escritura mientras un agente está en pruebas.

¿Y los datos sensibles?

Las tools sensibles (códigos de acceso, alarmas) están gateadas por permiso y auditan también cada lectura. Por MCP no viajan secrets ni credenciales; la ficha de casa que ve un agente excluye esos campos salvo tool explícita.

¿Qué pasa si el MCP se cae?

El chat no depende de él: los mensajes viajan por Stream. Los agentes degradan (responden sin dato o pasan a una persona) y los feature flags fallan cerrados: sin configuración, la IA no actúa.

¿Cómo se añade una tool nueva?

Un archivo en el backend con nombre, descripción, schema y ejecución, registrado en el módulo. Al desplegar, todos los clientes la descubren en su siguiente sesión. Los renombres no rompen a nadie: hay alias del nombre viejo al nuevo.

¿Cómo evita el agente ahogarse con 88 tools?

No las carga: Lola usa tool-search semántico y trae solo las 6 más relevantes para cada petición. Menos contexto, menos coste, menos error. Fabián ni busca: lleva su allowlist fija de 22.

¿Auditoría y trazabilidad?

Tres capas: audit log de escrituras y lecturas sensibles (con usuario y tool), traza completa de cada llamada LLM en Langfuse con versión de prompt, y telemetría de producto en PostHog (sugerencia mostrada, aceptada, editada).

¿Nos casamos con Anthropic?

No. MCP es un estándar abierto que ya adoptan OpenAI, Google y Microsoft: los mismos servidores sirven a Claude, ChatGPT o Cursor. Y el modelo es intercambiable: elegimos Sonnet frente a Opus con nuestras propias evals, y podemos repetir esa decisión cuando salga algo mejor.

¿Por qué no function-calling metido en cada agente?

Porque duplicaríamos el contrato en cada agente y framework. Con MCP el catálogo, los permisos y la auditoría viven una sola vez en el servidor, y nos sirve gratis para operar nosotros desde Claude Desktop o Cursor.

¿Qué falta, siendo honestos?

Tres cosas: la validación de inputs es declarativa (el schema guía al modelo; falta validación central de runtime), el rate limit es global por IP (100/min; falta límite por identidad), y los scopes por tool están declarados pero aún no se aplican. Están en la lista de abajo.

Dónde vive cada cosa

PiezaPlataformaNota
Backend de tools (chat, Fabián, MCP)RailwayNestJS · deploy por GitHub Actions con health-check del commit
Panel de CXVerceltools.vivla.com · entornos develop/prod
Concierge (Lola)RailwayMastra en contenedor Node 22 · healthcheck /api/agents
Atlas (API + MCP)Railwaymcp.atlas.vivla.com · documentos del negocio + fichas por casa
Web de Atlasatlas.vivla.comAstro + Starlight, tras Cloudflare Access (login Vivla)
Datos operativosSupabase (Postgres)canales, tickets, avisos, encuestas, eventos de dominio
Índice de AtlasPostgres + pgvectortsvector (léxico) + HNSW (vectorial) en la misma tabla
EmbeddingsCloudflare Workers AIbge-m3, 1024 dims
Chat (transporte)Streamcanales, presencia, webhooks hacia el backend
Jobs y syncsWindmillmotor de avisos (cada 30 s), eventos derivados diarios
IdentidadAuth0personas, apps y agentes; OAuth 2.1 + PKCE en el MCP
ObservabilidadLangfuse · PostHogtraza LLM con versión de prompt · métricas y feature flags

Técnicas que usamos (y por qué)

Salida estructurada · el LLM devuelve JSON validado, no prosa que parsear Tool-grounding de solo-lectura · responde consultando datos reales, sin poder escribir Supervisor + especialistas · Lola dirige y delega; cada agente hace poco y bien Tool-search semántico · busca la herramienta adecuada en vez de cargar 88 RAG híbrido (BM25 + vector + RRF) · léxico y semántico fusionados en SQL Rerank con juez barato · Haiku reordena candidatos por céntimos Guardarraíles + kill-switch · anti prompt-injection y bloqueo de escrituras en test Human-in-the-loop · la IA propone, la persona decide qué llega al cliente Evals con jueces LLM · dataset dorado + 4 dimensiones antes de cada cambio Feature flags fail-closed · si la config no responde, la IA no actúa Trazabilidad total · cada llamada LLM en Langfuse con versión de prompt Identidad delegada (OBO) · el agente actúa «en nombre de» un usuario concreto Reindexado incremental · Atlas solo re-embebe lo que cambió (hash de contenido)

Huecos honestos (lo siguiente)

  • El Fabián de producción no tiene evals automáticas. El harness de calidad vive en concierge; falta llevarlo al copiloto que ya atiende de verdad.
  • La identidad delegada corre en modo local. El código del token-exchange está completo; falta dar de alta la app en Auth0.
  • Los canales de reserva se crean y archivan a mano. La regla (30 días antes / +2 después) existe, pero es un clic humano: automatizarla es barato y quita una rutina diaria.
  • El MCP valida permisos, no inputs. El schema de cada tool guía al modelo, pero falta una capa central de validación de runtime; hoy cada tool se defiende sola.
  • Rate limit global, no por identidad. 100 peticiones/minuto por IP para todo el backend; falta límite y cuota por token/agente.
  • Doc del catálogo desfasada. La wiki dice 91 tools; el código tiene 98 (y manda). Toca regenerarla, y revisar si propose_ticket debe exponerse fuera del chat interno.

← volver a la web de Alma el plan de despliegue →